Crow  0.3
A C++ microframework for the web
utility.h
1 #pragma once
2 
3 #include <cstdint>
4 #include <stdexcept>
5 #include <tuple>
6 #include <type_traits>
7 #include <cstring>
8 #include <functional>
9 #include <string>
10 
11 #include "crow/settings.h"
12 
13 namespace crow
14 {
15  namespace black_magic
16  {
17 #ifndef CROW_MSVC_WORKAROUND
18  struct OutOfRange
19  {
20  OutOfRange(unsigned /*pos*/, unsigned /*length*/) {}
21  };
22  constexpr unsigned requires_in_range( unsigned i, unsigned len )
23  {
24  return i >= len ? throw OutOfRange(i, len) : i;
25  }
26 
27  /// A constant string implementation.
28  class const_str
29  {
30  const char * const begin_;
31  unsigned size_;
32 
33  public:
34  template< unsigned N >
35  constexpr const_str( const char(&arr)[N] ) : begin_(arr), size_(N - 1) {
36  static_assert( N >= 1, "not a string literal");
37  }
38  constexpr char operator[]( unsigned i ) const {
39  return requires_in_range(i, size_), begin_[i];
40  }
41 
42  constexpr operator const char *() const {
43  return begin_;
44  }
45 
46  constexpr const char* begin() const { return begin_; }
47  constexpr const char* end() const { return begin_ + size_; }
48 
49  constexpr unsigned size() const {
50  return size_;
51  }
52  };
53 
54  constexpr unsigned find_closing_tag(const_str s, unsigned p)
55  {
56  return s[p] == '>' ? p : find_closing_tag(s, p+1);
57  }
58 
59  constexpr bool is_valid(const_str s, unsigned i = 0, int f = 0)
60  {
61  return
62  i == s.size()
63  ? f == 0 :
64  f < 0 || f >= 2
65  ? false :
66  s[i] == '<'
67  ? is_valid(s, i+1, f+1) :
68  s[i] == '>'
69  ? is_valid(s, i+1, f-1) :
70  is_valid(s, i+1, f);
71  }
72 
73  constexpr bool is_equ_p(const char* a, const char* b, unsigned n)
74  {
75  return
76  *a == 0 && *b == 0 && n == 0
77  ? true :
78  (*a == 0 || *b == 0)
79  ? false :
80  n == 0
81  ? true :
82  *a != *b
83  ? false :
84  is_equ_p(a+1, b+1, n-1);
85  }
86 
87  constexpr bool is_equ_n(const_str a, unsigned ai, const_str b, unsigned bi, unsigned n)
88  {
89  return
90  ai + n > a.size() || bi + n > b.size()
91  ? false :
92  n == 0
93  ? true :
94  a[ai] != b[bi]
95  ? false :
96  is_equ_n(a,ai+1,b,bi+1,n-1);
97  }
98 
99  constexpr bool is_int(const_str s, unsigned i)
100  {
101  return is_equ_n(s, i, "<int>", 0, 5);
102  }
103 
104  constexpr bool is_uint(const_str s, unsigned i)
105  {
106  return is_equ_n(s, i, "<uint>", 0, 6);
107  }
108 
109  constexpr bool is_float(const_str s, unsigned i)
110  {
111  return is_equ_n(s, i, "<float>", 0, 7) ||
112  is_equ_n(s, i, "<double>", 0, 8);
113  }
114 
115  constexpr bool is_str(const_str s, unsigned i)
116  {
117  return is_equ_n(s, i, "<str>", 0, 5) ||
118  is_equ_n(s, i, "<string>", 0, 8);
119  }
120 
121  constexpr bool is_path(const_str s, unsigned i)
122  {
123  return is_equ_n(s, i, "<path>", 0, 6);
124  }
125 #endif
126  template <typename T>
128  {
129  static const int value = 0;
130  };
131 #define CROW_INTERNAL_PARAMETER_TAG(t, i) \
132 template <> \
133 struct parameter_tag<t> \
134 { \
135  static const int value = i; \
136 }
137  CROW_INTERNAL_PARAMETER_TAG(int, 1);
138  CROW_INTERNAL_PARAMETER_TAG(char, 1);
139  CROW_INTERNAL_PARAMETER_TAG(short, 1);
140  CROW_INTERNAL_PARAMETER_TAG(long, 1);
141  CROW_INTERNAL_PARAMETER_TAG(long long, 1);
142  CROW_INTERNAL_PARAMETER_TAG(unsigned int, 2);
143  CROW_INTERNAL_PARAMETER_TAG(unsigned char, 2);
144  CROW_INTERNAL_PARAMETER_TAG(unsigned short, 2);
145  CROW_INTERNAL_PARAMETER_TAG(unsigned long, 2);
146  CROW_INTERNAL_PARAMETER_TAG(unsigned long long, 2);
147  CROW_INTERNAL_PARAMETER_TAG(double, 3);
148  CROW_INTERNAL_PARAMETER_TAG(std::string, 4);
149 #undef CROW_INTERNAL_PARAMETER_TAG
150  template <typename ... Args>
152 
153  template <>
155  {
156  static const int value = 0;
157  };
158 
159  template <typename Arg, typename ... Args>
161  {
162  static const int sub_value =
163  compute_parameter_tag_from_args_list<Args...>::value;
164  static const int value =
166  ? sub_value* 6 + parameter_tag<typename std::decay<Arg>::type>::value
167  : sub_value;
168  };
169 
170  static inline bool is_parameter_tag_compatible(uint64_t a, uint64_t b)
171  {
172  if (a == 0)
173  return b == 0;
174  if (b == 0)
175  return a == 0;
176  int sa = a%6;
177  int sb = a%6;
178  if (sa == 5) sa = 4;
179  if (sb == 5) sb = 4;
180  if (sa != sb)
181  return false;
182  return is_parameter_tag_compatible(a/6, b/6);
183  }
184 
185  static inline unsigned find_closing_tag_runtime(const char* s, unsigned p)
186  {
187  return
188  s[p] == 0
189  ? throw std::runtime_error("unmatched tag <") :
190  s[p] == '>'
191  ? p : find_closing_tag_runtime(s, p + 1);
192  }
193 
194  static inline uint64_t get_parameter_tag_runtime(const char* s, unsigned p = 0)
195  {
196  return
197  s[p] == 0
198  ? 0 :
199  s[p] == '<' ? (
200  std::strncmp(s+p, "<int>", 5) == 0
201  ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 1 :
202  std::strncmp(s+p, "<uint>", 6) == 0
203  ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 2 :
204  (std::strncmp(s+p, "<float>", 7) == 0 ||
205  std::strncmp(s+p, "<double>", 8) == 0)
206  ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 3 :
207  (std::strncmp(s+p, "<str>", 5) == 0 ||
208  std::strncmp(s+p, "<string>", 8) == 0)
209  ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 4 :
210  std::strncmp(s+p, "<path>", 6) == 0
211  ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 5 :
212  throw std::runtime_error("invalid parameter type")
213  ) :
214  get_parameter_tag_runtime(s, p+1);
215  }
216 #ifndef CROW_MSVC_WORKAROUND
217  constexpr uint64_t get_parameter_tag(const_str s, unsigned p = 0)
218  {
219  return
220  p == s.size()
221  ? 0 :
222  s[p] == '<' ? (
223  is_int(s, p)
224  ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 1 :
225  is_uint(s, p)
226  ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 2 :
227  is_float(s, p)
228  ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 3 :
229  is_str(s, p)
230  ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 4 :
231  is_path(s, p)
232  ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 5 :
233  throw std::runtime_error("invalid parameter type")
234  ) :
235  get_parameter_tag(s, p+1);
236  }
237 #endif
238 
239  template <typename ... T>
240  struct S
241  {
242  template <typename U>
243  using push = S<U, T...>;
244  template <typename U>
245  using push_back = S<T..., U>;
246  template <template<typename ... Args> class U>
247  using rebind = U<T...>;
248  };
249 template <typename F, typename Set>
250  struct CallHelper;
251  template <typename F, typename ...Args>
252  struct CallHelper<F, S<Args...>>
253  {
254  template <typename F1, typename ...Args1, typename =
255  decltype(std::declval<F1>()(std::declval<Args1>()...))
256  >
257  static char __test(int);
258 
259  template <typename ...>
260  static int __test(...);
261 
262  static constexpr bool value = sizeof(__test<F, Args...>(0)) == sizeof(char);
263  };
264 
265 
266  template <int N>
268  {
269  };
270 
271  template <>
273  {
274  using type = int64_t;
275  };
276 
277  template <>
279  {
280  using type = uint64_t;
281  };
282 
283  template <>
285  {
286  using type = double;
287  };
288 
289  template <>
291  {
292  using type = std::string;
293  };
294 
295  template <>
297  {
298  using type = std::string;
299  };
300 
301 
302  template <uint64_t Tag>
303  struct arguments
304  {
305  using subarguments = typename arguments<Tag/6>::type;
306  using type =
307  typename subarguments::template push<typename single_tag_to_type<Tag%6>::type>;
308  };
309 
310  template <>
311  struct arguments<0>
312  {
313  using type = S<>;
314  };
315 
316  template <typename ... T>
318  {
319  using type = typename std::tuple_element<sizeof...(T)-1, std::tuple<T...>>::type;
320  };
321 
322 
323  template <>
325  {
326  };
327 
328 
329  // from http://stackoverflow.com/questions/13072359/c11-compile-time-array-with-logarithmic-evaluation-depth
330  template<class T> using Invoke = typename T::type;
331 
332  template<unsigned...> struct seq{ using type = seq; };
333 
334  template<class S1, class S2> struct concat;
335 
336  template<unsigned... I1, unsigned... I2>
337  struct concat<seq<I1...>, seq<I2...>>
338  : seq<I1..., (sizeof...(I1)+I2)...>{};
339 
340  template<class S1, class S2>
341  using Concat = Invoke<concat<S1, S2>>;
342 
343  template<unsigned N> struct gen_seq;
344  template<unsigned N> using GenSeq = Invoke<gen_seq<N>>;
345 
346  template<unsigned N>
347  struct gen_seq : Concat<GenSeq<N/2>, GenSeq<N - N/2>>{};
348 
349  template<> struct gen_seq<0> : seq<>{};
350  template<> struct gen_seq<1> : seq<0>{};
351 
352  template <typename Seq, typename Tuple>
354 
355  template <unsigned ... N, typename Tuple>
356  struct pop_back_helper<seq<N...>, Tuple>
357  {
358  template <template <typename ... Args> class U>
359  using rebind = U<typename std::tuple_element<N, Tuple>::type...>;
360  };
361 
362  template <typename ... T>
363  struct pop_back //: public pop_back_helper<typename gen_seq<sizeof...(T)-1>::type, std::tuple<T...>>
364  {
365  template <template <typename ... Args> class U>
366  using rebind = typename pop_back_helper<typename gen_seq<sizeof...(T)-1>::type, std::tuple<T...>>::template rebind<U>;
367  };
368 
369  template <>
370  struct pop_back<>
371  {
372  template <template <typename ... Args> class U>
373  using rebind = U<>;
374  };
375 
376  // from http://stackoverflow.com/questions/2118541/check-if-c0x-parameter-pack-contains-a-type
377  template < typename Tp, typename... List >
378  struct contains : std::true_type {};
379 
380  template < typename Tp, typename Head, typename... Rest >
381  struct contains<Tp, Head, Rest...>
382  : std::conditional< std::is_same<Tp, Head>::value,
383  std::true_type,
384  contains<Tp, Rest...>
385  >::type {};
386 
387  template < typename Tp >
388  struct contains<Tp> : std::false_type {};
389 
390  template <typename T>
392  {
393  };
394 
395  template <typename T>
396  struct promote
397  {
398  using type = T;
399  };
400 
401 #define CROW_INTERNAL_PROMOTE_TYPE(t1, t2) \
402  template<> \
403  struct promote<t1> \
404  { \
405  using type = t2; \
406  }
407 
408  CROW_INTERNAL_PROMOTE_TYPE(char, int64_t);
409  CROW_INTERNAL_PROMOTE_TYPE(short, int64_t);
410  CROW_INTERNAL_PROMOTE_TYPE(int, int64_t);
411  CROW_INTERNAL_PROMOTE_TYPE(long, int64_t);
412  CROW_INTERNAL_PROMOTE_TYPE(long long, int64_t);
413  CROW_INTERNAL_PROMOTE_TYPE(unsigned char, uint64_t);
414  CROW_INTERNAL_PROMOTE_TYPE(unsigned short, uint64_t);
415  CROW_INTERNAL_PROMOTE_TYPE(unsigned int, uint64_t);
416  CROW_INTERNAL_PROMOTE_TYPE(unsigned long, uint64_t);
417  CROW_INTERNAL_PROMOTE_TYPE(unsigned long long, uint64_t);
418  CROW_INTERNAL_PROMOTE_TYPE(float, double);
419 #undef CROW_INTERNAL_PROMOTE_TYPE
420 
421  template <typename T>
422  using promote_t = typename promote<T>::type;
423 
424  } // namespace black_magic
425 
426  namespace detail
427  {
428 
429  template <class T, std::size_t N, class... Args>
431  {
432  static constexpr auto value = N;
433  };
434 
435  template <class T, std::size_t N, class... Args>
437  {
438  static constexpr auto value = N;
439  };
440 
441  template <class T, std::size_t N, class U, class... Args>
443  {
444  static constexpr auto value = get_index_of_element_from_tuple_by_type_impl<T, N + 1, Args...>::value;
445  };
446 
447  } // namespace detail
448 
449  namespace utility
450  {
451  template <class T, class... Args>
452  T& get_element_by_type(std::tuple<Args...>& t)
453  {
454  return std::get<detail::get_index_of_element_from_tuple_by_type_impl<T, 0, Args...>::value>(t);
455  }
456 
457  template<typename T>
459 
460 #ifndef CROW_MSVC_WORKAROUND
461  template<typename T>
462  struct function_traits : public function_traits<decltype(&T::operator())>
463  {
464  using parent_t = function_traits<decltype(&T::operator())>;
465  static const size_t arity = parent_t::arity;
466  using result_type = typename parent_t::result_type;
467  template <size_t i>
468  using arg = typename parent_t::template arg<i>;
469 
470  };
471 #endif
472 
473  template<typename ClassType, typename R, typename ...Args>
474  struct function_traits<R(ClassType::*)(Args...) const>
475  {
476  static const size_t arity = sizeof...(Args);
477 
478  typedef R result_type;
479 
480  template <size_t i>
481  using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
482  };
483 
484  template<typename ClassType, typename R, typename ...Args>
485  struct function_traits<R(ClassType::*)(Args...)>
486  {
487  static const size_t arity = sizeof...(Args);
488 
489  typedef R result_type;
490 
491  template <size_t i>
492  using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
493  };
494 
495  template<typename R, typename ...Args>
496  struct function_traits<std::function<R(Args...)>>
497  {
498  static const size_t arity = sizeof...(Args);
499 
500  typedef R result_type;
501 
502  template <size_t i>
503  using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
504  };
505 
506  inline static std::string base64encode(const char* data, size_t size, const char* key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")
507  {
508  std::string ret;
509  ret.resize((size+2) / 3 * 4);
510  auto it = ret.begin();
511  while(size >= 3)
512  {
513  *it++ = key[(static_cast<unsigned char>(*data)&0xFC)>>2];
514  unsigned char h = (static_cast<unsigned char>(*data++) & 0x03) << 4;
515  *it++ = key[h|((static_cast<unsigned char>(*data)&0xF0)>>4)];
516  h = (static_cast<unsigned char>(*data++) & 0x0F) << 2;
517  *it++ = key[h|((static_cast<unsigned char>(*data)&0xC0)>>6)];
518  *it++ = key[static_cast<unsigned char>(*data++)&0x3F];
519 
520  size -= 3;
521  }
522  if (size == 1)
523  {
524  *it++ = key[(static_cast<unsigned char>(*data)&0xFC)>>2];
525  unsigned char h = (static_cast<unsigned char>(*data++) & 0x03) << 4;
526  *it++ = key[h];
527  *it++ = '=';
528  *it++ = '=';
529  }
530  else if (size == 2)
531  {
532  *it++ = key[(static_cast<unsigned char>(*data)&0xFC)>>2];
533  unsigned char h = (static_cast<unsigned char>(*data++) & 0x03) << 4;
534  *it++ = key[h|((static_cast<unsigned char>(*data)&0xF0)>>4)];
535  h = (static_cast<unsigned char>(*data++) & 0x0F) << 2;
536  *it++ = key[h];
537  *it++ = '=';
538  }
539  return ret;
540  }
541 
542  inline static std::string base64encode_urlsafe(const char* data, size_t size)
543  {
544  return base64encode(data, size, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_");
545  }
546 
547 
548  } // namespace utility
549 }
crow::black_magic::S
Definition: utility.h:240
crow::black_magic::OutOfRange
Definition: utility.h:18
crow::black_magic::single_tag_to_type< 5 >
Definition: utility.h:296
crow::black_magic::compute_parameter_tag_from_args_list
Definition: utility.h:151
crow::black_magic::pop_back_helper
Definition: utility.h:353
crow::black_magic::last_element_type
Definition: utility.h:317
crow::utility::function_traits
Definition: utility.h:458
crow::black_magic::const_str
A constant string implementation.
Definition: utility.h:28
crow::black_magic::CallHelper
Definition: utility.h:250
crow::black_magic::single_tag_to_type< 1 >
Definition: utility.h:272
crow::detail::get_index_of_element_from_tuple_by_type_impl
Definition: utility.h:430
crow::black_magic::single_tag_to_type< 4 >
Definition: utility.h:290
crow::black_magic::seq
Definition: utility.h:332
crow::black_magic::empty_context
Definition: utility.h:391
crow::black_magic::arguments
Definition: utility.h:303
crow::black_magic::gen_seq
Definition: utility.h:343
crow::black_magic::promote
Definition: utility.h:396
crow::black_magic::concat
Definition: utility.h:334
crow::black_magic::pop_back
Definition: utility.h:363
crow::black_magic::single_tag_to_type< 3 >
Definition: utility.h:284
crow::black_magic::contains
Definition: utility.h:378
crow::black_magic::single_tag_to_type< 2 >
Definition: utility.h:278
crow::black_magic::parameter_tag
Definition: utility.h:127
crow::black_magic::single_tag_to_type
Definition: utility.h:267