blob: d2557b0af5d3891b05472a28b90236b8922f3c30 [file] [log] [blame]
Ed Tanous7045c8d2017-04-03 10:04:37 -07001#pragma once
2
3#include <cstdint>
4#include <cstring>
5#include <functional>
6#include <stdexcept>
7#include <string>
8#include <tuple>
Ed Tanouse0d918b2018-03-27 17:41:04 -07009#include "nlohmann/json.hpp"
Ed Tanous1e439872018-05-18 11:48:52 -070010#include <boost/utility/string_view.hpp>
Ed Tanous7045c8d2017-04-03 10:04:37 -070011
12namespace crow {
13namespace black_magic {
Ed Tanous7045c8d2017-04-03 10:04:37 -070014struct OutOfRange {
15 OutOfRange(unsigned /*pos*/, unsigned /*length*/) {}
16};
Ed Tanous55c7b7a2018-05-22 15:27:24 -070017constexpr unsigned requiresInRange(unsigned i, unsigned len) {
Ed Tanous7045c8d2017-04-03 10:04:37 -070018 return i >= len ? throw OutOfRange(i, len) : i;
19}
20
Ed Tanous55c7b7a2018-05-22 15:27:24 -070021class ConstStr {
22 const char* const beginPtr;
23 unsigned sizeUint;
Ed Tanous7045c8d2017-04-03 10:04:37 -070024
25 public:
26 template <unsigned N>
Ed Tanous55c7b7a2018-05-22 15:27:24 -070027 constexpr ConstStr(const char (&arr)[N]) : beginPtr(arr), sizeUint(N - 1) {
Ed Tanous7045c8d2017-04-03 10:04:37 -070028 static_assert(N >= 1, "not a string literal");
29 }
30 constexpr char operator[](unsigned i) const {
Ed Tanous55c7b7a2018-05-22 15:27:24 -070031 return requiresInRange(i, sizeUint), beginPtr[i];
Ed Tanous7045c8d2017-04-03 10:04:37 -070032 }
33
Ed Tanous55c7b7a2018-05-22 15:27:24 -070034 constexpr operator const char*() const { return beginPtr; }
Ed Tanous7045c8d2017-04-03 10:04:37 -070035
Ed Tanous55c7b7a2018-05-22 15:27:24 -070036 constexpr const char* begin() const { return beginPtr; }
37 constexpr const char* end() const { return beginPtr + sizeUint; }
Ed Tanous7045c8d2017-04-03 10:04:37 -070038
Ed Tanous55c7b7a2018-05-22 15:27:24 -070039 constexpr unsigned size() const { return sizeUint; }
Ed Tanous7045c8d2017-04-03 10:04:37 -070040};
41
Ed Tanous55c7b7a2018-05-22 15:27:24 -070042constexpr unsigned findClosingTag(ConstStr s, unsigned p) {
43 return s[p] == '>' ? p : findClosingTag(s, p + 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -070044}
45
Ed Tanous55c7b7a2018-05-22 15:27:24 -070046constexpr bool isValid(ConstStr s, unsigned i = 0, int f = 0) {
Ed Tanous3dac7492017-08-02 13:46:20 -070047 return i == s.size()
48 ? f == 0
49 : f < 0 || f >= 2
50 ? false
Ed Tanous55c7b7a2018-05-22 15:27:24 -070051 : s[i] == '<' ? isValid(s, i + 1, f + 1)
52 : s[i] == '>' ? isValid(s, i + 1, f - 1)
53 : isValid(s, i + 1, f);
Ed Tanous7045c8d2017-04-03 10:04:37 -070054}
55
Ed Tanous55c7b7a2018-05-22 15:27:24 -070056constexpr bool isEquP(const char* a, const char* b, unsigned n) {
Ed Tanous7045c8d2017-04-03 10:04:37 -070057 return *a == 0 && *b == 0 && n == 0
58 ? true
59 : (*a == 0 || *b == 0)
60 ? false
Ed Tanous3dac7492017-08-02 13:46:20 -070061 : n == 0 ? true
Ed Tanous55c7b7a2018-05-22 15:27:24 -070062 : *a != *b ? false : isEquP(a + 1, b + 1, n - 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -070063}
64
Ed Tanous55c7b7a2018-05-22 15:27:24 -070065constexpr bool isEquN(ConstStr a, unsigned ai, ConstStr b, unsigned bi,
66 unsigned n) {
Ed Tanous7045c8d2017-04-03 10:04:37 -070067 return ai + n > a.size() || bi + n > b.size()
68 ? false
Ed Tanous3dac7492017-08-02 13:46:20 -070069 : n == 0 ? true
70 : a[ai] != b[bi] ? false
Ed Tanous55c7b7a2018-05-22 15:27:24 -070071 : isEquN(a, ai + 1, b, bi + 1, n - 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -070072}
73
Ed Tanous55c7b7a2018-05-22 15:27:24 -070074constexpr bool isInt(ConstStr s, unsigned i) {
75 return isEquN(s, i, "<int>", 0, 5);
Ed Tanous7045c8d2017-04-03 10:04:37 -070076}
77
Ed Tanous55c7b7a2018-05-22 15:27:24 -070078constexpr bool isUint(ConstStr s, unsigned i) {
79 return isEquN(s, i, "<uint>", 0, 6);
Ed Tanous7045c8d2017-04-03 10:04:37 -070080}
81
Ed Tanous55c7b7a2018-05-22 15:27:24 -070082constexpr bool isFloat(ConstStr s, unsigned i) {
83 return isEquN(s, i, "<float>", 0, 7) || isEquN(s, i, "<double>", 0, 8);
Ed Tanous7045c8d2017-04-03 10:04:37 -070084}
85
Ed Tanous55c7b7a2018-05-22 15:27:24 -070086constexpr bool isStr(ConstStr s, unsigned i) {
87 return isEquN(s, i, "<str>", 0, 5) || isEquN(s, i, "<string>", 0, 8);
Ed Tanous7045c8d2017-04-03 10:04:37 -070088}
89
Ed Tanous55c7b7a2018-05-22 15:27:24 -070090constexpr bool isPath(ConstStr s, unsigned i) {
91 return isEquN(s, i, "<path>", 0, 6);
Ed Tanous7045c8d2017-04-03 10:04:37 -070092}
Ed Tanous3dac7492017-08-02 13:46:20 -070093
Ed Tanous7045c8d2017-04-03 10:04:37 -070094template <typename T>
95struct parameter_tag {
96 static const int value = 0;
97};
Ed Tanous55c7b7a2018-05-22 15:27:24 -070098#define BMCWEB_INTERNAL_PARAMETER_TAG(t, i) \
99 template <> \
100 struct parameter_tag<t> { \
101 static const int value = i; \
Ed Tanous7045c8d2017-04-03 10:04:37 -0700102 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700103BMCWEB_INTERNAL_PARAMETER_TAG(int, 1);
104BMCWEB_INTERNAL_PARAMETER_TAG(char, 1);
105BMCWEB_INTERNAL_PARAMETER_TAG(short, 1);
106BMCWEB_INTERNAL_PARAMETER_TAG(long, 1);
107BMCWEB_INTERNAL_PARAMETER_TAG(long long, 1);
108BMCWEB_INTERNAL_PARAMETER_TAG(unsigned int, 2);
109BMCWEB_INTERNAL_PARAMETER_TAG(unsigned char, 2);
110BMCWEB_INTERNAL_PARAMETER_TAG(unsigned short, 2);
111BMCWEB_INTERNAL_PARAMETER_TAG(unsigned long, 2);
112BMCWEB_INTERNAL_PARAMETER_TAG(unsigned long long, 2);
113BMCWEB_INTERNAL_PARAMETER_TAG(double, 3);
114BMCWEB_INTERNAL_PARAMETER_TAG(std::string, 4);
115#undef BMCWEB_INTERNAL_PARAMETER_TAG
Ed Tanous7045c8d2017-04-03 10:04:37 -0700116template <typename... Args>
117struct compute_parameter_tag_from_args_list;
118
119template <>
120struct compute_parameter_tag_from_args_list<> {
121 static const int value = 0;
122};
123
124template <typename Arg, typename... Args>
125struct compute_parameter_tag_from_args_list<Arg, Args...> {
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700126 static const int subValue =
Ed Tanous7045c8d2017-04-03 10:04:37 -0700127 compute_parameter_tag_from_args_list<Args...>::value;
128 static const int value =
129 parameter_tag<typename std::decay<Arg>::type>::value
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700130 ? subValue * 6 + parameter_tag<typename std::decay<Arg>::type>::value
131 : subValue;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700132};
133
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700134static inline bool isParameterTagCompatible(uint64_t a, uint64_t b) {
Ed Tanous911ac312017-08-15 09:37:42 -0700135 if (a == 0) {
136 return b == 0;
137 }
138 if (b == 0) {
139 return a == 0;
140 }
Ed Tanous7045c8d2017-04-03 10:04:37 -0700141 int sa = a % 6;
142 int sb = a % 6;
Ed Tanous911ac312017-08-15 09:37:42 -0700143 if (sa == 5) {
144 sa = 4;
145 }
146 if (sb == 5) {
147 sb = 4;
148 }
149 if (sa != sb) {
150 return false;
151 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700152 return isParameterTagCompatible(a / 6, b / 6);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700153}
154
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700155static inline unsigned findClosingTagRuntime(const char* s, unsigned p) {
Ed Tanous7045c8d2017-04-03 10:04:37 -0700156 return s[p] == 0 ? throw std::runtime_error("unmatched tag <")
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700157 : s[p] == '>' ? p : findClosingTagRuntime(s, p + 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700158}
159
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700160static inline uint64_t getParameterTagRuntime(const char* s, unsigned p = 0) {
Ed Tanous7045c8d2017-04-03 10:04:37 -0700161 return s[p] == 0
162 ? 0
163 : s[p] == '<'
164 ? (std::strncmp(s + p, "<int>", 5) == 0
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700165 ? getParameterTagRuntime(
166 s, findClosingTagRuntime(s, p)) *
Ed Tanous7045c8d2017-04-03 10:04:37 -0700167 6 +
168 1
169 : std::strncmp(s + p, "<uint>", 6) == 0
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700170 ? getParameterTagRuntime(
171 s, findClosingTagRuntime(s, p)) *
Ed Tanous7045c8d2017-04-03 10:04:37 -0700172 6 +
173 2
174 : (std::strncmp(s + p, "<float>", 7) == 0 ||
175 std::strncmp(s + p, "<double>", 8) == 0)
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700176 ? getParameterTagRuntime(
177 s, findClosingTagRuntime(s, p)) *
Ed Tanous7045c8d2017-04-03 10:04:37 -0700178 6 +
179 3
180 : (std::strncmp(s + p, "<str>", 5) == 0 ||
181 std::strncmp(s + p, "<string>", 8) ==
182 0)
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700183 ? getParameterTagRuntime(
184 s,
185 findClosingTagRuntime(s, p)) *
Ed Tanous7045c8d2017-04-03 10:04:37 -0700186 6 +
187 4
188 : std::strncmp(s + p, "<path>",
189 6) == 0
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700190 ? getParameterTagRuntime(
Ed Tanous7045c8d2017-04-03 10:04:37 -0700191 s,
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700192 findClosingTagRuntime(
Ed Tanous7045c8d2017-04-03 10:04:37 -0700193 s, p)) *
194 6 +
195 5
196 : throw std::runtime_error(
197 "invalid parameter "
198 "type"))
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700199 : getParameterTagRuntime(s, p + 1);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700200}
Ed Tanous3dac7492017-08-02 13:46:20 -0700201
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700202constexpr uint64_t get_parameter_tag(ConstStr s, unsigned p = 0) {
Ed Tanous7045c8d2017-04-03 10:04:37 -0700203 return p == s.size()
204 ? 0
205 : s[p] == '<'
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700206 ? (isInt(s, p)
207 ? get_parameter_tag(s, findClosingTag(s, p)) * 6 + 1
208 : isUint(s, p)
209 ? get_parameter_tag(s, findClosingTag(s, p)) *
Ed Tanous7045c8d2017-04-03 10:04:37 -0700210 6 +
211 2
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700212 : isFloat(s, p)
Ed Tanous7045c8d2017-04-03 10:04:37 -0700213 ? get_parameter_tag(
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700214 s, findClosingTag(s, p)) *
Ed Tanous7045c8d2017-04-03 10:04:37 -0700215 6 +
216 3
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700217 : isStr(s, p)
Ed Tanous7045c8d2017-04-03 10:04:37 -0700218 ? get_parameter_tag(
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700219 s, findClosingTag(s, p)) *
Ed Tanous7045c8d2017-04-03 10:04:37 -0700220 6 +
221 4
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700222 : isPath(s, p)
Ed Tanous7045c8d2017-04-03 10:04:37 -0700223 ? get_parameter_tag(
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700224 s,
225 findClosingTag(s, p)) *
Ed Tanous7045c8d2017-04-03 10:04:37 -0700226 6 +
227 5
228 : throw std::runtime_error(
229 "invalid parameter "
230 "type"))
231 : get_parameter_tag(s, p + 1);
232}
Ed Tanous7045c8d2017-04-03 10:04:37 -0700233
234template <typename... T>
235struct S {
236 template <typename U>
237 using push = S<U, T...>;
238 template <typename U>
239 using push_back = S<T..., U>;
240 template <template <typename... Args> class U>
241 using rebind = U<T...>;
242};
243template <typename F, typename Set>
244struct CallHelper;
245template <typename F, typename... Args>
246struct CallHelper<F, S<Args...>> {
247 template <typename F1, typename... Args1,
248 typename = decltype(std::declval<F1>()(std::declval<Args1>()...))>
249 static char __test(int);
250
251 template <typename...>
252 static int __test(...);
253
254 static constexpr bool value = sizeof(__test<F, Args...>(0)) == sizeof(char);
255};
256
257template <int N>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700258struct SingleTagToType {};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700259
260template <>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700261struct SingleTagToType<1> {
Ed Tanous7045c8d2017-04-03 10:04:37 -0700262 using type = int64_t;
263};
264
265template <>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700266struct SingleTagToType<2> {
Ed Tanous7045c8d2017-04-03 10:04:37 -0700267 using type = uint64_t;
268};
269
270template <>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700271struct SingleTagToType<3> {
Ed Tanous7045c8d2017-04-03 10:04:37 -0700272 using type = double;
273};
274
275template <>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700276struct SingleTagToType<4> {
Ed Tanous7045c8d2017-04-03 10:04:37 -0700277 using type = std::string;
278};
279
280template <>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700281struct SingleTagToType<5> {
Ed Tanous7045c8d2017-04-03 10:04:37 -0700282 using type = std::string;
283};
284
285template <uint64_t Tag>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700286struct Arguments {
287 using subarguments = typename Arguments<Tag / 6>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700288 using type = typename subarguments::template push<
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700289 typename SingleTagToType<Tag % 6>::type>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700290};
291
292template <>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700293struct Arguments<0> {
Ed Tanous7045c8d2017-04-03 10:04:37 -0700294 using type = S<>;
295};
296
297template <typename... T>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700298struct LastElementType {
Ed Tanous7045c8d2017-04-03 10:04:37 -0700299 using type =
Ed Tanous3dac7492017-08-02 13:46:20 -0700300 typename std::tuple_element<sizeof...(T) - 1, std::tuple<T...>>::type;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700301};
302
303template <>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700304struct LastElementType<> {};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700305
306// from
307// http://stackoverflow.com/questions/13072359/c11-compile-time-array-with-logarithmic-evaluation-depth
308template <class T>
309using Invoke = typename T::type;
310
311template <unsigned...>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700312struct Seq {
313 using type = Seq;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700314};
315
316template <class S1, class S2>
317struct concat;
318
319template <unsigned... I1, unsigned... I2>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700320struct concat<Seq<I1...>, Seq<I2...>> : Seq<I1..., (sizeof...(I1) + I2)...> {};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700321
322template <class S1, class S2>
323using Concat = Invoke<concat<S1, S2>>;
324
325template <unsigned N>
326struct gen_seq;
327template <unsigned N>
328using GenSeq = Invoke<gen_seq<N>>;
329
330template <unsigned N>
331struct gen_seq : Concat<GenSeq<N / 2>, GenSeq<N - N / 2>> {};
332
333template <>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700334struct gen_seq<0> : Seq<> {};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700335template <>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700336struct gen_seq<1> : Seq<0> {};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700337
338template <typename Seq, typename Tuple>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700339struct PopBackHelper;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700340
341template <unsigned... N, typename Tuple>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700342struct PopBackHelper<Seq<N...>, Tuple> {
Ed Tanous7045c8d2017-04-03 10:04:37 -0700343 template <template <typename... Args> class U>
344 using rebind = U<typename std::tuple_element<N, Tuple>::type...>;
345};
346
347template <typename... T>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700348struct PopBack //: public PopBackHelper<typename
349 // gen_seq<sizeof...(T)-1>::type, std::tuple<T...>>
Ed Tanous7045c8d2017-04-03 10:04:37 -0700350{
351 template <template <typename... Args> class U>
352 using rebind =
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700353 typename PopBackHelper<typename gen_seq<sizeof...(T) - 1>::type,
354 std::tuple<T...>>::template rebind<U>;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700355};
356
357template <>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700358struct PopBack<> {
Ed Tanous7045c8d2017-04-03 10:04:37 -0700359 template <template <typename... Args> class U>
360 using rebind = U<>;
361};
362
363// from
364// http://stackoverflow.com/questions/2118541/check-if-c0x-parameter-pack-contains-a-type
365template <typename Tp, typename... List>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700366struct Contains : std::true_type {};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700367
368template <typename Tp, typename Head, typename... Rest>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700369struct Contains<Tp, Head, Rest...>
Ed Tanous7045c8d2017-04-03 10:04:37 -0700370 : std::conditional<std::is_same<Tp, Head>::value, std::true_type,
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700371 Contains<Tp, Rest...>>::type {};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700372
373template <typename Tp>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700374struct Contains<Tp> : std::false_type {};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700375
376template <typename T>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700377struct EmptyContext {};
Ed Tanous7045c8d2017-04-03 10:04:37 -0700378
379template <typename T>
380struct promote {
381 using type = T;
382};
383
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700384#define BMCWEB_INTERNAL_PROMOTE_TYPE(t1, t2) \
385 template <> \
386 struct promote<t1> { \
387 using type = t2; \
Ed Tanous7045c8d2017-04-03 10:04:37 -0700388 }
389
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700390BMCWEB_INTERNAL_PROMOTE_TYPE(char, int64_t);
391BMCWEB_INTERNAL_PROMOTE_TYPE(short, int64_t);
392BMCWEB_INTERNAL_PROMOTE_TYPE(int, int64_t);
393BMCWEB_INTERNAL_PROMOTE_TYPE(long, int64_t);
394BMCWEB_INTERNAL_PROMOTE_TYPE(long long, int64_t);
395BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned char, uint64_t);
396BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned short, uint64_t);
397BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned int, uint64_t);
398BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned long, uint64_t);
399BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned long long, uint64_t);
400BMCWEB_INTERNAL_PROMOTE_TYPE(float, double);
401#undef BMCWEB_INTERNAL_PROMOTE_TYPE
Ed Tanous7045c8d2017-04-03 10:04:37 -0700402
403template <typename T>
404using promote_t = typename promote<T>::type;
405
406} // namespace black_magic
407
408namespace detail {
409
410template <class T, std::size_t N, class... Args>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700411struct GetIndexOfElementFromTupleByTypeImpl {
Ed Tanous7045c8d2017-04-03 10:04:37 -0700412 static constexpr auto value = N;
413};
414
415template <class T, std::size_t N, class... Args>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700416struct GetIndexOfElementFromTupleByTypeImpl<T, N, T, Args...> {
Ed Tanous7045c8d2017-04-03 10:04:37 -0700417 static constexpr auto value = N;
418};
419
420template <class T, std::size_t N, class U, class... Args>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700421struct GetIndexOfElementFromTupleByTypeImpl<T, N, U, Args...> {
Ed Tanous7045c8d2017-04-03 10:04:37 -0700422 static constexpr auto value =
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700423 GetIndexOfElementFromTupleByTypeImpl<T, N + 1, Args...>::value;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700424};
425
426} // namespace detail
427
428namespace utility {
429template <class T, class... Args>
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700430T& getElementByType(std::tuple<Args...>& t) {
431 return std::get<
432 detail::GetIndexOfElementFromTupleByTypeImpl<T, 0, Args...>::value>(t);
Ed Tanous7045c8d2017-04-03 10:04:37 -0700433}
434
435template <typename T>
436struct function_traits;
437
Ed Tanous7045c8d2017-04-03 10:04:37 -0700438template <typename T>
439struct function_traits : public function_traits<decltype(&T::operator())> {
440 using parent_t = function_traits<decltype(&T::operator())>;
441 static const size_t arity = parent_t::arity;
442 using result_type = typename parent_t::result_type;
443 template <size_t i>
444 using arg = typename parent_t::template arg<i>;
445};
Ed Tanous3dac7492017-08-02 13:46:20 -0700446
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700447template <typename ClassType, typename r, typename... Args>
448struct function_traits<r (ClassType::*)(Args...) const> {
Ed Tanous7045c8d2017-04-03 10:04:37 -0700449 static const size_t arity = sizeof...(Args);
450
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700451 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700452
453 template <size_t i>
454 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
455};
456
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700457template <typename ClassType, typename r, typename... Args>
458struct function_traits<r (ClassType::*)(Args...)> {
Ed Tanous7045c8d2017-04-03 10:04:37 -0700459 static const size_t arity = sizeof...(Args);
460
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700461 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700462
463 template <size_t i>
464 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
465};
466
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700467template <typename r, typename... Args>
468struct function_traits<std::function<r(Args...)>> {
Ed Tanous7045c8d2017-04-03 10:04:37 -0700469 static const size_t arity = sizeof...(Args);
470
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700471 using result_type = r;
Ed Tanous7045c8d2017-04-03 10:04:37 -0700472
473 template <size_t i>
474 using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
475};
476
477inline static std::string base64encode(
478 const char* data, size_t size,
479 const char* key =
480 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") {
481 std::string ret;
482 ret.resize((size + 2) / 3 * 4);
483 auto it = ret.begin();
484 while (size >= 3) {
485 *it++ = key[(((unsigned char)*data) & 0xFC) >> 2];
486 unsigned char h = (((unsigned char)*data++) & 0x03) << 4;
487 *it++ = key[h | ((((unsigned char)*data) & 0xF0) >> 4)];
488 h = (((unsigned char)*data++) & 0x0F) << 2;
489 *it++ = key[h | ((((unsigned char)*data) & 0xC0) >> 6)];
490 *it++ = key[((unsigned char)*data++) & 0x3F];
491
492 size -= 3;
493 }
494 if (size == 1) {
495 *it++ = key[(((unsigned char)*data) & 0xFC) >> 2];
496 unsigned char h = (((unsigned char)*data++) & 0x03) << 4;
497 *it++ = key[h];
498 *it++ = '=';
499 *it++ = '=';
500 } else if (size == 2) {
501 *it++ = key[(((unsigned char)*data) & 0xFC) >> 2];
502 unsigned char h = (((unsigned char)*data++) & 0x03) << 4;
503 *it++ = key[h | ((((unsigned char)*data) & 0xF0) >> 4)];
504 h = (((unsigned char)*data++) & 0x0F) << 2;
505 *it++ = key[h];
506 *it++ = '=';
507 }
508 return ret;
509}
510
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700511inline static std::string base64encodeUrlsafe(const char* data, size_t size) {
Ed Tanous7045c8d2017-04-03 10:04:37 -0700512 return base64encode(
513 data, size,
514 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_");
515}
516
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100517// TODO this is temporary and should be deleted once base64 is refactored out of
518// crow
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700519inline bool base64Decode(const boost::string_view input, std::string& output) {
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100520 static const char nop = -1;
521 // See note on encoding_data[] in above function
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700522 static const char decodingData[] = {
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100523 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
524 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
525 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, 62, nop,
526 nop, nop, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, nop, nop,
527 nop, nop, nop, nop, nop, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
528 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
529 25, nop, nop, nop, nop, nop, nop, 26, 27, 28, 29, 30, 31, 32, 33,
530 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
531 49, 50, 51, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
532 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
533 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
534 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
535 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
536 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
537 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
538 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
539 nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
540 nop};
541
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700542 size_t inputLength = input.size();
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100543
544 // allocate space for output string
545 output.clear();
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700546 output.reserve(((inputLength + 2) / 3) * 4);
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100547
548 // for each 4-bytes sequence from the input, extract 4 6-bits sequences by
549 // droping first two bits
550 // and regenerate into 3 8-bits sequences
551
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700552 for (size_t i = 0; i < inputLength; i++) {
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100553 char base64code0;
554 char base64code1;
555 char base64code2 = 0; // initialized to 0 to suppress warnings
556 char base64code3;
557
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700558 base64code0 = decodingData[static_cast<int>(input[i])]; // NOLINT
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100559 if (base64code0 == nop) { // non base64 character
560 return false;
561 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700562 if (!(++i < inputLength)) { // we need at least two input bytes for first
563 // byte output
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100564 return false;
565 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700566 base64code1 = decodingData[static_cast<int>(input[i])]; // NOLINT
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100567 if (base64code1 == nop) { // non base64 character
568 return false;
569 }
570 output +=
571 static_cast<char>((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
572
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700573 if (++i < inputLength) {
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100574 char c = input[i];
575 if (c == '=') { // padding , end of input
576 return (base64code1 & 0x0f) == 0;
577 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700578 base64code2 = decodingData[static_cast<int>(input[i])]; // NOLINT
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100579 if (base64code2 == nop) { // non base64 character
580 return false;
581 }
582 output += static_cast<char>(((base64code1 << 4) & 0xf0) |
583 ((base64code2 >> 2) & 0x0f));
584 }
585
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700586 if (++i < inputLength) {
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100587 char c = input[i];
588 if (c == '=') { // padding , end of input
589 return (base64code2 & 0x03) == 0;
590 }
Ed Tanous55c7b7a2018-05-22 15:27:24 -0700591 base64code3 = decodingData[static_cast<int>(input[i])]; // NOLINT
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +0100592 if (base64code3 == nop) { // non base64 character
593 return false;
594 }
595 output += static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3));
596 }
597 }
598
599 return true;
600}
601
Ed Tanous7045c8d2017-04-03 10:04:37 -0700602} // namespace utility
Ed Tanous911ac312017-08-15 09:37:42 -0700603} // namespace crow