From 06842721d7da53a2235e6e4071760588ec285f90 Mon Sep 17 00:00:00 2001 From: Antony Woods Date: Tue, 14 Oct 2014 09:48:35 +0100 Subject: Wrapped qs_parse as query_string and added tests --- include/query_string.h | 305 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 305 insertions(+) create mode 100644 include/query_string.h (limited to 'include/query_string.h') diff --git a/include/query_string.h b/include/query_string.h new file mode 100644 index 0000000..5a42782 --- /dev/null +++ b/include/query_string.h @@ -0,0 +1,305 @@ +#pragma once + +#include +#include + +using namespace std; + +// ---------------------------------------------------------------------------- +// qs_parse (modified) +// https://github.com/bartgrantham/qs_parse +// ---------------------------------------------------------------------------- +/* Similar to strncmp, but handles URL-encoding for either string */ +int qs_strncmp(const char * s, const char * qs, register size_t n); + + +/* Finds the beginning of each key/value pair and stores a pointer in qs_kv. + * Also decodes the value portion of the k/v pair *in-place*. In a future + * enhancement it will also have a compile-time option of sorting qs_kv + * alphabetically by key. */ +int qs_parse(char * qs, char * qs_kv[], int qs_kv_size); + + +/* Used by qs_parse to decode the value portion of a k/v pair */ +int qs_decode(char * qs); + + +/* Looks up the value according to the key on a pre-processed query string + * A future enhancement will be a compile-time option to look up the key + * in a pre-sorted qs_kv array via a binary search. */ +//char * qs_k2v(const char * key, char * qs_kv[], int qs_kv_size); + char * qs_k2v(const char * key, char * const * qs_kv, int qs_kv_size, int nth); + + +/* Non-destructive lookup of value, based on key. User provides the + * destinaton string and length. */ +char * qs_scanvalue(const char * key, const char * qs, char * val, size_t val_len); + +// TODO: implement sorting of the qs_kv array; for now ensure it's not compiled +#undef _qsSORTING + +// isxdigit _is_ available in , but let's avoid another header instead +#define ISHEX(x) ((((x)>='0'&&(x)<='9') || ((x)>='A'&&(x)<='F') || ((x)>='a'&&(x)<='f')) ? 1 : 0) +#define HEX2DEC(x) (((x)>='0'&&(x)<='9') ? (x)-48 : ((x)>='A'&&(x)<='F') ? (x)-55 : ((x)>='a'&&(x)<='f') ? (x)-87 : 0) +#define ISQSCHR(x) ((((x)=='=')||((x)=='#')||((x)=='&')||((x)=='\0')) ? 0 : 1) + +int qs_strncmp(const char * s, const char * qs, register size_t n) +{ + int i=0; + register unsigned char u1, u2, unyb, lnyb; + + while(n-- > 0) + { + u1 = (unsigned char) *s++; + u2 = (unsigned char) *qs++; + + if ( ! ISQSCHR(u1) ) { u1 = '\0'; } + if ( ! ISQSCHR(u2) ) { u2 = '\0'; } + + if ( u1 == '+' ) { u1 = ' '; } + if ( u1 == '%' ) // easier/safer than scanf + { + unyb = (unsigned char) *s++; + lnyb = (unsigned char) *s++; + if ( ISHEX(unyb) && ISHEX(lnyb) ) + u1 = (HEX2DEC(unyb) * 16) + HEX2DEC(lnyb); + else + u1 = '\0'; + } + + if ( u2 == '+' ) { u2 = ' '; } + if ( u2 == '%' ) // easier/safer than scanf + { + unyb = (unsigned char) *qs++; + lnyb = (unsigned char) *qs++; + if ( ISHEX(unyb) && ISHEX(lnyb) ) + u2 = (HEX2DEC(unyb) * 16) + HEX2DEC(lnyb); + else + u2 = '\0'; + } + + if ( u1 != u2 ) + return u1 - u2; + if ( u1 == '\0' ) + return 0; + i++; + } + if ( ISQSCHR(*qs) ) + return -1; + else + return 0; +} + + +int qs_parse(char * qs, char * qs_kv[], int qs_kv_size) +{ + int i, j; + char * substr_ptr; + + for(i=0; i means x iterations of this loop -> means *x+1* k/v pairs + + // we only decode the values in place, the keys could have '='s in them + // which will hose our ability to distinguish keys from values later + for(j=0; j get_list (const string name) const + { + vector ret; + string plus = name + "[]"; + char* tmp = nullptr; + int count = 0; + do + { + tmp = qs_k2v(plus.c_str(), _kv_pairs, _kv_size, count++); + if(tmp != nullptr) { + ret.push_back(tmp); + } + } while(tmp != nullptr); + return move(ret); + } + + + private: + char _url[MAX_URL_SIZE]; + char* _kv_pairs[NUM_KV_PAIRS]; + int _kv_size; + }; + +} // end namespace \ No newline at end of file -- cgit v1.2.3-54-g00ecf From 3a2d22dfe068553931ae86d0477eac3d07aa4668 Mon Sep 17 00:00:00 2001 From: Antony Woods Date: Wed, 22 Oct 2014 09:34:30 +0100 Subject: Removed instance of 'using namespace std' --- include/logging.h | 14 ++++++-------- include/query_string.h | 8 +++----- 2 files changed, 9 insertions(+), 13 deletions(-) (limited to 'include/query_string.h') diff --git a/include/logging.h b/include/logging.h index 8f5b833..ad1f4bc 100644 --- a/include/logging.h +++ b/include/logging.h @@ -9,8 +9,6 @@ #include "settings.h" -using namespace std; - namespace crow { enum class LogLevel @@ -24,12 +22,12 @@ namespace crow class ILogHandler { public: - virtual void log(string message, LogLevel level) = 0; + virtual void log(std::string message, LogLevel level) = 0; }; class CerrLogHandler : public ILogHandler { public: - void log(string message, LogLevel level) override { + void log(std::string message, LogLevel level) override { cerr << message; } }; @@ -38,18 +36,18 @@ namespace crow private: // - static string timestamp() + static std::string timestamp() { char date[32]; time_t t = time(0); strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", gmtime(&t)); - return string(date); + return std::string(date); } public: - logger(string prefix, LogLevel level) : level_(level) { + logger(std::string prefix, LogLevel level) : level_(level) { #ifdef CROW_ENABLE_LOGGING stringstream_ << "(" << timestamp() << ") [" << prefix << "] "; #endif @@ -104,7 +102,7 @@ namespace crow } // - ostringstream stringstream_; + std::ostringstream stringstream_; LogLevel level_; }; } diff --git a/include/query_string.h b/include/query_string.h index 5a42782..afc112e 100644 --- a/include/query_string.h +++ b/include/query_string.h @@ -3,8 +3,6 @@ #include #include -using namespace std; - // ---------------------------------------------------------------------------- // qs_parse (modified) // https://github.com/bartgrantham/qs_parse @@ -273,16 +271,16 @@ namespace crow } - char* get (const string name) const + char* get (const std::string name) const { char* ret = qs_k2v(name.c_str(), _kv_pairs, _kv_size); return ret != 0 ? ret : nullptr; } - vector get_list (const string name) const + vector get_list (const std::string name) const { vector ret; - string plus = name + "[]"; + std::string plus = name + "[]"; char* tmp = nullptr; int count = 0; do -- cgit v1.2.3-54-g00ecf From ada303970732f00e2d3017b726effad65d27a4d2 Mon Sep 17 00:00:00 2001 From: Antony Woods Date: Wed, 22 Oct 2014 09:40:33 +0100 Subject: Fixed compiler errors and inlines some of the qs_parse functions --- amalgamate/crow_all.h | 40 ++++++++++++++++++---------------------- examples/example.cpp | 2 +- include/logging.h | 4 ++-- include/query_string.h | 16 ++++++++-------- 4 files changed, 29 insertions(+), 33 deletions(-) (limited to 'include/query_string.h') diff --git a/amalgamate/crow_all.h b/amalgamate/crow_all.h index 43a3af4..743eb52 100644 --- a/amalgamate/crow_all.h +++ b/amalgamate/crow_all.h @@ -327,8 +327,6 @@ template #include #include -using namespace std; - // ---------------------------------------------------------------------------- // qs_parse (modified) // https://github.com/bartgrantham/qs_parse @@ -367,7 +365,7 @@ char * qs_scanvalue(const char * key, const char * qs, char * val, size_t val_le #define HEX2DEC(x) (((x)>='0'&&(x)<='9') ? (x)-48 : ((x)>='A'&&(x)<='F') ? (x)-55 : ((x)>='a'&&(x)<='f') ? (x)-87 : 0) #define ISQSCHR(x) ((((x)=='=')||((x)=='#')||((x)=='&')||((x)=='\0')) ? 0 : 1) -int qs_strncmp(const char * s, const char * qs, register size_t n) +inline int qs_strncmp(const char * s, const char * qs, register size_t n) { int i=0; register unsigned char u1, u2, unyb, lnyb; @@ -415,7 +413,7 @@ int qs_strncmp(const char * s, const char * qs, register size_t n) } -int qs_parse(char * qs, char * qs_kv[], int qs_kv_size) +inline int qs_parse(char * qs, char * qs_kv[], int qs_kv_size) { int i, j; char * substr_ptr; @@ -458,7 +456,7 @@ int qs_parse(char * qs, char * qs_kv[], int qs_kv_size) } -int qs_decode(char * qs) +inline int qs_decode(char * qs) { int i=0, j=0; @@ -487,7 +485,7 @@ int qs_decode(char * qs) } -char * qs_k2v(const char * key, char * const * qs_kv, int qs_kv_size, int nth = 0) +inline char * qs_k2v(const char * key, char * const * qs_kv, int qs_kv_size, int nth = 0) { int i; size_t key_len, skip; @@ -518,7 +516,7 @@ char * qs_k2v(const char * key, char * const * qs_kv, int qs_kv_size, int nth = } -char * qs_scanvalue(const char * key, const char * qs, char * val, size_t val_len) +inline char * qs_scanvalue(const char * key, const char * qs, char * val, size_t val_len) { size_t i, key_len; const char * tmp; @@ -583,7 +581,7 @@ namespace crow _url[0] = 0; } - friend ostream& operator<<(ostream& os, const query_string& qs) + friend std::ostream& operator<<(std::ostream& os, const query_string& qs) { os << "[ "; for(int i = 0; i < qs._kv_size; ++i) { @@ -597,16 +595,16 @@ namespace crow } - char* get (const string name) const + char* get (const std::string name) const { char* ret = qs_k2v(name.c_str(), _kv_pairs, _kv_size); return ret != 0 ? ret : nullptr; } - vector get_list (const string name) const + std::vector get_list (const std::string name) const { - vector ret; - string plus = name + "[]"; + std::vector ret; + std::string plus = name + "[]"; char* tmp = nullptr; int count = 0; do @@ -702,8 +700,6 @@ namespace crow -using namespace std; - namespace crow { enum class LogLevel @@ -717,13 +713,13 @@ namespace crow class ILogHandler { public: - virtual void log(string message, LogLevel level) = 0; + virtual void log(std::string message, LogLevel level) = 0; }; class CerrLogHandler : public ILogHandler { public: - void log(string message, LogLevel level) override { - cerr << message; + void log(std::string message, LogLevel level) override { + std::cerr << message; } }; @@ -731,18 +727,18 @@ namespace crow private: // - static string timestamp() + static std::string timestamp() { char date[32]; time_t t = time(0); strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", gmtime(&t)); - return string(date); + return std::string(date); } public: - logger(string prefix, LogLevel level) : level_(level) { + logger(std::string prefix, LogLevel level) : level_(level) { #ifdef CROW_ENABLE_LOGGING stringstream_ << "(" << timestamp() << ") [" << prefix << "] "; #endif @@ -751,7 +747,7 @@ namespace crow ~logger() { #ifdef CROW_ENABLE_LOGGING if(level_ >= get_current_log_level()) { - stringstream_ << endl; + stringstream_ << std::endl; get_handler_ref()->log(stringstream_.str(), level_); } #endif @@ -797,7 +793,7 @@ namespace crow } // - ostringstream stringstream_; + std::ostringstream stringstream_; LogLevel level_; }; } diff --git a/examples/example.cpp b/examples/example.cpp index f9d006e..d7a4736 100644 --- a/examples/example.cpp +++ b/examples/example.cpp @@ -5,7 +5,7 @@ class ExampleLogHandler : public crow::ILogHandler { public: - void log(string message, crow::LogLevel level) override { + void log(std::string message, crow::LogLevel level) override { // cerr << "ExampleLogHandler -> " << message; } }; diff --git a/include/logging.h b/include/logging.h index ad1f4bc..0d77071 100644 --- a/include/logging.h +++ b/include/logging.h @@ -28,7 +28,7 @@ namespace crow class CerrLogHandler : public ILogHandler { public: void log(std::string message, LogLevel level) override { - cerr << message; + std::cerr << message; } }; @@ -56,7 +56,7 @@ namespace crow ~logger() { #ifdef CROW_ENABLE_LOGGING if(level_ >= get_current_log_level()) { - stringstream_ << endl; + stringstream_ << std::endl; get_handler_ref()->log(stringstream_.str(), level_); } #endif diff --git a/include/query_string.h b/include/query_string.h index afc112e..2d53ea0 100644 --- a/include/query_string.h +++ b/include/query_string.h @@ -41,7 +41,7 @@ char * qs_scanvalue(const char * key, const char * qs, char * val, size_t val_le #define HEX2DEC(x) (((x)>='0'&&(x)<='9') ? (x)-48 : ((x)>='A'&&(x)<='F') ? (x)-55 : ((x)>='a'&&(x)<='f') ? (x)-87 : 0) #define ISQSCHR(x) ((((x)=='=')||((x)=='#')||((x)=='&')||((x)=='\0')) ? 0 : 1) -int qs_strncmp(const char * s, const char * qs, register size_t n) +inline int qs_strncmp(const char * s, const char * qs, register size_t n) { int i=0; register unsigned char u1, u2, unyb, lnyb; @@ -89,7 +89,7 @@ int qs_strncmp(const char * s, const char * qs, register size_t n) } -int qs_parse(char * qs, char * qs_kv[], int qs_kv_size) +inline int qs_parse(char * qs, char * qs_kv[], int qs_kv_size) { int i, j; char * substr_ptr; @@ -132,7 +132,7 @@ int qs_parse(char * qs, char * qs_kv[], int qs_kv_size) } -int qs_decode(char * qs) +inline int qs_decode(char * qs) { int i=0, j=0; @@ -161,7 +161,7 @@ int qs_decode(char * qs) } -char * qs_k2v(const char * key, char * const * qs_kv, int qs_kv_size, int nth = 0) +inline char * qs_k2v(const char * key, char * const * qs_kv, int qs_kv_size, int nth = 0) { int i; size_t key_len, skip; @@ -192,7 +192,7 @@ char * qs_k2v(const char * key, char * const * qs_kv, int qs_kv_size, int nth = } -char * qs_scanvalue(const char * key, const char * qs, char * val, size_t val_len) +inline char * qs_scanvalue(const char * key, const char * qs, char * val, size_t val_len) { size_t i, key_len; const char * tmp; @@ -257,7 +257,7 @@ namespace crow _url[0] = 0; } - friend ostream& operator<<(ostream& os, const query_string& qs) + friend std::ostream& operator<<(std::ostream& os, const query_string& qs) { os << "[ "; for(int i = 0; i < qs._kv_size; ++i) { @@ -277,9 +277,9 @@ namespace crow return ret != 0 ? ret : nullptr; } - vector get_list (const std::string name) const + std::vector get_list (const std::string name) const { - vector ret; + std::vector ret; std::string plus = name + "[]"; char* tmp = nullptr; int count = 0; -- cgit v1.2.3-54-g00ecf From 5c5c8fb4f59a1235e5093056814f7d272c049ab5 Mon Sep 17 00:00:00 2001 From: ipknHama Date: Fri, 24 Oct 2014 01:18:29 +0900 Subject: improve code quality add missing includes (for amalgation) remove register keyword (remove clang warning) change define names to avoid name collision remove url size limit from query_string.h change MAX_KV_PAIRS define to const variable add & to arguments readability improve (although it requires additional allocation) --- amalgamate/crow_all.h | 1958 ++++++++++++++++++++++++------------------------ include/query_string.h | 103 +-- 2 files changed, 1036 insertions(+), 1025 deletions(-) (limited to 'include/query_string.h') diff --git a/amalgamate/crow_all.h b/amalgamate/crow_all.h index 743eb52..2c7613d 100644 --- a/amalgamate/crow_all.h +++ b/amalgamate/crow_all.h @@ -1,476 +1,155 @@ #pragma once -#include -#include -#include -#include +#include +#include +#include +#include +#include -namespace crow -{ - namespace black_magic - { - struct OutOfRange - { - OutOfRange(unsigned pos, unsigned length) {} - }; - constexpr unsigned requires_in_range( unsigned i, unsigned len ) - { - return i >= len ? throw OutOfRange(i, len) : i; - } +// ---------------------------------------------------------------------------- +// qs_parse (modified) +// https://github.com/bartgrantham/qs_parse +// ---------------------------------------------------------------------------- +/* Similar to strncmp, but handles URL-encoding for either string */ +int qs_strncmp(const char * s, const char * qs, size_t n); - class const_str - { - const char * const begin_; - unsigned size_; - public: - template< unsigned N > - constexpr const_str( const char(&arr)[N] ) : begin_(arr), size_(N - 1) { - static_assert( N >= 1, "not a string literal"); - } - constexpr char operator[]( unsigned i ) const { - return requires_in_range(i, size_), begin_[i]; - } +/* Finds the beginning of each key/value pair and stores a pointer in qs_kv. + * Also decodes the value portion of the k/v pair *in-place*. In a future + * enhancement it will also have a compile-time option of sorting qs_kv + * alphabetically by key. */ +int qs_parse(char * qs, char * qs_kv[], int qs_kv_size); - constexpr operator const char *() const { - return begin_; - } - constexpr const char* begin() const { return begin_; } - constexpr const char* end() const { return begin_ + size_; } +/* Used by qs_parse to decode the value portion of a k/v pair */ +int qs_decode(char * qs); - constexpr unsigned size() const { - return size_; - } - }; +/* Looks up the value according to the key on a pre-processed query string + * A future enhancement will be a compile-time option to look up the key + * in a pre-sorted qs_kv array via a binary search. */ +//char * qs_k2v(const char * key, char * qs_kv[], int qs_kv_size); + char * qs_k2v(const char * key, char * const * qs_kv, int qs_kv_size, int nth); - constexpr unsigned find_closing_tag(const_str s, unsigned p) - { - return s[p] == '>' ? p : find_closing_tag(s, p+1); - } - constexpr bool is_valid(const_str s, unsigned i = 0, int f = 0) - { - return - i == s.size() - ? f == 0 : - f < 0 || f >= 2 - ? false : - s[i] == '<' - ? is_valid(s, i+1, f+1) : - s[i] == '>' - ? is_valid(s, i+1, f-1) : - is_valid(s, i+1, f); - } +/* Non-destructive lookup of value, based on key. User provides the + * destinaton string and length. */ +char * qs_scanvalue(const char * key, const char * qs, char * val, size_t val_len); - constexpr bool is_equ_p(const char* a, const char* b, unsigned n) - { - return - *a == 0 && *b == 0 && n == 0 - ? true : - (*a == 0 || *b == 0) - ? false : - n == 0 - ? true : - *a != *b - ? false : - is_equ_p(a+1, b+1, n-1); - } +// TODO: implement sorting of the qs_kv array; for now ensure it's not compiled +#undef _qsSORTING - constexpr bool is_equ_n(const_str a, unsigned ai, const_str b, unsigned bi, unsigned n) - { - return - ai + n > a.size() || bi + n > b.size() - ? false : - n == 0 - ? true : - a[ai] != b[bi] - ? false : - is_equ_n(a,ai+1,b,bi+1,n-1); - } +// isxdigit _is_ available in , but let's avoid another header instead +#define CROW_QS_ISHEX(x) ((((x)>='0'&&(x)<='9') || ((x)>='A'&&(x)<='F') || ((x)>='a'&&(x)<='f')) ? 1 : 0) +#define CROW_QS_HEX2DEC(x) (((x)>='0'&&(x)<='9') ? (x)-48 : ((x)>='A'&&(x)<='F') ? (x)-55 : ((x)>='a'&&(x)<='f') ? (x)-87 : 0) +#define CROW_QS_ISQSCHR(x) ((((x)=='=')||((x)=='#')||((x)=='&')||((x)=='\0')) ? 0 : 1) - constexpr bool is_int(const_str s, unsigned i) - { - return is_equ_n(s, i, "", 0, 5); - } +inline int qs_strncmp(const char * s, const char * qs, size_t n) +{ + int i=0; + unsigned char u1, u2, unyb, lnyb; - constexpr bool is_uint(const_str s, unsigned i) - { - return is_equ_n(s, i, "", 0, 6); - } + while(n-- > 0) + { + u1 = (unsigned char) *s++; + u2 = (unsigned char) *qs++; - constexpr bool is_float(const_str s, unsigned i) - { - return is_equ_n(s, i, "", 0, 7) || - is_equ_n(s, i, "", 0, 8); - } + if ( ! CROW_QS_ISQSCHR(u1) ) { u1 = '\0'; } + if ( ! CROW_QS_ISQSCHR(u2) ) { u2 = '\0'; } - constexpr bool is_str(const_str s, unsigned i) + if ( u1 == '+' ) { u1 = ' '; } + if ( u1 == '%' ) // easier/safer than scanf { - return is_equ_n(s, i, "", 0, 5) || - is_equ_n(s, i, "", 0, 8); + unyb = (unsigned char) *s++; + lnyb = (unsigned char) *s++; + if ( CROW_QS_ISHEX(unyb) && CROW_QS_ISHEX(lnyb) ) + u1 = (CROW_QS_HEX2DEC(unyb) * 16) + CROW_QS_HEX2DEC(lnyb); + else + u1 = '\0'; } - constexpr bool is_path(const_str s, unsigned i) + if ( u2 == '+' ) { u2 = ' '; } + if ( u2 == '%' ) // easier/safer than scanf { - return is_equ_n(s, i, "", 0, 6); + unyb = (unsigned char) *qs++; + lnyb = (unsigned char) *qs++; + if ( CROW_QS_ISHEX(unyb) && CROW_QS_ISHEX(lnyb) ) + u2 = (CROW_QS_HEX2DEC(unyb) * 16) + CROW_QS_HEX2DEC(lnyb); + else + u2 = '\0'; } - constexpr uint64_t get_parameter_tag(const_str s, unsigned p = 0) - { - return - p == s.size() - ? 0 : - s[p] == '<' ? ( - is_int(s, p) - ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 1 : - is_uint(s, p) - ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 2 : - is_float(s, p) - ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 3 : - is_str(s, p) - ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 4 : - is_path(s, p) - ? get_parameter_tag(s, find_closing_tag(s, p)) * 6 + 5 : - throw std::runtime_error("invalid parameter type") - ) : - get_parameter_tag(s, p+1); - } + if ( u1 != u2 ) + return u1 - u2; + if ( u1 == '\0' ) + return 0; + i++; + } + if ( CROW_QS_ISQSCHR(*qs) ) + return -1; + else + return 0; +} - template - struct S - { - template - using push = S; - template - using push_back = S; - template class U> - using rebind = U; - }; -template - struct CallHelper; - template - struct CallHelper> - { - template ()(std::declval()...)) - > - static char __test(int); - template - static int __test(...); +inline int qs_parse(char * qs, char * qs_kv[], int qs_kv_size) +{ + int i, j; + char * substr_ptr; - static constexpr bool value = sizeof(__test(0)) == sizeof(char); - }; + for(i=0; i - struct single_tag_to_type - { - }; + i=0; + while(i means x iterations of this loop -> means *x+1* k/v pairs - template <> - struct single_tag_to_type<1> - { - using type = int64_t; - }; + // we only decode the values in place, the keys could have '='s in them + // which will hose our ability to distinguish keys from values later + for(j=0; j - struct single_tag_to_type<2> - { - using type = uint64_t; - }; +#ifdef _qsSORTING +// TODO: qsort qs_kv, using qs_strncmp() for the comparison +#endif - template <> - struct single_tag_to_type<3> - { - using type = double; - }; - - template <> - struct single_tag_to_type<4> - { - using type = std::string; - }; - - template <> - struct single_tag_to_type<5> - { - using type = std::string; - }; - - - template - struct arguments - { - using subarguments = typename arguments::type; - using type = - typename subarguments::template push::type>; - }; - - template <> - struct arguments<0> - { - using type = S<>; - }; - - template - struct last_element_type - { - using type = typename std::tuple_element>::type; - }; - - - template <> - struct last_element_type<> - { - }; - - - // from http://stackoverflow.com/questions/13072359/c11-compile-time-array-with-logarithmic-evaluation-depth - template using Invoke = typename T::type; - - template struct seq{ using type = seq; }; - - template struct concat; - - template - struct concat, seq> - : seq{}; - - template - using Concat = Invoke>; - - template struct gen_seq; - template using GenSeq = Invoke>; - - template - struct gen_seq : Concat, GenSeq>{}; - - template<> struct gen_seq<0> : seq<>{}; - template<> struct gen_seq<1> : seq<0>{}; - - template - struct pop_back_helper; - - template - struct pop_back_helper, Tuple> - { - template