blob: 3ea5806f0141c6f4cce17273f64dac1a30eb2ed1 [file] [log] [blame]
Ed Tanous7045c8d2017-04-03 10:04:37 -07001#pragma once
2
Ed Tanous1abe55e2018-09-05 08:30:59 -07003#include "nlohmann/json.hpp"
4
Ed Tanous7045c8d2017-04-03 10:04:37 -07005#include <cstdint>
6#include <cstring>
7#include <functional>
Ed Tanousa29c9972018-11-29 15:54:32 -08008#include <regex>
Ed Tanous7045c8d2017-04-03 10:04:37 -07009#include <stdexcept>
10#include <string>
11#include <tuple>
Ed Tanous7045c8d2017-04-03 10:04:37 -070012
Ed Tanous1abe55e2018-09-05 08:30:59 -070013namespace crow
14{
15namespace black_magic
16{
17struct OutOfRange
18{
19 OutOfRange(unsigned /*pos*/, unsigned /*length*/)
20 {
21 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070022};
Ed Tanous1abe55e2018-09-05 08:30:59 -070023constexpr unsigned requiresInRange(unsigned i, unsigned len)
24{
25 return i >= len ? throw OutOfRange(i, len) : i;
Ed Tanous7045c8d2017-04-03 10:04:37 -070026}
27
Ed Tanous1abe55e2018-09-05 08:30:59 -070028class ConstStr
29{
30 const char* const beginPtr;
31 unsigned sizeUint;
Ed Tanous7045c8d2017-04-03 10:04:37 -070032
Ed Tanous1abe55e2018-09-05 08:30:59 -070033 public:
34 template <unsigned N>
35 constexpr ConstStr(const char (&arr)[N]) : beginPtr(arr), sizeUint(N - 1)
36 {
37 static_assert(N >= 1, "not a string literal");
38 }
39 constexpr char operator[](unsigned i) const
40 {
41 return requiresInRange(i, sizeUint), beginPtr[i];
42 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070043
Ed Tanous1abe55e2018-09-05 08:30:59 -070044 constexpr operator const char*() const
45 {
46 return beginPtr;
47 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070048
Ed Tanous1abe55e2018-09-05 08:30:59 -070049 constexpr const char* begin() const
50 {
51 return beginPtr;
52 }
53 constexpr const char* end() const
54 {
55 return beginPtr + sizeUint;
56 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070057
Ed Tanous1abe55e2018-09-05 08:30:59 -070058 constexpr unsigned size() const
59 {
60 return sizeUint;
61 }
Ed Tanous7045c8d2017-04-03 10:04:37 -070062};
63
Ed Tanous1abe55e2018-09-05 08:30:59 -070064constexpr unsigned findClosingTag(ConstStr s, unsigned p)
65{
66 return s[p] == '>' ? p : findClosingTag(s, p + 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -070067}
68
Ed Tanous1abe55e2018-09-05 08:30:59 -070069constexpr bool isValid(ConstStr s, unsigned i = 0, int f = 0)
70{
71 return i == s.size()
72 ? f == 0
73 : f < 0 || f >= 2
74 ? false
75 : s[i] == '<' ? isValid(s, i + 1, f + 1)
76 : s[i] == '>' ? isValid(s, i + 1, f - 1)
77 : isValid(s, i + 1, f);
Ed Tanous7045c8d2017-04-03 10:04:37 -070078}
79
Ed Tanous1abe55e2018-09-05 08:30:59 -070080constexpr bool isEquP(const char* a, const char* b, unsigned n)
81{
82 return *a == 0 && *b == 0 && n == 0
83 ? true
84 : (*a == 0 || *b == 0)
85 ? false
86 : n == 0 ? true
87 : *a != *b ? false : isEquP(a + 1, b + 1, n - 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -070088}
89
Ed Tanous55c7b7a2018-05-22 15:27:24 -070090constexpr bool isEquN(ConstStr a, unsigned ai, ConstStr b, unsigned bi,
Ed Tanous1abe55e2018-09-05 08:30:59 -070091 unsigned n)
92{
93 return ai + n > a.size() || bi + n > b.size()
94 ? false
95 : n == 0 ? true
96 : a[ai] != b[bi] ? false
97 : isEquN(a, ai + 1, b, bi + 1, n - 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -070098}
99
Ed Tanous1abe55e2018-09-05 08:30:59 -0700100constexpr bool isInt(ConstStr s, unsigned i)
101{
102 return isEquN(s, i, "<int>", 0, 5);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700103}
104
Ed Tanous1abe55e2018-09-05 08:30:59 -0700105constexpr bool isUint(ConstStr s, unsigned i)
106{
107 return isEquN(s, i, "<uint>", 0, 6);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700108}
109
Ed Tanous1abe55e2018-09-05 08:30:59 -0700110constexpr bool isFloat(ConstStr s, unsigned i)
111{
112 return isEquN(s, i, "<float>", 0, 7) || isEquN(s, i, "<double>", 0, 8);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700113}
114
Ed Tanous1abe55e2018-09-05 08:30:59 -0700115constexpr bool isStr(ConstStr s, unsigned i)
116{
117 return isEquN(s, i, "<str>", 0, 5) || isEquN(s, i, "<string>", 0, 8);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700118}
119
Ed Tanous1abe55e2018-09-05 08:30:59 -0700120constexpr bool isPath(ConstStr s, unsigned i)
121{
122 return isEquN(s, i, "<path>", 0, 6);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700123}
Ed Tanous3dac7492017-08-02 13:46:20 -0700124
Ed Tanous69509012019-10-24 16:53:05 -0700125template <typename T> constexpr int getParameterTag()
Ed Tanous1abe55e2018-09-05 08:30:59 -0700126{
Ed Tanous69509012019-10-24 16:53:05 -0700127 if constexpr (std::is_same_v<int, T>)
128 {
129 return 1;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700130 }
Ed Tanous69509012019-10-24 16:53:05 -0700131 if constexpr (std::is_same_v<char, T>)
132 {
133 return 1;
134 }
135 if constexpr (std::is_same_v<short, T>)
136 {
137 return 1;
138 }
139 if constexpr (std::is_same_v<long, T>)
140 {
141 return 1;
142 }
143 if constexpr (std::is_same_v<long long, T>)
144 {
145 return 1;
146 }
147 if constexpr (std::is_same_v<unsigned int, T>)
148 {
149 return 2;
150 }
151 if constexpr (std::is_same_v<unsigned char, T>)
152 {
153 return 2;
154 }
155 if constexpr (std::is_same_v<unsigned short, T>)
156 {
157 return 2;
158 }
159 if constexpr (std::is_same_v<unsigned long, T>)
160 {
161 return 2;
162 }
163 if constexpr (std::is_same_v<unsigned long long, T>)
164 {
165 return 2;
166 }
167 if constexpr (std::is_same_v<double, T>)
168 {
169 return 3;
170 }
171 if constexpr (std::is_same_v<std::string, T>)
172 {
173 return 4;
174 }
175 return 0;
176}
177
Ed Tanous1abe55e2018-09-05 08:30:59 -0700178template <typename... Args> struct compute_parameter_tag_from_args_list;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700179
Ed Tanous1abe55e2018-09-05 08:30:59 -0700180template <> struct compute_parameter_tag_from_args_list<>
181{
Ed Tanous69509012019-10-24 16:53:05 -0700182 static constexpr int value = 0;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700183};
184
185template <typename Arg, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700186struct compute_parameter_tag_from_args_list<Arg, Args...>
187{
Ed Tanous69509012019-10-24 16:53:05 -0700188 static constexpr int subValue =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700189 compute_parameter_tag_from_args_list<Args...>::value;
Ed Tanous69509012019-10-24 16:53:05 -0700190 static constexpr int value =
191 getParameterTag<typename std::decay<Arg>::type>()
192 ? subValue * 6 + getParameterTag<typename std::decay<Arg>::type>()
Ed Tanous1abe55e2018-09-05 08:30:59 -0700193 : subValue;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700194};
195
Ed Tanous1abe55e2018-09-05 08:30:59 -0700196static inline bool isParameterTagCompatible(uint64_t a, uint64_t b)
197{
198 if (a == 0)
199 {
200 return b == 0;
201 }
202 if (b == 0)
203 {
204 return a == 0;
205 }
Ed Tanous271584a2019-07-09 16:24:22 -0700206 uint64_t sa = a % 6;
207 uint64_t sb = a % 6;
Ed Tanous1abe55e2018-09-05 08:30:59 -0700208 if (sa == 5)
209 {
210 sa = 4;
211 }
212 if (sb == 5)
213 {
214 sb = 4;
215 }
216 if (sa != sb)
217 {
218 return false;
219 }
220 return isParameterTagCompatible(a / 6, b / 6);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700221}
222
Ed Tanous1abe55e2018-09-05 08:30:59 -0700223static inline unsigned findClosingTagRuntime(const char* s, unsigned p)
224{
225 return s[p] == 0 ? throw std::runtime_error("unmatched tag <")
226 : s[p] == '>' ? p : findClosingTagRuntime(s, p + 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700227}
228
Ed Tanous1abe55e2018-09-05 08:30:59 -0700229static inline uint64_t getParameterTagRuntime(const char* s, unsigned p = 0)
230{
231 return s[p] == 0
232 ? 0
233 : s[p] == '<'
234 ? (std::strncmp(s + p, "<int>", 5) == 0
235 ? getParameterTagRuntime(
236 s, findClosingTagRuntime(s, p)) *
237 6 +
238 1
239 : std::strncmp(s + p, "<uint>", 6) == 0
240 ? getParameterTagRuntime(
241 s, findClosingTagRuntime(s, p)) *
242 6 +
243 2
244 : (std::strncmp(s + p, "<float>", 7) == 0 ||
245 std::strncmp(s + p, "<double>", 8) == 0)
246 ? getParameterTagRuntime(
247 s, findClosingTagRuntime(s, p)) *
248 6 +
249 3
250 : (std::strncmp(s + p, "<str>", 5) ==
251 0 ||
252 std::strncmp(s + p, "<string>", 8) ==
253 0)
254 ? getParameterTagRuntime(
255 s, findClosingTagRuntime(
256 s, p)) *
257 6 +
258 4
259 : std::strncmp(s + p, "<path>",
260 6) == 0
261 ? getParameterTagRuntime(
262 s,
263 findClosingTagRuntime(
264 s, p)) *
265 6 +
266 5
267 : throw std::runtime_error(
268 "invalid parameter "
269 "type"))
270 : getParameterTagRuntime(s, p + 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700271}
Ed Tanous3dac7492017-08-02 13:46:20 -0700272
Ed Tanous1abe55e2018-09-05 08:30:59 -0700273constexpr uint64_t get_parameter_tag(ConstStr s, unsigned p = 0)
274{
275 return p == s.size()
276 ? 0
277 : s[p] == '<'
278 ? (isInt(s, p)
279 ? get_parameter_tag(s, findClosingTag(s, p)) * 6 + 1
280 : isUint(s, p)
281 ? get_parameter_tag(s, findClosingTag(s, p)) *
282 6 +
283 2
284 : isFloat(s, p)
285 ? get_parameter_tag(
286 s, findClosingTag(s, p)) *
287 6 +
288 3
289 : isStr(s, p)
290 ? get_parameter_tag(
291 s, findClosingTag(s, p)) *
292 6 +
293 4
294 : isPath(s, p)
295 ? get_parameter_tag(
296 s, findClosingTag(
297 s, p)) *
298 6 +
299 5
300 : throw std::runtime_error(
301 "invalid parameter "
302 "type"))
303 : get_parameter_tag(s, p + 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700304}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700305
Ed Tanous1abe55e2018-09-05 08:30:59 -0700306template <typename... T> struct S
307{
308 template <typename U> using push = S<U, T...>;
309 template <typename U> using push_back = S<T..., U>;
310 template <template <typename... Args> class U> using rebind = U<T...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700311};
Ed Tanous1abe55e2018-09-05 08:30:59 -0700312template <typename F, typename Set> struct CallHelper;
313template <typename F, typename... Args> struct CallHelper<F, S<Args...>>
314{
315 template <typename F1, typename... Args1,
316 typename = decltype(std::declval<F1>()(std::declval<Args1>()...))>
317 static char __test(int);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700318
Ed Tanous1abe55e2018-09-05 08:30:59 -0700319 template <typename...> static int __test(...);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700320
Ed Tanous1abe55e2018-09-05 08:30:59 -0700321 static constexpr bool value = sizeof(__test<F, Args...>(0)) == sizeof(char);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700322};
323
Ed Tanous271584a2019-07-09 16:24:22 -0700324template <uint64_t N> struct SingleTagToType
Ed Tanous1abe55e2018-09-05 08:30:59 -0700325{
Ed Tanous7045c8d2017-04-03 10:04:37 -0700326};
327
Ed Tanous1abe55e2018-09-05 08:30:59 -0700328template <> struct SingleTagToType<1>
329{
330 using type = int64_t;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700331};
332
Ed Tanous1abe55e2018-09-05 08:30:59 -0700333template <> struct SingleTagToType<2>
334{
335 using type = uint64_t;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700336};
337
Ed Tanous1abe55e2018-09-05 08:30:59 -0700338template <> struct SingleTagToType<3>
339{
340 using type = double;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700341};
342
Ed Tanous1abe55e2018-09-05 08:30:59 -0700343template <> struct SingleTagToType<4>
344{
345 using type = std::string;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700346};
347
Ed Tanous1abe55e2018-09-05 08:30:59 -0700348template <> struct SingleTagToType<5>
349{
350 using type = std::string;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700351};
352
Ed Tanous1abe55e2018-09-05 08:30:59 -0700353template <uint64_t Tag> struct Arguments
354{
355 using subarguments = typename Arguments<Tag / 6>::type;
356 using type = typename subarguments::template push<
357 typename SingleTagToType<Tag % 6>::type>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700358};
359
Ed Tanous1abe55e2018-09-05 08:30:59 -0700360template <> struct Arguments<0>
361{
362 using type = S<>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700363};
364
Ed Tanous1abe55e2018-09-05 08:30:59 -0700365template <typename... T> struct LastElementType
366{
367 using type =
368 typename std::tuple_element<sizeof...(T) - 1, std::tuple<T...>>::type;
369};
370
371template <> struct LastElementType<>
372{
373};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700374
375// from
376// http://stackoverflow.com/questions/13072359/c11-compile-time-array-with-logarithmic-evaluation-depth
Ed Tanous1abe55e2018-09-05 08:30:59 -0700377template <class T> using Invoke = typename T::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700378
Ed Tanous1abe55e2018-09-05 08:30:59 -0700379template <unsigned...> struct Seq
380{
381 using type = Seq;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700382};
383
Ed Tanous1abe55e2018-09-05 08:30:59 -0700384template <class S1, class S2> struct concat;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700385
386template <unsigned... I1, unsigned... I2>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700387struct concat<Seq<I1...>, Seq<I2...>> : Seq<I1..., (sizeof...(I1) + I2)...>
388{
389};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700390
Ed Tanous1abe55e2018-09-05 08:30:59 -0700391template <class S1, class S2> using Concat = Invoke<concat<S1, S2>>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700392
Ed Tanous271584a2019-07-09 16:24:22 -0700393template <size_t N> struct gen_seq;
394template <size_t N> using GenSeq = Invoke<gen_seq<N>>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700395
Ed Tanous271584a2019-07-09 16:24:22 -0700396template <size_t N> struct gen_seq : Concat<GenSeq<N / 2>, GenSeq<N - N / 2>>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700397{
398};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700399
Ed Tanous1abe55e2018-09-05 08:30:59 -0700400template <> struct gen_seq<0> : Seq<>
401{
402};
403template <> struct gen_seq<1> : Seq<0>
404{
405};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700406
Ed Tanous1abe55e2018-09-05 08:30:59 -0700407template <typename Seq, typename Tuple> struct PopBackHelper;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700408
Ed Tanous1abe55e2018-09-05 08:30:59 -0700409template <unsigned... N, typename Tuple> struct PopBackHelper<Seq<N...>, Tuple>
410{
411 template <template <typename... Args> class U>
412 using rebind = U<typename std::tuple_element<N, Tuple>::type...>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700413};
414
415template <typename... T>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700416struct PopBack //: public PopBackHelper<typename
417 // gen_seq<sizeof...(T)-1>::type, std::tuple<T...>>
Ed Tanous7045c8d2017-04-03 10:04:37 -0700418{
Ed Tanous1abe55e2018-09-05 08:30:59 -0700419 template <template <typename... Args> class U>
420 using rebind =
Ed Tanous271584a2019-07-09 16:24:22 -0700421 typename PopBackHelper<typename gen_seq<sizeof...(T) - 1UL>::type,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700422 std::tuple<T...>>::template rebind<U>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700423};
424
Ed Tanous1abe55e2018-09-05 08:30:59 -0700425template <> struct PopBack<>
426{
427 template <template <typename... Args> class U> using rebind = U<>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700428};
429
430// from
431// http://stackoverflow.com/questions/2118541/check-if-c0x-parameter-pack-contains-a-type
Ed Tanous1abe55e2018-09-05 08:30:59 -0700432template <typename Tp, typename... List> struct Contains : std::true_type
433{
434};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700435
436template <typename Tp, typename Head, typename... Rest>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700437struct Contains<Tp, Head, Rest...>
Ed Tanous7045c8d2017-04-03 10:04:37 -0700438 : std::conditional<std::is_same<Tp, Head>::value, std::true_type,
Ed Tanous1abe55e2018-09-05 08:30:59 -0700439 Contains<Tp, Rest...>>::type
440{
Ed Tanous7045c8d2017-04-03 10:04:37 -0700441};
442
Ed Tanous1abe55e2018-09-05 08:30:59 -0700443template <typename Tp> struct Contains<Tp> : std::false_type
444{
445};
446
447template <typename T> struct EmptyContext
448{
449};
450
451template <typename T> struct promote
452{
453 using type = T;
454};
455
456#define BMCWEB_INTERNAL_PROMOTE_TYPE(t1, t2) \
457 template <> struct promote<t1> \
458 { \
459 using type = t2; \
460 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700461
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700462BMCWEB_INTERNAL_PROMOTE_TYPE(char, int64_t);
463BMCWEB_INTERNAL_PROMOTE_TYPE(short, int64_t);
464BMCWEB_INTERNAL_PROMOTE_TYPE(int, int64_t);
465BMCWEB_INTERNAL_PROMOTE_TYPE(long, int64_t);
466BMCWEB_INTERNAL_PROMOTE_TYPE(long long, int64_t);
467BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned char, uint64_t);
468BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned short, uint64_t);
469BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned int, uint64_t);
470BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned long, uint64_t);
471BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned long long, uint64_t);
472BMCWEB_INTERNAL_PROMOTE_TYPE(float, double);
473#undef BMCWEB_INTERNAL_PROMOTE_TYPE
Ed Tanous7045c8d2017-04-03 10:04:37 -0700474
Ed Tanous1abe55e2018-09-05 08:30:59 -0700475template <typename T> using promote_t = typename promote<T>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700476
Ed Tanous1abe55e2018-09-05 08:30:59 -0700477} // namespace black_magic
Ed Tanous7045c8d2017-04-03 10:04:37 -0700478
Ed Tanous1abe55e2018-09-05 08:30:59 -0700479namespace detail
480{
Ed Tanous7045c8d2017-04-03 10:04:37 -0700481
482template <class T, std::size_t N, class... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700483struct GetIndexOfElementFromTupleByTypeImpl
484{
Ed Tanous271584a2019-07-09 16:24:22 -0700485 static constexpr std::size_t value = N;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700486};
487
488template <class T, std::size_t N, class... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700489struct GetIndexOfElementFromTupleByTypeImpl<T, N, T, Args...>
490{
Ed Tanous271584a2019-07-09 16:24:22 -0700491 static constexpr std::size_t value = N;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700492};
493
494template <class T, std::size_t N, class U, class... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700495struct GetIndexOfElementFromTupleByTypeImpl<T, N, U, Args...>
496{
Ed Tanous271584a2019-07-09 16:24:22 -0700497 static constexpr std::size_t value =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700498 GetIndexOfElementFromTupleByTypeImpl<T, N + 1, Args...>::value;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700499};
500
Ed Tanous1abe55e2018-09-05 08:30:59 -0700501} // namespace detail
Ed Tanous7045c8d2017-04-03 10:04:37 -0700502
Ed Tanous1abe55e2018-09-05 08:30:59 -0700503namespace utility
504{
505template <class T, class... Args> T& getElementByType(std::tuple<Args...>& t)
506{
507 return std::get<
508 detail::GetIndexOfElementFromTupleByTypeImpl<T, 0, Args...>::value>(t);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700509}
510
Ed Tanous1abe55e2018-09-05 08:30:59 -0700511template <typename T> struct function_traits;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700512
Ed Tanous7045c8d2017-04-03 10:04:37 -0700513template <typename T>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700514struct function_traits : public function_traits<decltype(&T::operator())>
515{
516 using parent_t = function_traits<decltype(&T::operator())>;
517 static const size_t arity = parent_t::arity;
518 using result_type = typename parent_t::result_type;
519 template <size_t i> using arg = typename parent_t::template arg<i>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700520};
Ed Tanous3dac7492017-08-02 13:46:20 -0700521
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700522template <typename ClassType, typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700523struct function_traits<r (ClassType::*)(Args...) const>
524{
525 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700526
Ed Tanous1abe55e2018-09-05 08:30:59 -0700527 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700528
Ed Tanous1abe55e2018-09-05 08:30:59 -0700529 template <size_t i>
530 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700531};
532
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700533template <typename ClassType, typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700534struct function_traits<r (ClassType::*)(Args...)>
535{
536 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700537
Ed Tanous1abe55e2018-09-05 08:30:59 -0700538 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700539
Ed Tanous1abe55e2018-09-05 08:30:59 -0700540 template <size_t i>
541 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700542};
543
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700544template <typename r, typename... Args>
Ed Tanous1abe55e2018-09-05 08:30:59 -0700545struct function_traits<std::function<r(Args...)>>
546{
547 static const size_t arity = sizeof...(Args);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700548
Ed Tanous1abe55e2018-09-05 08:30:59 -0700549 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700550
Ed Tanous1abe55e2018-09-05 08:30:59 -0700551 template <size_t i>
552 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700553};
554
555inline static std::string base64encode(
Ed Tanousb01bf292019-03-25 19:25:26 +0000556 const char* data, size_t size,
Ed Tanous7045c8d2017-04-03 10:04:37 -0700557 const char* key =
Ed Tanous1abe55e2018-09-05 08:30:59 -0700558 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")
559{
560 std::string ret;
561 ret.resize((size + 2) / 3 * 4);
562 auto it = ret.begin();
563 while (size >= 3)
564 {
Ed Tanous271584a2019-07-09 16:24:22 -0700565 *it++ = key[(static_cast<unsigned char>(*data) & 0xFC) >> 2];
566 unsigned char h = static_cast<unsigned char>(
567 (static_cast<unsigned char>(*data++) & 0x03u) << 4u);
568 *it++ = key[h | ((static_cast<unsigned char>(*data) & 0xF0) >> 4)];
569 h = static_cast<unsigned char>(
570 (static_cast<unsigned char>(*data++) & 0x0F) << 2u);
571 *it++ = key[h | ((static_cast<unsigned char>(*data) & 0xC0) >> 6)];
572 *it++ = key[static_cast<unsigned char>(*data++) & 0x3F];
Ed Tanous7045c8d2017-04-03 10:04:37 -0700573
Ed Tanous1abe55e2018-09-05 08:30:59 -0700574 size -= 3;
575 }
576 if (size == 1)
577 {
Ed Tanous271584a2019-07-09 16:24:22 -0700578 *it++ = key[(static_cast<unsigned char>(*data) & 0xFC) >> 2];
579 unsigned char h = static_cast<unsigned char>(
580 (static_cast<unsigned char>(*data++) & 0x03) << 4u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700581 *it++ = key[h];
582 *it++ = '=';
583 *it++ = '=';
584 }
585 else if (size == 2)
586 {
Ed Tanous271584a2019-07-09 16:24:22 -0700587 *it++ = key[(static_cast<unsigned char>(*data) & 0xFC) >> 2];
588 unsigned char h = static_cast<unsigned char>(
589 (static_cast<unsigned char>(*data++) & 0x03) << 4u);
590 *it++ = key[h | ((static_cast<unsigned char>(*data) & 0xF0) >> 4)];
591 h = static_cast<unsigned char>(
592 (static_cast<unsigned char>(*data++) & 0x0F) << 2u);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700593 *it++ = key[h];
594 *it++ = '=';
595 }
596 return ret;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700597}
598
Ed Tanousb01bf292019-03-25 19:25:26 +0000599inline static std::string base64encodeUrlsafe(const char* data, size_t size)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700600{
601 return base64encode(
602 data, size,
603 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_");
Ed Tanous7045c8d2017-04-03 10:04:37 -0700604}
605
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100606// TODO this is temporary and should be deleted once base64 is refactored out of
607// crow
Ed Tanous39e77502019-03-04 17:35:53 -0800608inline bool base64Decode(const std::string_view input, std::string& output)
Ed Tanous1abe55e2018-09-05 08:30:59 -0700609{
Ed Tanous271584a2019-07-09 16:24:22 -0700610 static const char nop = static_cast<char>(-1);
Ed Tanous1abe55e2018-09-05 08:30:59 -0700611 // See note on encoding_data[] in above function
612 static const char decodingData[] = {
613 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
614 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
615 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
616 nop, 62, nop, nop, nop, 63, 52, 53, 54, 55, 56, 57, 58, 59,
617 60, 61, nop, nop, nop, nop, nop, nop, nop, 0, 1, 2, 3, 4,
618 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
619 19, 20, 21, 22, 23, 24, 25, nop, nop, nop, nop, nop, nop, 26,
620 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
621 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, nop, nop, nop,
622 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
623 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
624 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
625 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
626 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
627 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
628 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
629 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
630 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
631 nop, nop, nop, nop};
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100632
Ed Tanous1abe55e2018-09-05 08:30:59 -0700633 size_t inputLength = input.size();
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100634
Ed Tanous1abe55e2018-09-05 08:30:59 -0700635 // allocate space for output string
636 output.clear();
637 output.reserve(((inputLength + 2) / 3) * 4);
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100638
Ed Tanous1abe55e2018-09-05 08:30:59 -0700639 // for each 4-bytes sequence from the input, extract 4 6-bits sequences by
640 // droping first two bits
641 // and regenerate into 3 8-bits sequences
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100642
Ed Tanous1abe55e2018-09-05 08:30:59 -0700643 for (size_t i = 0; i < inputLength; i++)
644 {
645 char base64code0;
646 char base64code1;
647 char base64code2 = 0; // initialized to 0 to suppress warnings
648 char base64code3;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100649
Ed Tanous1abe55e2018-09-05 08:30:59 -0700650 base64code0 = decodingData[static_cast<int>(input[i])]; // NOLINT
651 if (base64code0 == nop)
652 { // non base64 character
653 return false;
654 }
655 if (!(++i < inputLength))
656 { // we need at least two input bytes for first
657 // byte output
658 return false;
659 }
660 base64code1 = decodingData[static_cast<int>(input[i])]; // NOLINT
661 if (base64code1 == nop)
662 { // non base64 character
663 return false;
664 }
665 output +=
666 static_cast<char>((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100667
Ed Tanous1abe55e2018-09-05 08:30:59 -0700668 if (++i < inputLength)
669 {
670 char c = input[i];
671 if (c == '=')
672 { // padding , end of input
673 return (base64code1 & 0x0f) == 0;
674 }
675 base64code2 = decodingData[static_cast<int>(input[i])]; // NOLINT
676 if (base64code2 == nop)
677 { // non base64 character
678 return false;
679 }
680 output += static_cast<char>(((base64code1 << 4) & 0xf0) |
681 ((base64code2 >> 2) & 0x0f));
682 }
683
684 if (++i < inputLength)
685 {
686 char c = input[i];
687 if (c == '=')
688 { // padding , end of input
689 return (base64code2 & 0x03) == 0;
690 }
691 base64code3 = decodingData[static_cast<int>(input[i])]; // NOLINT
692 if (base64code3 == nop)
693 { // non base64 character
694 return false;
695 }
696 output +=
697 static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3));
698 }
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100699 }
700
Ed Tanous1abe55e2018-09-05 08:30:59 -0700701 return true;
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100702}
703
Ed Tanousa29c9972018-11-29 15:54:32 -0800704inline void escapeHtml(std::string& data)
705{
706 std::string buffer;
Ed Tanousb01bf292019-03-25 19:25:26 +0000707 // less than 5% of characters should be larger, so reserve a buffer of the
Ed Tanousa29c9972018-11-29 15:54:32 -0800708 // right size
Ed Tanous271584a2019-07-09 16:24:22 -0700709 buffer.reserve(data.size() * 11 / 10);
Ed Tanousa29c9972018-11-29 15:54:32 -0800710 for (size_t pos = 0; pos != data.size(); ++pos)
711 {
712 switch (data[pos])
713 {
714 case '&':
715 buffer.append("&amp;");
716 break;
717 case '\"':
718 buffer.append("&quot;");
719 break;
720 case '\'':
721 buffer.append("&apos;");
722 break;
723 case '<':
724 buffer.append("&lt;");
725 break;
726 case '>':
727 buffer.append("&gt;");
728 break;
729 default:
730 buffer.append(&data[pos], 1);
731 break;
732 }
733 }
734 data.swap(buffer);
735}
736
737inline void convertToLinks(std::string& s)
738{
739 const static std::regex r{"(&quot;@odata\\.((id)|(Context))&quot;[ \\n]*:[ "
740 "\\n]*)(&quot;((?!&quot;).*)&quot;)"};
741 s = std::regex_replace(s, r, "$1<a href=\"$6\">$5</a>");
742
743 const static std::regex nextLink{
744 "(&quot;Members@odata\\.((nextLink))&quot;[ \\n]*:[ "
745 "\\n]*)(&quot;((?!&quot;).*)&quot;)"};
746 s = std::regex_replace(s, nextLink, "$1<a href=\"$5\">$4</a>");
Jason M. Billsc6c91d42019-03-29 13:09:34 -0700747
748 const static std::regex uri{"(&quot;((Uri))&quot;[ \\n]*:[ "
749 "\\n]*)(&quot;((?!&quot;).*)&quot;)"};
750 s = std::regex_replace(s, uri, "$1<a href=\"$5\">$4</a>");
Ed Tanousa29c9972018-11-29 15:54:32 -0800751}
752
Andrew Geisslercb92c032018-08-17 07:56:14 -0700753/**
754 * Method returns Date Time information according to requested format
755 *
756 * @param[in] time time in second since the Epoch
757 *
758 * @return Date Time according to requested format
759 */
760inline std::string getDateTime(const std::time_t& time)
761{
762 std::array<char, 128> dateTime;
763 std::string redfishDateTime("0000-00-00T00:00:00Z00:00");
764
765 if (std::strftime(dateTime.begin(), dateTime.size(), "%FT%T%z",
766 std::localtime(&time)))
767 {
768 // insert the colon required by the ISO 8601 standard
769 redfishDateTime = std::string(dateTime.data());
770 redfishDateTime.insert(redfishDateTime.end() - 2, ':');
771 }
772
773 return redfishDateTime;
774}
775
776inline std::string dateTimeNow()
777{
778 std::time_t time = std::time(nullptr);
779 return getDateTime(time);
780}
781
Ed Tanous1abe55e2018-09-05 08:30:59 -0700782} // namespace utility
783} // namespace crow