1 /**
2  * Copyright © 2018 Intel Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #pragma once
17 #include <boost/asio/spawn.hpp>
18 #include <boost/callable_traits.hpp>
19 #include <cstdint>
20 #include <map>
21 #include <memory>
22 #include <string>
23 #include <tuple>
24 #include <type_traits>
25 #include <vector>
26 
27 namespace ipmi
28 {
29 
30 struct Context;
31 
32 namespace utility
33 {
34 
35 /**
36  * @brief a utility template to extract the args after N from a tuple
37  *
38  * Given a tuple of type <T1, ...TN, TN+1, ...>, provide type = tuple<TN+1,...>
39  */
40 template <std::size_t N, typename FirstArg, typename... Rest>
41 struct StripFirstArgs;
42 
43 template <std::size_t N, typename FirstArg, typename... Rest>
44 struct StripFirstArgs<N, std::tuple<FirstArg, Rest...>>
45     : StripFirstArgs<N - 1, std::tuple<Rest...>>
46 {
47 };
48 
49 template <typename FirstArg, typename... Rest>
50 struct StripFirstArgs<0, std::tuple<FirstArg, Rest...>>
51 {
52     using type = std::tuple<FirstArg, Rest...>;
53 };
54 template <std::size_t N>
55 struct StripFirstArgs<N, std::tuple<>>
56 {
57     using type = std::tuple<>;
58 };
59 
60 /**
61  * @brief a utility template to extract the remaining args from a tuple
62  *
63  * Given a tuple of type <T1, T2,...>, provide type = tuple<T2,...>
64  */
65 template <typename T>
66 using StripFirstArg = StripFirstArgs<1, T>;
67 
68 /**
69  * @brief a utility template to find the number of non-special arguments
70  *
71  * Given a tuple, count the args after the first special args
72  */
73 template <typename FirstArg, typename... Rest>
74 struct NonIpmiArgsCount;
75 
76 template <>
77 struct NonIpmiArgsCount<std::tuple<>>
78 {
79     constexpr static std::size_t size()
80     {
81         return 0;
82     }
83 };
84 template <typename FirstArg, typename... OtherArgs>
85 struct NonIpmiArgsCount<std::tuple<FirstArg, OtherArgs...>>
86 {
87     constexpr static std::size_t size()
88     {
89         if constexpr (std::is_same<FirstArg, ipmi::Context>::value ||
90                       std::is_same<FirstArg, boost::asio::yield_context>::value)
91         {
92             return 1 + NonIpmiArgsCount<std::tuple<OtherArgs...>>::size();
93         }
94         else
95         {
96             return NonIpmiArgsCount<std::tuple<OtherArgs...>>::size();
97         }
98     }
99 };
100 
101 /**
102  * @brief a utility template to find the type of the first arg
103  *
104  * Given a tuple, provide the type of the first element
105  */
106 template <typename T>
107 struct GetFirstArg
108 {
109     using type = void;
110 };
111 
112 template <typename FirstArg, typename... Rest>
113 struct GetFirstArg<std::tuple<FirstArg, Rest...>>
114 {
115     using type = FirstArg;
116 };
117 
118 /**
119  * @brief a utility template to remove const and reference from types
120  *
121  * Given a tuple, provide the type of the first element
122  */
123 template <typename... Args>
124 struct DecayTuple;
125 
126 template <typename... Args>
127 struct DecayTuple<std::tuple<Args...>>
128 {
129     using type = std::tuple<typename std::decay<Args>::type...>;
130 };
131 
132 /** @brief Convert T[N] to T* if is_same<Tbase,T>
133  *
134  *  @tparam Tbase - The base type expected.
135  *  @tparam T - The type to convert.
136  */
137 template <typename Tbase, typename T>
138 using ArrayToPtr_t = typename std::conditional_t<
139     std::is_array<T>::value,
140     std::conditional_t<std::is_same<Tbase, std::remove_extent_t<T>>::value,
141                        std::add_pointer_t<std::remove_extent_t<T>>, T>,
142     T>;
143 
144 /** @brief Downcast type submembers.
145  *
146  * This allows std::tuple and std::pair members to be downcast to their
147  * non-const, nonref versions of themselves to limit duplication in template
148  * specializations
149  *
150  *  1. Remove references.
151  *  2. Remove 'const' and 'volatile'.
152  *  3. Convert 'char[N]' to 'char*'.
153  */
154 template <typename T>
155 struct DowncastMembers
156 {
157     using type = T;
158 };
159 template <typename... Args>
160 struct DowncastMembers<std::pair<Args...>>
161 {
162     using type = std::pair<utility::ArrayToPtr_t<
163         char, std::remove_cv_t<std::remove_reference_t<Args>>>...>;
164 };
165 
166 template <typename... Args>
167 struct DowncastMembers<std::tuple<Args...>>
168 {
169     using type = std::tuple<utility::ArrayToPtr_t<
170         char, std::remove_cv_t<std::remove_reference_t<Args>>>...>;
171 };
172 
173 template <typename T>
174 using DowncastMembers_t = typename DowncastMembers<T>::type;
175 
176 /** @brief Convert some C++ types to others for 'TypeId' conversion purposes.
177  *
178  *  Similar C++ types have the same dbus type-id, so 'downcast' those to limit
179  *  duplication in TypeId template specializations.
180  *
181  *  1. Remove references.
182  *  2. Remove 'const' and 'volatile'.
183  *  3. Convert 'char[N]' to 'char*'.
184  */
185 template <typename T>
186 struct TypeIdDowncast
187 {
188     using type = utility::ArrayToPtr_t<
189         char, DowncastMembers_t<std::remove_cv_t<std::remove_reference_t<T>>>>;
190 };
191 
192 template <typename T>
193 using TypeIdDowncast_t = typename TypeIdDowncast<T>::type;
194 
195 /** @brief Detect if a type is a tuple
196  *
197  */
198 template <typename>
199 struct is_tuple : std::false_type
200 {
201 };
202 
203 template <typename... T>
204 struct is_tuple<std::tuple<T...>> : std::true_type
205 {
206 };
207 
208 } // namespace utility
209 
210 } // namespace ipmi
211