blob: 026c3cf9fa964c6c27b958ae7684dca1649c67e2 [file] [log] [blame]
Patrick Williams51103a42016-07-20 17:43:38 -05001#pragma once
2
3#include <tuple>
4#include <string>
5#include <vector>
6
7#include <sdbusplus/utility/type_traits.hpp>
8
9namespace sdbusplus
10{
11
12namespace message
13{
14
15namespace types
16{
17
18/** @fn type_id()
19 * @brief Get a tuple containing the dbus type character(s) for a
20 * sequence of C++ types.
21 *
22 * @tparam ...Args - Types to get the type_id sequence for.
23 * @returns A tuple of characters representing the dbus types for ...Args.
24 *
25 * The design uses a tuple because a tuple can, at compile-time, be easily
26 * appended to, concatenated, and converted to an array (representing a
27 * C-string). There are other options to create a string of characters but
28 * they require runtime processing and memory allocation. By performing all
29 * options at compile-time the use of type-deduced dbus strings is equal to
30 * the cost of hard-coded type string constants.
31 */
32template <typename ...Args> constexpr auto type_id();
33
34namespace details
35{
36
Patrick Williams930460c2016-07-20 17:52:55 -050037/** @brief Convert some C++ types to others for 'type_id' conversion purposes.
38 *
39 * Similar C++ types have the same dbus type-id, so 'downcast' those to limit
40 * duplication in type_id template specializations.
41 *
42 * 1. Remove references.
43 * 2. Remove 'const' and 'volatile'.
44 * 3. Convert 'char[N]' to 'char*'.
45 */
46template <typename T> struct type_id_downcast
47{
48 using type = typename utility::array_to_ptr_t<
49 char, std::remove_cv_t<std::remove_reference_t<T>>>;
50};
51
52template <typename T> using type_id_downcast_t =
53 typename type_id_downcast<T>::type;
54
Patrick Williams51103a42016-07-20 17:43:38 -050055/** @struct undefined_type_id
56 * @brief Special type indicating no dbus-type_id is defined for a C++ type.
57 */
58struct undefined_type_id
59{
60 /** An empty tuple indicating no type-characters. */
61 // We want this to be tuple so that we can use operations like
62 // tuple_cat on it without cascading compile failures. There is a
63 // static_assert in type_id_single to ensure this is never used, but to
64 // keep the compile failures as clean as possible.
65 static constexpr auto value = std::make_tuple();
66};
67
68/** @struct tuple_type_id
69 * @brief Special type indicating a tuple of dbus-type_id's.
70 *
71 * @tparam C1 - The first dbus type character character.
72 * @tparam ...C - The remaining sequence of dbus type characters.
73 *
74 * A tuple_type_id must be one or more characters. The C1 template param
75 * ensures at least one is present.
76 */
77template <char C1, char... C> struct tuple_type_id
78{
79
80 /* This version check is required because a fix for auto is in 5.2+.
81 * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66421
82 */
83 /** A tuple containing the type-characters. */
84#if (__GNUC__ > 5) || (__GNUC__ == 5 && (__GNUC_MINOR__ >= 2))
85 static constexpr auto value = std::make_tuple(C1, C...);
86#else
87 static constexpr decltype(std::make_tuple(C1, C...)) value =
88 std::make_tuple(C1, C...);
89#endif
90};
91
92/** @fn type_id_single()
93 * @brief Get a tuple containing the dbus type character(s) for a C++ type.
94 *
95 * @tparam T - The type to get the dbus type character(s) for.
96 */
97template <typename T> constexpr auto& type_id_single();
98
99/** @fn type_id_multiple()
100 * @brief Get a tuple containing the dbus type characters for a sequence of
101 * C++ types.
102 *
103 * @tparam T - The first type to get the dbus type character(s) for.
104 * @tparam ...Args - The remaining types.
105 */
106template <typename T, typename ...Args> constexpr auto type_id_multiple();
107
108/** @struct type_id
109 * @brief Defined dbus type tuple for a C++ type.
110 *
111 * @tparam T - C++ type.
112 *
113 * Struct must have a 'value' tuple containing the dbus type. The default
114 * value is an empty tuple, which can be used to indicate
115 */
116template <typename T> struct type_id : public undefined_type_id {};
117 // Specializations for built-in types.
118template <> struct type_id<bool> : tuple_type_id<'b'> {};
119template <> struct type_id<uint8_t> : tuple_type_id<'y'> {};
120// int8_t isn't supported by dbus.
121template <> struct type_id<uint16_t> : tuple_type_id<'q'> {};
122template <> struct type_id<int16_t> : tuple_type_id<'n'> {};
123template <> struct type_id<uint32_t> : tuple_type_id<'u'> {};
124template <> struct type_id<int32_t> : tuple_type_id<'i'> {};
125template <> struct type_id<uint64_t> : tuple_type_id<'t'> {};
126template <> struct type_id<int64_t> : tuple_type_id<'x'> {};
127// float isn't supported by dbus.
128template <> struct type_id<double> : tuple_type_id<'d'> {};
129template <> struct type_id<const char*> : tuple_type_id<'s'> {};
130template <> struct type_id<char*> : tuple_type_id<'s'> {};
131template <> struct type_id<std::string> : tuple_type_id<'s'> {};
132
Patrick Williams930460c2016-07-20 17:52:55 -0500133template <typename T> struct type_id<std::vector<T>>
134{
135 static constexpr auto value = std::tuple_cat(
136 tuple_type_id<'a'>::value,
137 type_id<type_id_downcast_t<T>>::value);
138};
139
Patrick Williams51103a42016-07-20 17:43:38 -0500140template <typename T> constexpr auto& type_id_single()
141{
142 static_assert(!std::is_base_of<undefined_type_id, type_id<T>>::value,
143 "No dbus type conversion provided for type.");
144 return type_id<T>::value;
145}
146
147template <typename T, typename ...Args> constexpr auto type_id_multiple()
148{
149 return std::tuple_cat(type_id_single<T>(),
150 type_id_single<Args>()...);
151}
152
Patrick Williams51103a42016-07-20 17:43:38 -0500153} // namespace details
154
155template <typename ...Args> constexpr auto type_id()
156{
157 return std::tuple_cat(
158 details::type_id_multiple<details::type_id_downcast_t<Args>...>(),
159 std::make_tuple('\0') /* null terminator for C-string */ );
160}
161
162} // namespace types
163
164} // namespace message
165
166} // namespace sdbusplus