From dc5d9ba2908c2f7e9346e0d6d7f06011cf2ebdfc Mon Sep 17 00:00:00 2001 From: Huu Nguyen Date: Mon, 28 Sep 2015 20:22:02 -0400 Subject: Add two new gcc compilers to travis configuration --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index cec0186..8dc7d12 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,8 @@ compiler: env: matrix: - COMPILER=g++-4.8 CCOMPILER=gcc-4.8 PUSH_COVERAGE=ON + - COMPILER=g++-4.9 CCOMPILER=gcc-4.9 + - COMPILER=g++-5 CCOMPILER=gcc-5 addons: apt: @@ -19,6 +21,8 @@ addons: - boost-latest packages: - g++-4.8 + - g++-4.9 + - g++-5 - libboost1.55-all-dev - python-pip -- cgit v1.2.3-54-g00ecf From d42888fa286ea18e8d599e0191198ea3cff24d9d Mon Sep 17 00:00:00 2001 From: Huu Nguyen Date: Mon, 28 Sep 2015 20:22:42 -0400 Subject: Add clang compiler to travis configuration --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 8dc7d12..e283093 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,16 +13,20 @@ env: - COMPILER=g++-4.8 CCOMPILER=gcc-4.8 PUSH_COVERAGE=ON - COMPILER=g++-4.9 CCOMPILER=gcc-4.9 - COMPILER=g++-5 CCOMPILER=gcc-5 + - COMPILER=clang++-3.6 CCOMPILER=clang-3.6 addons: apt: sources: - ubuntu-toolchain-r-test - boost-latest + - llvm-toolchain-precise + - llvm-toolchain-precise-3.6 packages: - g++-4.8 - g++-4.9 - g++-5 + - clang-3.6 - libboost1.55-all-dev - python-pip -- cgit v1.2.3-54-g00ecf From d580ed7d25e6c642215db91a241faf4332be9a64 Mon Sep 17 00:00:00 2001 From: barcarolle Date: Thu, 20 Oct 2016 15:06:32 +0900 Subject: typo README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bea6c50..f6261b4 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ int main() - You can also use [json11](https://github.com/dropbox/json11) or [rapidjson](https://github.com/miloyip/rapidjson) for better speed or readability - [Mustache](http://mustache.github.io/) based templating library (crow::mustache) - Header only - - Provide an amalgamated header file `crow_all.h' with every features + - Provide an amalgamated header file `crow_all.h` with every features - Middleware support - Websocket support -- cgit v1.2.3-54-g00ecf From 990a8a34d090db2754d5004d0f793ea149fcd330 Mon Sep 17 00:00:00 2001 From: Javier Jerónimo Suárez Date: Sat, 19 Nov 2016 11:18:21 +0100 Subject: Trying to add support for conan.io dependency system... --- CMakeLists.txt | 4 ++++ conanfile.txt | 7 +++++++ 2 files changed, 11 insertions(+) create mode 100644 conanfile.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index e2d3bc7..4d257bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,9 @@ cmake_minimum_required(VERSION 2.8) project (crow_all) + +include(build/conanbuildinfo.cmake) +conan_basic_setup() + set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/") find_package(Tcmalloc) find_package(Threads) diff --git a/conanfile.txt b/conanfile.txt new file mode 100644 index 0000000..22b112a --- /dev/null +++ b/conanfile.txt @@ -0,0 +1,7 @@ +[requires] +Boost/1.60.0@lasote/stable +OpenSSL/1.0.2i@lasote/stable + +[generators] +cmake + -- cgit v1.2.3-54-g00ecf From bcf943b9b19552465c2482652444178152799cb4 Mon Sep 17 00:00:00 2001 From: Javier Jerónimo Suárez Date: Sat, 19 Nov 2016 11:35:49 +0100 Subject: Trying to add support for conan.io --- conanfile.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 conanfile.py diff --git a/conanfile.py b/conanfile.py new file mode 100644 index 0000000..416ffd1 --- /dev/null +++ b/conanfile.py @@ -0,0 +1,23 @@ +from conans import ConanFile, CMake + +class CrowConan(ConanFile): + name = "Crow" + version = "0.1" + settings = "os", "compiler", "build_type", "arch" + # No exports necessary + + def source(self): + # this will create a hello subfolder, take it into account + self.run("git clone https://github.com/javierjeronimo/crow.git") + + def build(self): + cmake = CMake(self.settings) + self.run("cmake . %s" % cmake.build_config) + self.run("make") + + def package(self): + self.copy("*.h", dst="include", src="amalgamate") + + def package_info(self): + self.cpp_info.libs = ["crow"] + -- cgit v1.2.3-54-g00ecf From ede9a21dbc7658b64571233af8f06ee671c9888e Mon Sep 17 00:00:00 2001 From: Javier Jerónimo Suárez Date: Sat, 19 Nov 2016 11:40:17 +0100 Subject: More... --- conanfile.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/conanfile.py b/conanfile.py index 416ffd1..677c678 100644 --- a/conanfile.py +++ b/conanfile.py @@ -3,6 +3,8 @@ from conans import ConanFile, CMake class CrowConan(ConanFile): name = "Crow" version = "0.1" + url = "https://github.com/javierjeronimo/crow" + license = "see https://github.com/ipkn/crow/blob/master/LICENSE" settings = "os", "compiler", "build_type", "arch" # No exports necessary @@ -12,6 +14,7 @@ class CrowConan(ConanFile): def build(self): cmake = CMake(self.settings) + self.run('cmake %s %s' % (self.conanfile_directory, cmake.command_line)) self.run("cmake . %s" % cmake.build_config) self.run("make") -- cgit v1.2.3-54-g00ecf From 0f4cfc91086dc2d1f05407ac738a581f5768951b Mon Sep 17 00:00:00 2001 From: Javier Jerónimo Suárez Date: Sat, 19 Nov 2016 11:44:15 +0100 Subject: More --- conanfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conanfile.py b/conanfile.py index 677c678..ba12a10 100644 --- a/conanfile.py +++ b/conanfile.py @@ -14,7 +14,7 @@ class CrowConan(ConanFile): def build(self): cmake = CMake(self.settings) - self.run('cmake %s %s' % (self.conanfile_directory, cmake.command_line)) + # self.run('cmake %s %s' % (self.conanfile_directory, cmake.command_line)) self.run("cmake . %s" % cmake.build_config) self.run("make") -- cgit v1.2.3-54-g00ecf From 748a95c84fe43471c5de58122de4c778f08ae2b3 Mon Sep 17 00:00:00 2001 From: Javier Jerónimo Suárez Date: Sat, 19 Nov 2016 11:51:32 +0100 Subject: More --- conanfile.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/conanfile.py b/conanfile.py index ba12a10..533179f 100644 --- a/conanfile.py +++ b/conanfile.py @@ -1,4 +1,5 @@ from conans import ConanFile, CMake +import shutil class CrowConan(ConanFile): name = "Crow" @@ -11,6 +12,7 @@ class CrowConan(ConanFile): def source(self): # this will create a hello subfolder, take it into account self.run("git clone https://github.com/javierjeronimo/crow.git") + shutil.move("crow/*", ".") def build(self): cmake = CMake(self.settings) -- cgit v1.2.3-54-g00ecf From 09cae9f4c213628f909fd0f8a9dcdaf5e10c17dd Mon Sep 17 00:00:00 2001 From: Javier Jerónimo Suárez Date: Sat, 19 Nov 2016 11:54:34 +0100 Subject: More --- conanfile.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/conanfile.py b/conanfile.py index 533179f..b72db5c 100644 --- a/conanfile.py +++ b/conanfile.py @@ -1,5 +1,4 @@ from conans import ConanFile, CMake -import shutil class CrowConan(ConanFile): name = "Crow" @@ -12,11 +11,10 @@ class CrowConan(ConanFile): def source(self): # this will create a hello subfolder, take it into account self.run("git clone https://github.com/javierjeronimo/crow.git") - shutil.move("crow/*", ".") def build(self): cmake = CMake(self.settings) - # self.run('cmake %s %s' % (self.conanfile_directory, cmake.command_line)) + self.run('cmake %s/crow %s' % (self.conanfile_directory, cmake.command_line)) self.run("cmake . %s" % cmake.build_config) self.run("make") -- cgit v1.2.3-54-g00ecf From 5037825a59811027047c0100dced0760e78b8ff0 Mon Sep 17 00:00:00 2001 From: Javier Jerónimo Suárez Date: Sat, 19 Nov 2016 11:56:33 +0100 Subject: More --- conanfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/conanfile.py b/conanfile.py index b72db5c..8a19503 100644 --- a/conanfile.py +++ b/conanfile.py @@ -15,7 +15,7 @@ class CrowConan(ConanFile): def build(self): cmake = CMake(self.settings) self.run('cmake %s/crow %s' % (self.conanfile_directory, cmake.command_line)) - self.run("cmake . %s" % cmake.build_config) + self.run("cmake --build . %s" % cmake.build_config) self.run("make") def package(self): -- cgit v1.2.3-54-g00ecf From d43cd764353cd12a40cdb9c692593d9caba2cd43 Mon Sep 17 00:00:00 2001 From: Javier Jerónimo Suárez Date: Sat, 19 Nov 2016 12:00:26 +0100 Subject: More --- conanfile.py | 1 + 1 file changed, 1 insertion(+) diff --git a/conanfile.py b/conanfile.py index 8a19503..4f2987e 100644 --- a/conanfile.py +++ b/conanfile.py @@ -6,6 +6,7 @@ class CrowConan(ConanFile): url = "https://github.com/javierjeronimo/crow" license = "see https://github.com/ipkn/crow/blob/master/LICENSE" settings = "os", "compiler", "build_type", "arch" + generators = "cmake" # No exports necessary def source(self): -- cgit v1.2.3-54-g00ecf From e9c97b1350025d93247704dc1f47a8b6fd6211cc Mon Sep 17 00:00:00 2001 From: Javier Jerónimo Suárez Date: Sat, 19 Nov 2016 12:02:04 +0100 Subject: More --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d257bd..05a90b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 2.8) project (crow_all) -include(build/conanbuildinfo.cmake) +include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) conan_basic_setup() set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/") -- cgit v1.2.3-54-g00ecf From 2877991498b009a16723a2b171967b846c8a74ca Mon Sep 17 00:00:00 2001 From: Javier Jerónimo Suárez Date: Sat, 19 Nov 2016 12:07:14 +0100 Subject: Requirements --- conanfile.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/conanfile.py b/conanfile.py index 4f2987e..cf0c798 100644 --- a/conanfile.py +++ b/conanfile.py @@ -7,6 +7,9 @@ class CrowConan(ConanFile): license = "see https://github.com/ipkn/crow/blob/master/LICENSE" settings = "os", "compiler", "build_type", "arch" generators = "cmake" + + requires = (("Boost/1.60.0@lasote/stable"), + ("OpenSSL/1.0.2i@lasote/stable")) # No exports necessary def source(self): -- cgit v1.2.3-54-g00ecf From c2f3aea0a1f60c7d2d5f586fe7abb2362c40faf3 Mon Sep 17 00:00:00 2001 From: Javier Jerónimo Suárez Date: Sat, 19 Nov 2016 12:39:13 +0100 Subject: Its a header only conan package --- conanfile.py | 1 - 1 file changed, 1 deletion(-) diff --git a/conanfile.py b/conanfile.py index cf0c798..9b06378 100644 --- a/conanfile.py +++ b/conanfile.py @@ -5,7 +5,6 @@ class CrowConan(ConanFile): version = "0.1" url = "https://github.com/javierjeronimo/crow" license = "see https://github.com/ipkn/crow/blob/master/LICENSE" - settings = "os", "compiler", "build_type", "arch" generators = "cmake" requires = (("Boost/1.60.0@lasote/stable"), -- cgit v1.2.3-54-g00ecf From 5f786cdccd2b511f867d08dbe7a10b7566e1e9fe Mon Sep 17 00:00:00 2001 From: Javier Jerónimo Suárez Date: Sun, 20 Nov 2016 22:40:47 +0100 Subject: Fixes --- conanfile.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/conanfile.py b/conanfile.py index 9b06378..73d9b14 100644 --- a/conanfile.py +++ b/conanfile.py @@ -6,6 +6,7 @@ class CrowConan(ConanFile): url = "https://github.com/javierjeronimo/crow" license = "see https://github.com/ipkn/crow/blob/master/LICENSE" generators = "cmake" + settings = "os", "compiler", "build_type", "arch" requires = (("Boost/1.60.0@lasote/stable"), ("OpenSSL/1.0.2i@lasote/stable")) @@ -17,13 +18,9 @@ class CrowConan(ConanFile): def build(self): cmake = CMake(self.settings) - self.run('cmake %s/crow %s' % (self.conanfile_directory, cmake.command_line)) - self.run("cmake --build . %s" % cmake.build_config) - self.run("make") + self.run('cmake %s/crow %s' % (self.conanfile_directory, cmake.command_line)) + self.run("cmake --build . %s" % cmake.build_config) + self.run("make") def package(self): self.copy("*.h", dst="include", src="amalgamate") - - def package_info(self): - self.cpp_info.libs = ["crow"] - -- cgit v1.2.3-54-g00ecf From 18bc428f06d71e061e49b71813027d9ef8ab8fb0 Mon Sep 17 00:00:00 2001 From: Javier Jerónimo Suárez Date: Sun, 20 Nov 2016 22:43:34 +0100 Subject: indent --- conanfile.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/conanfile.py b/conanfile.py index 73d9b14..36d8ba5 100644 --- a/conanfile.py +++ b/conanfile.py @@ -1,5 +1,6 @@ from conans import ConanFile, CMake + class CrowConan(ConanFile): name = "Crow" version = "0.1" @@ -10,6 +11,7 @@ class CrowConan(ConanFile): requires = (("Boost/1.60.0@lasote/stable"), ("OpenSSL/1.0.2i@lasote/stable")) + # No exports necessary def source(self): @@ -18,9 +20,10 @@ class CrowConan(ConanFile): def build(self): cmake = CMake(self.settings) - self.run('cmake %s/crow %s' % (self.conanfile_directory, cmake.command_line)) - self.run("cmake --build . %s" % cmake.build_config) - self.run("make") + self.run('cmake %s/crow %s' % (self.conanfile_directory, cmake.command_line)) + self.run("cmake --build . %s" % cmake.build_config) + self.run("make") + - def package(self): - self.copy("*.h", dst="include", src="amalgamate") +def package(self): + self.copy("*.h", dst="include", src="amalgamate") -- cgit v1.2.3-54-g00ecf From 79ca284d6c341f43157e038c722c30440859b1ee Mon Sep 17 00:00:00 2001 From: Javier Jerónimo Suárez Date: Sun, 20 Nov 2016 22:47:14 +0100 Subject: indent --- conanfile.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/conanfile.py b/conanfile.py index 36d8ba5..a8eb8c1 100644 --- a/conanfile.py +++ b/conanfile.py @@ -24,6 +24,5 @@ class CrowConan(ConanFile): self.run("cmake --build . %s" % cmake.build_config) self.run("make") - -def package(self): - self.copy("*.h", dst="include", src="amalgamate") + def package(self): + self.copy("*.h", dst="include", src="amalgamate") -- cgit v1.2.3-54-g00ecf From 91ac9111d45fa618a311c9dd2c8f30c031d8f46b Mon Sep 17 00:00:00 2001 From: Javier Jerónimo Suárez Date: Sun, 20 Nov 2016 23:04:25 +0100 Subject: fix --- conanfile.txt | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 conanfile.txt diff --git a/conanfile.txt b/conanfile.txt deleted file mode 100644 index 22b112a..0000000 --- a/conanfile.txt +++ /dev/null @@ -1,7 +0,0 @@ -[requires] -Boost/1.60.0@lasote/stable -OpenSSL/1.0.2i@lasote/stable - -[generators] -cmake - -- cgit v1.2.3-54-g00ecf From a71c0a0edb9262eb7dc83c67bf523fa7272d701f Mon Sep 17 00:00:00 2001 From: Javier Jerónimo Suárez Date: Sun, 20 Nov 2016 23:20:48 +0100 Subject: ignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 6dcb0a2..cfe8b64 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,6 @@ build .directory crow_all.h + +# conan.io +build/ -- cgit v1.2.3-54-g00ecf From c03d3b2d5aebbfc11fd85af93d6c389ca4d39d73 Mon Sep 17 00:00:00 2001 From: Javier Jerónimo Suárez Date: Tue, 22 Nov 2016 17:50:06 +0100 Subject: Make it compatible with conan.io (but optional). --- CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 05a90b7..f7f2d99 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,10 @@ cmake_minimum_required(VERSION 2.8) project (crow_all) +if(EXISTS "${CMAKE_BINARY_DIR}/conanbuildinfo.cmake") include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) conan_basic_setup() +endif() set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/") find_package(Tcmalloc) @@ -28,13 +30,13 @@ endif() include_directories( ${Boost_INCLUDE_DIR} ) -set(PROJECT_INCLUDE_DIR +set(PROJECT_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include ) include_directories("${PROJECT_INCLUDE_DIR}") include_directories("${PROJECT_SOURCE_DIR}") - + #add_subdirectory(src) add_subdirectory(examples) if (MSVC) -- cgit v1.2.3-54-g00ecf From 32d66d6fd1ac7f90512a573991de4940b5063374 Mon Sep 17 00:00:00 2001 From: Vsevolod Kvachev Date: Tue, 6 Dec 2016 18:22:10 +0300 Subject: Upgrade amalgamate --- amalgamate/crow_all.h | 6551 ++++++++++++++++++++++++------------------------ include/crow/routing.h | 8 +- 2 files changed, 3281 insertions(+), 3278 deletions(-) diff --git a/amalgamate/crow_all.h b/amalgamate/crow_all.h index 41b06ff..6ffbe66 100644 --- a/amalgamate/crow_all.h +++ b/amalgamate/crow_all.h @@ -1,3 +1,239 @@ +#pragma once + +#include +#include +#include + +namespace crow +{ + struct ci_hash + { + size_t operator()(const std::string& key) const + { + std::size_t seed = 0; + std::locale locale; + + for(auto c : key) + { + boost::hash_combine(seed, std::toupper(c, locale)); + } + + return seed; + } + }; + + struct ci_key_eq + { + bool operator()(const std::string& l, const std::string& r) const + { + return boost::iequals(l, r); + } + }; + + using ci_map = std::unordered_multimap; +} + + + +/* + * + * TinySHA1 - a header only implementation of the SHA1 algorithm in C++. Based + * on the implementation in boost::uuid::details. + * + * SHA1 Wikipedia Page: http://en.wikipedia.org/wiki/SHA-1 + * + * Copyright (c) 2012-22 SAURAV MOHAPATRA + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef _TINY_SHA1_HPP_ +#define _TINY_SHA1_HPP_ +#include +#include +#include +#include +namespace sha1 +{ + class SHA1 + { + public: + typedef uint32_t digest32_t[5]; + typedef uint8_t digest8_t[20]; + inline static uint32_t LeftRotate(uint32_t value, size_t count) { + return (value << count) ^ (value >> (32-count)); + } + SHA1(){ reset(); } + virtual ~SHA1() {} + SHA1(const SHA1& s) { *this = s; } + const SHA1& operator = (const SHA1& s) { + memcpy(m_digest, s.m_digest, 5 * sizeof(uint32_t)); + memcpy(m_block, s.m_block, 64); + m_blockByteIndex = s.m_blockByteIndex; + m_byteCount = s.m_byteCount; + return *this; + } + SHA1& reset() { + m_digest[0] = 0x67452301; + m_digest[1] = 0xEFCDAB89; + m_digest[2] = 0x98BADCFE; + m_digest[3] = 0x10325476; + m_digest[4] = 0xC3D2E1F0; + m_blockByteIndex = 0; + m_byteCount = 0; + return *this; + } + SHA1& processByte(uint8_t octet) { + this->m_block[this->m_blockByteIndex++] = octet; + ++this->m_byteCount; + if(m_blockByteIndex == 64) { + this->m_blockByteIndex = 0; + processBlock(); + } + return *this; + } + SHA1& processBlock(const void* const start, const void* const end) { + const uint8_t* begin = static_cast(start); + const uint8_t* finish = static_cast(end); + while(begin != finish) { + processByte(*begin); + begin++; + } + return *this; + } + SHA1& processBytes(const void* const data, size_t len) { + const uint8_t* block = static_cast(data); + processBlock(block, block + len); + return *this; + } + const uint32_t* getDigest(digest32_t digest) { + size_t bitCount = this->m_byteCount * 8; + processByte(0x80); + if (this->m_blockByteIndex > 56) { + while (m_blockByteIndex != 0) { + processByte(0); + } + while (m_blockByteIndex < 56) { + processByte(0); + } + } else { + while (m_blockByteIndex < 56) { + processByte(0); + } + } + processByte(0); + processByte(0); + processByte(0); + processByte(0); + processByte( static_cast((bitCount>>24) & 0xFF)); + processByte( static_cast((bitCount>>16) & 0xFF)); + processByte( static_cast((bitCount>>8 ) & 0xFF)); + processByte( static_cast((bitCount) & 0xFF)); + + memcpy(digest, m_digest, 5 * sizeof(uint32_t)); + return digest; + } + const uint8_t* getDigestBytes(digest8_t digest) { + digest32_t d32; + getDigest(d32); + size_t di = 0; + digest[di++] = ((d32[0] >> 24) & 0xFF); + digest[di++] = ((d32[0] >> 16) & 0xFF); + digest[di++] = ((d32[0] >> 8) & 0xFF); + digest[di++] = ((d32[0]) & 0xFF); + + digest[di++] = ((d32[1] >> 24) & 0xFF); + digest[di++] = ((d32[1] >> 16) & 0xFF); + digest[di++] = ((d32[1] >> 8) & 0xFF); + digest[di++] = ((d32[1]) & 0xFF); + + digest[di++] = ((d32[2] >> 24) & 0xFF); + digest[di++] = ((d32[2] >> 16) & 0xFF); + digest[di++] = ((d32[2] >> 8) & 0xFF); + digest[di++] = ((d32[2]) & 0xFF); + + digest[di++] = ((d32[3] >> 24) & 0xFF); + digest[di++] = ((d32[3] >> 16) & 0xFF); + digest[di++] = ((d32[3] >> 8) & 0xFF); + digest[di++] = ((d32[3]) & 0xFF); + + digest[di++] = ((d32[4] >> 24) & 0xFF); + digest[di++] = ((d32[4] >> 16) & 0xFF); + digest[di++] = ((d32[4] >> 8) & 0xFF); + digest[di++] = ((d32[4]) & 0xFF); + return digest; + } + + protected: + void processBlock() { + uint32_t w[80]; + for (size_t i = 0; i < 16; i++) { + w[i] = (m_block[i*4 + 0] << 24); + w[i] |= (m_block[i*4 + 1] << 16); + w[i] |= (m_block[i*4 + 2] << 8); + w[i] |= (m_block[i*4 + 3]); + } + for (size_t i = 16; i < 80; i++) { + w[i] = LeftRotate((w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]), 1); + } + + uint32_t a = m_digest[0]; + uint32_t b = m_digest[1]; + uint32_t c = m_digest[2]; + uint32_t d = m_digest[3]; + uint32_t e = m_digest[4]; + + for (std::size_t i=0; i<80; ++i) { + uint32_t f = 0; + uint32_t k = 0; + + if (i<20) { + f = (b & c) | (~b & d); + k = 0x5A827999; + } else if (i<40) { + f = b ^ c ^ d; + k = 0x6ED9EBA1; + } else if (i<60) { + f = (b & c) | (b & d) | (c & d); + k = 0x8F1BBCDC; + } else { + f = b ^ c ^ d; + k = 0xCA62C1D6; + } + uint32_t temp = LeftRotate(a, 5) + f + e + k + w[i]; + e = d; + d = c; + c = LeftRotate(b, 30); + b = a; + a = temp; + } + + m_digest[0] += a; + m_digest[1] += b; + m_digest[2] += c; + m_digest[3] += d; + m_digest[4] += e; + } + private: + digest32_t m_digest; + uint8_t m_block[64]; + size_t m_blockByteIndex; + size_t m_byteCount; + }; +} +#endif + + + #pragma once #include @@ -6,6 +242,8 @@ #include #include +namespace crow +{ // ---------------------------------------------------------------------------- // qs_parse (modified) // https://github.com/bartgrantham/qs_parse @@ -231,6 +469,7 @@ inline char * qs_scanvalue(const char * key, const char * qs, char * val, size_t return val; } +} // ---------------------------------------------------------------------------- @@ -2987,250 +3226,14 @@ http_parser_version(void) { #pragma once +// settings for crow +// TODO - replace with runtime config. libucl? -#include -#include -#include +/* #ifdef - enables debug mode */ +#define CROW_ENABLE_DEBUG -namespace crow -{ - struct ci_hash - { - size_t operator()(const std::string& key) const - { - std::size_t seed = 0; - std::locale locale; - - for(auto c : key) - { - boost::hash_combine(seed, std::toupper(c, locale)); - } - - return seed; - } - }; - - struct ci_key_eq - { - bool operator()(const std::string& l, const std::string& r) const - { - return boost::iequals(l, r); - } - }; - - using ci_map = std::unordered_multimap; -} - - - -/* - * - * TinySHA1 - a header only implementation of the SHA1 algorithm in C++. Based - * on the implementation in boost::uuid::details. - * - * SHA1 Wikipedia Page: http://en.wikipedia.org/wiki/SHA-1 - * - * Copyright (c) 2012-22 SAURAV MOHAPATRA - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ -#ifndef _TINY_SHA1_HPP_ -#define _TINY_SHA1_HPP_ -#include -#include -#include -#include -namespace sha1 -{ - class SHA1 - { - public: - typedef uint32_t digest32_t[5]; - typedef uint8_t digest8_t[20]; - inline static uint32_t LeftRotate(uint32_t value, size_t count) { - return (value << count) ^ (value >> (32-count)); - } - SHA1(){ reset(); } - virtual ~SHA1() {} - SHA1(const SHA1& s) { *this = s; } - const SHA1& operator = (const SHA1& s) { - memcpy(m_digest, s.m_digest, 5 * sizeof(uint32_t)); - memcpy(m_block, s.m_block, 64); - m_blockByteIndex = s.m_blockByteIndex; - m_byteCount = s.m_byteCount; - return *this; - } - SHA1& reset() { - m_digest[0] = 0x67452301; - m_digest[1] = 0xEFCDAB89; - m_digest[2] = 0x98BADCFE; - m_digest[3] = 0x10325476; - m_digest[4] = 0xC3D2E1F0; - m_blockByteIndex = 0; - m_byteCount = 0; - return *this; - } - SHA1& processByte(uint8_t octet) { - this->m_block[this->m_blockByteIndex++] = octet; - ++this->m_byteCount; - if(m_blockByteIndex == 64) { - this->m_blockByteIndex = 0; - processBlock(); - } - return *this; - } - SHA1& processBlock(const void* const start, const void* const end) { - const uint8_t* begin = static_cast(start); - const uint8_t* finish = static_cast(end); - while(begin != finish) { - processByte(*begin); - begin++; - } - return *this; - } - SHA1& processBytes(const void* const data, size_t len) { - const uint8_t* block = static_cast(data); - processBlock(block, block + len); - return *this; - } - const uint32_t* getDigest(digest32_t digest) { - size_t bitCount = this->m_byteCount * 8; - processByte(0x80); - if (this->m_blockByteIndex > 56) { - while (m_blockByteIndex != 0) { - processByte(0); - } - while (m_blockByteIndex < 56) { - processByte(0); - } - } else { - while (m_blockByteIndex < 56) { - processByte(0); - } - } - processByte(0); - processByte(0); - processByte(0); - processByte(0); - processByte( static_cast((bitCount>>24) & 0xFF)); - processByte( static_cast((bitCount>>16) & 0xFF)); - processByte( static_cast((bitCount>>8 ) & 0xFF)); - processByte( static_cast((bitCount) & 0xFF)); - - memcpy(digest, m_digest, 5 * sizeof(uint32_t)); - return digest; - } - const uint8_t* getDigestBytes(digest8_t digest) { - digest32_t d32; - getDigest(d32); - size_t di = 0; - digest[di++] = ((d32[0] >> 24) & 0xFF); - digest[di++] = ((d32[0] >> 16) & 0xFF); - digest[di++] = ((d32[0] >> 8) & 0xFF); - digest[di++] = ((d32[0]) & 0xFF); - - digest[di++] = ((d32[1] >> 24) & 0xFF); - digest[di++] = ((d32[1] >> 16) & 0xFF); - digest[di++] = ((d32[1] >> 8) & 0xFF); - digest[di++] = ((d32[1]) & 0xFF); - - digest[di++] = ((d32[2] >> 24) & 0xFF); - digest[di++] = ((d32[2] >> 16) & 0xFF); - digest[di++] = ((d32[2] >> 8) & 0xFF); - digest[di++] = ((d32[2]) & 0xFF); - - digest[di++] = ((d32[3] >> 24) & 0xFF); - digest[di++] = ((d32[3] >> 16) & 0xFF); - digest[di++] = ((d32[3] >> 8) & 0xFF); - digest[di++] = ((d32[3]) & 0xFF); - - digest[di++] = ((d32[4] >> 24) & 0xFF); - digest[di++] = ((d32[4] >> 16) & 0xFF); - digest[di++] = ((d32[4] >> 8) & 0xFF); - digest[di++] = ((d32[4]) & 0xFF); - return digest; - } - - protected: - void processBlock() { - uint32_t w[80]; - for (size_t i = 0; i < 16; i++) { - w[i] = (m_block[i*4 + 0] << 24); - w[i] |= (m_block[i*4 + 1] << 16); - w[i] |= (m_block[i*4 + 2] << 8); - w[i] |= (m_block[i*4 + 3]); - } - for (size_t i = 16; i < 80; i++) { - w[i] = LeftRotate((w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]), 1); - } - - uint32_t a = m_digest[0]; - uint32_t b = m_digest[1]; - uint32_t c = m_digest[2]; - uint32_t d = m_digest[3]; - uint32_t e = m_digest[4]; - - for (std::size_t i=0; i<80; ++i) { - uint32_t f = 0; - uint32_t k = 0; - - if (i<20) { - f = (b & c) | (~b & d); - k = 0x5A827999; - } else if (i<40) { - f = b ^ c ^ d; - k = 0x6ED9EBA1; - } else if (i<60) { - f = (b & c) | (b & d) | (c & d); - k = 0x8F1BBCDC; - } else { - f = b ^ c ^ d; - k = 0xCA62C1D6; - } - uint32_t temp = LeftRotate(a, 5) + f + e + k + w[i]; - e = d; - d = c; - c = LeftRotate(b, 30); - b = a; - a = temp; - } - - m_digest[0] += a; - m_digest[1] += b; - m_digest[2] += c; - m_digest[3] += d; - m_digest[4] += e; - } - private: - digest32_t m_digest; - uint8_t m_block[64]; - size_t m_blockByteIndex; - size_t m_byteCount; - }; -} -#endif - - - -#pragma once -// settings for crow -// TODO - replace with runtime config. libucl? - -/* #ifdef - enables debug mode */ -#define CROW_ENABLE_DEBUG - -/* #ifdef - enables logging */ -#define CROW_ENABLE_LOGGING +/* #ifdef - enables logging */ +#define CROW_ENABLE_LOGGING /* #ifdef - enables ssl */ //#define CROW_ENABLE_SSL @@ -3381,2945 +3384,2945 @@ namespace crow #pragma once -//#define CROW_JSON_NO_ERROR_CHECK - +#include +#include +#include +#include +#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(__GNUG__) || defined(__clang__) -#define crow_json_likely(x) __builtin_expect(x, 1) -#define crow_json_unlikely(x) __builtin_expect(x, 0) -#else -#define crow_json_likely(x) x -#define crow_json_unlikely(x) x -#endif - namespace crow { - namespace mustache - { - class template_t; - } - - namespace json + namespace black_magic { - inline void escape(const std::string& str, std::string& ret) - { - ret.reserve(ret.size() + str.size()+str.size()/4); - for(char c:str) - { - switch(c) - { - case '"': ret += "\\\""; break; - case '\\': ret += "\\\\"; break; - case '\n': ret += "\\n"; break; - case '\b': ret += "\\b"; break; - case '\f': ret += "\\f"; break; - case '\r': ret += "\\r"; break; - case '\t': ret += "\\t"; break; - default: - if (0 <= c && c < 0x20) - { - ret += "\\u00"; - auto to_hex = [](char c) - { - c = c&0xf; - if (c < 10) - return '0' + c; - return 'a'+c-10; - }; - ret += to_hex(c/16); - ret += to_hex(c%16); - } - else - ret += c; - break; - } - } - } - inline std::string escape(const std::string& str) - { - std::string ret; - escape(str, ret); - return ret; - } - - enum class type : char +#ifndef CROW_MSVC_WORKAROUND + struct OutOfRange { - Null, - False, - True, - Number, - String, - List, - Object, + OutOfRange(unsigned /*pos*/, unsigned /*length*/) {} }; - - inline const char* get_type_str(type t) { - switch(t){ - case type::Number: return "Number"; - case type::False: return "False"; - case type::True: return "True"; - case type::List: return "List"; - case type::String: return "String"; - case type::Object: return "Object"; - default: return "Unknown"; - } + constexpr unsigned requires_in_range( unsigned i, unsigned len ) + { + return i >= len ? throw OutOfRange(i, len) : i; } - class rvalue; - rvalue load(const char* data, size_t size); - - namespace detail + class const_str { + const char * const begin_; + unsigned size_; - struct r_string - : boost::less_than_comparable, - boost::less_than_comparable, - boost::equality_comparable, - boost::equality_comparable - { - r_string() {}; - r_string(char* s, char* e) - : s_(s), e_(e) - {}; - ~r_string() - { - if (owned_) - delete[] s_; - } - - r_string(const r_string& r) - { - *this = r; - } - - r_string(r_string&& r) - { - *this = r; - } - - r_string& operator = (r_string&& r) - { - s_ = r.s_; - e_ = r.e_; - owned_ = r.owned_; - if (r.owned_) - r.owned_ = 0; - return *this; - } - - r_string& operator = (const r_string& r) - { - s_ = r.s_; - e_ = r.e_; - owned_ = 0; - return *this; + 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]; + } - operator std::string () const - { - return std::string(s_, e_); - } + constexpr operator const char *() const { + return begin_; + } + constexpr const char* begin() const { return begin_; } + constexpr const char* end() const { return begin_ + size_; } - const char* begin() const { return s_; } - const char* end() const { return e_; } - size_t size() const { return end() - begin(); } + constexpr unsigned size() const { + return size_; + } + }; - using iterator = const char*; - using const_iterator = const char*; + constexpr unsigned find_closing_tag(const_str s, unsigned p) + { + return s[p] == '>' ? p : find_closing_tag(s, p+1); + } - char* s_; - mutable char* e_; - uint8_t owned_{0}; - friend std::ostream& operator << (std::ostream& os, const r_string& s) - { - os << (std::string)s; - return os; - } - private: - void force(char* s, uint32_t /*length*/) - { - s_ = s; - owned_ = 1; - } - friend rvalue crow::json::load(const char* data, size_t size); - }; + 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); + } - inline bool operator < (const r_string& l, const r_string& r) - { - return boost::lexicographical_compare(l,r); - } + 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); + } - inline bool operator < (const r_string& l, const std::string& r) - { - return boost::lexicographical_compare(l,r); - } + 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); + } - inline bool operator > (const r_string& l, const std::string& r) - { - return boost::lexicographical_compare(r,l); - } + constexpr bool is_int(const_str s, unsigned i) + { + return is_equ_n(s, i, "", 0, 5); + } - inline bool operator == (const r_string& l, const r_string& r) - { - return boost::equals(l,r); - } + constexpr bool is_uint(const_str s, unsigned i) + { + return is_equ_n(s, i, "", 0, 6); + } - inline bool operator == (const r_string& l, const std::string& r) - { - return boost::equals(l,r); - } + constexpr bool is_float(const_str s, unsigned i) + { + return is_equ_n(s, i, "", 0, 7) || + is_equ_n(s, i, "", 0, 8); } - class rvalue + constexpr bool is_str(const_str s, unsigned i) { - static const int cached_bit = 2; - static const int error_bit = 4; - public: - rvalue() noexcept : option_{error_bit} - {} - rvalue(type t) noexcept - : lsize_{}, lremain_{}, t_{t} - {} - rvalue(type t, char* s, char* e) noexcept - : start_{s}, - end_{e}, - t_{t} - {} + return is_equ_n(s, i, "", 0, 5) || + is_equ_n(s, i, "", 0, 8); + } - rvalue(const rvalue& r) - : start_(r.start_), - end_(r.end_), - key_(r.key_), - t_(r.t_), - option_(r.option_) - { - copy_l(r); - } + constexpr bool is_path(const_str s, unsigned i) + { + return is_equ_n(s, i, "", 0, 6); + } +#endif + template + struct parameter_tag + { + static const int value = 0; + }; +#define CROW_INTERNAL_PARAMETER_TAG(t, i) \ +template <> \ +struct parameter_tag \ +{ \ + static const int value = i; \ +} + CROW_INTERNAL_PARAMETER_TAG(int, 1); + CROW_INTERNAL_PARAMETER_TAG(char, 1); + CROW_INTERNAL_PARAMETER_TAG(short, 1); + CROW_INTERNAL_PARAMETER_TAG(long, 1); + CROW_INTERNAL_PARAMETER_TAG(long long, 1); + CROW_INTERNAL_PARAMETER_TAG(unsigned int, 2); + CROW_INTERNAL_PARAMETER_TAG(unsigned char, 2); + CROW_INTERNAL_PARAMETER_TAG(unsigned short, 2); + CROW_INTERNAL_PARAMETER_TAG(unsigned long, 2); + CROW_INTERNAL_PARAMETER_TAG(unsigned long long, 2); + CROW_INTERNAL_PARAMETER_TAG(double, 3); + CROW_INTERNAL_PARAMETER_TAG(std::string, 4); +#undef CROW_INTERNAL_PARAMETER_TAG + template + struct compute_parameter_tag_from_args_list; - rvalue(rvalue&& r) noexcept - { - *this = std::move(r); - } + template <> + struct compute_parameter_tag_from_args_list<> + { + static const int value = 0; + }; - rvalue& operator = (const rvalue& r) - { - start_ = r.start_; - end_ = r.end_; - key_ = r.key_; - copy_l(r); - t_ = r.t_; - option_ = r.option_; - return *this; - } - rvalue& operator = (rvalue&& r) noexcept - { - start_ = r.start_; - end_ = r.end_; - key_ = std::move(r.key_); - l_ = std::move(r.l_); - lsize_ = r.lsize_; - lremain_ = r.lremain_; - t_ = r.t_; - option_ = r.option_; - return *this; - } + template + struct compute_parameter_tag_from_args_list + { + static const int sub_value = + compute_parameter_tag_from_args_list::value; + static const int value = + parameter_tag::type>::value + ? sub_value* 6 + parameter_tag::type>::value + : sub_value; + }; - explicit operator bool() const noexcept - { - return (option_ & error_bit) == 0; - } + static inline bool is_parameter_tag_compatible(uint64_t a, uint64_t b) + { + if (a == 0) + return b == 0; + if (b == 0) + return a == 0; + int sa = a%6; + int sb = a%6; + if (sa == 5) sa = 4; + if (sb == 5) sb = 4; + if (sa != sb) + return false; + return is_parameter_tag_compatible(a/6, b/6); + } - explicit operator int64_t() const - { - return i(); - } + static inline unsigned find_closing_tag_runtime(const char* s, unsigned p) + { + return + s[p] == 0 + ? throw std::runtime_error("unmatched tag <") : + s[p] == '>' + ? p : find_closing_tag_runtime(s, p + 1); + } + + static inline uint64_t get_parameter_tag_runtime(const char* s, unsigned p = 0) + { + return + s[p] == 0 + ? 0 : + s[p] == '<' ? ( + std::strncmp(s+p, "", 5) == 0 + ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 1 : + std::strncmp(s+p, "", 6) == 0 + ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 2 : + (std::strncmp(s+p, "", 7) == 0 || + std::strncmp(s+p, "", 8) == 0) + ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 3 : + (std::strncmp(s+p, "", 5) == 0 || + std::strncmp(s+p, "", 8) == 0) + ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 4 : + std::strncmp(s+p, "", 6) == 0 + ? get_parameter_tag_runtime(s, find_closing_tag_runtime(s, p)) * 6 + 5 : + throw std::runtime_error("invalid parameter type") + ) : + get_parameter_tag_runtime(s, p+1); + } +#ifndef CROW_MSVC_WORKAROUND + 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); + } +#endif - explicit operator uint64_t() const - { - return u(); - } + 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); - explicit operator int() const - { - return (int)i(); - } + template + static int __test(...); - type t() const - { -#ifndef CROW_JSON_NO_ERROR_CHECK - if (option_ & error_bit) - { - throw std::runtime_error("invalid json object"); - } -#endif - return t_; - } + static constexpr bool value = sizeof(__test(0)) == sizeof(char); + }; - int64_t i() const - { -#ifndef CROW_JSON_NO_ERROR_CHECK - switch (t()) { - case type::Number: - case type::String: - return boost::lexical_cast(start_, end_-start_); - default: - const std::string msg = "expected number, got: " - + std::string(get_type_str(t())); - throw std::runtime_error(msg); - } -#endif - return boost::lexical_cast(start_, end_-start_); - } - uint64_t u() const - { -#ifndef CROW_JSON_NO_ERROR_CHECK - switch (t()) { - case type::Number: - case type::String: - return boost::lexical_cast(start_, end_-start_); - default: - throw std::runtime_error(std::string("expected number, got: ") + get_type_str(t())); - } -#endif - return boost::lexical_cast(start_, end_-start_); - } + template + struct single_tag_to_type + { + }; - double d() const - { -#ifndef CROW_JSON_NO_ERROR_CHECK - if (t() != type::Number) - throw std::runtime_error("value is not number"); -#endif - return boost::lexical_cast(start_, end_-start_); - } + template <> + struct single_tag_to_type<1> + { + using type = int64_t; + }; - bool b() const - { -#ifndef CROW_JSON_NO_ERROR_CHECK - if (t() != type::True && t() != type::False) - throw std::runtime_error("value is not boolean"); -#endif - return t() == type::True; - } + template <> + struct single_tag_to_type<2> + { + using type = uint64_t; + }; - void unescape() const - { - if (*(start_-1)) - { - char* head = start_; - char* tail = start_; - while(head != end_) - { - if (*head == '\\') - { - switch(*++head) - { - case '"': *tail++ = '"'; break; - case '\\': *tail++ = '\\'; break; - case '/': *tail++ = '/'; break; - case 'b': *tail++ = '\b'; break; - case 'f': *tail++ = '\f'; break; - case 'n': *tail++ = '\n'; break; - case 'r': *tail++ = '\r'; break; - case 't': *tail++ = '\t'; break; - case 'u': - { - auto from_hex = [](char c) - { - if (c >= 'a') - return c - 'a' + 10; - if (c >= 'A') - return c - 'A' + 10; - return c - '0'; - }; - unsigned int code = - (from_hex(head[1])<<12) + - (from_hex(head[2])<< 8) + - (from_hex(head[3])<< 4) + - from_hex(head[4]); - if (code >= 0x800) - { - *tail++ = 0xE0 | (code >> 12); - *tail++ = 0x80 | ((code >> 6) & 0x3F); - *tail++ = 0x80 | (code & 0x3F); - } - else if (code >= 0x80) - { - *tail++ = 0xC0 | (code >> 6); - *tail++ = 0x80 | (code & 0x3F); - } - else - { - *tail++ = code; - } - head += 4; - } - break; - } - } - else - *tail++ = *head; - head++; - } - end_ = tail; - *end_ = 0; - *(start_-1) = 0; - } - } + template <> + struct single_tag_to_type<3> + { + using type = double; + }; - detail::r_string s() const - { -#ifndef CROW_JSON_NO_ERROR_CHECK - if (t() != type::String) - throw std::runtime_error("value is not string"); -#endif - unescape(); - return detail::r_string{start_, end_}; - } + template <> + struct single_tag_to_type<4> + { + using type = std::string; + }; - bool has(const char* str) const - { - return has(std::string(str)); - } + template <> + struct single_tag_to_type<5> + { + using type = std::string; + }; - bool has(const std::string& str) const - { - struct Pred - { - bool operator()(const rvalue& l, const rvalue& r) const - { - return l.key_ < r.key_; - }; - bool operator()(const rvalue& l, const std::string& r) const - { - return l.key_ < r; - }; - bool operator()(const std::string& l, const rvalue& r) const - { - return l < r.key_; - }; - }; - if (!is_cached()) - { - std::sort(begin(), end(), Pred()); - set_cached(); - } - auto it = lower_bound(begin(), end(), str, Pred()); - return it != end() && it->key_ == str; - } - int count(const std::string& str) - { - return has(str) ? 1 : 0; - } + template + struct arguments + { + using subarguments = typename arguments::type; + using type = + typename subarguments::template push::type>; + }; - rvalue* begin() const - { -#ifndef CROW_JSON_NO_ERROR_CHECK - if (t() != type::Object && t() != type::List) - throw std::runtime_error("value is not a container"); -#endif - return l_.get(); - } - rvalue* end() const - { -#ifndef CROW_JSON_NO_ERROR_CHECK - if (t() != type::Object && t() != type::List) - throw std::runtime_error("value is not a container"); -#endif - return l_.get()+lsize_; - } + template <> + struct arguments<0> + { + using type = S<>; + }; - const detail::r_string& key() const - { - return key_; - } + template + struct last_element_type + { + using type = typename std::tuple_element>::type; + }; - size_t size() const - { - if (t() == type::String) - return s().size(); -#ifndef CROW_JSON_NO_ERROR_CHECK - if (t() != type::Object && t() != type::List) - throw std::runtime_error("value is not a container"); -#endif - return lsize_; - } - const rvalue& operator[](int index) const - { -#ifndef CROW_JSON_NO_ERROR_CHECK - if (t() != type::List) - throw std::runtime_error("value is not a list"); - if (index >= (int)lsize_ || index < 0) - throw std::runtime_error("list out of bound"); -#endif - return l_[index]; - } + template <> + struct last_element_type<> + { + }; - const rvalue& operator[](size_t index) const - { -#ifndef CROW_JSON_NO_ERROR_CHECK - if (t() != type::List) - throw std::runtime_error("value is not a list"); - if (index >= lsize_) - throw std::runtime_error("list out of bound"); -#endif - return l_[index]; - } - const rvalue& operator[](const char* str) const - { - return this->operator[](std::string(str)); - } + // from http://stackoverflow.com/questions/13072359/c11-compile-time-array-with-logarithmic-evaluation-depth + template using Invoke = typename T::type; - const rvalue& operator[](const std::string& str) const - { -#ifndef CROW_JSON_NO_ERROR_CHECK - if (t() != type::Object) - throw std::runtime_error("value is not an object"); -#endif - struct Pred - { - bool operator()(const rvalue& l, const rvalue& r) const - { - return l.key_ < r.key_; - }; - bool operator()(const rvalue& l, const std::string& r) const - { - return l.key_ < r; - }; - bool operator()(const std::string& l, const rvalue& r) const - { - return l < r.key_; - }; - }; - if (!is_cached()) - { - std::sort(begin(), end(), Pred()); - set_cached(); - } - auto it = lower_bound(begin(), end(), str, Pred()); - if (it != end() && it->key_ == str) - return *it; -#ifndef CROW_JSON_NO_ERROR_CHECK - throw std::runtime_error("cannot find key"); -#else - static rvalue nullValue; - return nullValue; -#endif - } + template struct seq{ using type = seq; }; - void set_error() - { - option_|=error_bit; - } + template struct concat; - bool error() const - { - return (option_&error_bit)!=0; - } - private: - bool is_cached() const - { - return (option_&cached_bit)!=0; - } - void set_cached() const - { - option_ |= cached_bit; - } - void copy_l(const rvalue& r) - { - if (r.t() != type::Object && r.t() != type::List) - return; - lsize_ = r.lsize_; - lremain_ = 0; - l_.reset(new rvalue[lsize_]); - std::copy(r.begin(), r.end(), begin()); - } + template + struct concat, seq> + : seq{}; - void emplace_back(rvalue&& v) - { - if (!lremain_) - { - int new_size = lsize_ + lsize_; - if (new_size - lsize_ > 60000) - new_size = lsize_ + 60000; - if (new_size < 4) - new_size = 4; - rvalue* p = new rvalue[new_size]; - rvalue* p2 = p; - for(auto& x : *this) - *p2++ = std::move(x); - l_.reset(p); - lremain_ = new_size - lsize_; - } - l_[lsize_++] = std::move(v); - lremain_ --; - } + template + using Concat = Invoke>; - mutable char* start_; - mutable char* end_; - detail::r_string key_; - std::unique_ptr l_; - uint32_t lsize_; - uint16_t lremain_; - type t_; - mutable uint8_t option_{0}; + template struct gen_seq; + template using GenSeq = Invoke>; - friend rvalue load_nocopy_internal(char* data, size_t size); - friend rvalue load(const char* data, size_t size); - friend std::ostream& operator <<(std::ostream& os, const rvalue& r) - { - switch(r.t_) - { + template + struct gen_seq : Concat, GenSeq>{}; - case type::Null: os << "null"; break; - case type::False: os << "false"; break; - case type::True: os << "true"; break; - case type::Number: os << r.d(); break; - case type::String: os << '"' << r.s() << '"'; break; - case type::List: - { - os << '['; - bool first = true; - for(auto& x : r) - { - if (!first) - os << ','; - first = false; - os << x; - } - os << ']'; - } - break; - case type::Object: - { - os << '{'; - bool first = true; - for(auto& x : r) - { - if (!first) - os << ','; - os << '"' << escape(x.key_) << "\":"; - first = false; - os << x; - } - os << '}'; - } - break; - } - return os; - } + 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