1 #pragma once
2 
3 #include <sdbusplus/message/native_types.hpp>
4 
5 #include <cstring>
6 #include <stdexcept>
7 #include <string>
8 #include <type_traits>
9 #include <utility>
10 
11 namespace phosphor
12 {
13 namespace inventory
14 {
15 namespace manager
16 {
17 /** @struct MakeVariantVisitor
18  *  @brief Return a variant if the visited type is a possible variant type.
19  *
20  *  @tparam V - The desired variant type.
21  */
22 template <typename V>
23 struct MakeVariantVisitor
24 {
25     /** @struct Make
26      *  @brief Return variant visitor.
27      *
28      *  @tparam T - The variant type to return.
29      *  @tparam Arg - The type being visited in the source variant.
30      *  @tparam Enable - Overload resolution removal.
31      */
32     template <typename T, typename Arg, typename Enable = void>
33     struct Make
34     {
makephosphor::inventory::manager::MakeVariantVisitor::Make35         static auto make(Arg&& /* arg */)
36         {
37             throw std::runtime_error(
38                 std::string("Invalid conversion in MakeVariantVisitor::") +
39                 __PRETTY_FUNCTION__);
40             return T();
41         }
42     };
43 
44     /** @struct Make
45      *  @brief Return variant visitor.
46      *
47      *  struct Make specialization if Arg is in T (int -> variant<int, char>),
48      *  but not a string. Strings are used to represent enumerations by
49      *  sdbusplus, so they are attempted in the following specialization.
50      */
51     template <typename T, typename Arg>
52     struct Make<
53         T, Arg,
54         typename std::enable_if_t<
55             !std::is_same_v<std::string,
56                             std::remove_cv_t<std::remove_reference_t<Arg>>> &&
57             std::is_convertible_v<Arg, T>>>
58     {
makephosphor::inventory::manager::MakeVariantVisitor::Make59         static auto make(Arg&& arg)
60         {
61             return T(std::forward<Arg>(arg));
62         }
63     };
64 
65     /** @struct Make
66      *  @brief Return variant visitor.
67      *
68      *  struct Make specialization if Arg is a string.Strings might
69      *  be convertable (for ex. to enumerations) using underlying sdbusplus
70      *  routines, so give them an attempt. In case the string is not convertible
71      *  to an enumeration, sdbusplus::message::convert_from_string will return a
72      *  string back anyway.
73      */
74     template <typename T, typename Arg>
75     struct Make<
76         T, Arg,
77         typename std::enable_if_t<
78             std::is_same_v<std::string,
79                            std::remove_cv_t<std::remove_reference_t<Arg>>> &&
80             sdbusplus::message::has_convert_from_string_v<T>>>
81     {
makephosphor::inventory::manager::MakeVariantVisitor::Make82         static auto make(Arg&& arg) -> T
83         {
84             auto r = sdbusplus::message::convert_from_string<T>(
85                 std::forward<Arg>(arg));
86             if (r)
87             {
88                 return *r;
89             }
90 
91             throw std::runtime_error(
92                 std::string("Invalid conversion in MakeVariantVisitor::") +
93                 __PRETTY_FUNCTION__);
94 
95             return {};
96         }
97     };
98 
99     /** @brief Make variant visitor.  */
100     template <typename Arg>
operator ()phosphor::inventory::manager::MakeVariantVisitor101     auto operator()(Arg&& arg) const
102     {
103         return Make<V, Arg>::make(arg);
104     }
105 };
106 
107 /** @brief Convert variants with different contained types.
108  *
109  *  @tparam V - The desired variant type.
110  *  @tparam Arg - The source variant type.
111  *
112  *  @param[in] v - The source variant.
113  *  @returns - The converted variant.
114  */
115 template <typename V, typename Arg>
convertVariant(Arg && v)116 auto convertVariant(Arg&& v)
117 {
118     return std::visit(MakeVariantVisitor<V>(), v);
119 }
120 
121 /** @struct CompareFirst
122  *  @brief std::pair binary comparison adapter.
123  *
124  *  Adapt a binary comparison function to a comparison of
125  *  the first pair element.
126  *
127  *  @tparam Compare - The function object type being adapted.
128  */
129 template <typename Compare>
130 struct CompareFirst
131 {
132     /** @brief Construct a CompareFirst adapter.
133      *
134      *  @param[in] c - The function object being adapted.
135      */
CompareFirstphosphor::inventory::manager::CompareFirst136     explicit CompareFirst(Compare&& c) : compare(std::forward<Compare>(c)) {}
137 
138     /** @brief Compare two pairs adapter.
139      *
140      *  @tparam L1 - First pair first_type.
141      *  @tparam L2 - First pair second_type.
142      *  @tparam R1 - Second pair first_type, convertible to L1.
143      *  @tparam R2 - Second pair second_type.
144      *
145      *  @param[in] l - The first pair.
146      *  @param[in] r - The second pair.
147      *
148      *  @returns - The result of the comparison.
149      */
150     template <typename L1, typename L2, typename R1, typename R2>
operator ()phosphor::inventory::manager::CompareFirst151     bool operator()(const std::pair<L1, L2>& l,
152                     const std::pair<R1, R2>& r) const
153     {
154         return compare(l.first, r.first);
155     }
156 
157     /** @brief Compare one pair adapter.
158      *
159      *  @tparam L1 - Pair first_type.
160      *  @tparam L2 - Pair second_type.
161      *  @tparam R - Convertible to L1 for comparison.
162      *
163      *  @param[in] l - The pair.
164      *  @param[in] r - To be compared to l.first.
165      *
166      *  @returns - The result of the comparison.
167      */
168     template <typename L1, typename L2, typename R>
operator ()phosphor::inventory::manager::CompareFirst169     bool operator()(const std::pair<L1, L2>& l, const R& r) const
170     {
171         return compare(l.first, r);
172     }
173 
174     /** @brief Compare one pair adapter.
175      *
176      *  @tparam L - Convertible to R1 for comparison.
177      *  @tparam R1 - Pair first_type.
178      *  @tparam R2 - Pair second_type.
179      *
180      *  @param[in] l - To be compared to r.first.
181      *  @param[in] r - The pair.
182      *
183      *  @returns - The result of the comparison.
184      */
185     template <typename L, typename R1, typename R2>
operator ()phosphor::inventory::manager::CompareFirst186     bool operator()(const L& l, const std::pair<R1, R2>& r) const
187     {
188         return compare(l, r.first);
189     }
190 
191     /* @brief The function being adapted. */
192     Compare compare;
193 };
194 
195 /* @brief Implicit template instantation wrapper for CompareFirst. */
196 template <typename Compare>
compareFirst(Compare && c)197 CompareFirst<Compare> compareFirst(Compare&& c)
198 {
199     return CompareFirst<Compare>(std::forward<Compare>(c));
200 }
201 
202 /** @struct RelPathCompare
203  *  @brief Compare two strings after removing an optional prefix.
204  */
205 struct RelPathCompare
206 {
207     /** @brief Construct a RelPathCompare comparison functor.
208      *
209      *  @param[in] p - The prefix to check for and remove.
210      */
RelPathComparephosphor::inventory::manager::RelPathCompare211     explicit RelPathCompare(const char* p) : prefix(p) {}
212 
213     /** @brief Check for the prefix and remove if found.
214      *
215      *  @param[in] s - The string to check for and remove prefix from.
216      */
relPathphosphor::inventory::manager::RelPathCompare217     auto relPath(const std::string& s) const
218     {
219         if (s.find(prefix) == 0)
220         {
221             return s.substr(strlen(prefix));
222         }
223 
224         return s;
225     }
226 
227     /** @brief Comparison method.
228      *
229      *  @param[in] l - The first string.
230      *  @param[in] r - The second string.
231      *
232      *  @returns - The result of the comparison.
233      */
operator ()phosphor::inventory::manager::RelPathCompare234     bool operator()(const std::string& l, const std::string& r) const
235     {
236         return relPath(l) < relPath(r);
237     }
238 
239     /* The path prefix to remove when comparing two paths. */
240     const char* prefix;
241 };
242 } // namespace manager
243 } // namespace inventory
244 } // namespace phosphor
245 
246 // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
247