blob: d709b6f6c4940057803cbb1e0b93c2fff5a3289c [file] [log] [blame]
#pragma once
#include <sdbusplus/message/native_types.hpp>
#include <cstring>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <utility>
namespace phosphor
{
namespace inventory
{
namespace manager
{
/** @struct MakeVariantVisitor
* @brief Return a variant if the visited type is a possible variant type.
*
* @tparam V - The desired variant type.
*/
template <typename V>
struct MakeVariantVisitor
{
/** @struct Make
* @brief Return variant visitor.
*
* @tparam T - The variant type to return.
* @tparam Arg - The type being visited in the source variant.
* @tparam Enable - Overload resolution removal.
*/
template <typename T, typename Arg, typename Enable = void>
struct Make
{
static auto make(Arg&& /* arg */)
{
throw std::runtime_error(
std::string("Invalid conversion in MakeVariantVisitor::") +
__PRETTY_FUNCTION__);
return T();
}
};
/** @struct Make
* @brief Return variant visitor.
*
* struct Make specialization if Arg is in T (int -> variant<int, char>),
* but not a string. Strings are used to represent enumerations by
* sdbusplus, so they are attempted in the following specialization.
*/
template <typename T, typename Arg>
struct Make<
T, Arg,
typename std::enable_if_t<
!std::is_same_v<std::string,
std::remove_cv_t<std::remove_reference_t<Arg>>> &&
std::is_convertible_v<Arg, T>>>
{
static auto make(Arg&& arg)
{
return T(std::forward<Arg>(arg));
}
};
/** @struct Make
* @brief Return variant visitor.
*
* struct Make specialization if Arg is a string.Strings might
* be convertable (for ex. to enumerations) using underlying sdbusplus
* routines, so give them an attempt. In case the string is not convertible
* to an enumeration, sdbusplus::message::convert_from_string will return a
* string back anyway.
*/
template <typename T, typename Arg>
struct Make<
T, Arg,
typename std::enable_if_t<
std::is_same_v<std::string,
std::remove_cv_t<std::remove_reference_t<Arg>>> &&
sdbusplus::message::has_convert_from_string_v<T>>>
{
static auto make(Arg&& arg) -> T
{
auto r = sdbusplus::message::convert_from_string<T>(
std::forward<Arg>(arg));
if (r)
{
return *r;
}
throw std::runtime_error(
std::string("Invalid conversion in MakeVariantVisitor::") +
__PRETTY_FUNCTION__);
return {};
}
};
/** @brief Make variant visitor. */
template <typename Arg>
auto operator()(Arg&& arg) const
{
return Make<V, Arg>::make(arg);
}
};
/** @brief Convert variants with different contained types.
*
* @tparam V - The desired variant type.
* @tparam Arg - The source variant type.
*
* @param[in] v - The source variant.
* @returns - The converted variant.
*/
template <typename V, typename Arg>
auto convertVariant(Arg&& v)
{
return std::visit(MakeVariantVisitor<V>(), v);
}
/** @struct CompareFirst
* @brief std::pair binary comparison adapter.
*
* Adapt a binary comparison function to a comparison of
* the first pair element.
*
* @tparam Compare - The function object type being adapted.
*/
template <typename Compare>
struct CompareFirst
{
/** @brief Construct a CompareFirst adapter.
*
* @param[in] c - The function object being adapted.
*/
explicit CompareFirst(Compare&& c) : compare(std::forward<Compare>(c)) {}
/** @brief Compare two pairs adapter.
*
* @tparam L1 - First pair first_type.
* @tparam L2 - First pair second_type.
* @tparam R1 - Second pair first_type, convertible to L1.
* @tparam R2 - Second pair second_type.
*
* @param[in] l - The first pair.
* @param[in] r - The second pair.
*
* @returns - The result of the comparison.
*/
template <typename L1, typename L2, typename R1, typename R2>
bool operator()(const std::pair<L1, L2>& l,
const std::pair<R1, R2>& r) const
{
return compare(l.first, r.first);
}
/** @brief Compare one pair adapter.
*
* @tparam L1 - Pair first_type.
* @tparam L2 - Pair second_type.
* @tparam R - Convertible to L1 for comparison.
*
* @param[in] l - The pair.
* @param[in] r - To be compared to l.first.
*
* @returns - The result of the comparison.
*/
template <typename L1, typename L2, typename R>
bool operator()(const std::pair<L1, L2>& l, const R& r) const
{
return compare(l.first, r);
}
/** @brief Compare one pair adapter.
*
* @tparam L - Convertible to R1 for comparison.
* @tparam R1 - Pair first_type.
* @tparam R2 - Pair second_type.
*
* @param[in] l - To be compared to r.first.
* @param[in] r - The pair.
*
* @returns - The result of the comparison.
*/
template <typename L, typename R1, typename R2>
bool operator()(const L& l, const std::pair<R1, R2>& r) const
{
return compare(l, r.first);
}
/* @brief The function being adapted. */
Compare compare;
};
/* @brief Implicit template instantation wrapper for CompareFirst. */
template <typename Compare>
CompareFirst<Compare> compareFirst(Compare&& c)
{
return CompareFirst<Compare>(std::forward<Compare>(c));
}
/** @struct RelPathCompare
* @brief Compare two strings after removing an optional prefix.
*/
struct RelPathCompare
{
/** @brief Construct a RelPathCompare comparison functor.
*
* @param[in] p - The prefix to check for and remove.
*/
explicit RelPathCompare(const char* p) : prefix(p) {}
/** @brief Check for the prefix and remove if found.
*
* @param[in] s - The string to check for and remove prefix from.
*/
auto relPath(const std::string& s) const
{
if (s.find(prefix) == 0)
{
return s.substr(strlen(prefix));
}
return s;
}
/** @brief Comparison method.
*
* @param[in] l - The first string.
* @param[in] r - The second string.
*
* @returns - The result of the comparison.
*/
bool operator()(const std::string& l, const std::string& r) const
{
return relPath(l) < relPath(r);
}
/* The path prefix to remove when comparing two paths. */
const char* prefix;
};
} // namespace manager
} // namespace inventory
} // namespace phosphor
// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4