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