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 
20 #include <cstdint>
21 #include <map>
22 #include <memory>
23 #include <string>
24 #include <tuple>
25 #include <type_traits>
26 #include <vector>
27 
28 namespace ipmi
29 {
30 
31 // forward declare Context and Request for NonIpmiArgsCount
32 struct Context;
33 namespace message
34 {
35 struct Request;
36 }
37 
38 namespace utility
39 {
40 
41 /**
42  * @brief a utility template to extract the args after N from a tuple
43  *
44  * Given a tuple of type <T1, ...TN, TN+1, ...>, provide type = tuple<TN+1,...>
45  */
46 template <std::size_t N, typename FirstArg, typename... Rest>
47 struct StripFirstArgs;
48 
49 template <std::size_t N, typename FirstArg, typename... Rest>
50 struct StripFirstArgs<N, std::tuple<FirstArg, Rest...>> :
51     StripFirstArgs<N - 1, std::tuple<Rest...>>
52 {};
53 
54 template <typename FirstArg, typename... Rest>
55 struct StripFirstArgs<0, std::tuple<FirstArg, Rest...>>
56 {
57     using type = std::tuple<FirstArg, Rest...>;
58 };
59 template <std::size_t N>
60 struct StripFirstArgs<N, std::tuple<>>
61 {
62     using type = std::tuple<>;
63 };
64 
65 /**
66  * @brief a utility template to extract the remaining args from a tuple
67  *
68  * Given a tuple of type <T1, T2,...>, provide type = tuple<T2,...>
69  */
70 template <typename T>
71 using StripFirstArg = StripFirstArgs<1, T>;
72 
73 /**
74  * @brief a utility template to find the number of non-special arguments
75  *
76  * Given a tuple, count the args after the first special args
77  */
78 template <typename FirstArg, typename... Rest>
79 struct NonIpmiArgsCount;
80 
81 template <>
82 struct NonIpmiArgsCount<std::tuple<>>
83 {
84     constexpr static std::size_t size()
85     {
86         return 0;
87     }
88 };
89 template <typename FirstArg, typename... OtherArgs>
90 struct NonIpmiArgsCount<std::tuple<FirstArg, OtherArgs...>>
91 {
sizeipmi::utility::NonIpmiArgsCount92     constexpr static std::size_t size()
93     {
94         if constexpr (std::is_same<
95                           FirstArg,
96                           std::shared_ptr<ipmi::message::Request>>::value ||
97                       std::is_same<FirstArg,
98                                    std::shared_ptr<ipmi::Context>>::value ||
99                       std::is_same<FirstArg, boost::asio::yield_context>::value)
100         {
101             return 1 + NonIpmiArgsCount<std::tuple<OtherArgs...>>::size();
102         }
103         else
104         {
105             return NonIpmiArgsCount<std::tuple<OtherArgs...>>::size();
106         }
107     }
108 };
109 
110 /**
111  * @brief a utility template to find the type of the first arg
112  *
113  * Given a tuple, provide the type of the first element
114  */
115 template <typename T>
116 struct GetFirstArg
117 {
118     using type = void;
119 };
120 
121 template <typename FirstArg, typename... Rest>
122 struct GetFirstArg<std::tuple<FirstArg, Rest...>>
123 {
124     using type = FirstArg;
125 };
126 
127 /**
128  * @brief a utility template to remove const and reference from types
129  *
130  * Given a tuple, provide the type of the first element
131  */
132 template <typename... Args>
133 struct DecayTuple;
134 
135 template <typename... Args>
136 struct DecayTuple<std::tuple<Args...>>
137 {
138     using type = std::tuple<typename std::decay<Args>::type...>;
139 };
140 
141 /** @brief Convert T[N] to T* if is_same<Tbase,T>
142  *
143  *  @tparam Tbase - The base type expected.
144  *  @tparam T - The type to convert.
145  */
146 template <typename Tbase, typename T>
147 using ArrayToPtr_t = typename std::conditional_t<
148     std::is_array<T>::value,
149     std::conditional_t<std::is_same<Tbase, std::remove_extent_t<T>>::value,
150                        std::add_pointer_t<std::remove_extent_t<T>>, T>,
151     T>;
152 
153 /** @brief Downcast type submembers.
154  *
155  * This allows std::tuple and std::pair members to be downcast to their
156  * non-const, nonref versions of themselves to limit duplication in template
157  * specializations
158  *
159  *  1. Remove references.
160  *  2. Remove 'const' and 'volatile'.
161  *  3. Convert 'char[N]' to 'char*'.
162  */
163 template <typename T>
164 struct DowncastMembers
165 {
166     using type = T;
167 };
168 template <typename... Args>
169 struct DowncastMembers<std::pair<Args...>>
170 {
171     using type = std::pair<utility::ArrayToPtr_t<
172         char, std::remove_cv_t<std::remove_reference_t<Args>>>...>;
173 };
174 
175 template <typename... Args>
176 struct DowncastMembers<std::tuple<Args...>>
177 {
178     using type = std::tuple<utility::ArrayToPtr_t<
179         char, std::remove_cv_t<std::remove_reference_t<Args>>>...>;
180 };
181 
182 template <typename T>
183 using DowncastMembers_t = typename DowncastMembers<T>::type;
184 
185 /** @brief Convert some C++ types to others for 'TypeId' conversion purposes.
186  *
187  *  Similar C++ types have the same dbus type-id, so 'downcast' those to limit
188  *  duplication in TypeId template specializations.
189  *
190  *  1. Remove references.
191  *  2. Remove 'const' and 'volatile'.
192  *  3. Convert 'char[N]' to 'char*'.
193  */
194 template <typename T>
195 struct TypeIdDowncast
196 {
197     using type = utility::ArrayToPtr_t<
198         char, DowncastMembers_t<std::remove_cv_t<std::remove_reference_t<T>>>>;
199 };
200 
201 template <typename T>
202 using TypeIdDowncast_t = typename TypeIdDowncast<T>::type;
203 
204 /** @brief Detect if a type is a tuple
205  *
206  */
207 template <typename>
208 struct is_tuple : std::false_type
209 {};
210 
211 template <typename... T>
212 struct is_tuple<std::tuple<T...>> : std::true_type
213 {};
214 
215 /** @brief used for static_assert in a constexpr-if else statement
216  */
217 template <typename T>
218 struct dependent_false : std::false_type
219 {};
220 
221 } // namespace utility
222 
223 } // namespace ipmi
224