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     {
35         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      */
49     template <typename T, typename Arg>
50     struct Make<T, Arg,
51                 typename std::enable_if_t<std::is_convertible_v<Arg, T>>>
52     {
53         static auto make(Arg&& arg)
54         {
55             return T(std::forward<Arg>(arg));
56         }
57     };
58 
59     /** @struct Make
60      *  @brief Return variant visitor.
61      *
62      *  struct Make specialization if Arg is a string, but not otherwise
63      *  directly convertable by C++ conversion constructors.  Strings might
64      *  be convertable using underlying sdbusplus routines, so give them an
65      *  attempt.
66      */
67     template <typename T, typename Arg>
68     struct Make<
69         T, Arg,
70         typename std::enable_if_t<
71             !std::is_convertible_v<Arg, T> &&
72             std::is_same_v<std::string,
73                            std::remove_cv_t<std::remove_reference_t<Arg>>> &&
74             sdbusplus::message::has_convert_from_string_v<T>>>
75     {
76         static auto make(Arg&& arg) -> T
77         {
78             auto r = sdbusplus::message::convert_from_string<T>(
79                 std::forward<Arg>(arg));
80             if (r)
81             {
82                 return *r;
83             }
84 
85             throw std::runtime_error(
86                 std::string("Invalid conversion in MakeVariantVisitor::") +
87                 __PRETTY_FUNCTION__);
88 
89             return {};
90         }
91     };
92 
93     /** @brief Make variant visitor.  */
94     template <typename Arg>
95     auto operator()(Arg&& arg) const
96     {
97         return Make<V, Arg>::make(arg);
98     }
99 };
100 
101 /** @brief Convert variants with different contained types.
102  *
103  *  @tparam V - The desired variant type.
104  *  @tparam Arg - The source variant type.
105  *
106  *  @param[in] v - The source variant.
107  *  @returns - The converted variant.
108  */
109 template <typename V, typename Arg>
110 auto convertVariant(Arg&& v)
111 {
112     return std::visit(MakeVariantVisitor<V>(), v);
113 }
114 
115 /** @struct CompareFirst
116  *  @brief std::pair binary comparison adapter.
117  *
118  *  Adapt a binary comparison function to a comparison of
119  *  the first pair element.
120  *
121  *  @tparam Compare - The function object type being adapted.
122  */
123 template <typename Compare>
124 struct CompareFirst
125 {
126     /** @brief Construct a CompareFirst adapter.
127      *
128      *  @param[in] c - The function object being adapted.
129      */
130     explicit CompareFirst(Compare&& c) : compare(std::forward<Compare>(c))
131     {}
132 
133     /** @brief Compare two pairs adapter.
134      *
135      *  @tparam L1 - First pair first_type.
136      *  @tparam L2 - First pair second_type.
137      *  @tparam R1 - Second pair first_type, convertible to L1.
138      *  @tparam R2 - Second pair second_type.
139      *
140      *  @param[in] l - The first pair.
141      *  @param[in] r - The second pair.
142      *
143      *  @returns - The result of the comparison.
144      */
145     template <typename L1, typename L2, typename R1, typename R2>
146     bool operator()(const std::pair<L1, L2>& l,
147                     const std::pair<R1, R2>& r) const
148     {
149         return compare(l.first, r.first);
150     }
151 
152     /** @brief Compare one pair adapter.
153      *
154      *  @tparam L1 - Pair first_type.
155      *  @tparam L2 - Pair second_type.
156      *  @tparam R - Convertible to L1 for comparison.
157      *
158      *  @param[in] l - The pair.
159      *  @param[in] r - To be compared to l.first.
160      *
161      *  @returns - The result of the comparison.
162      */
163     template <typename L1, typename L2, typename R>
164     bool operator()(const std::pair<L1, L2>& l, const R& r) const
165     {
166         return compare(l.first, r);
167     }
168 
169     /** @brief Compare one pair adapter.
170      *
171      *  @tparam L - Convertible to R1 for comparison.
172      *  @tparam R1 - Pair first_type.
173      *  @tparam R2 - Pair second_type.
174      *
175      *  @param[in] l - To be compared to r.first.
176      *  @param[in] r - The pair.
177      *
178      *  @returns - The result of the comparison.
179      */
180     template <typename L, typename R1, typename R2>
181     bool operator()(const L& l, const std::pair<R1, R2>& r) const
182     {
183         return compare(l, r.first);
184     }
185 
186     /* @brief The function being adapted. */
187     Compare compare;
188 };
189 
190 /* @brief Implicit template instantation wrapper for CompareFirst. */
191 template <typename Compare>
192 CompareFirst<Compare> compareFirst(Compare&& c)
193 {
194     return CompareFirst<Compare>(std::forward<Compare>(c));
195 }
196 
197 /** @struct RelPathCompare
198  *  @brief Compare two strings after removing an optional prefix.
199  */
200 struct RelPathCompare
201 {
202     /** @brief Construct a RelPathCompare comparison functor.
203      *
204      *  @param[in] p - The prefix to check for and remove.
205      */
206     explicit RelPathCompare(const char* p) : prefix(p)
207     {}
208 
209     /** @brief Check for the prefix and remove if found.
210      *
211      *  @param[in] s - The string to check for and remove prefix from.
212      */
213     auto relPath(const std::string& s) const
214     {
215         if (s.find(prefix) == 0)
216         {
217             return s.substr(strlen(prefix));
218         }
219 
220         return s;
221     }
222 
223     /** @brief Comparison method.
224      *
225      *  @param[in] l - The first string.
226      *  @param[in] r - The second string.
227      *
228      *  @returns - The result of the comparison.
229      */
230     bool operator()(const std::string& l, const std::string& r) const
231     {
232         return relPath(l) < relPath(r);
233     }
234 
235     /* The path prefix to remove when comparing two paths. */
236     const char* prefix;
237 };
238 } // namespace manager
239 } // namespace inventory
240 } // namespace phosphor
241 
242 // vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
243