diff options
Diffstat (limited to 'vendor')
113 files changed, 45306 insertions, 17619 deletions
diff --git a/vendor/CppQuickCheck b/vendor/CppQuickCheck new file mode 120000 index 00000000..693f84ae --- /dev/null +++ b/vendor/CppQuickCheck @@ -0,0 +1 @@ +CppQuickCheck-2018-03-28
\ No newline at end of file diff --git a/vendor/CppQuickCheck-2018-03-28/.travis.yml b/vendor/CppQuickCheck-2018-03-28/.travis.yml new file mode 100644 index 00000000..46fc72ff --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/.travis.yml @@ -0,0 +1,36 @@ +language: cpp + +sudo: required +dist: trusty + +compiler: + - gcc + - clang + +os: +- linux + +# source: https://github.com/OpenLightingProject/ola/blob/master/.travis.yml +before_install: + - sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y + - sudo add-apt-repository ppa:h-rayflood/gcc-upper -y + - sudo add-apt-repository "deb http://llvm.org/apt/trusty/ llvm-toolchain-trusty-3.8 main" -y + - wget -O - http://llvm.org/apt/llvm-snapshot.gpg.key | sudo apt-key add - + - sudo apt-get update + + - if [ "$CXX" = "g++" ]; then sudo apt-get install g++-4.9; fi + - if [ "$CXX" = "g++" ]; then export CXX="g++-4.9" CC="gcc-4.9"; fi +#Remove the old g++/gcc to ensure we're using the latest ones + - if [ "$CXX" = "g++-4.9" ]; then sudo rm /usr/bin/g++; sudo rm /usr/bin/gcc; fi + + - if [ "$CXX" = "clang++" ]; then sudo apt-get install --force-yes clang-3.8; fi + - if [ "$CXX" = "clang++" ]; then export CXX="clang++-3.8" CC="clang-3.8"; fi +#Remove the old clang to ensure we're using the latest ones + +#Report the compiler version + - $CXX --version + + - sudo apt-get update + - sudo apt-get install libboost-thread-dev libboost-system-dev + +script: mkdir build && cd build && cmake .. && make && ./all-catch-tests diff --git a/vendor/CppQuickCheck-2018-03-28/CMakeLists.txt b/vendor/CppQuickCheck-2018-03-28/CMakeLists.txt new file mode 100644 index 00000000..c837c1e3 --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/CMakeLists.txt @@ -0,0 +1,32 @@ +cmake_minimum_required(VERSION 2.6) +project(CppQuickCheck) +set(CMAKE_CXX_FLAGS "-O3 -g -Wall -std=c++11") + +find_package(Boost REQUIRED) +include_directories(${Boost_INCLUDE_DIR}) + +include_directories("${PROJECT_SOURCE_DIR}/include") + +add_subdirectory(examples) + +add_library(cppqc SHARED src/Arbitrary.cpp) + +install(DIRECTORY "include/" DESTINATION "include" + PATTERN ".*" EXCLUDE) +install(TARGETS cppqc DESTINATION "lib") + +# "catch" based unit tests +enable_testing() +add_executable( + all-catch-tests + test/catch-main.cpp + test/shrink-explosion-protection.cpp + test/compact-check-tests.cpp + test/functional-tests.cpp) +target_link_libraries(all-catch-tests cppqc) +add_test(all-catch-tests all-catch-tests) + +# workaround to force cmake to build test executable before running the test +# (source: http://stackoverflow.com/a/736838/783510) +add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} + DEPENDS all-catch-tests) diff --git a/vendor/CppQuickCheck-2018-03-28/COPYING b/vendor/CppQuickCheck-2018-03-28/COPYING new file mode 100644 index 00000000..384456ae --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/COPYING @@ -0,0 +1,23 @@ +Copyright (c) 2010, Gregory Rogers All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + diff --git a/vendor/CppQuickCheck-2018-03-28/INSTALL b/vendor/CppQuickCheck-2018-03-28/INSTALL new file mode 100644 index 00000000..45845dac --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/INSTALL @@ -0,0 +1,11 @@ +CppQuickCheck is built using the CMake tool: http://www.cmake.org so you must have that installed on your system. In addition, the library uses significant functionality from the popular BOOST library: http://www.boost.org so you must have that installed to be able to use CppQuickCheck. + +To build and install the library, invoke the following commands: + + cmake . + make + sudo make install + +This will install CppQuickCheck into the default install location (usually /usr/local/include). See the cmake homepage for more details on different options. + +CppQuickCheck is a header only library. You do not need to link any libraries to use it. When building, it will build the examples but these will not be installed. diff --git a/vendor/CppQuickCheck-2018-03-28/LICENSE b/vendor/CppQuickCheck-2018-03-28/LICENSE new file mode 100644 index 00000000..444b683c --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/LICENSE @@ -0,0 +1,21 @@ +Copyright (c) 2010, Gregory Rogers All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/CppQuickCheck-2018-03-28/README.md b/vendor/CppQuickCheck-2018-03-28/README.md new file mode 100644 index 00000000..d16f89e0 --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/README.md @@ -0,0 +1,74 @@ +***CppQuickCheck*** + +## ABOUT + +CppQuickCheck is a library for automated testing of C++ code. You provide a +specification how your code is supposed to behave through *properties* and +CppQuickCheck will generate a large number of random test cases that attempt to +prove or disprove the properties. The specifications are written in pure C++ +using the functionality of the CppQuickCheck library. + +## DOCUMENTATION + +You can find examples in 'examples/src'. + +## BACKGROUND + +CppQuickCheck is inspired and based on the +[QuickCheck](http://code.haskell.org/QuickCheck/) library for +Haskell. CppQuickCheck differs in some aspects of the implementation and +interface (as well as being written in C++ instead of Haskell), but tries to +maintain similar functionality to the QuickCheck library. + +A similar library for C++ exists called +[QuickCheck++](http://software.legiasoft.com/quickcheck/). QuickCheck++ does +not support several important things that the Haskell QuickCheck supports +including: + + * *Generator combinators* - In QuickCheck++ custom generators for user + defined types are written by hand, with no provided random number + generation facility. One example of a way that Haskell's QuickCheck (and + CppQuickCheck) improve on this is the function `oneof` whick takes a list + of generators and creates a new generator that when called, selects a + random generator from the list and uses that to generate the input. In + QuickCheck++ this has to be written by hand using some external random + number generating library. + * *Shrinking the input for failed test cases* - When a randomly generated + test case fails, Haskell's QuickCheck (and CppQuickCheck, but not + QuickCheck++) will try to shrink the input to provide a minimal failing + case. This makes debugging the failure easier because instead of working + with a potentially large input case, much of the input can be removed to + reveal the structure of the failure. + +For these reasons, CppQuickCheck tries to maintain all the functionality of the +Haskell QuickCheck, and so taking a different implementation approach than +QuickCheck++. + +## UNIT TESTS + +Unit tests exists in the directory 'test'. + +``` +$ mkdir build +$ cd build +$ cmake .. +$ make check +``` + +To get a more detailed output, rerun it with + +``` +$ ./all-catch-tests +``` + +## CONTRIBUTING + +Please direct your pull requests to https://github.com/philipp-classen/CppQuickCheck, +which is the repository where the active development takes place. + +Currently, CppQuickCheck uses C++11 but not C++14. Travis will compile +the library and run the tests with GCC 4.9 and Clang 3.8. + +## LICENSE + +CppQuickCheck is distributed under a BSD license (see LICENSE). diff --git a/vendor/CppQuickCheck-2018-03-28/examples/CMakeLists.txt b/vendor/CppQuickCheck-2018-03-28/examples/CMakeLists.txt new file mode 100644 index 00000000..794e0c47 --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/examples/CMakeLists.txt @@ -0,0 +1,33 @@ +add_executable(sampleOutput src/sampleOutput.cpp) +target_link_libraries(sampleOutput cppqc) + +add_executable(sampleShrinkOutput src/sampleShrinkOutput.cpp) +target_link_libraries(sampleShrinkOutput cppqc) + +add_executable(testReverse src/TestReverse.cpp) +target_link_libraries(testReverse cppqc) + +add_executable(testReverseArray src/TestReverseArray.cpp) +target_link_libraries(testReverseArray cppqc) + +add_executable(testSort src/TestSort.cpp) +target_link_libraries(testSort cppqc) + +add_executable(testSortCompact src/TestSortCompact.cpp) +target_link_libraries(testSortCompact cppqc) + +add_executable(testChooseGenerator src/TestChooseGenerator.cpp) +target_link_libraries(testChooseGenerator cppqc) + +add_executable(exampleElementsGen src/exampleElementsGen.cpp) +target_link_libraries(exampleElementsGen cppqc) + +add_executable(testSlowShrinking src/TestSlowShrinking.cpp) +target_link_libraries(testSlowShrinking cppqc) + +add_executable(testWithCustomGenerator src/TestWithCustomGenerator.cpp) +target_link_libraries(testSlowShrinking cppqc) + +# requires c++1y compile flag +#add_executable(testBoostTupleSupport src/BoostTupleSupport.cpp) +#target_link_libraries(testBoostTupleSupport cppqc) diff --git a/vendor/CppQuickCheck-2018-03-28/examples/src/BoostTupleSupport.cpp b/vendor/CppQuickCheck-2018-03-28/examples/src/BoostTupleSupport.cpp new file mode 100644 index 00000000..72a5f17d --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/examples/src/BoostTupleSupport.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2015, Gregory Rogers All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +// It demonstrates how to add support for boost::tuple by +// writing a custom generator (using std::tuple). +// +// Note this file uses C++14 features. + +#include "cppqc.h" + +#include <boost/tuple/tuple.hpp> +#include "boost/tuple/tuple_comparison.hpp" +#include <boost/tuple/tuple_io.hpp> +#include <utility> + +using namespace cppqc; + +namespace { + + template <typename StdTuple, std::size_t... Is> + auto asBoostTuple(StdTuple &&stdTuple, std::index_sequence<Is...>) { + return boost::tuple<std::tuple_element_t<Is, std::decay_t<StdTuple>>...> + (std::get<Is>(std::forward<StdTuple>(stdTuple))...); + } + + template <typename BoostTuple, std::size_t... Is> + auto asStdTuple(BoostTuple &&boostTuple, std::index_sequence<Is...>) { + return std::tuple<typename boost::tuples::element<Is, std::decay_t<BoostTuple>>::type...> + (boost::get<Is>(std::forward<BoostTuple>(boostTuple))...); + } + + template <typename StdTuple> + auto asBoostTuple(StdTuple &&stdTuple) { + return asBoostTuple(std::forward<StdTuple>(stdTuple), + std::make_index_sequence<std::tuple_size<std::decay_t<StdTuple>>::value>()); + } + + template <typename BoostTuple> + auto asStdTuple(BoostTuple&& boostTuple) { + return asStdTuple(std::forward<BoostTuple>(boostTuple), + std::make_index_sequence<boost::tuples::length<std::decay_t<BoostTuple>>::value>()); + } + + template<typename... T> + struct BoostTupleGenerator + { + BoostTupleGenerator(const Generator<T> &...g) : + m_tupleGenerator(tupleOf(g...)) + { + } + + boost::tuple<T...> unGen(RngEngine &rng, std::size_t size) const + { + return asBoostTuple(m_tupleGenerator.unGen(rng, size)); + } + + std::vector<boost::tuple<T...>> shrink(boost::tuple<T...> shrinkInput) const + { + std::vector<boost::tuple<T...>> result; + for (const auto &shrink : m_tupleGenerator.shrink(asStdTuple(shrinkInput))) { + result.push_back(asBoostTuple(shrink)); + } + return result; + } + + private: + + Generator<std::tuple<T...>> m_tupleGenerator; + }; + +} + +template<typename... T> +Generator<boost::tuple<T...>> boostTupleOf(const Generator<T> &...g) +{ + return BoostTupleGenerator<T...>(g...); +} + +template<typename... T> +Generator<boost::tuple<T...>> boostTupleOf() +{ + return BoostTupleGenerator<T...>(Arbitrary<T>()...); +} + + +struct AntisymmetricRelationProp : Property<boost::tuple<int, std::string, int>, + boost::tuple<int, std::string, int>> +{ + AntisymmetricRelationProp() : Property( + boostTupleOf<int, std::string, int>(), + boostTupleOf<int, std::string, int>()) + {} + + bool check(const boost::tuple<int, std::string, int> &v1, + const boost::tuple<int, std::string, int> &v2) const override + { + return (v1 <= v2 && v1 >= v2) == (v1 == v2); + } + + std::string name() const override + { + return "Comparison must be antisymmetric"; + } +}; + +int main() +{ + cppqc::quickCheckOutput(AntisymmetricRelationProp()); +} diff --git a/vendor/CppQuickCheck-2018-03-28/examples/src/TestChooseGenerator.cpp b/vendor/CppQuickCheck-2018-03-28/examples/src/TestChooseGenerator.cpp new file mode 100644 index 00000000..25d69aa4 --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/examples/src/TestChooseGenerator.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2010, Gregory Rogers All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cppqc.h" + +// This property tests that A*A > A holds. +// +// In general, this is not true, for instance, if A is zero. +// However, by using the "choose" generator, we can define that +// A is in a given interval (between 2 and 1000 in this example). +struct AxA_isGreaterThan_A : cppqc::Property<int> +{ + static constexpr int MIN = 2; + static constexpr int MAX = 1000; + + AxA_isGreaterThan_A() : Property(cppqc::choose(MIN, MAX)) {} + + bool check(const int &A) const override + { + return A * A > A; + } + + std::string name() const override + { + return "A*A > A"; + } +}; + +int main() +{ + cppqc::quickCheckOutput(AxA_isGreaterThan_A()); +} diff --git a/vendor/CppQuickCheck-2018-03-28/examples/src/TestReverse.cpp b/vendor/CppQuickCheck-2018-03-28/examples/src/TestReverse.cpp new file mode 100644 index 00000000..751e19c5 --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/examples/src/TestReverse.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2010, Gregory Rogers All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cppqc.h" + +#include <algorithm> +#include <sstream> + +struct PropTestReverse : cppqc::Property<std::vector<int>> +{ + bool check(const std::vector<int> &v) const override + { + std::vector<int> vrev(v); + std::reverse(vrev.begin(), vrev.end()); + std::reverse(vrev.begin(), vrev.end()); + return std::equal(v.begin(), v.end(), vrev.begin()); + } + std::string name() const override + { + return "Reversing Twice is Identity"; + } + std::string classify(const std::vector<int> &v) const override + { + std::ostringstream sstr; + sstr << "size " << v.size(); + return sstr.str(); + } + bool trivial(const std::vector<int> &v) const override + { + return v.empty() || v.size() == 1; + } +}; + +int main() +{ + cppqc::quickCheckOutput(PropTestReverse()); +} diff --git a/vendor/CppQuickCheck-2018-03-28/examples/src/TestReverseArray.cpp b/vendor/CppQuickCheck-2018-03-28/examples/src/TestReverseArray.cpp new file mode 100644 index 00000000..02ba1956 --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/examples/src/TestReverseArray.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2014, Gregory Rogers All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cppqc.h" + +#include <algorithm> +#include <boost/static_assert.hpp> + +const int ArraySize = 5; + +struct PropTestArrayReverse : + cppqc::Property<std::array<std::string, ArraySize>> +{ + bool check(const std::array<std::string, ArraySize> &v) const override + { + auto vrev = v; + std::reverse(vrev.begin(), vrev.end()); + std::reverse(vrev.begin(), vrev.end()); + return std::equal(v.begin(), v.end(), vrev.begin()); + } + std::string name() const override + { + return "Reversing Twice is Identity"; + } +}; + +struct PropTestBoolArrayReverse : + cppqc::Property<std::array<bool, ArraySize>> +{ + bool check(const std::array<bool, ArraySize> &v) const override + { + auto vrev = v; + std::reverse(vrev.begin(), vrev.end()); + std::reverse(vrev.begin(), vrev.end()); + return std::equal(v.begin(), v.end(), vrev.begin()); + } + std::string name() const override + { + return "Reversing Twice is Identity"; + } +}; + +int main() +{ + cppqc::quickCheckOutput(PropTestArrayReverse()); + cppqc::quickCheckOutput(PropTestBoolArrayReverse()); +} diff --git a/vendor/CppQuickCheck-2018-03-28/examples/src/TestSlowShrinking.cpp b/vendor/CppQuickCheck-2018-03-28/examples/src/TestSlowShrinking.cpp new file mode 100644 index 00000000..641016c4 --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/examples/src/TestSlowShrinking.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016, Philipp Classen All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cppqc.h" + +#include <vector> +#include <chrono> +#include <thread> +#include <atomic> + +// This simulates a test that is extremely slow. For such tests, +// shrinking can become a problem, as it can take quite a while. +struct PropTestSlowFunction: cppqc::Property<std::vector<int>> +{ + mutable std::atomic<bool> shrinking{false}; + + bool check(const std::vector<int> &v) const override + { + if (shrinking) { + std::cout << "Sleeping..." << std::endl; + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + + if (v.size() >= 4 && (v[3] % 5) == 1) { + shrinking = true; + return false; + } + return true; + } + std::string name() const override + { + return "Sorting should be sorted"; + } +}; + +int main() +{ + cppqc::quickCheckOutput(PropTestSlowFunction()); +} diff --git a/vendor/CppQuickCheck-2018-03-28/examples/src/TestSort.cpp b/vendor/CppQuickCheck-2018-03-28/examples/src/TestSort.cpp new file mode 100644 index 00000000..f5e3c4dc --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/examples/src/TestSort.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2010, Gregory Rogers All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cppqc.h" + +#include <algorithm> +#include <iterator> +#include <boost/static_assert.hpp> +#include <sstream> + +namespace uut { + +template <typename InputIterator> +void selection_sort(InputIterator b, InputIterator e, bool make_mistakes = false) +{ + //Selection sort performs the following steps: + //1) From the current iterator, find the smallest value + //2) Swap the smallest value with the current iterator + //3) Continue until end of range + + make_mistakes && b != e ? ++b : b; + for(InputIterator c = b; c != e ; ++c) + { + std::swap(*(std::min_element(c, e)), *c); + } +} + +} + +struct PropTestSort: cppqc::Property<std::vector<int>> +{ + bool check(const std::vector<int> &v) const override + { + std::vector<int> v_copy(v); + uut::selection_sort(std::begin(v_copy), std::end(v_copy), true); + return std::is_sorted(std::begin(v_copy), std::end(v_copy)); + } + std::string name() const override + { + return "Sorting should be sorted"; + } + std::string classify(const std::vector<int> &v) const override + { + std::ostringstream sstr; + sstr << "size " << v.size(); + return sstr.str(); + } + bool trivial(const std::vector<int> &v) const override + { + return v.empty() || v.size() == 1; + } +}; + +int main() +{ + cppqc::quickCheckOutput(PropTestSort()); +} diff --git a/vendor/CppQuickCheck-2018-03-28/examples/src/TestSortCompact.cpp b/vendor/CppQuickCheck-2018-03-28/examples/src/TestSortCompact.cpp new file mode 100644 index 00000000..a3a6ee71 --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/examples/src/TestSortCompact.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2016, Vladimir Strisovsky All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cppqc.h" +#include "cppqc/CompactCheck.h" + +#include <algorithm> +#include <iterator> +#include <boost/static_assert.hpp> +#include <sstream> + +namespace uut { + +template <typename InputIterator> +void selection_sort(InputIterator b, InputIterator e, bool make_mistakes = false) +{ + //Selection sort performs the following steps: + //1) From the current iterator, find the smallest value + //2) Swap the smallest value with the current iterator + //3) Continue until end of range + + make_mistakes && b != e ? ++b : b; + for(InputIterator c = b; c != e ; ++c) + { + std::swap(*(std::min_element(c, e)), *c); + } +} + +} + +int main() +{ + std::cout << "* uut::selection_sort" << std::endl; + + cppqc::gen<std::vector<int>>() + .property("Sorting should be sorted", + [](const std::vector<int> &v) + { + std::vector<int> v_copy(v); + uut::selection_sort(std::begin(v_copy), std::end(v_copy), true); + return std::is_sorted(std::begin(v_copy), std::end(v_copy)); + }) + .classify([](const std::vector<int> &v) + { + return std::to_string(v.size()); + }) + .trivial([](const std::vector<int> &v) + { + return v.empty() || v.size() == 1; + }) + .testWithOutput(); + + std::cout << "* std::sort" << std::endl; + + cppqc::gen<std::vector<int>>() + .property("Sorting should be sorted", + [](const std::vector<int> &v) + { + std::vector<int> v_copy(v); + std::sort(v_copy.begin(), v_copy.end()); + return std::is_sorted(std::begin(v_copy), std::end(v_copy)); + }) + .classify([](const std::vector<int> &v) + { + return std::to_string(v.size()); + }) + .trivial([](const std::vector<int> &v) + { + return v.empty() || v.size() == 1; + }) + .testWithOutput(); + +} diff --git a/vendor/CppQuickCheck-2018-03-28/examples/src/TestWithCustomGenerator.cpp b/vendor/CppQuickCheck-2018-03-28/examples/src/TestWithCustomGenerator.cpp new file mode 100644 index 00000000..0113cac4 --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/examples/src/TestWithCustomGenerator.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2018, Amy de Buitléir All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cppqc.h" + +#include <random> +#include <sstream> + +class Rectangle { +public: + Rectangle (int w, int h) { + width = w; + height = h; + } + int getWidth() const { return width; } + int getHeight() const { return height; } + int getArea() const { return width*height; } + friend std::ostream& operator << (std::ostream& os, const Rectangle& r) { + os << "width: " << r.width << " height: " << r.height << std::endl; + return os ; + } +private: + int width; + int height; +}; + +class CustomGenerator { +public: + Rectangle unGen(cppqc::RngEngine &rng, std::size_t n) { + std::uniform_int_distribution<> dist{1, static_cast<int>(n) + 1}; + int w = dist(rng); + int h = (n + 1)/w; + return Rectangle(w, h); + } + + std::vector<Rectangle> shrink(const Rectangle &r) { + std::vector<Rectangle> ret; + if (r.getWidth() > 1) + ret.push_back(Rectangle(r.getWidth()-1, r.getHeight())); + if (r.getHeight() > 1) { + ret.push_back(Rectangle(r.getWidth(), r.getHeight()-1)); + } + return ret; + } +}; + +// A silly test just to demonstrate the custom generator. +struct PropTestCustomGen : cppqc::Property<Rectangle> +{ + PropTestCustomGen() : Property(CustomGenerator()) {} + bool check(const Rectangle &r) const override + { + return (r.getArea() == r.getWidth() * r.getHeight()); + } + std::string name() const override + { + return "TestCustomGen"; + } +}; + +int main() +{ + cppqc::quickCheckOutput(PropTestCustomGen()); +} diff --git a/vendor/CppQuickCheck-2018-03-28/examples/src/exampleElementsGen.cpp b/vendor/CppQuickCheck-2018-03-28/examples/src/exampleElementsGen.cpp new file mode 100644 index 00000000..fe6e953f --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/examples/src/exampleElementsGen.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2010, Gregory Rogers All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cppqc.h" + +#include <algorithm> +#include <sstream> + +// Useless property just to show usage of elements generator + +struct PropTestElementsGen : cppqc::Property<int> +{ + PropTestElementsGen() : Property(cppqc::elements({1, 4, 5})) {} + bool check(const int &v) const override + { + return (v == 1) || (v == 4) || (v == 5); + } + std::string name() const override + { + return "TestElementsGen"; + } + std::string classify(const int &v) const override + { + std::ostringstream sstr; + sstr << v; + return sstr.str(); + } +}; + +int main() +{ + cppqc::quickCheckOutput(PropTestElementsGen()); +} diff --git a/vendor/CppQuickCheck-2018-03-28/examples/src/sampleOutput.cpp b/vendor/CppQuickCheck-2018-03-28/examples/src/sampleOutput.cpp new file mode 100644 index 00000000..82d586b3 --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/examples/src/sampleOutput.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2010, Gregory Rogers All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cppqc.h" + +#include <map> +#include <boost/bind.hpp> +#include <boost/assign/list_of.hpp> + +using namespace cppqc; + +const std::map<std::string, boost::function<void ()> > +sampleOutputCommand = boost::assign::map_list_of<std::string, boost::function<void ()> > +("bool", boost::bind(sampleOutput<bool>, Arbitrary<bool>(), boost::ref(std::cout), 0, 0)) +("char", boost::bind(sampleOutput<char>, Arbitrary<char>(), boost::ref(std::cout), 0, 0)) +("wchar_t", boost::bind(sampleOutput<wchar_t>, Arbitrary<wchar_t>(), boost::ref(std::cout), 0, 0)) +("signed char", boost::bind(sampleOutput<signed char>, Arbitrary<signed char>(), boost::ref(std::cout), 0, 0)) +("unsigned char", boost::bind(sampleOutput<unsigned char>, Arbitrary<unsigned char>(), boost::ref(std::cout), 0, 0)) +("short", boost::bind(sampleOutput<short>, Arbitrary<short>(), boost::ref(std::cout), 0, 0)) +("signed short", boost::bind(sampleOutput<signed short>, Arbitrary<signed short>(), boost::ref(std::cout), 0, 0)) +("unsigned short", boost::bind(sampleOutput<unsigned short>, Arbitrary<unsigned short>(), boost::ref(std::cout), 0, 0)) +("int", boost::bind(sampleOutput<int>, Arbitrary<int>(), boost::ref(std::cout), 0, 0)) +("signed", boost::bind(sampleOutput<signed>, Arbitrary<signed>(), boost::ref(std::cout), 0, 0)) +("unsigned", boost::bind(sampleOutput<unsigned>, Arbitrary<unsigned>(), boost::ref(std::cout), 0, 0)) +("signed int", boost::bind(sampleOutput<signed int>, Arbitrary<signed int>(), boost::ref(std::cout), 0, 0)) +("unsigned int", boost::bind(sampleOutput<unsigned int>, Arbitrary<unsigned int>(), boost::ref(std::cout), 0, 0)) +("long", boost::bind(sampleOutput<long>, Arbitrary<long>(), boost::ref(std::cout), 0, 0)) +("signed long", boost::bind(sampleOutput<signed long>, Arbitrary<signed long>(), boost::ref(std::cout), 0, 0)) +("unsigned long", boost::bind(sampleOutput<unsigned long>, Arbitrary<unsigned long>(), boost::ref(std::cout), 0, 0)) +("float", boost::bind(sampleOutput<float>, Arbitrary<float>(), boost::ref(std::cout), 0, 0)) +("double", boost::bind(sampleOutput<double>, Arbitrary<double>(), boost::ref(std::cout), 0, 0)) +("long double", boost::bind(sampleOutput<long double>, Arbitrary<long double>(), boost::ref(std::cout), 0, 0)) +("pair", boost::bind(sampleOutput<std::pair<int,int> >, Arbitrary<std::pair<int,int> >(), boost::ref(std::cout), 0, 0)) +("tuple", boost::bind(sampleOutput<std::tuple<int,int,int> >, tupleOf<int,int,int>(), boost::ref(std::cout), 0, 0)) +("string", boost::bind(sampleOutput<std::string>, Arbitrary<std::string>(), boost::ref(std::cout), 0, 0)); + +int main(int argc, char **argv) +{ + if(argc == 1) { + std::cout << "Usage: TYPES... (e.g., int, double, string)\n"; + return 0; + } + + for (int i = 1; i < argc; ++i) { + auto it = sampleOutputCommand.find(argv[i]); + if (it != sampleOutputCommand.end()) + it->second(); + else + std::cout << "unrecognized type \"" << argv[i] << "\"\n"; + } +} diff --git a/vendor/CppQuickCheck-2018-03-28/examples/src/sampleShrinkOutput.cpp b/vendor/CppQuickCheck-2018-03-28/examples/src/sampleShrinkOutput.cpp new file mode 100644 index 00000000..b7c65ff2 --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/examples/src/sampleShrinkOutput.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2010, Gregory Rogers All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cppqc.h" + +#include <map> +#include <boost/bind.hpp> +#include <boost/assign/list_of.hpp> + +using namespace cppqc; + +namespace std { + template<class T1, class T2> + std::ostream &operator<<(std::ostream &out, const std::pair<T1, T2> &x) + { + return out << '(' << x.first << ',' << x.second << ')'; + } +} + +const std::map<std::string, boost::function<void ()> > +sampleShrinkOutputCommand = boost::assign::map_list_of<std::string, boost::function<void ()> > +("bool", boost::bind(sampleShrinkOutput<bool>, Arbitrary<bool>(), boost::ref(std::cout), 0, true, 0)) +("char", boost::bind(sampleShrinkOutput<char>, Arbitrary<char>(), boost::ref(std::cout), 0, true, 0)) +("wchar_t", boost::bind(sampleShrinkOutput<wchar_t>, Arbitrary<wchar_t>(), boost::ref(std::cout), 0, true, 0)) +("signed char", boost::bind(sampleShrinkOutput<signed char>, Arbitrary<signed char>(), boost::ref(std::cout), 0, true, 0)) +("unsigned char", boost::bind(sampleShrinkOutput<unsigned char>, Arbitrary<unsigned char>(), boost::ref(std::cout), 0, true, 0)) +("short", boost::bind(sampleShrinkOutput<short>, Arbitrary<short>(), boost::ref(std::cout), 0, true, 0)) +("signed short", boost::bind(sampleShrinkOutput<signed short>, Arbitrary<signed short>(), boost::ref(std::cout), 0, true, 0)) +("unsigned short", boost::bind(sampleShrinkOutput<unsigned short>, Arbitrary<unsigned short>(), boost::ref(std::cout), 0, true, 0)) +("int", boost::bind(sampleShrinkOutput<int>, Arbitrary<int>(), boost::ref(std::cout), 0, true, 0)) +("signed", boost::bind(sampleShrinkOutput<signed>, Arbitrary<signed>(), boost::ref(std::cout), 0, true, 0)) +("unsigned", boost::bind(sampleShrinkOutput<unsigned>, Arbitrary<unsigned>(), boost::ref(std::cout), 0, true, 0)) +("signed int", boost::bind(sampleShrinkOutput<signed int>, Arbitrary<signed int>(), boost::ref(std::cout), 0, true, 0)) +("unsigned int", boost::bind(sampleShrinkOutput<unsigned int>, Arbitrary<unsigned int>(), boost::ref(std::cout), 0, true, 0)) +("long", boost::bind(sampleShrinkOutput<long>, Arbitrary<long>(), boost::ref(std::cout), 0, true, 0)) +("signed long", boost::bind(sampleShrinkOutput<signed long>, Arbitrary<signed long>(), boost::ref(std::cout), 0, true, 0)) +("unsigned long", boost::bind(sampleShrinkOutput<unsigned long>, Arbitrary<unsigned long>(), boost::ref(std::cout), 0, true, 0)) +("float", boost::bind(sampleShrinkOutput<float>, Arbitrary<float>(), boost::ref(std::cout), 0, true, 0)) +("double", boost::bind(sampleShrinkOutput<double>, Arbitrary<double>(), boost::ref(std::cout), 0, true, 0)) +("long double", boost::bind(sampleShrinkOutput<long double>, Arbitrary<long double>(), boost::ref(std::cout), 0, true, 0)) +("pair", boost::bind(sampleShrinkOutput<std::pair<int,int> >, Arbitrary<std::pair<int,int> >(), boost::ref(std::cout), 0, true, 0)) +("tuple", boost::bind(sampleShrinkOutput<std::tuple<int,int,int> >, tupleOf<int,int,int>(), boost::ref(std::cout), 0, true, 0)) +("string", boost::bind(sampleShrinkOutput<std::string>, Arbitrary<std::string>(), boost::ref(std::cout), 0, true, 0)); + +int main(int argc, char **argv) +{ + if(argc == 1) { + std::cout << "Usage: TYPES... (e.g., int, double, string)\n"; + return 0; + } + + for (int i = 1; i < argc; ++i) { + std::map<std::string, boost::function<void ()> >::const_iterator it = + sampleShrinkOutputCommand.find(argv[i]); + if (it != sampleShrinkOutputCommand.end()) + it->second(); + else + std::cout << "unrecognized type \"" << argv[i] << "\"\n"; + } +} diff --git a/vendor/CppQuickCheck-2018-03-28/include/cppqc.h b/vendor/CppQuickCheck-2018-03-28/include/cppqc.h new file mode 100644 index 00000000..234bb264 --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/include/cppqc.h @@ -0,0 +1,9 @@ +#ifndef CPPQC_H +#define CPPQC_H + +#include "cppqc/Generator.h" +#include "cppqc/Arbitrary.h" +#include "cppqc/Property.h" +#include "cppqc/Test.h" + +#endif diff --git a/vendor/CppQuickCheck-2018-03-28/include/cppqc/Arbitrary.h b/vendor/CppQuickCheck-2018-03-28/include/cppqc/Arbitrary.h new file mode 100644 index 00000000..ecfc56c1 --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/include/cppqc/Arbitrary.h @@ -0,0 +1,446 @@ +/* + * Copyright (c) 2010, Gregory Rogers All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CPPQC_ARBITRARY_H +#define CPPQC_ARBITRARY_H + +#include "Generator.h" + +#include <limits> + +#include <boost/random/uniform_int.hpp> +#include <boost/random/uniform_smallint.hpp> +#include <boost/random/uniform_real.hpp> +#include <boost/random/uniform_01.hpp> +#include <boost/random/poisson_distribution.hpp> +#include <boost/random/variate_generator.hpp> + +namespace cppqc { + +// default generators + +template<class Integral> +Integral arbitrarySizedIntegral(RngEngine &rng, std::size_t size) +{ + boost::uniform_int<Integral> dist(std::numeric_limits<Integral>::is_signed ? + -Integral(size) : Integral(size), + Integral(size)); + return dist(rng); +} + +template<class Integral> +Integral arbitraryBoundedIntegral(RngEngine &rng, std::size_t /*size*/) +{ + boost::uniform_int<Integral> dist(std::numeric_limits<Integral>::min(), + std::numeric_limits<Integral>::max()); + return dist(rng); +} + +template<class Integral> +Integral arbitrarySizedBoundedIntegral(RngEngine &rng, std::size_t size) +{ + boost::poisson_distribution<Integral> dist(size == 0 ? 1 : size); + boost::variate_generator<RngEngine&, boost::uniform_01<> > gen(rng, boost::uniform_01<>()); + Integral r = dist(gen); + if (std::numeric_limits<Integral>::is_signed) { + if (boost::uniform_smallint<int>(0, 1)(rng)) + r = -r; + } + return r; +} + +template<class Real> +Real arbitrarySizedReal(RngEngine &rng, std::size_t size) +{ + boost::uniform_real<Real> dist(-Real(size + 1.0), Real(size + 1.0)); + return dist(rng); +} + +// default shrinkers + +template<class T> +std::vector<T> shrinkNothing(const T &) +{ + return std::vector<T>(); +} + +template<class Integral> +std::vector<Integral> shrinkIntegral(Integral x) +{ + std::vector<Integral> ret; + if (std::numeric_limits<Integral>::is_signed && x < 0) { + if (x == std::numeric_limits<Integral>::min()) { + ret.push_back(std::numeric_limits<Integral>::max()); + } else { + assert(-x > 0); + ret.push_back(-x); + } + } + + for (Integral n = x; n != 0; n /= 2) + ret.push_back(x - n); + return ret; +} + +template<class Real> +std::vector<Real> shrinkReal(Real x) +{ + std::vector<Real> ret; + if (x == 0) + return ret; + if (x < 0) + ret.push_back(-x); + ret.push_back(Real(0)); + + if (std::isnan(x) && std::abs(x) >= 2) { + if (std::abs(x) < 1e100) { + ret.push_back(x / Real(2)); + } else { + // special case: reduce faster if the numbers are huge + // (Note: Maybe there is a better heuristic. Looks quite crude.) + ret.push_back(x / Real(1e20)); + } + } + return ret; +} + + +template<class T> +struct Arbitrary +{ + typedef boost::function<T (RngEngine &, std::size_t)> unGenType; + typedef boost::function<std::vector<T> (T)> shrinkType; + + static const unGenType unGen; + static const shrinkType shrink; +}; + +/* + * specialize ArbitraryImpl and implement the members: + * static const Arbitrary<T>::unGenType unGen; + * static const Arbitrary<T>::shrinkType shrink; + */ +template<class T> +struct ArbitraryImpl +{ + // no default implementation - users must specialize ArbitraryImpl + // and give an implementation of unGen and shrink. If they do not + // and they try to use Arbitrary<TheirClass>, a compile error will result. +}; + +// Note: The call is wrapped in a function to avoid issues +// with static ordering when ArbitraryImpl is defined +// in another compilation unit. Do not simplify it +// by replacing it with an assignment. +template<class T> +const typename Arbitrary<T>::unGenType Arbitrary<T>::unGen = [](RngEngine &rng, + std::size_t size) { + return ArbitraryImpl<T>::unGen(rng, size); +}; + +// (function call is needed: see above) +template<class T> +const typename Arbitrary<T>::shrinkType Arbitrary<T>::shrink = [](const T &v) { + return ArbitraryImpl<T>::shrink(v); +}; + +// included specializations + +inline bool arbitraryBool(RngEngine &rng, std::size_t /*size*/) +{ + if (boost::uniform_smallint<int>(0, 1)(rng)) + return true; + return false; +} +inline std::vector<bool> shrinkBool(bool x) +{ + std::vector<bool> ret; + if (x) ret.push_back(false); + return ret; +} +template<> +struct ArbitraryImpl<bool> +{ + static const Arbitrary<bool>::unGenType unGen; + static const Arbitrary<bool>::shrinkType shrink; +}; + +template<> +struct ArbitraryImpl<signed char> +{ + static const Arbitrary<signed char>::unGenType unGen; + static const Arbitrary<signed char>::shrinkType shrink; +}; + +template<> +struct ArbitraryImpl<unsigned char> +{ + static const Arbitrary<unsigned char>::unGenType unGen; + static const Arbitrary<unsigned char>::shrinkType shrink; +}; + +template<> +struct ArbitraryImpl<signed short> +{ + static const Arbitrary<signed short>::unGenType unGen; + static const Arbitrary<signed short>::shrinkType shrink; +}; + +template<> +struct ArbitraryImpl<unsigned short> +{ + static const Arbitrary<unsigned short>::unGenType unGen; + static const Arbitrary<unsigned short>::shrinkType shrink; +}; + +template<> +struct ArbitraryImpl<signed int> +{ + static const Arbitrary<signed int>::unGenType unGen; + static const Arbitrary<signed int>::shrinkType shrink; +}; + +template<> +struct ArbitraryImpl<unsigned int> +{ + static const Arbitrary<unsigned int>::unGenType unGen; + static const Arbitrary<unsigned int>::shrinkType shrink; +}; + +template<> +struct ArbitraryImpl<signed long> +{ + static const Arbitrary<signed long>::unGenType unGen; + static const Arbitrary<signed long>::shrinkType shrink; +}; + +template<> +struct ArbitraryImpl<unsigned long> +{ + static const Arbitrary<unsigned long>::unGenType unGen; + static const Arbitrary<unsigned long>::shrinkType shrink; +}; + +template<> +struct ArbitraryImpl<signed long long> +{ + static const Arbitrary<signed long long>::unGenType unGen; + static const Arbitrary<signed long long>::shrinkType shrink; +}; + +template<> +struct ArbitraryImpl<unsigned long long> +{ + static const Arbitrary<unsigned long long>::unGenType unGen; + static const Arbitrary<unsigned long long>::shrinkType shrink; +}; + +template<> +struct ArbitraryImpl<float> +{ + static const Arbitrary<float>::unGenType unGen; + static const Arbitrary<float>::shrinkType shrink; +}; + +template<> +struct ArbitraryImpl<double> +{ + static const Arbitrary<double>::unGenType unGen; + static const Arbitrary<double>::shrinkType shrink; +}; + +template<> +struct ArbitraryImpl<long double> +{ + static const Arbitrary<long double>::unGenType unGen; + static const Arbitrary<long double>::shrinkType shrink; +}; + +inline char arbitraryChar(RngEngine &rng, std::size_t) +{ + boost::uniform_int<char> dist(0x20, 0x7f); + return dist(rng); +} +inline std::vector<char> shrinkChar(char c) +{ + const char possShrinks[] = {'a', 'b', 'c', 'A', 'B', 'C', '1', '2', '3', + ' ', '\n', '\0'}; + std::vector<char> ret; + for (auto & possShrink : possShrinks) { + if (possShrink < c) + ret.push_back(possShrink); + } + if (isupper(c) && + std::find(possShrinks, possShrinks + sizeof(possShrinks), + tolower(c)) != possShrinks + sizeof(possShrinks)) + ret.push_back(tolower(c)); + return ret; +} +template<> +struct ArbitraryImpl<char> +{ + static const Arbitrary<char>::unGenType unGen; + static const Arbitrary<char>::shrinkType shrink; +}; + +template<> +struct ArbitraryImpl<wchar_t> +{ + static const Arbitrary<wchar_t>::unGenType unGen; + static const Arbitrary<wchar_t>::shrinkType shrink; +}; + +template<class String> +String arbitraryString(RngEngine &rng, std::size_t size) +{ + boost::uniform_int<std::size_t> dist(0, size); + std::size_t n = dist(rng); + String ret; + ret.reserve(n); + while (n-- > 0) + ret.push_back(Arbitrary<typename String::value_type>::unGen(rng, size)); + return ret; +} +template<class String> +std::vector<String> shrinkString(const String &x) +{ + std::vector<String> ret; + ret.reserve(x.size()); + for (auto it = x.begin(); it != x.end(); ++it) { + ret.push_back(String()); + ret.back().reserve(x.size() - 1); + ret.back().insert(ret.back().end(), x.begin(), it); + ret.back().insert(ret.back().end(), it + 1, x.end()); + } + return ret; +} +template<class CharT, class Traits, class Alloc> +struct ArbitraryImpl<std::basic_string<CharT, Traits, Alloc> > +{ + static const typename + Arbitrary<std::basic_string<CharT, Traits, Alloc> >::unGenType unGen; + static const typename + Arbitrary<std::basic_string<CharT, Traits, Alloc> >::shrinkType shrink; +}; +template<class CharT, class Traits, class Alloc> +const typename Arbitrary<std::basic_string<CharT, Traits, Alloc> >::unGenType +ArbitraryImpl<std::basic_string<CharT, Traits, Alloc> >::unGen = +arbitraryString<std::basic_string<CharT, Traits, Alloc> >; +template<class CharT, class Traits, class Alloc> +const typename Arbitrary<std::basic_string<CharT, Traits, Alloc> >::shrinkType +ArbitraryImpl<std::basic_string<CharT, Traits, Alloc> >::shrink = +shrinkString<std::basic_string<CharT, Traits, Alloc> >; + +template<class PairType> +PairType arbitraryPair(RngEngine &rng, std::size_t size) +{ + return PairType(Arbitrary<typename PairType::first_type>::unGen(rng, size), + Arbitrary<typename PairType::second_type>::unGen(rng, size)); +} +template<class PairType> +std::vector<PairType> shrinkPair(const PairType &x) +{ + typedef typename PairType::first_type FirstType; + typedef typename PairType::second_type SecondType; + std::vector<FirstType> shrinks1 = Arbitrary<FirstType>::shrink(x.first); + std::vector<SecondType> shrinks2 = Arbitrary<SecondType>::shrink(x.second); + std::vector<PairType> ret; + ret.reserve(shrinks1.size() + shrinks2.size()); + for (auto it = shrinks1.begin(); it != shrinks1.end(); ++it) { + ret.push_back(PairType(*it, x.second)); + } + for (auto it = shrinks2.begin(); it != shrinks2.end(); ++it) { + ret.push_back(PairType(x.first, *it)); + } + return ret; +} +template<class T1, class T2> +struct ArbitraryImpl<std::pair<T1, T2> > +{ + static const typename Arbitrary<std::pair<T1, T2> >::unGenType unGen; + static const typename Arbitrary<std::pair<T1, T2> >::shrinkType shrink; +}; +template<class T1, class T2> +const typename Arbitrary<std::pair<T1, T2> >::unGenType +ArbitraryImpl<std::pair<T1, T2> >::unGen = arbitraryPair<std::pair<T1, T2> >; +template<class T1, class T2> +const typename Arbitrary<std::pair<T1, T2> >::shrinkType +ArbitraryImpl<std::pair<T1, T2> >::shrink = shrinkPair<std::pair<T1, T2> >; + +template<typename T> +struct ArbitraryImpl<std::vector<T>> +{ + static const typename Arbitrary<std::vector<T>>::unGenType unGen; + static const typename Arbitrary<std::vector<T>>::shrinkType shrink; +}; + +template <typename T> +const typename Arbitrary<std::vector<T>>::unGenType + ArbitraryImpl<std::vector<T>>::unGen = [](RngEngine &rng, + std::size_t size) { + const auto& vectorGenerator = listOf<T>(); + return vectorGenerator.unGen(rng, size); +}; + +template <typename T> +const typename Arbitrary<std::vector<T>>::shrinkType + ArbitraryImpl<std::vector<T>>::shrink = [](const std::vector<T> &v) { + + const auto& vectorGenerator = listOf<T>(); + return vectorGenerator.shrink(v); +}; + + +template<typename T, std::size_t N> +struct ArbitraryImpl<std::array<T, N>> +{ + static const typename Arbitrary<std::array<T, N>>::unGenType unGen; + static const typename Arbitrary<std::array<T, N>>::shrinkType shrink; +}; + +/// Note: N is the fixed size of the array. +/// It differs from the "size" param in the "unGen" function: +/// +/// If "size" is increased, the output array will still contain +/// N elements, but each element will, in general, be more complex. +template <typename T, std::size_t N> +const typename Arbitrary<std::array<T, N>>::unGenType + ArbitraryImpl<std::array<T, N>>::unGen = [](RngEngine &rng, + std::size_t size) { + const auto& arrayGenerator = arrayOf<T, N>(); + return arrayGenerator.unGen(rng, size); +}; + +template <typename T, std::size_t N> +const typename Arbitrary<std::array<T, N>>::shrinkType + ArbitraryImpl<std::array<T, N>>::shrink = [](const std::array<T, N> &arr) { + + const auto& arrayGenerator = arrayOf<T, N>(); + return arrayGenerator.shrink(arr); +}; + +} + +#endif diff --git a/vendor/CppQuickCheck-2018-03-28/include/cppqc/CompactCheck.h b/vendor/CppQuickCheck-2018-03-28/include/cppqc/CompactCheck.h new file mode 100644 index 00000000..cdd204a0 --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/include/cppqc/CompactCheck.h @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2016, Vladimir Strisovsky All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Test.h" +#include "Arbitrary.h" + +namespace cppqc +{ + +template<typename Function> +struct CompactCheckFunction +{ + using type = Function; + Function m_Function; + + CompactCheckFunction(Function&& fnc) + : m_Function(std::move(fnc)) + {} + + CompactCheckFunction(CompactCheckFunction&&) = default; + + static const bool valid = true; + + template<typename ReturnType, typename ... T> + ReturnType apply(ReturnType, const T& ... v) const + { + return m_Function(v ...); + } +}; + +template<> +struct CompactCheckFunction<void> +{ + using type = void; + static const bool valid = false; + + CompactCheckFunction() = default; + CompactCheckFunction(CompactCheckFunction&&) = default; + + template<typename ReturnType, typename ... T> + ReturnType apply(ReturnType r, const T& ... v) const + { + return r; + } +}; + +template<typename CheckFunction, typename TrivialFunction, typename ClassifyFunction, typename ... T> +class CompactCheck : public Property<T ...> +{ + std::string m_name; + + template<typename _CheckFunction, typename _TrivialFunction, typename _ClassifyFunction, typename ... _T> + friend class CompactCheck; + + using CheckFunctionT = CompactCheckFunction<CheckFunction>; + CheckFunctionT m_checkFnc; + + using TrivialFunctionT = CompactCheckFunction<TrivialFunction>; + TrivialFunctionT m_trivialFnc; + + using ClassifyFunctionT = CompactCheckFunction<ClassifyFunction>; + ClassifyFunctionT m_classifyFnc; + + CompactCheck( std::string name, + CheckFunctionT&& checkFunction, + TrivialFunctionT&& trivialFunctions, + ClassifyFunctionT&& classifyFunction) + : m_name(std::move(name)) + , m_checkFnc(std::move(checkFunction)) + , m_trivialFnc(std::move(trivialFunctions)) + , m_classifyFnc(std::move(classifyFunction)) + {} + + bool check(const T& ... v) const override + { + return m_checkFnc.apply(true, v ...); + } + + bool trivial(const T& ... v) const override + { + return m_trivialFnc.apply(false, v ...); + } + + std::string classify(const T& ... v) const override + { + return m_classifyFnc.apply(std::string(), v ...); + } + + std::string name() const + { + return m_name.empty() ? "no-name" : m_name; + } + +public: + CompactCheck() + {} + + CompactCheck(const Generator<T>& ... g) + : Property<T ...>(g ...) + {} + + template<typename _CheckFunction> + CompactCheck<_CheckFunction, TrivialFunction, ClassifyFunction, T ...> property(const std::string& name, _CheckFunction&& checkFnc) + { + static_assert(CheckFunctionT::valid == false, "Check function is already set"); + return CompactCheck<_CheckFunction, TrivialFunction, ClassifyFunction, T ...>( name, + std::move(checkFnc), + std::move(m_trivialFnc), + std::move(m_classifyFnc)); + } + + template<typename _TrivialFunction> + CompactCheck<CheckFunction, _TrivialFunction, ClassifyFunction, T ...> trivial(_TrivialFunction&& trivialFnc) + { + static_assert(TrivialFunctionT::valid == false, "Trivial function is already set"); + return CompactCheck<CheckFunction, _TrivialFunction, ClassifyFunction, T ...>( std::move(m_name), + std::move(m_checkFnc), + std::move(trivialFnc), + std::move(m_classifyFnc)); + } + + template<typename _ClassifyFunction> + CompactCheck<CheckFunction, TrivialFunction, _ClassifyFunction, T ...> classify(_ClassifyFunction&& classifyFnc) + { + static_assert(ClassifyFunctionT::valid == false, "Classsify function is already set"); + return CompactCheck<CheckFunction, TrivialFunction, _ClassifyFunction, T ...>( std::move(m_name), + std::move(m_checkFnc), + std::move(m_trivialFnc), + std::move(classifyFnc)); + } + + Result test( std::size_t maxSuccess = 100, std::size_t maxDiscarded = 0, std::size_t maxSize = 0) + { + return quickCheck(*this, maxSuccess, maxDiscarded, maxSize); + } + + Result testWithOutput( std::ostream &out = std::cout, std::size_t maxSuccess = 100, std::size_t maxDiscarded = 0, std::size_t maxSize = 0) + { + return quickCheckOutput(*this, out, maxSuccess, maxDiscarded, maxSize); + } +}; + +template<typename ... T> +CompactCheck<void, void, void, T ...> gen() +{ + return CompactCheck<void, void, void, T ...>(); +} + +template<typename ... T> +CompactCheck<void, void, void, T ...> gen(const Generator<T>& ... g) +{ + return CompactCheck<void, void, void, T ...>(g ...); +} + + +} diff --git a/vendor/CppQuickCheck-2018-03-28/include/cppqc/Generator.h b/vendor/CppQuickCheck-2018-03-28/include/cppqc/Generator.h new file mode 100644 index 00000000..98b96092 --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/include/cppqc/Generator.h @@ -0,0 +1,1355 @@ +/* + * Copyright (c) 2010, Gregory Rogers All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CPPQC_GEN_H +#define CPPQC_GEN_H + +#include <boost/function.hpp> +#include <boost/random/uniform_int.hpp> +#include <tuple> +#include <utility> +#include <cstddef> +#include <iosfwd> +#include <vector> +#include <map> +#include <algorithm> +#include <stdexcept> +#include <random> + +namespace cppqc { + +typedef std::mt19937 RngEngine; + +template<class T> struct Arbitrary; + +/* + * When creating user defined generators, they must model a + * "GeneratorConcept<T>", that is, they must be copy-constructable and have + * member functions compatible with the following signatures: + * + * T unGen(RngEngine &, std::size_t); + * std::vector<T> shrink(const T &); + * + * The unGen function generates a new value, and the shrink function shrinks + * the last previously generated value down - generating an std::vector<T> of + * possible alternative shrinks. It possible to create a stateful generator + * modelling GenConcept, which in the generator stores some state in unGen that + * is looked up when calling shrink. Note however that the shrink function may + * be called multiple times, the subsequent calls may be called with the + * argument being one of the values returned by the previous call to shrink. + * This limits the types of statefulness possible. + * + * GeneratorConcept<T>: + * T unGen(RngEngine &, std::size_t); + * std::vector<T> shrink(const T &); + * + * StatelessGeneratorConcept<T> (also models GeneratorConcept<T>): + * T unGen(RngEngine &, std::size_t) const; + * std::vector<T> shrink(const T &) const; + */ + + +namespace detail { + + template<class T> + struct GenConcept + { + virtual ~GenConcept() + { + } + virtual T unGen(RngEngine &, std::size_t) = 0; + virtual std::vector<T> shrink(const T &) = 0; + virtual GenConcept *clone() const = 0; + }; + + template<class T> + struct StatelessGenConcept : GenConcept<T> + { + virtual ~StatelessGenConcept() + { + } + virtual T unGen(RngEngine &, std::size_t) override = 0; + virtual std::vector<T> shrink(const T &) override = 0; + virtual StatelessGenConcept *clone() const override = 0; + }; +} + +template<class T> +class Generator; + +template<class T> +class StatelessGenerator +{ + template<class StatelessGeneratorModel> class StatelessGenModel; + public: + template<class StatelessGeneratorModel> + StatelessGenerator(const StatelessGeneratorModel &gm) : + m_gen(new StatelessGenModel<StatelessGeneratorModel>(gm)) + { + } + + StatelessGenerator(const StatelessGenerator &g) : + m_gen(g.m_gen->clone()) + { + } + + template<class StatelessGeneratorModel> + StatelessGenerator &operator=(const StatelessGeneratorModel &gm) + { + detail::StatelessGenConcept<T> *tmp = + new StatelessGenModel<StatelessGeneratorModel>(gm); + delete m_gen; + m_gen = tmp; + return *this; + } + + StatelessGenerator &operator=(const StatelessGenerator &g) + { + detail::StatelessGenConcept<T> *tmp = g.m_gen.clone(); + delete m_gen; + m_gen = tmp; + return *this; + } + + ~StatelessGenerator() + { + delete m_gen; + } + + T unGen(RngEngine &rng, std::size_t size) const + { + return m_gen->unGen(rng, size); + } + + std::vector<T> shrink(const T &x) const + { + return m_gen->shrink(x); + } + + private: + template<class StatelessGeneratorModel> + class StatelessGenModel : public detail::StatelessGenConcept<T> + { + public: + StatelessGenModel(StatelessGeneratorModel gm) : m_obj(std::move(gm)) + { + } + + T unGen(RngEngine &rng, std::size_t size) + { + return m_obj.unGen(rng, size); + } + + T unGen(RngEngine &rng, std::size_t size) const + { + return m_obj.unGen(rng, size); + } + + std::vector<T> shrink(const T &x) + { + return m_obj.shrink(x); + } + + std::vector<T> shrink(const T &x) const + { + return m_obj.shrink(x); + } + + detail::StatelessGenConcept<T> *clone() const + { + return new StatelessGenModel(m_obj); + } + + private: + const StatelessGeneratorModel m_obj; + }; + + friend class Generator<T>; + detail::StatelessGenConcept<T> *m_gen; +}; + +template<class T> +class Generator +{ + template<class GeneratorModel> class GenModel; + public: + template<class GeneratorModel> + Generator(const GeneratorModel &gm) : + m_gen(new GenModel<GeneratorModel>(gm)) + { + } + + Generator(const Generator &g) : + m_gen(g.m_gen->clone()) + { + } + + Generator(const StatelessGenerator<T> &g) : + m_gen(g.m_gen->clone()) + { + } + + template<class GeneratorModel> + Generator &operator=(const GeneratorModel &gm) + { + detail::GenConcept<T> *tmp = new GenModel<GeneratorModel>(gm); + delete m_gen; + m_gen = tmp; + return *this; + } + + Generator &operator=(const Generator &g) + { + detail::GenConcept<T> *tmp = g.m_gen->clone(); + delete m_gen; + m_gen = tmp; + return *this; + } + + Generator &operator=(const StatelessGenerator<T> &g) + { + detail::GenConcept<T> *tmp = g.m_gen->clone(); + delete m_gen; + m_gen = tmp; + return *this; + } + + ~Generator() + { + delete m_gen; + } + + T unGen(RngEngine &rng, std::size_t size) const + { + return m_gen->unGen(rng, size); + } + + std::vector<T> shrink(const T &x) const + { + return m_gen->shrink(x); + } + + private: + template<class GeneratorModel> + class GenModel : public detail::GenConcept<T> + { + public: + GenModel(GeneratorModel gm) : m_obj(std::move(gm)) + { + } + + T unGen(RngEngine &rng, std::size_t size) override + { + return m_obj.unGen(rng, size); + } + + std::vector<T> shrink(const T &x) override + { + return m_obj.shrink(x); + } + + detail::GenConcept<T> *clone() const override + { + return new GenModel(m_obj); + } + + private: + GeneratorModel m_obj; + }; + + detail::GenConcept<T> *m_gen; +}; + + +/// Generates some example values and returns them. +template<class T> +std::vector<T> sample(const Generator<T> &g, std::size_t num = 0, + std::size_t seed = 0) +{ + if (num == 0) + num = 20; + if (seed == 0) + seed = time(nullptr); + RngEngine rng(seed); + std::vector<T> ret; + ret.reserve(num); + try { + for (std::size_t i = 0; i < num; ++i) + ret.push_back(g.unGen(rng, i)); + } catch (...) { + } + return ret; +} + +/// Generates some example values and prints them. +template<class T> +void sampleOutput(const Generator<T> &g, + std::ostream &out, std::size_t num = 0, + std::size_t seed = 0) +{ + if (num == 0) + num = 20; + if (seed == 0) + seed = time(nullptr); + RngEngine rng(seed); + try { + for (std::size_t i = 0; i < num; ++i) { + if (i != 0) + out << ' '; + out << g.unGen(rng, i); + } + } catch (...) { + } + out << std::endl; +} + +/// Generates some example values, then generates a list of possible shrinks +/// for each value and returns both the value and the shrinks. +template<class T> +std::vector<std::pair<T, std::vector<T> > > sampleShrink(const Generator<T> &g, + std::size_t num = 0, std::size_t seed = 0) +{ + if (num == 0) + num = 20; + if (seed == 0) + seed = time(nullptr); + RngEngine rng(seed); + std::vector<std::pair<T, std::vector<T> > > ret; + ret.reserve(num); + try { + for (std::size_t i = 0; i < num; ++i) { + T x = g.unGen(rng, i); + ret.push_back(std::make_pair(x, g.shrink(x))); + } + } catch (...) { + } + return ret; +} + +/// Outputs some example values from a generator. For each value, outputs +/// several possible shrinks of that value. +template<class T> +void sampleShrinkOutput(const Generator<T> &g, std::ostream &out, + std::size_t num = 0, bool randomized = false, std::size_t seed = 0) +{ + if (num == 0) + num = 20; + if (seed == 0) + seed = time(nullptr); + RngEngine rng(seed); + try { + for (std::size_t i = 0; i < num; ++i) { + T x = g.unGen(rng, i); + std::vector<T> shr = g.shrink(x); + if (randomized) + std::random_shuffle(shr.begin(), shr.end()); + out << x << " ->"; + for (std::size_t j = 0; j < num && j < shr.size(); ++j) + out << ' ' << shr[j]; + out << '\n'; + } + } catch (...) { + } + out << std::flush; +} + + +// generator combinators + +namespace detail { + template<class T> + class NoShrinkGenerator + { + public: + NoShrinkGenerator(const Generator<T> &g) : + m_gen(g) + { + } + + T unGen(RngEngine &rng, std::size_t size) + { + return m_gen.unGen(rng, size); + } + + std::vector<T> shrink(const T &) + { + return std::vector<T>(); + } + + private: + Generator<T> m_gen; + }; + + template<class T> + class NoShrinkStatelessGenerator + { + public: + NoShrinkStatelessGenerator(const Generator<T> &g) : + m_gen(g) + { + } + + T unGen(RngEngine &rng, std::size_t size) + { + return m_gen.unGen(rng, size); + } + + std::vector<T> shrink(const T &) + { + return std::vector<T>(); + } + + private: + StatelessGenerator<T> m_gen; + }; +} + +// Generates a value the same way as the input generator, but doesn't shrink. +template<class T> +Generator<T> noShrink(const Generator<T> &g) +{ + return detail::NoShrinkGenerator<T>(g); +} +template<class T> +StatelessGenerator<T> noShrink(const StatelessGenerator<T> &g) +{ + return detail::NoShrinkStatelessGenerator<T>(g); +} + + +namespace detail { + template<class T> + class SizedGenerator + { + public: + SizedGenerator(boost::function<Generator<T> (std::size_t)> f) : + m_genfun(f), m_lastgen(f(0)) + { + } + + T unGen(RngEngine &rng, std::size_t size) + { + m_lastgen = m_genfun(size); + return m_lastgen.unGen(rng, size); + } + + std::vector<T> shrink(const T &x) + { + return m_lastgen.shrink(x); + } + + private: + const boost::function<Generator<T> (std::size_t)> m_genfun; + Generator<T> m_lastgen; + }; +} + +/// Used to create generators that depend on the size parameter. +template<class T> +Generator<T> sized(boost::function<Generator<T> (std::size_t)> f) +{ + return detail::SizedGenerator<T>(f); +} + + +namespace detail { + template<class T> + class ResizeGenerator + { + public: + ResizeGenerator(std::size_t size, const Generator<T> &g) : + m_size(size), m_gen(g) + { + } + + T unGen(RngEngine &rng, std::size_t) + { + return m_gen.unGen(rng, m_size); + } + + std::vector<T> shrink(const T &x) + { + return m_gen.shrink(x); + } + + private: + const std::size_t m_size; + const Generator<T> m_gen; + }; + + template<class T> + class ResizeStatelessGenerator + { + public: + ResizeStatelessGenerator(std::size_t size, + const StatelessGenerator<T> &g) : + m_size(size), m_gen(g) + { + } + + T unGen(RngEngine &rng, std::size_t) const + { + return m_gen.unGen(rng, m_size); + } + + std::vector<T> shrink(const T &x) const + { + return m_gen.shrink(x); + } + + private: + const std::size_t m_size; + const StatelessGenerator<T> m_gen; + }; +} + +/// Overrides the size parameter. Returns a generator which uses the given size +/// instead of the runtime size parameter. +template<class T> +Generator<T> resize(std::size_t size, const Generator<T> &g) +{ + return detail::ResizeGenerator<T>(size, g); +} +template<class T> +StatelessGenerator<T> resize(std::size_t size, const StatelessGenerator<T> &g) +{ + return detail::ResizeStatelessGenerator<T>(size, g); +} + + +namespace detail { + template<class Integer> + class ChooseStatelessGenerator + { + public: + ChooseStatelessGenerator(Integer min, Integer max) : + m_min(min), m_max(max) + { + assert(min <= max); + } + + Integer unGen(RngEngine &rng, std::size_t) const + { + boost::uniform_int<Integer> dist(m_min, m_max); + return dist(rng); + } + + std::vector<Integer> shrink(Integer x) const + { + std::vector<Integer> ret; + ret.reserve(x - m_min); + if (abs(m_min) <= abs(m_max)) { + for (Integer i = m_min; i != x; ++i) + ret.push_back(i); + } else { + for (Integer i = m_max; i != x; --i) + ret.push_back(i); + } + return ret; + } + + private: + const Integer m_min; + const Integer m_max; + }; +} + +/// Generates a random integer in the range min..max inclusive, requires that +/// min <= max. Shrinks towards smaller absolute values. +template<class Integer> +StatelessGenerator<Integer> choose(Integer min, Integer max) +{ + return detail::ChooseStatelessGenerator<Integer>(min, max); +} + + +namespace detail { + template<class T> + class SuchThatGenerator + { + public: + SuchThatGenerator(const Generator<T> &g, + boost::function<bool (T)> pred) : + m_gen(g), m_pred(pred) + { + } + + T unGen(RngEngine &rng, std::size_t size) + { + T ret = m_gen.unGen(rng, size); + if (!m_pred(ret)) + throw std::runtime_error("suchThat: generated value did not satisfy pred"); + return ret; + } + + std::vector<T> shrink(const T &x) + { + std::vector<T> ret = m_gen.shrink(x); + ret.erase(std::remove_if(ret.begin(), ret.end(), + std::not1(m_pred)), ret.end()); + return ret; + } + + private: + const Generator<T> m_gen; + const boost::function<bool (T)> m_pred; + }; + + template<class T> + class SuchThatStatelessGenerator + { + public: + SuchThatStatelessGenerator(const StatelessGenerator<T> &g, + boost::function<bool (T)> pred) : + m_gen(g), m_pred(pred) + { + } + + T unGen(RngEngine &rng, std::size_t size) const + { + T ret = m_gen.unGen(rng, size); + if (!m_pred(ret)) + throw std::runtime_error("suchThat: generated value did not satisfy pred"); + return ret; + } + + std::vector<T> shrink(const T &x) const + { + std::vector<T> ret = m_gen.shrink(x); + ret.erase(std::remove_if(ret.begin(), ret.end(), + std::not1(m_pred)), ret.end()); + return ret; + } + + private: + const StatelessGenerator<T> m_gen; + const boost::function<bool (T)> m_pred; + }; +} + +/// Generates a value that satisfies a predicate. +template<class T, class Pred> +Generator<T> suchThat(const Generator<T> &g, Pred pred) +{ + return detail::SuchThatGenerator<T>(g, pred); +} +template<class T, class Pred> +StatelessGenerator<T> suchThat(const StatelessGenerator<T> &g, Pred pred) +{ + return detail::SuchThatStatelessGenerator<T>(g, pred); +} + + +namespace detail { + template<class T> + class OneOfGenerator + { + public: + OneOfGenerator &operator()(const Generator<T> &g) + { + m_gens.push_back(g); + return *this; + } + + T unGen(RngEngine &rng, std::size_t size) + { + boost::uniform_int<std::size_t> dist(0, m_gens.size() - 1); + m_last_index = dist(rng); + return m_gens[m_last_index].unGen(rng, size); + } + + std::vector<T> shrink(const T &x) + { + return m_gens[m_last_index].shrink(x); + } + + private: + std::vector<Generator<T> > m_gens; + std::size_t m_last_index; + }; +} + +/// Randomly uses one of the given generators. +template<class T> +detail::OneOfGenerator<T> oneof(const Generator<T> &g) +{ + detail::OneOfGenerator<T> ret; + return ret(g); +} + + +namespace detail { + template<class T> + class FrequencyGenerator + { + public: + FrequencyGenerator() : m_tot(0) + { + } + + FrequencyGenerator &operator()(std::size_t weight, + const Generator<T> &g) + { + if (weight != 0) { + m_tot += weight; + m_gens.insert(std::make_pair(m_tot, g)); + } + return *this; + } + + T unGen(RngEngine &rng, std::size_t size) + { + boost::uniform_int<std::size_t> dist(1, m_tot); + std::size_t weight = dist(rng); + typename std::map<std::size_t, Generator<T> >::iterator it = + m_gens.lower_bound(weight); + if (it == m_gens.end()) { + throw std::logic_error("frequency: all generators have weight 0"); + } else { + m_last_index = it->first; + return it->second.unGen(rng, size); + } + } + + std::vector<T> shrink(const T &x) + { + typename std::map<std::size_t, Generator<T> >::iterator it = + m_gens.find(m_last_index); + assert(it != m_gens.end()); + return it->second.shrink(x); + } + + private: + std::map<std::size_t, Generator<T> > m_gens; + std::size_t m_tot; + std::size_t m_last_index; + }; +} + +/// Chooses one of the given generators, with a weighted random distribution. +/// Any generator with weight "0" will not be chosen. +template<class T> +detail::FrequencyGenerator<T> frequency(std::size_t f, const Generator<T> &g) +{ + detail::FrequencyGenerator<T> ret; + return ret(f, g); +} + + +namespace detail { + template<class T> + class ElementsGenerator + { + public: + ElementsGenerator &operator()(const std::initializer_list<T> x) + { + for (auto &i: x) + m_elems.push_back(i); + return *this; + } + + ElementsGenerator &operator()(const T &x) + { + m_elems.push_back(x); + return *this; + } + + T unGen(RngEngine &rng, std::size_t /*size*/) + { + boost::uniform_int<std::size_t> dist(0, m_elems.size() - 1); + m_last_index = dist(rng); + return m_elems[m_last_index]; + } + + std::vector<T> shrink(const T &) + { + std::vector<T> ret; + ret.reserve(m_last_index); + for (std::size_t i = 0; i != m_last_index; ++i) + ret.push_back(m_elems[i]); + return ret; + } + + private: + std::vector<T> m_elems; + std::size_t m_last_index; + }; +} + +/// Generates one of the given values. +template<class T> +detail::ElementsGenerator<T> elements(const std::initializer_list<T> x) +{ + detail::ElementsGenerator<T> ret; + return ret(x); +} + +template<class T> +detail::ElementsGenerator<T> elements(const T &x) +{ + detail::ElementsGenerator<T> ret; + return ret(x); +} + + +namespace detail { + template<class T> + class FixedGenerator + { + public: + FixedGenerator() : m_last_index_plus_one(0) + { + } + + FixedGenerator &operator()(const T &x) + { + m_fixed.push_back(x); + return *this; + } + + T unGen(RngEngine &, std::size_t) + { + ++m_last_index_plus_one; + if (m_last_index_plus_one >= m_fixed.size()) { + throw std::runtime_error("fixed: exhausted fixed test cases"); + } else { + return m_fixed[m_last_index_plus_one]; + } + } + + std::vector<T> shrink(const T &) + { + return std::vector<T>(); + } + + private: + std::size_t m_last_index_plus_one; + std::vector<T> m_fixed; + }; +} + +/// Generates each fixed test case until all have been generated. Does not +/// shrink. Especially useful with "chain". +template<class T> +detail::FixedGenerator<T> fixed(const T &x) +{ + detail::FixedGenerator<T> ret; + return ret(x); +} + + +namespace detail { + template<class T> + class ChainGenerator + { + public: + ChainGenerator() : m_last_index(0) + { + } + + ChainGenerator &operator()(const Generator<T> &x) + { + m_gens.push_back(x); + return *this; + } + + T unGen(RngEngine &rng, std::size_t size) + { + for (m_last_index = 0; m_last_index < m_gens.size(); + ++m_last_index) { + try { + return m_gens[m_last_index].unGen(rng, size); + } catch (...) { + } + } + + throw std::runtime_error("chain: exhausted all possible generators"); + } + + std::vector<T> shrink(const T &x) + { + return m_gens[m_last_index].shrink(x); + } + + private: + std::size_t m_last_index; + std::vector<Generator<T> > m_gens; + }; +} + +/// Attempts to generate from each generator, if a generator fails to generate +/// input, the next one is tried. +template<class T> +detail::ChainGenerator<T> chain(const Generator<T> &g) +{ + detail::ChainGenerator<T> ret; + return ret(g); +} + + +namespace detail { + template<class T, class U> + class ConvertGenerator + { + public: + ConvertGenerator(boost::function<T (U)> f, const Generator<U> &g) : + m_convert(f), m_gen(g) + { + } + + T unGen(RngEngine &rng, std::size_t size) + { + m_lastgen_u.clear(); + m_lastgen_t.clear(); + m_lastgen_u.push_back(m_gen.unGen(rng, size)); + m_lastgen_t.push_back(m_convert(m_lastgen_u.back())); + return m_lastgen_t.back(); + } + + std::vector<T> shrink(const T &x) + { + typename std::vector<T>::iterator it = + std::find(m_lastgen_t.begin(), m_lastgen_t.end(), x); + assert(it != m_lastgen_t.end()); + U last_u = m_lastgen_u[it - m_lastgen_t.begin()]; + m_lastgen_t.clear(); + m_lastgen_u = m_gen.shrink(last_u); + m_lastgen_t.reserve(m_lastgen_u.size()); + std::transform(m_lastgen_u.begin(), m_lastgen_u.end(), + std::back_inserter(m_lastgen_t), m_convert); + return m_lastgen_t; + } + + private: + boost::function<T (U)> m_convert; + const Generator<U> m_gen; + std::vector<T> m_lastgen_t; + std::vector<U> m_lastgen_u; + }; +} + +/// Converts a generator of U's into a generator of T's by passing the results +/// through a function which converts U's into T's. +template<class T, class U> +Generator<T> convert(boost::function<T (U)> f, + const Generator<U> &g = Arbitrary<U>()) +{ + return detail::ConvertGenerator<T, U>(f, g); +} + +/// Convenience function to aid generic programming, equivalent to convert. +template<class T, class U1> +Generator<T> combine(boost::function<T (U1)> f, + const Generator<U1> &g1 = Arbitrary<U1>()) +{ + return detail::ConvertGenerator<T, U1>(f, g1); +} + + +namespace detail { + template<class T, class U1, class U2> + class CombineGenerator + { + public: + CombineGenerator(boost::function<T (U1, U2)> f, + const Generator<U1> &g1, + const Generator<U2> &g2) : + m_combine(f), m_gen1(g1), m_gen2(g2) + { + } + + T unGen(RngEngine &rng, std::size_t size) + { + m_lastgen_u1.clear(); + m_lastgen_u2.clear(); + m_lastgen_t.clear(); + m_lastgen_u1.push_back(m_gen1.unGen(rng, size)); + m_lastgen_u2.push_back(m_gen2.unGen(rng, size)); + m_lastgen_t.push_back(m_combine(m_lastgen_u1.back(), + m_lastgen_u2.back())); + return m_lastgen_t.back(); + } + + std::vector<T> shrink(const T &x) + { + typename std::vector<T>::const_iterator it = + std::find(m_lastgen_t.begin(), m_lastgen_t.end(), x); + assert(it != m_lastgen_t.end()); + std::size_t dist = it - m_lastgen_t.begin(); + U1 last_u1 = m_lastgen_u1[dist]; + U2 last_u2 = m_lastgen_u2[dist]; + m_lastgen_t.clear(); + std::vector<U1> shrink1 = m_gen1.shrink(last_u1); + std::vector<U2> shrink2 = m_gen2.shrink(last_u2); + m_lastgen_u1.assign(shrink1.begin(), shrink1.end()); + m_lastgen_u1.insert(m_lastgen_u1.end(), + shrink2.size(), last_u1); + m_lastgen_u2.assign(shrink1.size(), last_u2); + m_lastgen_u2.insert(m_lastgen_u2.end(), + shrink2.begin(), shrink2.end()); + + m_lastgen_t.reserve(m_lastgen_u1.size()); + std::transform(m_lastgen_u1.begin(), m_lastgen_u1.end(), + m_lastgen_u2.begin(), std::back_inserter(m_lastgen_t), + m_combine); + return m_lastgen_t; + } + + private: + boost::function<T (U1, U2)> m_combine; + const Generator<U1> m_gen1; + const Generator<U2> m_gen2; + std::vector<T> m_lastgen_t; + std::vector<U1> m_lastgen_u1; + std::vector<U2> m_lastgen_u2; + }; +} + +/// Combines generators of U1's and U2's into a generator of T's by passing the +/// results through a function which converts U1's and U2's into T's. Ie. the +/// same as convert for functions taking more than one argument. +template<class T, class U1, class U2> +Generator<T> combine(boost::function<T (U1, U2)> f, + const Generator<U1> &g1 = Arbitrary<U1>(), + const Generator<U2> &g2 = Arbitrary<U2>()) +{ + return detail::CombineGenerator<T, U1, U2>(f, g1, g2); +} + + +namespace detail { + template<class T> + class ListOfStatelessGenerator + { + public: + ListOfStatelessGenerator(const StatelessGenerator<T> &g) : m_gen(g) + { + } + + std::vector<T> unGen(RngEngine &rng, std::size_t size) const + { + boost::uniform_int<std::size_t> dist(0, size); + std::size_t n = dist(rng); + std::vector<T> ret; + ret.reserve(n); + while (n-- > 0) + ret.push_back(m_gen.unGen(rng, size)); + return ret; + } + + std::vector<std::vector<T>> shrink(const std::vector<T> &v) const + { + std::vector<std::vector<T>> result; + + // 1) leave one element out (reduces size of new arrays by one) + for(auto it = v.begin(); it != v.end(); ++it) { + typename std::vector<T> shortendV; + shortendV.reserve(v.size() - 1); + shortendV.insert(shortendV.end(), v.begin(), it); + shortendV.insert(shortendV.end(), it + 1, v.end()); + assert(shortendV.size() == v.size() - 1); + result.push_back(std::move(shortendV)); + } + + // 2) shrink each element + // (array size stays the same but inner elements shrink) + for(int i = 0; i < static_cast<int>(v.size()); ++i) { + typename std::vector<T> shrinkedTypes = Arbitrary<T>::shrink(v[i]); + for(T &shrinked : Arbitrary<T>::shrink(v[i])) { + auto copy = v; + copy[i] = std::move(shrinked); + result.push_back(std::move(copy)); + } + } + return result; + } + + private: + const StatelessGenerator<T> m_gen; + }; +} + +/// Generates an std::vector of random length. The maximum length depends on the +/// generation size parameter. Shrinks by removing elements from the vector. +template<class T> +StatelessGenerator<std::vector<T>> listOf( + const StatelessGenerator<T> &g = Arbitrary<T>()) +{ + return detail::ListOfStatelessGenerator<T>(g); +} + + +namespace detail { + template<class T> + class ListOfNonEmptyStatelessGenerator + { + public: + ListOfNonEmptyStatelessGenerator(const StatelessGenerator<T> &g) : + m_gen(g), m_vectorGen(listOf<T>(g)) + { + } + + std::vector<T> unGen(RngEngine &rng, std::size_t size) const + { + std::vector<T> result = m_vectorGen.unGen(rng, size); + if (result.empty()) + result.emplace_back(m_gen.unGen(rng, size)); + return result; + } + + std::vector<std::vector<T>> shrink(const std::vector<T> &x) const + { + assert(!x.empty()); + + // TODO: should work for now, but uses (too much?!) internal + // knowledge of the "ListOfStatelessGenerator" + // shrink function implementation + if (x.size() > 1) + return m_vectorGen.shrink(x); + else + return {}; + } + + private: + const StatelessGenerator<T> m_gen; + const StatelessGenerator<std::vector<T>> m_vectorGen; + }; +} + +/// Generates a non-empty std::vector of random length. The maximum length +/// depends on the generation size parameter. Shrinks by removing elements from +/// the vector. +template<class T> +StatelessGenerator<std::vector<T>> listOfNonEmpty( + const StatelessGenerator<T> &g = Arbitrary<T>()) +{ + return detail::ListOfNonEmptyStatelessGenerator<T>(g); +} + + +namespace detail { + template<class T, std::size_t N> + class ArrayOfStatelessGenerator + { + public: + ArrayOfStatelessGenerator(const StatelessGenerator<T> &g) : + m_gen(g) + { + } + + std::array<T, N> unGen(RngEngine &rng, std::size_t size) const + { + std::array<T, N> result; + for (size_t i = 0; i < N; i++) + result[i] = m_gen.unGen(rng, size); + return result; + } + + std::vector<std::array<T, N>> shrink( + const std::array<T, N> &arr) const + { + std::vector<std::array<T, N>> result; + + // shrink each element + // (array size stays the same but inner elements shrink) + for (size_t i = 0; i < N; i++) { + for (const auto &shrinkedInnerElem : m_gen.shrink(arr[i])) { + auto copy = arr; + copy[i] = shrinkedInnerElem; + result.push_back(std::move(copy)); + } + } + + return result; + } + + private: + const StatelessGenerator<T> m_gen; + }; +} + +/// Generates an std::array of fixed length N. +/// As the array's length is fixed, it cannot be shrunken. +/// However, its inner elements can be. +template<class T, std::size_t N> +StatelessGenerator<std::array<T, N>> arrayOf( + const StatelessGenerator<T> &g = Arbitrary<T>()) +{ + return detail::ArrayOfStatelessGenerator<T, N>(g); +} + + +namespace detail { + template<class T> + class VectorOfStatelessGenerator + { + public: + VectorOfStatelessGenerator(std::size_t size, + const StatelessGenerator<T> &g) : + m_size(size), m_gen(g) + { + } + + std::vector<T> unGen(RngEngine &rng, std::size_t size) const + { + std::vector<T> ret; + std::size_t n = m_size; + ret.reserve(n); + while (n-- > 0) + ret.push_back(m_gen.unGen(rng, size)); + return ret; + } + + std::vector<std::vector<T> > shrink(const std::vector<T> &) const + { + return std::vector<std::vector<T> >(); + } + + private: + std::size_t m_size; + const StatelessGenerator<T> m_gen; + }; +} + +/// Generates an std::vector of the given length. Does not shrink. Prefer using +/// listOf or listOfNonEmpty to vectorOf because those can shrink. +template<class T> +StatelessGenerator<std::vector<T> > vectorOf(std::size_t size, + const StatelessGenerator<T> &g = Arbitrary<T>()) +{ + return detail::VectorOfStatelessGenerator<T>(size, g); +} + + +namespace detail { + + template<int offset, typename T, typename... Ts> + struct TupleGeneratorHelper_unGen + { + template <typename Generators> + static std::tuple<T, Ts...> unGen(RngEngine &rng, std::size_t size, + const Generators &generators) + { + return std::tuple_cat( + std::make_tuple(std::get<offset>(generators).unGen(rng, size)), + TupleGeneratorHelper_unGen< + offset + 1, Ts...>::unGen(rng, size, generators)); + } + }; + + template<int offset, typename T> + struct TupleGeneratorHelper_unGen<offset, T> + { + template <typename Generators> + static std::tuple<T> unGen(RngEngine &rng, std::size_t size, + const Generators &generators) + { + return std::tuple<T>(std::get<offset>(generators).unGen(rng, size)); + } + }; + + template<int offset, typename... T> + struct TupleGeneratorHelper_shrink + { + template <typename Generators> + static void appendShrinks(const std::tuple<T...> &shrinkInput, + std::vector<std::tuple<T...>>& shrinkOutput, + const Generators &generators) + { + // Compute all shrink combinations for the tuple + // element at the position "offset". + // All other elements will not be changed. + static_assert(offset >= 0 && offset < sizeof...(T), + "offset out of bounds"); + auto allLocalShrinks = + std::get<offset>(generators).shrink(std::get<offset>(shrinkInput)); + for (auto&& localShrink : allLocalShrinks) { + auto copiedShrinkInput = shrinkInput; + std::get<offset>(copiedShrinkInput) = std::move(localShrink); + shrinkOutput.push_back(std::move(copiedShrinkInput)); + } + + // continue recursion (from right to left) + TupleGeneratorHelper_shrink<offset - 1, T...>::appendShrinks( + shrinkInput, shrinkOutput, generators); + } + }; + + template<typename... T> + struct TupleGeneratorHelper_shrink<-1, T...> + { + template <typename Generators> + static void appendShrinks(const std::tuple<T...> & /*shrinkInput*/, + std::vector<std::tuple<T...>> & /*shrinkOutput*/, + const Generators & /*generators*/) + { + // nothing to do (end of recursion) + } + }; + + template<typename... T> + struct TupleGenerator + { + TupleGenerator(const Generator<T> &...g) : + m_gen(g...) + { + } + + std::tuple<T...> unGen(RngEngine &rng, std::size_t size) const + { + return TupleGeneratorHelper_unGen<0, T...>::unGen(rng, size, m_gen); + } + + std::vector<std::tuple<T...>> shrink(const std::tuple<T...> &shrinkInput) const + { + std::vector<std::tuple<T...>> shrinkOutput; + constexpr auto last_index = sizeof...(T) - 1; + TupleGeneratorHelper_shrink<last_index, T...>::appendShrinks( + shrinkInput, shrinkOutput, m_gen); + return shrinkOutput; + } + + private: + std::tuple<Generator<T>...> m_gen; + }; + +} + +template<typename... T> +Generator<std::tuple<T...>> tupleOf(const Generator<T> &...g) +{ + return detail::TupleGenerator<T...>(g...); +} + +template<typename... T> +Generator<std::tuple<T...>> tupleOf() +{ + return detail::TupleGenerator<T...>(Arbitrary<T>()...); +} + + +} + +#endif diff --git a/vendor/CppQuickCheck-2018-03-28/include/cppqc/PrettyPrint.h b/vendor/CppQuickCheck-2018-03-28/include/cppqc/PrettyPrint.h new file mode 100644 index 00000000..2285cfb6 --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/include/cppqc/PrettyPrint.h @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2010, Gregory Rogers All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CPPQC_PRETTY_PRINT_H +#define CPPQC_PRETTY_PRINT_H + +#include "cxx-prettyprint.h" +#include <string> +#include <sstream> + +namespace cppqc { + + // The default implementation falls back to the std::ofstream + // implementation. Note that because of the usage of "cxx-prettyprint", + // it can handle understands C++ containers, pairs and tuples. + // + // Strings are quoted to improve readability. + // + template <class T> + struct PrettyPrint + { + static std::string toString(const T& x) + { + std::ostringstream out; + out << x; + return out.str(); + } + }; + + template <> + struct PrettyPrint<std::string> + { + static std::string toString(const std::string& x) + { + return '\"' + x + '\"'; + } + }; + + template <class T> + std::string prettyPrint(const T& x) + { + return PrettyPrint<T>::toString(x); + } + +} + +#endif diff --git a/vendor/CppQuickCheck-2018-03-28/include/cppqc/Property.h b/vendor/CppQuickCheck-2018-03-28/include/cppqc/Property.h new file mode 100644 index 00000000..579e6c53 --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/include/cppqc/Property.h @@ -0,0 +1,461 @@ +/* + * Copyright (c) 2010, Gregory Rogers All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CPPQC_PROPERTY_H +#define CPPQC_PROPERTY_H + +#include "Generator.h" +#include "PrettyPrint.h" + +namespace cppqc { + +namespace detail { + struct null_type {}; +} + +class PropertyBase +{ + public: + // By default, it is expected that every check passes. + virtual bool expect() const { return true; } + + // Should be overwriten by subclasses, as the default + // implementation is compiler dependent. + // (However, in practice, gcc and clang produce useful defaults.) + virtual std::string name() const { return typeid(*this).name(); } + + virtual ~PropertyBase() {} +}; + +template<class T0, class T1 = detail::null_type, class T2 = detail::null_type, + class T3 = detail::null_type, class T4 = detail::null_type> +class Property : public PropertyBase +{ + public: + typedef std::tuple<T0, T1, T2, T3, T4> Input; + + Property(const Generator<T0> &g0 = Arbitrary<T0>(), + const Generator<T1> &g1 = Arbitrary<T1>(), + const Generator<T2> &g2 = Arbitrary<T2>(), + const Generator<T3> &g3 = Arbitrary<T3>(), + const Generator<T4> &g4 = Arbitrary<T4>()) : + m_gen(tupleOf(g0, g1, g2, g3, g4)) + { + } + + Input generateInput(RngEngine &rng, std::size_t size) const + { + return m_gen.unGen(rng, size); + } + std::vector<Input> shrinkInput(const Input &in) const + { + return m_gen.shrink(in); + } + bool trivialInput(const Input &in) const + { + return trivial(std::get<0>(in), std::get<1>(in), + std::get<2>(in), std::get<3>(in), std::get<4>(in)); + } + std::string classifyInput(const Input &in) const + { + return classify(std::get<0>(in), std::get<1>(in), + std::get<2>(in), std::get<3>(in), std::get<4>(in)); + } + bool checkInput(const Input &in) const + { + return check(std::get<0>(in), std::get<1>(in), + std::get<2>(in), std::get<3>(in), std::get<4>(in)); + } + + private: + virtual bool trivial(const T0 &, const T1 &, const T2 &, const T3 &, + const T4 &) const + { + return false; + } + + virtual std::string classify(const T0 &, const T1 &, const T2 &, + const T3 &, const T4 &) const + { + return ""; + } + + virtual bool check(const T0 &, const T1 &, const T2 &, + const T3 &, const T4 &) const = 0; + + private: + const Generator<Input> m_gen; +}; + +template<class T0> +class Property<T0, detail::null_type, detail::null_type, detail::null_type, + detail::null_type> : public PropertyBase +{ + public: + typedef std::tuple<T0> Input; + + Property(const Generator<T0> &g0 = Arbitrary<T0>()) : + m_gen(tupleOf(g0)) + { + } + + Input generateInput(RngEngine &rng, std::size_t size) const + { + return m_gen.unGen(rng, size); + } + std::vector<Input> shrinkInput(const Input &in) const + { + return m_gen.shrink(in); + } + bool trivialInput(const Input &in) const + { + return trivial(std::get<0>(in)); + } + std::string classifyInput(const Input &in) const + { + return classify(std::get<0>(in)); + } + bool checkInput(const Input &in) const + { + return check(std::get<0>(in)); + } + + private: + virtual bool trivial(const T0 &) const + { + return false; + } + + virtual std::string classify(const T0 &) const + { + return ""; + } + + virtual bool check(const T0 &) const = 0; + + private: + const Generator<Input> m_gen; +}; + +template<class T0, class T1> +class Property<T0, T1, detail::null_type, detail::null_type, + detail::null_type> : public PropertyBase +{ + public: + typedef std::tuple<T0, T1> Input; + + Property(const Generator<T0> &g0 = Arbitrary<T0>(), + const Generator<T1> &g1 = Arbitrary<T1>()) : + m_gen(tupleOf(g0, g1)) + { + } + + Input generateInput(RngEngine &rng, std::size_t size) const + { + return m_gen.unGen(rng, size); + } + std::vector<Input> shrinkInput(const Input &in) const + { + return m_gen.shrink(in); + } + bool trivialInput(const Input &in) const + { + return trivial(std::get<0>(in), std::get<1>(in)); + } + std::string classifyInput(const Input &in) const + { + return classify(std::get<0>(in), std::get<1>(in)); + } + bool checkInput(const Input &in) const + { + return check(std::get<0>(in), std::get<1>(in)); + } + + private: + virtual bool trivial(const T0 &, const T1 &) const + { + return false; + } + + virtual std::string classify(const T0 &, const T1 &) const + { + return ""; + } + + virtual bool check(const T0 &, const T1 &) const = 0; + + private: + const Generator<Input> m_gen; +}; + +template<class T0, class T1, class T2> +class Property<T0, T1, T2, detail::null_type, detail::null_type> : + public PropertyBase +{ + public: + typedef std::tuple<T0, T1, T2> Input; + + Property(const Generator<T0> &g0 = Arbitrary<T0>(), + const Generator<T1> &g1 = Arbitrary<T1>(), + const Generator<T2> &g2 = Arbitrary<T2>()) : + m_gen(tupleOf(g0, g1, g2)) + { + } + + Input generateInput(RngEngine &rng, std::size_t size) const + { + return m_gen.unGen(rng, size); + } + std::vector<Input> shrinkInput(const Input &in) const + { + return m_gen.shrink(in); + } + bool trivialInput(const Input &in) const + { + return trivial(std::get<0>(in), std::get<1>(in), + std::get<2>(in)); + } + std::string classifyInput(const Input &in) const + { + return classify(std::get<0>(in), std::get<1>(in), + std::get<2>(in)); + } + bool checkInput(const Input &in) const + { + return check(std::get<0>(in), std::get<1>(in), + std::get<2>(in)); + } + + private: + virtual bool trivial(const T0 &, const T1 &, const T2 &) const + { + return false; + } + + virtual std::string classify(const T0 &, const T1 &, const T2 &) const + { + return ""; + } + + virtual bool check(const T0 &, const T1 &, const T2 &) const = 0; + + private: + const Generator<Input> m_gen; +}; + +template<class T0, class T1, class T2, class T3> +class Property<T0, T1, T2, T3, detail::null_type> : public PropertyBase +{ + public: + typedef std::tuple<T0, T1, T2, T3> Input; + + Property(const Generator<T0> &g0 = Arbitrary<T0>(), + const Generator<T1> &g1 = Arbitrary<T1>(), + const Generator<T2> &g2 = Arbitrary<T2>(), + const Generator<T3> &g3 = Arbitrary<T3>()) : + m_gen(tupleOf(g0, g1, g2, g3)) + { + } + + Input generateInput(RngEngine &rng, std::size_t size) const + { + return m_gen.unGen(rng, size); + } + std::vector<Input> shrinkInput(const Input &in) const + { + return m_gen.shrink(in); + } + bool trivialInput(const Input &in) const + { + return trivial(std::get<0>(in), std::get<1>(in), + std::get<2>(in), std::get<3>(in)); + } + std::string classifyInput(const Input &in) const + { + return classify(std::get<0>(in), std::get<1>(in), + std::get<2>(in), std::get<3>(in)); + } + bool checkInput(const Input &in) const + { + return check(std::get<0>(in), std::get<1>(in), + std::get<2>(in), std::get<3>(in)); + } + + private: + virtual bool trivial(const T0 &, const T1 &, const T2 &, + const T3 &) const + { + return false; + } + + virtual std::string classify(const T0 &, const T1 &, const T2 &, + const T3 &) const + { + return ""; + } + + virtual bool check(const T0 &, const T1 &, const T2 &, + const T3 &) const = 0; + + private: + const Generator<Input> m_gen; +}; + + +// named +// expectFailure +// classifyWith +// trivializeWith + + template<class T0> + std::ostream &printInput(std::ostream &out, const std::tuple<T0> &in) + { + return out << " 0: " << prettyPrint(std::get<0>(in)) << '\n' + << std::flush; + } + + template<class T0, class T1> + std::ostream &printInput(std::ostream &out, const std::tuple<T0, T1> &in) + { + return out << " 0: " << prettyPrint(std::get<0>(in)) << '\n' + << " 1: " << prettyPrint(std::get<1>(in)) << '\n' + << std::flush; + } + + template<class T0, class T1, class T2> + std::ostream &printInput(std::ostream &out, + const std::tuple<T0, T1, T2> &in) + { + return out << " 0: " << prettyPrint(std::get<0>(in)) << '\n' + << " 1: " << prettyPrint(std::get<1>(in)) << '\n' + << " 2: " << prettyPrint(std::get<2>(in)) << '\n' + << std::flush; + } + + template<class T0, class T1, class T2, class T3> + std::ostream &printInput(std::ostream &out, + const std::tuple<T0, T1, T2, T3> &in) + { + return out << " 0: " << prettyPrint(std::get<0>(in)) << '\n' + << " 1: " << prettyPrint(std::get<1>(in)) << '\n' + << " 2: " << prettyPrint(std::get<2>(in)) << '\n' + << " 3: " << prettyPrint(std::get<3>(in)) << '\n' + << std::flush; + } + + template<class T0, class T1, class T2, class T3, class T4> + std::ostream &printInput(std::ostream &out, + const std::tuple<T0, T1, T2, T3, T4> &in) + { + return out << " 0: " << prettyPrint(std::get<0>(in)) << '\n' + << " 1: " << prettyPrint(std::get<1>(in)) << '\n' + << " 2: " << prettyPrint(std::get<2>(in)) << '\n' + << " 3: " << prettyPrint(std::get<3>(in)) << '\n' + << " 4: " << prettyPrint(std::get<4>(in)) << '\n' + << std::flush; + } + + template<class T0, class T1, class T2, class T3, class T4, class T5> + std::ostream &printInput(std::ostream &out, + const std::tuple<T0, T1, T2, T3, T4, T5> &in) + { + return out << " 0: " << prettyPrint(std::get<0>(in)) << '\n' + << " 1: " << prettyPrint(std::get<1>(in)) << '\n' + << " 2: " << prettyPrint(std::get<2>(in)) << '\n' + << " 3: " << prettyPrint(std::get<3>(in)) << '\n' + << " 4: " << prettyPrint(std::get<4>(in)) << '\n' + << " 5: " << prettyPrint(std::get<5>(in)) << '\n' + << std::flush; + } + + template<class T0, class T1, class T2, class T3, class T4, + class T5, class T6> + std::ostream &printInput(std::ostream &out, + const std::tuple<T0, T1, T2, T3, T4, T5, T6> &in) + { + return out << " 0: " << prettyPrint(std::get<0>(in)) << '\n' + << " 1: " << prettyPrint(std::get<1>(in)) << '\n' + << " 2: " << prettyPrint(std::get<2>(in)) << '\n' + << " 3: " << prettyPrint(std::get<3>(in)) << '\n' + << " 4: " << prettyPrint(std::get<4>(in)) << '\n' + << " 5: " << prettyPrint(std::get<5>(in)) << '\n' + << " 6: " << prettyPrint(std::get<6>(in)) << '\n' + << std::flush; + } + + template<class T0, class T1, class T2, class T3, class T4, + class T5, class T6, class T7> + std::ostream &printInput(std::ostream &out, + const std::tuple<T0, T1, T2, T3, T4, T5, T6, T7> &in) + { + return out << " 0: " << prettyPrint(std::get<0>(in)) << '\n' + << " 1: " << prettyPrint(std::get<1>(in)) << '\n' + << " 2: " << prettyPrint(std::get<2>(in)) << '\n' + << " 3: " << prettyPrint(std::get<3>(in)) << '\n' + << " 4: " << prettyPrint(std::get<4>(in)) << '\n' + << " 5: " << prettyPrint(std::get<5>(in)) << '\n' + << " 6: " << prettyPrint(std::get<6>(in)) << '\n' + << " 7: " << prettyPrint(std::get<7>(in)) << '\n' + << std::flush; + } + + template<class T0, class T1, class T2, class T3, class T4, + class T5, class T6, class T7, class T8> + std::ostream &printInput(std::ostream &out, + const std::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8> &in) + { + return out << " 0: " << prettyPrint(std::get<0>(in)) << '\n' + << " 1: " << prettyPrint(std::get<1>(in)) << '\n' + << " 2: " << prettyPrint(std::get<2>(in)) << '\n' + << " 3: " << prettyPrint(std::get<3>(in)) << '\n' + << " 4: " << prettyPrint(std::get<4>(in)) << '\n' + << " 5: " << prettyPrint(std::get<5>(in)) << '\n' + << " 6: " << prettyPrint(std::get<6>(in)) << '\n' + << " 7: " << prettyPrint(std::get<7>(in)) << '\n' + << " 8: " << prettyPrint(std::get<8>(in)) << '\n' + << std::flush; + } + + template<class T0, class T1, class T2, class T3, class T4, + class T5, class T6, class T7, class T8, class T9> + std::ostream &printInput(std::ostream &out, + const std::tuple<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> &in) + { + return out << " 0: " << prettyPrint(std::get<0>(in)) << '\n' + << " 1: " << prettyPrint(std::get<1>(in)) << '\n' + << " 2: " << prettyPrint(std::get<2>(in)) << '\n' + << " 3: " << prettyPrint(std::get<3>(in)) << '\n' + << " 4: " << prettyPrint(std::get<4>(in)) << '\n' + << " 5: " << prettyPrint(std::get<5>(in)) << '\n' + << " 6: " << prettyPrint(std::get<6>(in)) << '\n' + << " 7: " << prettyPrint(std::get<7>(in)) << '\n' + << " 8: " << prettyPrint(std::get<8>(in)) << '\n' + << " 9: " << prettyPrint(std::get<9>(in)) << '\n' + << std::flush; + } + +} + +#endif diff --git a/vendor/CppQuickCheck-2018-03-28/include/cppqc/Test.h b/vendor/CppQuickCheck-2018-03-28/include/cppqc/Test.h new file mode 100644 index 00000000..8809c642 --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/include/cppqc/Test.h @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2010, Gregory Rogers All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CPPQC_TEST_H +#define CPPQC_TEST_H + +#include "Property.h" + +#include <map> +#include <string> +#include <iostream> +#include <iomanip> +#include <ostream> +#include <limits> +#include <chrono> + +namespace cppqc { + +using SeedType = uint32_t; + +// By default, a random seed will be used. +// To overwrite the default behaviour, set the environment variable +// "CPPQUICKCHECK_SEED". +constexpr SeedType USE_DEFAULT_SEED = std::numeric_limits<uint32_t>::max(); + +// If this environment variable is set, its value will overwrite the +// default seed. In other words, no random seed will be generated but +// if a seed has been explicitly set, it will will be used. +constexpr const char* CPPQUICKCHECK_SEED_ENV = "CPPQUICKCHECK_SEED"; + +// If this environment variable is set, failing tests will be +// looped forever. Useful for attaching a debugger. +constexpr const char *CPPQUICKCHECK_LOOP_FAILING_TESTS_ENV = + "CPPQUICKCHECK_LOOP_FAILING_TESTS"; + +enum ResultType +{ + QC_SUCCESS, // All tests succeeded + QC_GAVE_UP, // Failed to generate data + QC_FAILURE, // A test failed + QC_NO_EXPECTED_FAILURE // The property was expected to fail but didn't +}; + +struct Result +{ + ResultType result; + std::size_t numTests; + std::multimap<std::size_t, std::string> labels; + SeedType seed; + + // only used if result is QC_FAILURE + std::size_t numShrinks; + std::size_t usedSize; +}; + +namespace detail { + struct NullOstream : std::ostream + { + NullOstream() : std::ios(nullptr), std::ostream(nullptr) {} + }; +} + +template<class T0, class T1, class T2, class T3, class T4> +Result quickCheck(const Property<T0, T1, T2, T3, T4> &prop, + std::size_t maxSuccess = 100, std::size_t maxDiscarded = 0, + std::size_t maxSize = 0) +{ + detail::NullOstream out; + return quickCheckOutput(prop, out, maxSuccess, maxDiscarded, maxSize); +} + +namespace detail { + inline std::multimap<std::size_t, std::string> convertLabels( + const std::map<std::string, std::size_t> &labelsCollected) + { + std::multimap<std::size_t, std::string> labels; + for (const auto & elem : labelsCollected) { + labels.insert(std::make_pair(elem.second, elem.first)); + } + return labels; + } + + inline void outputLabels(std::ostream &out, std::size_t numSuccess, + const std::multimap<std::size_t, std::string> &labels) + { + std::size_t cnt = 20; + for (auto it = labels.rbegin(); it != labels.rend(); --cnt, ++it) { + if (cnt == 0) { + out << " ..." << std::endl; + break; + } + + if (it->second != "") { + out << std::setw(3) << (100 * it->first / numSuccess) << "% " + << it->second << std::endl; + } + } + } + + template<class T0, class T1, class T2, class T3, class T4> + std::pair<std::size_t, typename Property<T0, T1, T2, T3, T4>::Input> + doShrink(const Property<T0, T1, T2, T3, T4> &prop, + const typename Property<T0, T1, T2, T3, T4>::Input &in, + std::chrono::duration<double> timeout) + { + typedef typename Property<T0, T1, T2, T3, T4>::Input Input; + + std::size_t numShrinks = 0; + Input shrunk = in; + const auto start = std::chrono::steady_clock::now(); + + try { +continueShrinking: + std::vector<Input> shrinks = + prop.shrinkInput(shrunk); + for (Input input : shrinks) { + if (!prop.checkInput(input)) { + shrunk = std::move(input); + numShrinks++; + goto continueShrinking; + } + + // No progress was made. Check the time limit: + const std::chrono::duration<double> elapsed = + std::chrono::steady_clock::now() - start; + if (elapsed >= timeout) { + std::cout << "Shrinking timed out...\n"; + break; + } + } + } catch (...) { + } + return std::make_pair(numShrinks, shrunk); + } +} + +namespace detail { + inline SeedType resolveSeed(SeedType originalSeed = USE_DEFAULT_SEED) + { + if (originalSeed == USE_DEFAULT_SEED) { + const char* seed_from_env = std::getenv(CPPQUICKCHECK_SEED_ENV); + if (seed_from_env != nullptr) { + try { + return static_cast<uint32_t>(std::stoi(seed_from_env)); + } catch (std::invalid_argument&) { + std::ostringstream err; + err << "Failed to parse seed in environment variable " + << CPPQUICKCHECK_SEED_ENV + << ": Got <" << seed_from_env + << ">, but expected an integer between " + << "0 and " << (USE_DEFAULT_SEED - 1) + << ". To use a random seed instead, " + "unset the environment variable."; + throw std::invalid_argument{err.str()}; + } + } else { + return static_cast<SeedType>(time(0)); + } + } else { + return originalSeed; + } + } +} + +constexpr auto DEFAULT_SHRINK_TIMEOUT = std::chrono::seconds(30); +constexpr auto DISABLE_SHRINK_TIMEOUT = std::chrono::seconds::max(); + +template<class T0, class T1, class T2, class T3, class T4> +Result quickCheckOutput(const Property<T0, T1, T2, T3, T4> &prop, + std::ostream &out = std::cout, + std::size_t maxSuccess = 100, + std::size_t maxDiscarded = 0, std::size_t maxSize = 0, + std::chrono::duration<double> shrinkTimeout = DEFAULT_SHRINK_TIMEOUT, + SeedType seed = USE_DEFAULT_SEED) +{ + typedef typename Property<T0, T1, T2, T3, T4>::Input Input; + + out << "* Checking property \"" << prop.name() << "\" ..." << std::endl; + + if (maxDiscarded == 0) + maxDiscarded = maxSuccess * 5; + if (maxSize == 0) + maxSize = 100; + + std::map<std::string, std::size_t> labelsCollected; + std::size_t numSuccess = 0, numDiscarded = 0, numTrivial = 0; + + seed = detail::resolveSeed(seed); + RngEngine rng{seed}; + while (numSuccess < maxSuccess) { + try { + std::size_t size = (numSuccess * maxSize + numDiscarded) / maxSuccess; + Input in = prop.generateInput(rng, size); + bool success = false; + try { + success = prop.checkInput(in); + } catch (...) { + out << "Caught exception checking property...\n"; + } + + if (prop.trivialInput(in)) + ++numTrivial; + ++labelsCollected[prop.classifyInput(in)]; + + if (success) { + ++numSuccess; + } else { + if (prop.expect()) { + out << "*** Failed! "; + } else { + out << "+++ OK, failed as expected. "; + } + + std::size_t numShrinks = 0; + try { + out << "Starting shrinking..." << std::flush; + std::pair<std::size_t, Input> shrinkRes = + detail::doShrink(prop, in, shrinkTimeout); + numShrinks = shrinkRes.first; + in = shrinkRes.second; + out << "done\n"; + } catch (...) { + out << "WARN: Aborted shrinking because an exception was thrown\n"; + } + out << "Falsifiable after " << numSuccess + 1 + << (numSuccess == 0 ? " test" : " tests"); + if (numShrinks > 0) { + out << " and " << numShrinks + << (numShrinks == 1 ? " shrink" : " shrinks"); + } + out << " for input:\n"; + printInput(out, in); + out << "(To reproduce the test, use " + << CPPQUICKCHECK_SEED_ENV << '=' << seed << ")\n"; + + if (prop.expect()) { + while (getenv(CPPQUICKCHECK_LOOP_FAILING_TESTS_ENV) != nullptr) { + out << "Looping failing test...\n"; + prop.checkInput(in); + } + Result ret; + ret.result = QC_FAILURE; + ret.numTests = numSuccess + 1; + ret.labels = detail::convertLabels(labelsCollected); + ret.seed = seed; + ret.numShrinks = numShrinks; + ret.usedSize = size; + return ret; + } else { + Result ret; + ret.result = QC_SUCCESS; + ret.numTests = numSuccess + 1; + ret.labels = detail::convertLabels(labelsCollected); + ret.seed = seed; + return ret; + } + } + } catch (...) { + if (++numDiscarded >= maxDiscarded) { + out << "*** Gave up! Passed only " << numSuccess << " tests." + << std::endl; + + Result ret; + ret.result = QC_GAVE_UP; + ret.numTests = numSuccess; + ret.labels = detail::convertLabels(labelsCollected); + ret.seed = seed; + return ret; + } + } + } + + std::multimap<std::size_t, std::string> labels = + detail::convertLabels(labelsCollected); + + if (prop.expect()) { + out << "+++ OK, passed " << numSuccess << " tests"; + if (numTrivial != 0) + out << " (" << (100 * numTrivial / numSuccess) << "% trivial)"; + out << '.' << std::endl; + detail::outputLabels(out, numSuccess, labels); + + Result ret; + ret.result = QC_SUCCESS; + ret.numTests = numSuccess; + ret.labels = labels; + ret.seed = seed; + return ret; + } else { + out << "*** Failed! Expected failure but passed " << numSuccess + << " tests"; + if (numTrivial != 0) + out << " (" << (100 * numTrivial / numSuccess) << "% trivial)"; + out << '.' << std::endl; + detail::outputLabels(out, numSuccess, labels); + + Result ret; + ret.result = QC_NO_EXPECTED_FAILURE; + ret.numTests = numSuccess; + ret.labels = labels; + ret.seed = seed; + return ret; + } +} + +} + +#endif diff --git a/vendor/CppQuickCheck-2018-03-28/include/cppqc/cxx-prettyprint.h b/vendor/CppQuickCheck-2018-03-28/include/cppqc/cxx-prettyprint.h new file mode 100644 index 00000000..bbc644be --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/include/cppqc/cxx-prettyprint.h @@ -0,0 +1,472 @@ +// Copyright Louis Delacroix 2010 - 2014. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// A pretty printing library for C++ +// +// Usage: +// Include this header, and operator<< will "just work". + +#ifndef H_PRETTY_PRINT +#define H_PRETTY_PRINT + +#include <cstddef> +#include <iterator> +#include <memory> +#include <ostream> +#include <set> +#include <tuple> +#include <type_traits> +#include <unordered_set> +#include <utility> +#include <valarray> +#include <sstream> + +namespace pretty_print +{ + namespace detail + { + // SFINAE type trait to detect whether T::const_iterator exists. + + struct sfinae_base + { + using yes = char; + using no = yes[2]; + }; + + template <typename T> + struct has_const_iterator : private sfinae_base + { + private: + template <typename C> static yes & test(typename C::const_iterator*); + template <typename C> static no & test(...); + public: + static const bool value = sizeof(test<T>(nullptr)) == sizeof(yes); + using type = T; + }; + + template <typename T> + struct has_begin_end : private sfinae_base + { + private: + template <typename C> + static yes & f(typename std::enable_if< + std::is_same<decltype(static_cast<typename C::const_iterator(C::*)() const>(&C::begin)), + typename C::const_iterator(C::*)() const>::value>::type *); + + template <typename C> static no & f(...); + + template <typename C> + static yes & g(typename std::enable_if< + std::is_same<decltype(static_cast<typename C::const_iterator(C::*)() const>(&C::end)), + typename C::const_iterator(C::*)() const>::value, void>::type*); + + template <typename C> static no & g(...); + + public: + static bool const beg_value = sizeof(f<T>(nullptr)) == sizeof(yes); + static bool const end_value = sizeof(g<T>(nullptr)) == sizeof(yes); + }; + + } // namespace detail + + + // Holds the delimiter values for a specific character type + + template <typename TChar> + struct delimiters_values + { + using char_type = TChar; + const char_type * prefix; + const char_type * delimiter; + const char_type * postfix; + }; + + + // Defines the delimiter values for a specific container and character type + + template <typename T, typename TChar> + struct delimiters + { + using type = delimiters_values<TChar>; + static const type values; + }; + + template <typename T> + struct quoting_handler + { + static std::string toString(const T& x) + { + std::ostringstream out; + out << x; + return out.str(); + } + }; + + template <> + struct quoting_handler<std::string> + { + static std::string toString(const std::string& x) + { + return '\"' + x + '\"'; + } + }; + + template <class T> + std::string quote_if_necessary(const T& x) + { + return quoting_handler<T>::toString(x); + } + + // Functor to print containers. You can use this directly if you want + // to specificy a non-default delimiters type. The printing logic can + // be customized by specializing the nested template. + + template <typename T, + typename TChar = char, + typename TCharTraits = ::std::char_traits<TChar>, + typename TDelimiters = delimiters<T, TChar>> + struct print_container_helper + { + using delimiters_type = TDelimiters; + using ostream_type = std::basic_ostream<TChar, TCharTraits>; + + template <typename U> + struct printer + { + static void print_body(const U & c, ostream_type & stream) + { + using std::begin; + using std::end; + + auto it = begin(c); + const auto the_end = end(c); + + if (it != the_end) + { + for ( ; ; ) + { + stream << quote_if_necessary(*it); + + if (++it == the_end) + break; + + if (delimiters_type::values.delimiter != NULL) + stream << delimiters_type::values.delimiter; + } + } + } + }; + + print_container_helper(const T & container) + : container_(container) + { } + + inline void operator()(ostream_type & stream) const + { + if (delimiters_type::values.prefix != NULL) + stream << delimiters_type::values.prefix; + + printer<T>::print_body(container_, stream); + + if (delimiters_type::values.postfix != NULL) + stream << delimiters_type::values.postfix; + } + + private: + const T & container_; + }; + + // Specialization for pairs + + template <typename T, typename TChar, typename TCharTraits, typename TDelimiters> + template <typename T1, typename T2> + struct print_container_helper<T, TChar, TCharTraits, TDelimiters>::printer<std::pair<T1, T2>> + { + using ostream_type = print_container_helper<T, TChar, TCharTraits, TDelimiters>::ostream_type; + + static void print_body(const std::pair<T1, T2> & c, ostream_type & stream) + { + stream << quote_if_necessary(c.first); + if (print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter != NULL) + stream << print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter; + stream << quote_if_necessary(c.second); + } + }; + + // Specialization for tuples + + template <typename T, typename TChar, typename TCharTraits, typename TDelimiters> + template <typename ...Args> + struct print_container_helper<T, TChar, TCharTraits, TDelimiters>::printer<std::tuple<Args...>> + { + using ostream_type = print_container_helper<T, TChar, TCharTraits, TDelimiters>::ostream_type; + using element_type = std::tuple<Args...>; + + template <std::size_t I> struct Int { }; + + static void print_body(const element_type & c, ostream_type & stream) + { + tuple_print(c, stream, Int<0>()); + } + + static void tuple_print(const element_type &, ostream_type &, Int<sizeof...(Args)>) + { + } + + static void tuple_print(const element_type & c, ostream_type & stream, + typename std::conditional<sizeof...(Args) != 0, Int<0>, std::nullptr_t>::type) + { + stream << quote_if_necessary(std::get<0>(c)); + tuple_print(c, stream, Int<1>()); + } + + template <std::size_t N> + static void tuple_print(const element_type & c, ostream_type & stream, Int<N>) + { + if (print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter != NULL) + stream << print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter; + + stream << quote_if_necessary(std::get<N>(c)); + + tuple_print(c, stream, Int<N + 1>()); + } + }; + + // Prints a print_container_helper to the specified stream. + + template<typename T, typename TChar, typename TCharTraits, typename TDelimiters> + inline std::basic_ostream<TChar, TCharTraits> & operator<<( + std::basic_ostream<TChar, TCharTraits> & stream, + const print_container_helper<T, TChar, TCharTraits, TDelimiters> & helper) + { + helper(stream); + return stream; + } + + + // Basic is_container template; specialize to derive from std::true_type for all desired container types + + template <typename T> + struct is_container : public std::integral_constant<bool, + detail::has_const_iterator<T>::value && + detail::has_begin_end<T>::beg_value && + detail::has_begin_end<T>::end_value> { }; + + template <typename T, std::size_t N> + struct is_container<T[N]> : std::true_type { }; + + template <std::size_t N> + struct is_container<char[N]> : std::false_type { }; + + template <typename T> + struct is_container<std::valarray<T>> : std::true_type { }; + + template <typename T1, typename T2> + struct is_container<std::pair<T1, T2>> : std::true_type { }; + + template <typename ...Args> + struct is_container<std::tuple<Args...>> : std::true_type { }; + + + // Default delimiters + + template <typename T> struct delimiters<T, char> { static const delimiters_values<char> values; }; + template <typename T> const delimiters_values<char> delimiters<T, char>::values = { "[", ", ", "]" }; + template <typename T> struct delimiters<T, wchar_t> { static const delimiters_values<wchar_t> values; }; + template <typename T> const delimiters_values<wchar_t> delimiters<T, wchar_t>::values = { L"[", L", ", L"]" }; + + + // Delimiters for (multi)set and unordered_(multi)set + + template <typename T, typename TComp, typename TAllocator> + struct delimiters< ::std::set<T, TComp, TAllocator>, char> { static const delimiters_values<char> values; }; + + template <typename T, typename TComp, typename TAllocator> + const delimiters_values<char> delimiters< ::std::set<T, TComp, TAllocator>, char>::values = { "{", ", ", "}" }; + + template <typename T, typename TComp, typename TAllocator> + struct delimiters< ::std::set<T, TComp, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; }; + + template <typename T, typename TComp, typename TAllocator> + const delimiters_values<wchar_t> delimiters< ::std::set<T, TComp, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" }; + + template <typename T, typename TComp, typename TAllocator> + struct delimiters< ::std::multiset<T, TComp, TAllocator>, char> { static const delimiters_values<char> values; }; + + template <typename T, typename TComp, typename TAllocator> + const delimiters_values<char> delimiters< ::std::multiset<T, TComp, TAllocator>, char>::values = { "{", ", ", "}" }; + + template <typename T, typename TComp, typename TAllocator> + struct delimiters< ::std::multiset<T, TComp, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; }; + + template <typename T, typename TComp, typename TAllocator> + const delimiters_values<wchar_t> delimiters< ::std::multiset<T, TComp, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" }; + + template <typename T, typename THash, typename TEqual, typename TAllocator> + struct delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, char> { static const delimiters_values<char> values; }; + + template <typename T, typename THash, typename TEqual, typename TAllocator> + const delimiters_values<char> delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, char>::values = { "{", ", ", "}" }; + + template <typename T, typename THash, typename TEqual, typename TAllocator> + struct delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; }; + + template <typename T, typename THash, typename TEqual, typename TAllocator> + const delimiters_values<wchar_t> delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" }; + + template <typename T, typename THash, typename TEqual, typename TAllocator> + struct delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, char> { static const delimiters_values<char> values; }; + + template <typename T, typename THash, typename TEqual, typename TAllocator> + const delimiters_values<char> delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, char>::values = { "{", ", ", "}" }; + + template <typename T, typename THash, typename TEqual, typename TAllocator> + struct delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; }; + + template <typename T, typename THash, typename TEqual, typename TAllocator> + const delimiters_values<wchar_t> delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" }; + + + // Delimiters for pair and tuple + + template <typename T1, typename T2> struct delimiters<std::pair<T1, T2>, char> { static const delimiters_values<char> values; }; + template <typename T1, typename T2> const delimiters_values<char> delimiters<std::pair<T1, T2>, char>::values = { "(", ", ", ")" }; + template <typename T1, typename T2> struct delimiters< ::std::pair<T1, T2>, wchar_t> { static const delimiters_values<wchar_t> values; }; + template <typename T1, typename T2> const delimiters_values<wchar_t> delimiters< ::std::pair<T1, T2>, wchar_t>::values = { L"(", L", ", L")" }; + + template <typename ...Args> struct delimiters<std::tuple<Args...>, char> { static const delimiters_values<char> values; }; + template <typename ...Args> const delimiters_values<char> delimiters<std::tuple<Args...>, char>::values = { "(", ", ", ")" }; + template <typename ...Args> struct delimiters< ::std::tuple<Args...>, wchar_t> { static const delimiters_values<wchar_t> values; }; + template <typename ...Args> const delimiters_values<wchar_t> delimiters< ::std::tuple<Args...>, wchar_t>::values = { L"(", L", ", L")" }; + + + // Type-erasing helper class for easy use of custom delimiters. + // Requires TCharTraits = std::char_traits<TChar> and TChar = char or wchar_t, and MyDelims needs to be defined for TChar. + // Usage: "cout << pretty_print::custom_delims<MyDelims>(x)". + + struct custom_delims_base + { + virtual ~custom_delims_base() { } + virtual std::ostream & stream(::std::ostream &) = 0; + virtual std::wostream & stream(::std::wostream &) = 0; + }; + + template <typename T, typename Delims> + struct custom_delims_wrapper : custom_delims_base + { + custom_delims_wrapper(const T & t_) : t(t_) { } + + std::ostream & stream(std::ostream & s) + { + return s << print_container_helper<T, char, std::char_traits<char>, Delims>(t); + } + + std::wostream & stream(std::wostream & s) + { + return s << print_container_helper<T, wchar_t, std::char_traits<wchar_t>, Delims>(t); + } + + private: + const T & t; + }; + + template <typename Delims> + struct custom_delims + { + template <typename Container> + custom_delims(const Container & c) : base(new custom_delims_wrapper<Container, Delims>(c)) { } + + std::unique_ptr<custom_delims_base> base; + }; + + template <typename TChar, typename TCharTraits, typename Delims> + inline std::basic_ostream<TChar, TCharTraits> & operator<<(std::basic_ostream<TChar, TCharTraits> & s, const custom_delims<Delims> & p) + { + return p.base->stream(s); + } + + + // A wrapper for a C-style array given as pointer-plus-size. + // Usage: std::cout << pretty_print_array(arr, n) << std::endl; + + template<typename T> + struct array_wrapper_n + { + typedef const T * const_iterator; + typedef T value_type; + + array_wrapper_n(const T * const a, size_t n) : _array(a), _n(n) { } + inline const_iterator begin() const { return _array; } + inline const_iterator end() const { return _array + _n; } + + private: + const T * const _array; + size_t _n; + }; + + + // A wrapper for hash-table based containers that offer local iterators to each bucket. + // Usage: std::cout << bucket_print(m, 4) << std::endl; (Prints bucket 5 of container m.) + + template <typename T> + struct bucket_print_wrapper + { + typedef typename T::const_local_iterator const_iterator; + typedef typename T::size_type size_type; + + const_iterator begin() const + { + return m_map.cbegin(n); + } + + const_iterator end() const + { + return m_map.cend(n); + } + + bucket_print_wrapper(const T & m, size_type bucket) : m_map(m), n(bucket) { } + + private: + const T & m_map; + const size_type n; + }; + +} // namespace pretty_print + + +// Global accessor functions for the convenience wrappers + +template<typename T> +inline pretty_print::array_wrapper_n<T> pretty_print_array(const T * const a, size_t n) +{ + return pretty_print::array_wrapper_n<T>(a, n); +} + +template <typename T> pretty_print::bucket_print_wrapper<T> +bucket_print(const T & m, typename T::size_type n) +{ + return pretty_print::bucket_print_wrapper<T>(m, n); +} + + +// Main magic entry point: An overload snuck into namespace std. +// Can we do better? + +namespace std +{ + // Prints a container to the stream using default delimiters + + template<typename T, typename TChar, typename TCharTraits> + inline typename enable_if< ::pretty_print::is_container<T>::value, + basic_ostream<TChar, TCharTraits> &>::type + operator<<(basic_ostream<TChar, TCharTraits> & stream, const T & container) + { + return stream << ::pretty_print::print_container_helper<T, TChar, TCharTraits>(container); + } +} + + + +#endif // H_PRETTY_PRINT diff --git a/vendor/CppQuickCheck-2018-03-28/src/Arbitrary.cpp b/vendor/CppQuickCheck-2018-03-28/src/Arbitrary.cpp new file mode 100644 index 00000000..5da4d3d7 --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/src/Arbitrary.cpp @@ -0,0 +1,80 @@ +#include "cppqc/Arbitrary.h" + +namespace cppqc { + +const Arbitrary<bool>::unGenType ArbitraryImpl<bool>::unGen = arbitraryBool; +const Arbitrary<bool>::shrinkType ArbitraryImpl<bool>::shrink = shrinkBool; + +const Arbitrary<signed char>::unGenType ArbitraryImpl<signed char>::unGen = + arbitrarySizedBoundedIntegral<signed char>; +const Arbitrary<signed char>::shrinkType ArbitraryImpl<signed char>::shrink = + shrinkIntegral<signed char>; + +const Arbitrary<unsigned char>::unGenType ArbitraryImpl<unsigned char>::unGen = + arbitrarySizedBoundedIntegral<unsigned char>; +const Arbitrary<unsigned char>::shrinkType + ArbitraryImpl<unsigned char>::shrink = shrinkIntegral<unsigned char>; + +const Arbitrary<signed short>::unGenType ArbitraryImpl<signed short>::unGen = + arbitrarySizedBoundedIntegral<signed short>; +const Arbitrary<signed short>::shrinkType ArbitraryImpl<signed short>::shrink = + shrinkIntegral<signed short>; + +const Arbitrary<unsigned short>::unGenType + ArbitraryImpl<unsigned short>::unGen = + arbitrarySizedBoundedIntegral<unsigned short>; +const Arbitrary<unsigned short>::shrinkType + ArbitraryImpl<unsigned short>::shrink = shrinkIntegral<unsigned short>; + +const Arbitrary<signed int>::unGenType ArbitraryImpl<signed int>::unGen = + arbitrarySizedBoundedIntegral<signed int>; +const Arbitrary<signed int>::shrinkType ArbitraryImpl<signed int>::shrink = + shrinkIntegral<signed int>; + +const Arbitrary<unsigned int>::unGenType ArbitraryImpl<unsigned int>::unGen = + arbitrarySizedBoundedIntegral<unsigned int>; +const Arbitrary<unsigned int>::shrinkType ArbitraryImpl<unsigned int>::shrink = + shrinkIntegral<unsigned int>; + +const Arbitrary<signed long>::unGenType ArbitraryImpl<signed long>::unGen = + arbitrarySizedBoundedIntegral<signed long>; +const Arbitrary<signed long>::shrinkType ArbitraryImpl<signed long>::shrink = + shrinkIntegral<signed long>; + +const Arbitrary<unsigned long>::unGenType ArbitraryImpl<unsigned long>::unGen = + arbitrarySizedBoundedIntegral<unsigned long>; +const Arbitrary<unsigned long>::shrinkType ArbitraryImpl<unsigned long>::shrink = + shrinkIntegral<unsigned long>; + +const Arbitrary<signed long long>::unGenType ArbitraryImpl<signed long long>::unGen = + arbitrarySizedBoundedIntegral<signed long long>; +const Arbitrary<signed long long>::shrinkType ArbitraryImpl<signed long long>::shrink = + shrinkIntegral<signed long long>; + +const Arbitrary<unsigned long long>::unGenType ArbitraryImpl<unsigned long long>::unGen = + arbitrarySizedBoundedIntegral<unsigned long long>; +const Arbitrary<unsigned long long>::shrinkType ArbitraryImpl<unsigned long long>::shrink = + shrinkIntegral<unsigned long long>; + +const Arbitrary<float>::unGenType ArbitraryImpl<float>::unGen = + arbitrarySizedReal<float>; +const Arbitrary<float>::shrinkType ArbitraryImpl<float>::shrink = shrinkReal<float>; + +const Arbitrary<double>::unGenType ArbitraryImpl<double>::unGen = + arbitrarySizedReal<double>; +const Arbitrary<double>::shrinkType ArbitraryImpl<double>::shrink = shrinkReal<double>; + +const Arbitrary<long double>::unGenType ArbitraryImpl<long double>::unGen = + arbitrarySizedReal<long double>; +const Arbitrary<long double>::shrinkType ArbitraryImpl<long double>::shrink = + shrinkReal<long double>; + +const Arbitrary<char>::unGenType ArbitraryImpl<char>::unGen = arbitraryChar; +const Arbitrary<char>::shrinkType ArbitraryImpl<char>::shrink = shrinkChar; + +const Arbitrary<wchar_t>::unGenType ArbitraryImpl<wchar_t>::unGen = + arbitraryBoundedIntegral<wchar_t>; +const Arbitrary<wchar_t>::shrinkType ArbitraryImpl<wchar_t>::shrink = + shrinkIntegral<wchar_t>; + +} diff --git a/vendor/CppQuickCheck-2018-03-28/test/catch-main.cpp b/vendor/CppQuickCheck-2018-03-28/test/catch-main.cpp new file mode 100644 index 00000000..50c80130 --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/test/catch-main.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2016, Philipp Classen All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file +#include "catch.hpp" diff --git a/vendor/CppQuickCheck-2018-03-28/test/catch.hpp b/vendor/CppQuickCheck-2018-03-28/test/catch.hpp new file mode 100644 index 00000000..ec75bf1d --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/test/catch.hpp @@ -0,0 +1,9427 @@ +/* + * CATCH v1.1 build 14 (develop branch) + * Generated: 2015-03-04 18:32:24.627737 + * ---------------------------------------------------------- + * This file has been merged from multiple headers. Please don't edit it directly + * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED + +#define TWOBLUECUBES_CATCH_HPP_INCLUDED + +// #included from: internal/catch_suppress_warnings.h + +#define TWOBLUECUBES_CATCH_SUPPRESS_WARNINGS_H_INCLUDED + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(push) +# pragma warning(disable: 161 1682) +# else // __ICC +# pragma clang diagnostic ignored "-Wglobal-constructors" +# pragma clang diagnostic ignored "-Wvariadic-macros" +# pragma clang diagnostic ignored "-Wc99-extensions" +# pragma clang diagnostic ignored "-Wunused-variable" +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic ignored "-Wc++98-compat" +# pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic ignored "-Wvariadic-macros" +# pragma GCC diagnostic ignored "-Wunused-variable" +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpadded" +#endif + +#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) +# define CATCH_IMPL +#endif + +#ifdef CATCH_IMPL +# ifndef CLARA_CONFIG_MAIN +# define CLARA_CONFIG_MAIN_NOT_DEFINED +# define CLARA_CONFIG_MAIN +# endif +#endif + +// #included from: internal/catch_notimplemented_exception.h +#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED + +// #included from: catch_common.h +#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED + +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) + +#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr +#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr ) + +#include <sstream> +#include <stdexcept> +#include <algorithm> + +// #included from: catch_compiler_capabilities.h +#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED + +// Much of the following code is based on Boost (1.53) + +#ifdef __clang__ + +# if __has_feature(cxx_nullptr) +# define CATCH_CONFIG_CPP11_NULLPTR +# endif + +# if __has_feature(cxx_noexcept) +# define CATCH_CONFIG_CPP11_NOEXCEPT +# endif + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// Borland +#ifdef __BORLANDC__ + +#if (__BORLANDC__ > 0x582 ) +//#define CATCH_CONFIG_SFINAE // Not confirmed +#endif + +#endif // __BORLANDC__ + +//////////////////////////////////////////////////////////////////////////////// +// EDG +#ifdef __EDG_VERSION__ + +#if (__EDG_VERSION__ > 238 ) +//#define CATCH_CONFIG_SFINAE // Not confirmed +#endif + +#endif // __EDG_VERSION__ + +//////////////////////////////////////////////////////////////////////////////// +// Digital Mars +#ifdef __DMC__ + +#if (__DMC__ > 0x840 ) +//#define CATCH_CONFIG_SFINAE // Not confirmed +#endif + +#endif // __DMC__ + +//////////////////////////////////////////////////////////////////////////////// +// GCC +#ifdef __GNUC__ + +#if __GNUC__ < 3 + +#if (__GNUC_MINOR__ >= 96 ) +//#define CATCH_CONFIG_SFINAE +#endif + +#elif __GNUC__ >= 3 + +// #define CATCH_CONFIG_SFINAE // Taking this out completely for now + +#endif // __GNUC__ < 3 + +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) ) + +#define CATCH_CONFIG_CPP11_NULLPTR +#endif + +#endif // __GNUC__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#ifdef _MSC_VER + +#if (_MSC_VER >= 1600) +#define CATCH_CONFIG_CPP11_NULLPTR +#endif + +#if (_MSC_VER >= 1310 ) // (VC++ 7.0+) +//#define CATCH_CONFIG_SFINAE // Not confirmed +#endif + +#endif // _MSC_VER + +// Use variadic macros if the compiler supports them +#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ + ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ + ( defined __GNUC__ && __GNUC__ >= 3 ) || \ + ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L ) + +#ifndef CATCH_CONFIG_NO_VARIADIC_MACROS +#define CATCH_CONFIG_VARIADIC_MACROS +#endif + +#endif + +//////////////////////////////////////////////////////////////////////////////// +// C++ language feature support + +// detect language version: +#if (__cplusplus == 201103L) +# define CATCH_CPP11 +# define CATCH_CPP11_OR_GREATER +#elif (__cplusplus >= 201103L) +# define CATCH_CPP11_OR_GREATER +#endif + +// noexcept support: +#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT) +# define CATCH_NOEXCEPT noexcept +# define CATCH_NOEXCEPT_IS(x) noexcept(x) +#else +# define CATCH_NOEXCEPT throw() +# define CATCH_NOEXCEPT_IS(x) +#endif + +namespace Catch { + + class NonCopyable { +#ifdef CATCH_CPP11_OR_GREATER + NonCopyable( NonCopyable const& ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable& operator = ( NonCopyable const& ) = delete; + NonCopyable& operator = ( NonCopyable && ) = delete; +#else + NonCopyable( NonCopyable const& info ); + NonCopyable& operator = ( NonCopyable const& ); +#endif + + protected: + NonCopyable() {} + virtual ~NonCopyable(); + }; + + class SafeBool { + public: + typedef void (SafeBool::*type)() const; + + static type makeSafe( bool value ) { + return value ? &SafeBool::trueValue : 0; + } + private: + void trueValue() const {} + }; + + template<typename ContainerT> + inline void deleteAll( ContainerT& container ) { + typename ContainerT::const_iterator it = container.begin(); + typename ContainerT::const_iterator itEnd = container.end(); + for(; it != itEnd; ++it ) + delete *it; + } + template<typename AssociativeContainerT> + inline void deleteAllValues( AssociativeContainerT& container ) { + typename AssociativeContainerT::const_iterator it = container.begin(); + typename AssociativeContainerT::const_iterator itEnd = container.end(); + for(; it != itEnd; ++it ) + delete it->second; + } + + bool startsWith( std::string const& s, std::string const& prefix ); + bool endsWith( std::string const& s, std::string const& suffix ); + bool contains( std::string const& s, std::string const& infix ); + void toLowerInPlace( std::string& s ); + std::string toLower( std::string const& s ); + std::string trim( std::string const& str ); + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ); + + struct pluralise { + pluralise( std::size_t count, std::string const& label ); + + friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ); + + std::size_t m_count; + std::string m_label; + }; + + struct SourceLineInfo { + + SourceLineInfo(); + SourceLineInfo( char const* _file, std::size_t _line ); + SourceLineInfo( SourceLineInfo const& other ); +# ifdef CATCH_CPP11_OR_GREATER + SourceLineInfo( SourceLineInfo && ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo& operator = ( SourceLineInfo && ) = default; +# endif + bool empty() const; + bool operator == ( SourceLineInfo const& other ) const; + bool operator < ( SourceLineInfo const& other ) const; + + std::string file; + std::size_t line; + }; + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); + + // This is just here to avoid compiler warnings with macro constants and boolean literals + inline bool isTrue( bool value ){ return value; } + inline bool alwaysTrue() { return true; } + inline bool alwaysFalse() { return false; } + + void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); + + // Use this in variadic streaming macros to allow + // >> +StreamEndStop + // as well as + // >> stuff +StreamEndStop + struct StreamEndStop { + std::string operator+() { + return std::string(); + } + }; + template<typename T> + T const& operator + ( T const& value, StreamEndStop ) { + return value; + } +} + +#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) ) +#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO ); + +#include <ostream> + +namespace Catch { + + class NotImplementedException : public std::exception + { + public: + NotImplementedException( SourceLineInfo const& lineInfo ); + NotImplementedException( NotImplementedException const& ) {} + + virtual ~NotImplementedException() CATCH_NOEXCEPT {} + + virtual const char* what() const CATCH_NOEXCEPT; + + private: + std::string m_what; + SourceLineInfo m_lineInfo; + }; + +} // end namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO ) + +// #included from: internal/catch_context.h +#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED + +// #included from: catch_interfaces_generators.h +#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED + +#include <string> + +namespace Catch { + + struct IGeneratorInfo { + virtual ~IGeneratorInfo(); + virtual bool moveNext() = 0; + virtual std::size_t getCurrentIndex() const = 0; + }; + + struct IGeneratorsForTest { + virtual ~IGeneratorsForTest(); + + virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0; + virtual bool moveNext() = 0; + }; + + IGeneratorsForTest* createGeneratorsForTest(); + +} // end namespace Catch + +// #included from: catch_ptr.hpp +#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + // An intrusive reference counting smart pointer. + // T must implement addRef() and release() methods + // typically implementing the IShared interface + template<typename T> + class Ptr { + public: + Ptr() : m_p( NULL ){} + Ptr( T* p ) : m_p( p ){ + if( m_p ) + m_p->addRef(); + } + Ptr( Ptr const& other ) : m_p( other.m_p ){ + if( m_p ) + m_p->addRef(); + } + ~Ptr(){ + if( m_p ) + m_p->release(); + } + void reset() { + if( m_p ) + m_p->release(); + m_p = NULL; + } + Ptr& operator = ( T* p ){ + Ptr temp( p ); + swap( temp ); + return *this; + } + Ptr& operator = ( Ptr const& other ){ + Ptr temp( other ); + swap( temp ); + return *this; + } + void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } + T* get() { return m_p; } + const T* get() const{ return m_p; } + T& operator*() const { return *m_p; } + T* operator->() const { return m_p; } + bool operator !() const { return m_p == NULL; } + operator SafeBool::type() const { return SafeBool::makeSafe( m_p != NULL ); } + + private: + T* m_p; + }; + + struct IShared : NonCopyable { + virtual ~IShared(); + virtual void addRef() const = 0; + virtual void release() const = 0; + }; + + template<typename T = IShared> + struct SharedImpl : T { + + SharedImpl() : m_rc( 0 ){} + + virtual void addRef() const { + ++m_rc; + } + virtual void release() const { + if( --m_rc == 0 ) + delete this; + } + + mutable unsigned int m_rc; + }; + +} // end namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#include <memory> +#include <vector> +#include <stdlib.h> + +namespace Catch { + + class TestCase; + class Stream; + struct IResultCapture; + struct IRunner; + struct IGeneratorsForTest; + struct IConfig; + + struct IContext + { + virtual ~IContext(); + + virtual IResultCapture* getResultCapture() = 0; + virtual IRunner* getRunner() = 0; + virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0; + virtual bool advanceGeneratorsForCurrentTest() = 0; + virtual Ptr<IConfig const> getConfig() const = 0; + }; + + struct IMutableContext : IContext + { + virtual ~IMutableContext(); + virtual void setResultCapture( IResultCapture* resultCapture ) = 0; + virtual void setRunner( IRunner* runner ) = 0; + virtual void setConfig( Ptr<IConfig const> const& config ) = 0; + }; + + IContext& getCurrentContext(); + IMutableContext& getCurrentMutableContext(); + void cleanUpContext(); + Stream createStream( std::string const& streamName ); + +} + +// #included from: internal/catch_test_registry.hpp +#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED + +// #included from: catch_interfaces_testcase.h +#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED + +#include <vector> + +namespace Catch { + + class TestSpec; + + struct ITestCase : IShared { + virtual void invoke () const = 0; + protected: + virtual ~ITestCase(); + }; + + class TestCase; + struct IConfig; + + struct ITestCaseRegistry { + virtual ~ITestCaseRegistry(); + virtual std::vector<TestCase> const& getAllTests() const = 0; + virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector<TestCase>& matchingTestCases, bool negated = false ) const = 0; + + }; +} + +namespace Catch { + +template<typename C> +class MethodTestCase : public SharedImpl<ITestCase> { + +public: + MethodTestCase( void (C::*method)() ) : m_method( method ) {} + + virtual void invoke() const { + C obj; + (obj.*m_method)(); + } + +private: + virtual ~MethodTestCase() {} + + void (C::*m_method)(); +}; + +typedef void(*TestFunction)(); + +struct NameAndDesc { + NameAndDesc( const char* _name = "", const char* _description= "" ) + : name( _name ), description( _description ) + {} + + const char* name; + const char* description; +}; + +struct AutoReg { + + AutoReg( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); + + template<typename C> + AutoReg( void (C::*method)(), + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + registerTestCase( new MethodTestCase<C>( method ), + className, + nameAndDesc, + lineInfo ); + } + + void registerTestCase( ITestCase* testCase, + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ); + + ~AutoReg(); + +private: + AutoReg( AutoReg const& ); + void operator= ( AutoReg const& ); +}; + +} // end namespace Catch + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE( ... ) \ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); } + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\ + namespace{ \ + struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \ + } \ + void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + +#else + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\ + static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )() + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \ + namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); } + + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\ + namespace{ \ + struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \ + void test(); \ + }; \ + Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \ + } \ + void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + +#endif + +// #included from: internal/catch_capture.hpp +#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED + +// #included from: catch_result_builder.h +#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED + +// #included from: catch_result_type.h +#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED + +namespace Catch { + + // ResultWas::OfType enum + struct ResultWas { enum OfType { + Unknown = -1, + Ok = 0, + Info = 1, + Warning = 2, + + FailureBit = 0x10, + + ExpressionFailed = FailureBit | 1, + ExplicitFailure = FailureBit | 2, + + Exception = 0x100 | FailureBit, + + ThrewException = Exception | 1, + DidntThrowException = Exception | 2, + + FatalErrorCondition = 0x200 | FailureBit + + }; }; + + inline bool isOk( ResultWas::OfType resultType ) { + return ( resultType & ResultWas::FailureBit ) == 0; + } + inline bool isJustInfo( int flags ) { + return flags == ResultWas::Info; + } + + // ResultDisposition::Flags enum + struct ResultDisposition { enum Flags { + Normal = 0x00, + + ContinueOnFailure = 0x01, // Failures fail test, but execution continues + FalseTest = 0x02, // Prefix expression with ! + SuppressFail = 0x04 // Failures are reported but do not fail the test + }; }; + + inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { + return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) ); + } + + inline bool shouldContinueOnFailure( int flags ) { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; } + inline bool isFalseTest( int flags ) { return ( flags & ResultDisposition::FalseTest ) != 0; } + inline bool shouldSuppressFailure( int flags ) { return ( flags & ResultDisposition::SuppressFail ) != 0; } + +} // end namespace Catch + +// #included from: catch_assertionresult.h +#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED + +#include <string> + +namespace Catch { + + struct AssertionInfo + { + AssertionInfo() {} + AssertionInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + std::string const& _capturedExpression, + ResultDisposition::Flags _resultDisposition ); + + std::string macroName; + SourceLineInfo lineInfo; + std::string capturedExpression; + ResultDisposition::Flags resultDisposition; + }; + + struct AssertionResultData + { + AssertionResultData() : resultType( ResultWas::Unknown ) {} + + std::string reconstructedExpression; + std::string message; + ResultWas::OfType resultType; + }; + + class AssertionResult { + public: + AssertionResult(); + AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); + ~AssertionResult(); +# ifdef CATCH_CPP11_OR_GREATER + AssertionResult( AssertionResult const& ) = default; + AssertionResult( AssertionResult && ) = default; + AssertionResult& operator = ( AssertionResult const& ) = default; + AssertionResult& operator = ( AssertionResult && ) = default; +# endif + + bool isOk() const; + bool succeeded() const; + ResultWas::OfType getResultType() const; + bool hasExpression() const; + bool hasMessage() const; + std::string getExpression() const; + std::string getExpressionInMacro() const; + bool hasExpandedExpression() const; + std::string getExpandedExpression() const; + std::string getMessage() const; + SourceLineInfo getSourceInfo() const; + std::string getTestMacroName() const; + + protected: + AssertionInfo m_info; + AssertionResultData m_resultData; + }; + +} // end namespace Catch + +namespace Catch { + + struct TestFailureException{}; + + template<typename T> class ExpressionLhs; + + struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison; + + struct CopyableStream { + CopyableStream() {} + CopyableStream( CopyableStream const& other ) { + oss << other.oss.str(); + } + CopyableStream& operator=( CopyableStream const& other ) { + oss.str(""); + oss << other.oss.str(); + return *this; + } + std::ostringstream oss; + }; + + class ResultBuilder { + public: + ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition ); + + template<typename T> + ExpressionLhs<T const&> operator->* ( T const& operand ); + ExpressionLhs<bool> operator->* ( bool value ); + + template<typename T> + ResultBuilder& operator << ( T const& value ) { + m_stream.oss << value; + return *this; + } + + template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); + template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); + + ResultBuilder& setResultType( ResultWas::OfType result ); + ResultBuilder& setResultType( bool result ); + ResultBuilder& setLhs( std::string const& lhs ); + ResultBuilder& setRhs( std::string const& rhs ); + ResultBuilder& setOp( std::string const& op ); + + void endExpression(); + + std::string reconstructExpression() const; + AssertionResult build() const; + + void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); + void captureResult( ResultWas::OfType resultType ); + void captureExpression(); + void react(); + bool shouldDebugBreak() const; + bool allowThrows() const; + + private: + AssertionInfo m_assertionInfo; + AssertionResultData m_data; + struct ExprComponents { + ExprComponents() : testFalse( false ) {} + bool testFalse; + std::string lhs, rhs, op; + } m_exprComponents; + CopyableStream m_stream; + + bool m_shouldDebugBreak; + bool m_shouldThrow; + }; + +} // namespace Catch + +// Include after due to circular dependency: +// #included from: catch_expression_lhs.hpp +#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED + +// #included from: catch_evaluate.hpp +#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable:4389) // '==' : signed/unsigned mismatch +#endif + +#include <cstddef> + +namespace Catch { +namespace Internal { + + enum Operator { + IsEqualTo, + IsNotEqualTo, + IsLessThan, + IsGreaterThan, + IsLessThanOrEqualTo, + IsGreaterThanOrEqualTo + }; + + template<Operator Op> struct OperatorTraits { static const char* getName(){ return "*error*"; } }; + template<> struct OperatorTraits<IsEqualTo> { static const char* getName(){ return "=="; } }; + template<> struct OperatorTraits<IsNotEqualTo> { static const char* getName(){ return "!="; } }; + template<> struct OperatorTraits<IsLessThan> { static const char* getName(){ return "<"; } }; + template<> struct OperatorTraits<IsGreaterThan> { static const char* getName(){ return ">"; } }; + template<> struct OperatorTraits<IsLessThanOrEqualTo> { static const char* getName(){ return "<="; } }; + template<> struct OperatorTraits<IsGreaterThanOrEqualTo>{ static const char* getName(){ return ">="; } }; + + template<typename T> + inline T& opCast(T const& t) { return const_cast<T&>(t); } + +// nullptr_t support based on pull request #154 from Konstantin Baumann +#ifdef CATCH_CONFIG_CPP11_NULLPTR + inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; } +#endif // CATCH_CONFIG_CPP11_NULLPTR + + // So the compare overloads can be operator agnostic we convey the operator as a template + // enum, which is used to specialise an Evaluator for doing the comparison. + template<typename T1, typename T2, Operator Op> + class Evaluator{}; + + template<typename T1, typename T2> + struct Evaluator<T1, T2, IsEqualTo> { + static bool evaluate( T1 const& lhs, T2 const& rhs) { + return opCast( lhs ) == opCast( rhs ); + } + }; + template<typename T1, typename T2> + struct Evaluator<T1, T2, IsNotEqualTo> { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return opCast( lhs ) != opCast( rhs ); + } + }; + template<typename T1, typename T2> + struct Evaluator<T1, T2, IsLessThan> { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return opCast( lhs ) < opCast( rhs ); + } + }; + template<typename T1, typename T2> + struct Evaluator<T1, T2, IsGreaterThan> { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return opCast( lhs ) > opCast( rhs ); + } + }; + template<typename T1, typename T2> + struct Evaluator<T1, T2, IsGreaterThanOrEqualTo> { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return opCast( lhs ) >= opCast( rhs ); + } + }; + template<typename T1, typename T2> + struct Evaluator<T1, T2, IsLessThanOrEqualTo> { + static bool evaluate( T1 const& lhs, T2 const& rhs ) { + return opCast( lhs ) <= opCast( rhs ); + } + }; + + template<Operator Op, typename T1, typename T2> + bool applyEvaluator( T1 const& lhs, T2 const& rhs ) { + return Evaluator<T1, T2, Op>::evaluate( lhs, rhs ); + } + + // This level of indirection allows us to specialise for integer types + // to avoid signed/ unsigned warnings + + // "base" overload + template<Operator Op, typename T1, typename T2> + bool compare( T1 const& lhs, T2 const& rhs ) { + return Evaluator<T1, T2, Op>::evaluate( lhs, rhs ); + } + + // unsigned X to int + template<Operator Op> bool compare( unsigned int lhs, int rhs ) { + return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) ); + } + template<Operator Op> bool compare( unsigned long lhs, int rhs ) { + return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) ); + } + template<Operator Op> bool compare( unsigned char lhs, int rhs ) { + return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) ); + } + + // unsigned X to long + template<Operator Op> bool compare( unsigned int lhs, long rhs ) { + return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) ); + } + template<Operator Op> bool compare( unsigned long lhs, long rhs ) { + return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) ); + } + template<Operator Op> bool compare( unsigned char lhs, long rhs ) { + return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) ); + } + + // int to unsigned X + template<Operator Op> bool compare( int lhs, unsigned int rhs ) { + return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs ); + } + template<Operator Op> bool compare( int lhs, unsigned long rhs ) { + return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs ); + } + template<Operator Op> bool compare( int lhs, unsigned char rhs ) { + return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs ); + } + + // long to unsigned X + template<Operator Op> bool compare( long lhs, unsigned int rhs ) { + return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs ); + } + template<Operator Op> bool compare( long lhs, unsigned long rhs ) { + return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs ); + } + template<Operator Op> bool compare( long lhs, unsigned char rhs ) { + return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs ); + } + + // pointer to long (when comparing against NULL) + template<Operator Op, typename T> bool compare( long lhs, T* rhs ) { + return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs ); + } + template<Operator Op, typename T> bool compare( T* lhs, long rhs ) { + return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) ); + } + + // pointer to int (when comparing against NULL) + template<Operator Op, typename T> bool compare( int lhs, T* rhs ) { + return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs ); + } + template<Operator Op, typename T> bool compare( T* lhs, int rhs ) { + return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) ); + } + +#ifdef CATCH_CONFIG_CPP11_NULLPTR + // pointer to nullptr_t (when comparing against nullptr) + template<Operator Op, typename T> bool compare( std::nullptr_t, T* rhs ) { + return Evaluator<T*, T*, Op>::evaluate( NULL, rhs ); + } + template<Operator Op, typename T> bool compare( T* lhs, std::nullptr_t ) { + return Evaluator<T*, T*, Op>::evaluate( lhs, NULL ); + } +#endif // CATCH_CONFIG_CPP11_NULLPTR + +} // end of namespace Internal +} // end of namespace Catch + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +// #included from: catch_tostring.h +#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED + +// #included from: catch_sfinae.hpp +#define TWOBLUECUBES_CATCH_SFINAE_HPP_INCLUDED + +// Try to detect if the current compiler supports SFINAE + +namespace Catch { + + struct TrueType { + static const bool value = true; + typedef void Enable; + char sizer[1]; + }; + struct FalseType { + static const bool value = false; + typedef void Disable; + char sizer[2]; + }; + +#ifdef CATCH_CONFIG_SFINAE + + template<bool> struct NotABooleanExpression; + + template<bool c> struct If : NotABooleanExpression<c> {}; + template<> struct If<true> : TrueType {}; + template<> struct If<false> : FalseType {}; + + template<int size> struct SizedIf; + template<> struct SizedIf<sizeof(TrueType)> : TrueType {}; + template<> struct SizedIf<sizeof(FalseType)> : FalseType {}; + +#endif // CATCH_CONFIG_SFINAE + +} // end namespace Catch + +#include <sstream> +#include <iomanip> +#include <limits> +#include <vector> +#include <cstddef> + +#ifdef __OBJC__ +// #included from: catch_objc_arc.hpp +#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED + +#import <Foundation/Foundation.h> + +#ifdef __has_feature +#define CATCH_ARC_ENABLED __has_feature(objc_arc) +#else +#define CATCH_ARC_ENABLED 0 +#endif + +void arcSafeRelease( NSObject* obj ); +id performOptionalSelector( id obj, SEL sel ); + +#if !CATCH_ARC_ENABLED +inline void arcSafeRelease( NSObject* obj ) { + [obj release]; +} +inline id performOptionalSelector( id obj, SEL sel ) { + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; + return nil; +} +#define CATCH_UNSAFE_UNRETAINED +#define CATCH_ARC_STRONG +#else +inline void arcSafeRelease( NSObject* ){} +inline id performOptionalSelector( id obj, SEL sel ) { +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" +#endif + if( [obj respondsToSelector: sel] ) + return [obj performSelector: sel]; +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + return nil; +} +#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained +#define CATCH_ARC_STRONG __strong +#endif + +#endif + +#ifdef CATCH_CPP11_OR_GREATER +#include <tuple> +#include <type_traits> +#endif + +namespace Catch { + +// Why we're here. +template<typename T> +std::string toString( T const& value ); + +// Built in overloads + +std::string toString( std::string const& value ); +std::string toString( std::wstring const& value ); +std::string toString( const char* const value ); +std::string toString( char* const value ); +std::string toString( const wchar_t* const value ); +std::string toString( wchar_t* const value ); +std::string toString( int value ); +std::string toString( unsigned long value ); +std::string toString( unsigned int value ); +std::string toString( const double value ); +std::string toString( const float value ); +std::string toString( bool value ); +std::string toString( char value ); +std::string toString( signed char value ); +std::string toString( unsigned char value ); + +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ); +#endif + +#ifdef __OBJC__ + std::string toString( NSString const * const& nsstring ); + std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ); + std::string toString( NSObject* const& nsObject ); +#endif + +namespace Detail { + + extern std::string unprintableString; + +// SFINAE is currently disabled by default for all compilers. +// If the non SFINAE version of IsStreamInsertable is ambiguous for you +// and your compiler supports SFINAE, try #defining CATCH_CONFIG_SFINAE +#ifdef CATCH_CONFIG_SFINAE + + template<typename T> + class IsStreamInsertableHelper { + template<int N> struct TrueIfSizeable : TrueType {}; + + template<typename T2> + static TrueIfSizeable<sizeof((*(std::ostream*)0) << *((T2 const*)0))> dummy(T2*); + static FalseType dummy(...); + + public: + typedef SizedIf<sizeof(dummy((T*)0))> type; + }; + + template<typename T> + struct IsStreamInsertable : IsStreamInsertableHelper<T>::type {}; + +#else + + struct BorgType { + template<typename T> BorgType( T const& ); + }; + + TrueType& testStreamable( std::ostream& ); + FalseType testStreamable( FalseType ); + + FalseType operator<<( std::ostream const&, BorgType const& ); + + template<typename T> + struct IsStreamInsertable { + static std::ostream &s; + static T const&t; + enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; + }; + +#endif + +#if defined(CATCH_CPP11_OR_GREATER) + template<typename T, + bool IsEnum = std::is_enum<T>::value + > + struct EnumStringMaker + { + static std::string convert( T const& ) { return unprintableString; } + }; + + template<typename T> + struct EnumStringMaker<T,true> + { + static std::string convert( T const& v ) + { + return ::Catch::toString( + static_cast<typename std::underlying_type<T>::type>(v) + ); + } + }; +#endif + template<bool C> + struct StringMakerBase { +#if defined(CATCH_CPP11_OR_GREATER) + template<typename T> + static std::string convert( T const& v ) + { + return EnumStringMaker<T>::convert( v ); + } +#else + template<typename T> + static std::string convert( T const& ) { return unprintableString; } +#endif + }; + + template<> + struct StringMakerBase<true> { + template<typename T> + static std::string convert( T const& _value ) { + std::ostringstream oss; + oss << _value; + return oss.str(); + } + }; + + std::string rawMemoryToString( const void *object, std::size_t size ); + + template<typename T> + inline std::string rawMemoryToString( const T& object ) { + return rawMemoryToString( &object, sizeof(object) ); + } + +} // end namespace Detail + +template<typename T> +struct StringMaker : + Detail::StringMakerBase<Detail::IsStreamInsertable<T>::value> {}; + +template<typename T> +struct StringMaker<T*> { + template<typename U> + static std::string convert( U* p ) { + if( !p ) + return INTERNAL_CATCH_STRINGIFY( NULL ); + else + return Detail::rawMemoryToString( p ); + } +}; + +template<typename R, typename C> +struct StringMaker<R C::*> { + static std::string convert( R C::* p ) { + if( !p ) + return INTERNAL_CATCH_STRINGIFY( NULL ); + else + return Detail::rawMemoryToString( p ); + } +}; + +namespace Detail { + template<typename InputIterator> + std::string rangeToString( InputIterator first, InputIterator last ); +} + +//template<typename T, typename Allocator> +//struct StringMaker<std::vector<T, Allocator> > { +// static std::string convert( std::vector<T,Allocator> const& v ) { +// return Detail::rangeToString( v.begin(), v.end() ); +// } +//}; + +template<typename T, typename Allocator> +std::string toString( std::vector<T,Allocator> const& v ) { + return Detail::rangeToString( v.begin(), v.end() ); +} + +#ifdef CATCH_CPP11_OR_GREATER + +// toString for tuples +namespace TupleDetail { + template< + typename Tuple, + std::size_t N = 0, + bool = (N < std::tuple_size<Tuple>::value) + > + struct ElementPrinter { + static void print( const Tuple& tuple, std::ostream& os ) + { + os << ( N ? ", " : " " ) + << Catch::toString(std::get<N>(tuple)); + ElementPrinter<Tuple,N+1>::print(tuple,os); + } + }; + + template< + typename Tuple, + std::size_t N + > + struct ElementPrinter<Tuple,N,false> { + static void print( const Tuple&, std::ostream& ) {} + }; + +} + +template<typename ...Types> +struct StringMaker<std::tuple<Types...>> { + + static std::string convert( const std::tuple<Types...>& tuple ) + { + std::ostringstream os; + os << '{'; + TupleDetail::ElementPrinter<std::tuple<Types...>>::print( tuple, os ); + os << " }"; + return os.str(); + } +}; +#endif + +namespace Detail { + template<typename T> + std::string makeString( T const& value ) { + return StringMaker<T>::convert( value ); + } +} // end namespace Detail + +/// \brief converts any type to a string +/// +/// The default template forwards on to ostringstream - except when an +/// ostringstream overload does not exist - in which case it attempts to detect +/// that and writes {?}. +/// Overload (not specialise) this template for custom typs that you don't want +/// to provide an ostream overload for. +template<typename T> +std::string toString( T const& value ) { + return StringMaker<T>::convert( value ); +} + + namespace Detail { + template<typename InputIterator> + std::string rangeToString( InputIterator first, InputIterator last ) { + std::ostringstream oss; + oss << "{ "; + if( first != last ) { + oss << Catch::toString( *first ); + for( ++first ; first != last ; ++first ) + oss << ", " << Catch::toString( *first ); + } + oss << " }"; + return oss.str(); + } +} + +} // end namespace Catch + +namespace Catch { + +// Wraps the LHS of an expression and captures the operator and RHS (if any) - +// wrapping them all in a ResultBuilder object +template<typename T> +class ExpressionLhs { + ExpressionLhs& operator = ( ExpressionLhs const& ); +# ifdef CATCH_CPP11_OR_GREATER + ExpressionLhs& operator = ( ExpressionLhs && ) = delete; +# endif + +public: + ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {} +# ifdef CATCH_CPP11_OR_GREATER + ExpressionLhs( ExpressionLhs const& ) = default; + ExpressionLhs( ExpressionLhs && ) = default; +# endif + + template<typename RhsT> + ResultBuilder& operator == ( RhsT const& rhs ) { + return captureExpression<Internal::IsEqualTo>( rhs ); + } + + template<typename RhsT> + ResultBuilder& operator != ( RhsT const& rhs ) { + return captureExpression<Internal::IsNotEqualTo>( rhs ); + } + + template<typename RhsT> + ResultBuilder& operator < ( RhsT const& rhs ) { + return captureExpression<Internal::IsLessThan>( rhs ); + } + + template<typename RhsT> + ResultBuilder& operator > ( RhsT const& rhs ) { + return captureExpression<Internal::IsGreaterThan>( rhs ); + } + + template<typename RhsT> + ResultBuilder& operator <= ( RhsT const& rhs ) { + return captureExpression<Internal::IsLessThanOrEqualTo>( rhs ); + } + + template<typename RhsT> + ResultBuilder& operator >= ( RhsT const& rhs ) { + return captureExpression<Internal::IsGreaterThanOrEqualTo>( rhs ); + } + + ResultBuilder& operator == ( bool rhs ) { + return captureExpression<Internal::IsEqualTo>( rhs ); + } + + ResultBuilder& operator != ( bool rhs ) { + return captureExpression<Internal::IsNotEqualTo>( rhs ); + } + + void endExpression() { + bool value = m_lhs ? true : false; + m_rb + .setLhs( Catch::toString( value ) ) + .setResultType( value ) + .endExpression(); + } + + // Only simple binary expressions are allowed on the LHS. + // If more complex compositions are required then place the sub expression in parentheses + template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& ); + template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& ); + template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& ); + template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& ); + template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& ); + template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& ); + +private: + template<Internal::Operator Op, typename RhsT> + ResultBuilder& captureExpression( RhsT const& rhs ) { + return m_rb + .setResultType( Internal::compare<Op>( m_lhs, rhs ) ) + .setLhs( Catch::toString( m_lhs ) ) + .setRhs( Catch::toString( rhs ) ) + .setOp( Internal::OperatorTraits<Op>::getName() ); + } + +private: + ResultBuilder& m_rb; + T m_lhs; +}; + +} // end namespace Catch + + +namespace Catch { + + template<typename T> + inline ExpressionLhs<T const&> ResultBuilder::operator->* ( T const& operand ) { + return ExpressionLhs<T const&>( *this, operand ); + } + + inline ExpressionLhs<bool> ResultBuilder::operator->* ( bool value ) { + return ExpressionLhs<bool>( *this, value ); + } + +} // namespace Catch + +// #included from: catch_message.h +#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED + +#include <string> + +namespace Catch { + + struct MessageInfo { + MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ); + + std::string macroName; + SourceLineInfo lineInfo; + ResultWas::OfType type; + std::string message; + unsigned int sequence; + + bool operator == ( MessageInfo const& other ) const { + return sequence == other.sequence; + } + bool operator < ( MessageInfo const& other ) const { + return sequence < other.sequence; + } + private: + static unsigned int globalCount; + }; + + struct MessageBuilder { + MessageBuilder( std::string const& macroName, + SourceLineInfo const& lineInfo, + ResultWas::OfType type ) + : m_info( macroName, lineInfo, type ) + {} + + template<typename T> + MessageBuilder& operator << ( T const& value ) { + m_stream << value; + return *this; + } + + MessageInfo m_info; + std::ostringstream m_stream; + }; + + class ScopedMessage { + public: + ScopedMessage( MessageBuilder const& builder ); + ScopedMessage( ScopedMessage const& other ); + ~ScopedMessage(); + + MessageInfo m_info; + }; + +} // end namespace Catch + +// #included from: catch_interfaces_capture.h +#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED + +#include <string> + +namespace Catch { + + class TestCase; + class AssertionResult; + struct AssertionInfo; + struct SectionInfo; + struct MessageInfo; + class ScopedMessageBuilder; + struct Counts; + + struct IResultCapture { + + virtual ~IResultCapture(); + + virtual void assertionEnded( AssertionResult const& result ) = 0; + virtual bool sectionStarted( SectionInfo const& sectionInfo, + Counts& assertions ) = 0; + virtual void sectionEnded( SectionInfo const& name, Counts const& assertions, double _durationInSeconds ) = 0; + virtual void pushScopedMessage( MessageInfo const& message ) = 0; + virtual void popScopedMessage( MessageInfo const& message ) = 0; + + virtual std::string getCurrentTestName() const = 0; + virtual const AssertionResult* getLastResult() const = 0; + + virtual void handleFatalErrorCondition( std::string const& message ) = 0; + }; + + IResultCapture& getResultCapture(); +} + +// #included from: catch_debugger.h +#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED + +// #included from: catch_platform.h +#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED + +#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +#define CATCH_PLATFORM_MAC +#elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) +#define CATCH_PLATFORM_IPHONE +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) +#define CATCH_PLATFORM_WINDOWS +#endif + +#include <string> + +namespace Catch{ + + bool isDebuggerActive(); + void writeToDebugConsole( std::string const& text ); +} + +#ifdef CATCH_PLATFORM_MAC + + // The following code snippet based on: + // http://cocoawithlove.com/2008/03/break-into-debugger.html + #ifdef DEBUG + #if defined(__ppc64__) || defined(__ppc__) + #define CATCH_BREAK_INTO_DEBUGGER() \ + if( Catch::isDebuggerActive() ) { \ + __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \ + : : : "memory","r0","r3","r4" ); \ + } + #else + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );} + #endif + #endif + +#elif defined(_MSC_VER) + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { __debugbreak(); } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) void __stdcall DebugBreak(); + #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { DebugBreak(); } +#endif + +#ifndef CATCH_BREAK_INTO_DEBUGGER +#define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue(); +#endif + +// #included from: catch_interfaces_runner.h +#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED + +namespace Catch { + class TestCase; + + struct IRunner { + virtual ~IRunner(); + virtual bool aborting() const = 0; + }; +} + +/////////////////////////////////////////////////////////////////////////////// +// In the event of a failure works out if the debugger needs to be invoked +// and/or an exception thrown and takes appropriate action. +// This needs to be done as a macro so the debugger will stop in the user +// source code rather than in Catch library code +#define INTERNAL_CATCH_REACT( resultBuilder ) \ + if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \ + resultBuilder.react(); + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + try { \ + ( __catchResult->*expr ).endExpression(); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::isTrue( false && (expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \ + INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ + if( Catch::getResultCapture().getLastResult()->succeeded() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \ + INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \ + if( !Catch::getResultCapture().getLastResult()->succeeded() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( resultDisposition ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS( expr, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + if( __catchResult.allowThrows() ) \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( ... ) { \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + else \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + if( __catchResult.allowThrows() ) \ + try { \ + expr; \ + __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ + } \ + catch( exceptionType ) { \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + } \ + catch( ... ) { \ + __catchResult.useActiveException( resultDisposition ); \ + } \ + else \ + __catchResult.captureResult( Catch::ResultWas::Ok ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +/////////////////////////////////////////////////////////////////////////////// +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \ + __catchResult.captureResult( messageType ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#else + #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \ + __catchResult << log + ::Catch::StreamEndStop(); \ + __catchResult.captureResult( messageType ); \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) +#endif + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_INFO( log, macroName ) \ + Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log; + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \ + do { \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg " " #matcher, resultDisposition ); \ + try { \ + std::string matcherAsString = ::Catch::Matchers::matcher.toString(); \ + __catchResult \ + .setLhs( Catch::toString( arg ) ) \ + .setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \ + .setOp( "matches" ) \ + .setResultType( ::Catch::Matchers::matcher.match( arg ) ); \ + __catchResult.captureExpression(); \ + } catch( ... ) { \ + __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ + } \ + INTERNAL_CATCH_REACT( __catchResult ) \ + } while( Catch::alwaysFalse() ) + +// #included from: internal/catch_section.h +#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED + +// #included from: catch_section_info.h +#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED + +namespace Catch { + + struct SectionInfo { + SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description = std::string() ); + + std::string name; + std::string description; + SourceLineInfo lineInfo; + }; + +} // end namespace Catch + +// #included from: catch_totals.hpp +#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED + +#include <cstddef> + +namespace Catch { + + struct Counts { + Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {} + + Counts operator - ( Counts const& other ) const { + Counts diff; + diff.passed = passed - other.passed; + diff.failed = failed - other.failed; + diff.failedButOk = failedButOk - other.failedButOk; + return diff; + } + Counts& operator += ( Counts const& other ) { + passed += other.passed; + failed += other.failed; + failedButOk += other.failedButOk; + return *this; + } + + std::size_t total() const { + return passed + failed + failedButOk; + } + bool allPassed() const { + return failed == 0 && failedButOk == 0; + } + bool allOk() const { + return failed == 0; + } + + std::size_t passed; + std::size_t failed; + std::size_t failedButOk; + }; + + struct Totals { + + Totals operator - ( Totals const& other ) const { + Totals diff; + diff.assertions = assertions - other.assertions; + diff.testCases = testCases - other.testCases; + return diff; + } + + Totals delta( Totals const& prevTotals ) const { + Totals diff = *this - prevTotals; + if( diff.assertions.failed > 0 ) + ++diff.testCases.failed; + else if( diff.assertions.failedButOk > 0 ) + ++diff.testCases.failedButOk; + else + ++diff.testCases.passed; + return diff; + } + + Totals& operator += ( Totals const& other ) { + assertions += other.assertions; + testCases += other.testCases; + return *this; + } + + Counts assertions; + Counts testCases; + }; +} + +// #included from: catch_timer.h +#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED + +#ifdef CATCH_PLATFORM_WINDOWS +typedef unsigned long long uint64_t; +#else +#include <stdint.h> +#endif + +namespace Catch { + + class Timer { + public: + Timer() : m_ticks( 0 ) {} + void start(); + unsigned int getElapsedMicroseconds() const; + unsigned int getElapsedMilliseconds() const; + double getElapsedSeconds() const; + + private: + uint64_t m_ticks; + }; + +} // namespace Catch + +#include <string> + +namespace Catch { + + class Section : NonCopyable { + public: + Section( SectionInfo const& info ); + ~Section(); + + // This indicates whether the section should be executed or not + operator bool() const; + + private: + SectionInfo m_info; + + std::string m_name; + Counts m_assertions; + bool m_sectionIncluded; + Timer m_timer; + }; + +} // end namespace Catch + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define INTERNAL_CATCH_SECTION( ... ) \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) +#else + #define INTERNAL_CATCH_SECTION( name, desc ) \ + if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) ) +#endif + +// #included from: internal/catch_generators.hpp +#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED + +#include <iterator> +#include <vector> +#include <string> +#include <stdlib.h> + +namespace Catch { + +template<typename T> +struct IGenerator { + virtual ~IGenerator() {} + virtual T getValue( std::size_t index ) const = 0; + virtual std::size_t size () const = 0; +}; + +template<typename T> +class BetweenGenerator : public IGenerator<T> { +public: + BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){} + + virtual T getValue( std::size_t index ) const { + return m_from+static_cast<int>( index ); + } + + virtual std::size_t size() const { + return static_cast<std::size_t>( 1+m_to-m_from ); + } + +private: + + T m_from; + T m_to; +}; + +template<typename T> +class ValuesGenerator : public IGenerator<T> { +public: + ValuesGenerator(){} + + void add( T value ) { + m_values.push_back( value ); + } + + virtual T getValue( std::size_t index ) const { + return m_values[index]; + } + + virtual std::size_t size() const { + return m_values.size(); + } + +private: + std::vector<T> m_values; +}; + +template<typename T> +class CompositeGenerator { +public: + CompositeGenerator() : m_totalSize( 0 ) {} + + // *** Move semantics, similar to auto_ptr *** + CompositeGenerator( CompositeGenerator& other ) + : m_fileInfo( other.m_fileInfo ), + m_totalSize( 0 ) + { + move( other ); + } + + CompositeGenerator& setFileInfo( const char* fileInfo ) { + m_fileInfo = fileInfo; + return *this; + } + + ~CompositeGenerator() { + deleteAll( m_composed ); + } + + operator T () const { + size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize ); + + typename std::vector<const IGenerator<T>*>::const_iterator it = m_composed.begin(); + typename std::vector<const IGenerator<T>*>::const_iterator itEnd = m_composed.end(); + for( size_t index = 0; it != itEnd; ++it ) + { + const IGenerator<T>* generator = *it; + if( overallIndex >= index && overallIndex < index + generator->size() ) + { + return generator->getValue( overallIndex-index ); + } + index += generator->size(); + } + CATCH_INTERNAL_ERROR( "Indexed past end of generated range" ); + return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so + } + + void add( const IGenerator<T>* generator ) { + m_totalSize += generator->size(); + m_composed.push_back( generator ); + } + + CompositeGenerator& then( CompositeGenerator& other ) { + move( other ); + return *this; + } + + CompositeGenerator& then( T value ) { + ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); + valuesGen->add( value ); + add( valuesGen ); + return *this; + } + +private: + + void move( CompositeGenerator& other ) { + std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) ); + m_totalSize += other.m_totalSize; + other.m_composed.clear(); + } + + std::vector<const IGenerator<T>*> m_composed; + std::string m_fileInfo; + size_t m_totalSize; +}; + +namespace Generators +{ + template<typename T> + CompositeGenerator<T> between( T from, T to ) { + CompositeGenerator<T> generators; + generators.add( new BetweenGenerator<T>( from, to ) ); + return generators; + } + + template<typename T> + CompositeGenerator<T> values( T val1, T val2 ) { + CompositeGenerator<T> generators; + ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + generators.add( valuesGen ); + return generators; + } + + template<typename T> + CompositeGenerator<T> values( T val1, T val2, T val3 ){ + CompositeGenerator<T> generators; + ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + valuesGen->add( val3 ); + generators.add( valuesGen ); + return generators; + } + + template<typename T> + CompositeGenerator<T> values( T val1, T val2, T val3, T val4 ) { + CompositeGenerator<T> generators; + ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>(); + valuesGen->add( val1 ); + valuesGen->add( val2 ); + valuesGen->add( val3 ); + valuesGen->add( val4 ); + generators.add( valuesGen ); + return generators; + } + +} // end namespace Generators + +using namespace Generators; + +} // end namespace Catch + +#define INTERNAL_CATCH_LINESTR2( line ) #line +#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line ) + +#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" ) + +// #included from: internal/catch_interfaces_exception.h +#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED + +#include <string> +// #included from: catch_interfaces_registry_hub.h +#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED + +#include <string> + +namespace Catch { + + class TestCase; + struct ITestCaseRegistry; + struct IExceptionTranslatorRegistry; + struct IExceptionTranslator; + struct IReporterRegistry; + struct IReporterFactory; + + struct IRegistryHub { + virtual ~IRegistryHub(); + + virtual IReporterRegistry const& getReporterRegistry() const = 0; + virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0; + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0; + }; + + struct IMutableRegistryHub { + virtual ~IMutableRegistryHub(); + virtual void registerReporter( std::string const& name, IReporterFactory* factory ) = 0; + virtual void registerTest( TestCase const& testInfo ) = 0; + virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; + }; + + IRegistryHub& getRegistryHub(); + IMutableRegistryHub& getMutableRegistryHub(); + void cleanUp(); + std::string translateActiveException(); + +} + + +namespace Catch { + + typedef std::string(*exceptionTranslateFunction)(); + + struct IExceptionTranslator { + virtual ~IExceptionTranslator(); + virtual std::string translate() const = 0; + }; + + struct IExceptionTranslatorRegistry { + virtual ~IExceptionTranslatorRegistry(); + + virtual std::string translateActiveException() const = 0; + }; + + class ExceptionTranslatorRegistrar { + template<typename T> + class ExceptionTranslator : public IExceptionTranslator { + public: + + ExceptionTranslator( std::string(*translateFunction)( T& ) ) + : m_translateFunction( translateFunction ) + {} + + virtual std::string translate() const { + try { + throw; + } + catch( T& ex ) { + return m_translateFunction( ex ); + } + } + + protected: + std::string(*m_translateFunction)( T& ); + }; + + public: + template<typename T> + ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) { + getMutableRegistryHub().registerTranslator + ( new ExceptionTranslator<T>( translateFunction ) ); + } + }; +} + +/////////////////////////////////////////////////////////////////////////////// +#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \ + static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \ + namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\ + static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ) + +// #included from: internal/catch_approx.hpp +#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED + +#include <cmath> +#include <limits> + +namespace Catch { +namespace Detail { + + class Approx { + public: + explicit Approx ( double value ) + : m_epsilon( std::numeric_limits<float>::epsilon()*100 ), + m_scale( 1.0 ), + m_value( value ) + {} + + Approx( Approx const& other ) + : m_epsilon( other.m_epsilon ), + m_scale( other.m_scale ), + m_value( other.m_value ) + {} + + static Approx custom() { + return Approx( 0 ); + } + + Approx operator()( double value ) { + Approx approx( value ); + approx.epsilon( m_epsilon ); + approx.scale( m_scale ); + return approx; + } + + friend bool operator == ( double lhs, Approx const& rhs ) { + // Thanks to Richard Harris for his help refining this formula + return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) ); + } + + friend bool operator == ( Approx const& lhs, double rhs ) { + return operator==( rhs, lhs ); + } + + friend bool operator != ( double lhs, Approx const& rhs ) { + return !operator==( lhs, rhs ); + } + + friend bool operator != ( Approx const& lhs, double rhs ) { + return !operator==( rhs, lhs ); + } + + Approx& epsilon( double newEpsilon ) { + m_epsilon = newEpsilon; + return *this; + } + + Approx& scale( double newScale ) { + m_scale = newScale; + return *this; + } + + std::string toString() const { + std::ostringstream oss; + oss << "Approx( " << Catch::toString( m_value ) << " )"; + return oss.str(); + } + + private: + double m_epsilon; + double m_scale; + double m_value; + }; +} + +template<> +inline std::string toString<Detail::Approx>( Detail::Approx const& value ) { + return value.toString(); +} + +} // end namespace Catch + +// #included from: internal/catch_matchers.hpp +#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED + +namespace Catch { +namespace Matchers { + namespace Impl { + + template<typename ExpressionT> + struct Matcher : SharedImpl<IShared> + { + typedef ExpressionT ExpressionType; + + virtual ~Matcher() {} + virtual Ptr<Matcher> clone() const = 0; + virtual bool match( ExpressionT const& expr ) const = 0; + virtual std::string toString() const = 0; + }; + + template<typename DerivedT, typename ExpressionT> + struct MatcherImpl : Matcher<ExpressionT> { + + virtual Ptr<Matcher<ExpressionT> > clone() const { + return Ptr<Matcher<ExpressionT> >( new DerivedT( static_cast<DerivedT const&>( *this ) ) ); + } + }; + + namespace Generic { + + template<typename ExpressionT> + class AllOf : public MatcherImpl<AllOf<ExpressionT>, ExpressionT> { + public: + + AllOf() {} + AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {} + + AllOf& add( Matcher<ExpressionT> const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( !m_matchers[i]->match( expr ) ) + return false; + return true; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " and "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + private: + std::vector<Ptr<Matcher<ExpressionT> > > m_matchers; + }; + + template<typename ExpressionT> + class AnyOf : public MatcherImpl<AnyOf<ExpressionT>, ExpressionT> { + public: + + AnyOf() {} + AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {} + + AnyOf& add( Matcher<ExpressionT> const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( m_matchers[i]->match( expr ) ) + return true; + return false; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " or "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + private: + std::vector<Ptr<Matcher<ExpressionT> > > m_matchers; + }; + + } + + namespace StdString { + + inline std::string makeString( std::string const& str ) { return str; } + inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } + + struct Equals : MatcherImpl<Equals, std::string> { + Equals( std::string const& str ) : m_str( str ){} + Equals( Equals const& other ) : m_str( other.m_str ){} + + virtual ~Equals(); + + virtual bool match( std::string const& expr ) const { + return m_str == expr; + } + virtual std::string toString() const { + return "equals: \"" + m_str + "\""; + } + + std::string m_str; + }; + + struct Contains : MatcherImpl<Contains, std::string> { + Contains( std::string const& substr ) : m_substr( substr ){} + Contains( Contains const& other ) : m_substr( other.m_substr ){} + + virtual ~Contains(); + + virtual bool match( std::string const& expr ) const { + return expr.find( m_substr ) != std::string::npos; + } + virtual std::string toString() const { + return "contains: \"" + m_substr + "\""; + } + + std::string m_substr; + }; + + struct StartsWith : MatcherImpl<StartsWith, std::string> { + StartsWith( std::string const& substr ) : m_substr( substr ){} + StartsWith( StartsWith const& other ) : m_substr( other.m_substr ){} + + virtual ~StartsWith(); + + virtual bool match( std::string const& expr ) const { + return expr.find( m_substr ) == 0; + } + virtual std::string toString() const { + return "starts with: \"" + m_substr + "\""; + } + + std::string m_substr; + }; + + struct EndsWith : MatcherImpl<EndsWith, std::string> { + EndsWith( std::string const& substr ) : m_substr( substr ){} + EndsWith( EndsWith const& other ) : m_substr( other.m_substr ){} + + virtual ~EndsWith(); + + virtual bool match( std::string const& expr ) const { + return expr.find( m_substr ) == expr.size() - m_substr.size(); + } + virtual std::string toString() const { + return "ends with: \"" + m_substr + "\""; + } + + std::string m_substr; + }; + } // namespace StdString + } // namespace Impl + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + template<typename ExpressionT> + inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1, + Impl::Matcher<ExpressionT> const& m2 ) { + return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 ); + } + template<typename ExpressionT> + inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1, + Impl::Matcher<ExpressionT> const& m2, + Impl::Matcher<ExpressionT> const& m3 ) { + return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 ); + } + template<typename ExpressionT> + inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1, + Impl::Matcher<ExpressionT> const& m2 ) { + return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 ); + } + template<typename ExpressionT> + inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1, + Impl::Matcher<ExpressionT> const& m2, + Impl::Matcher<ExpressionT> const& m3 ) { + return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 ); + } + + inline Impl::StdString::Equals Equals( std::string const& str ) { + return Impl::StdString::Equals( str ); + } + inline Impl::StdString::Equals Equals( const char* str ) { + return Impl::StdString::Equals( Impl::StdString::makeString( str ) ); + } + inline Impl::StdString::Contains Contains( std::string const& substr ) { + return Impl::StdString::Contains( substr ); + } + inline Impl::StdString::Contains Contains( const char* substr ) { + return Impl::StdString::Contains( Impl::StdString::makeString( substr ) ); + } + inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { + return Impl::StdString::StartsWith( substr ); + } + inline Impl::StdString::StartsWith StartsWith( const char* substr ) { + return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) ); + } + inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) { + return Impl::StdString::EndsWith( substr ); + } + inline Impl::StdString::EndsWith EndsWith( const char* substr ) { + return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) ); + } + +} // namespace Matchers + +using namespace Matchers; + +} // namespace Catch + +// #included from: internal/catch_interfaces_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED + +// #included from: catch_tag_alias.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED + +#include <string> + +namespace Catch { + + struct TagAlias { + TagAlias( std::string _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {} + + std::string tag; + SourceLineInfo lineInfo; + }; + + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + }; + +} // end namespace Catch + +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } +// #included from: catch_option.hpp +#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED + +namespace Catch { + + // An optional type + template<typename T> + class Option { + public: + Option() : nullableValue( NULL ) {} + Option( T const& _value ) + : nullableValue( new( storage ) T( _value ) ) + {} + Option( Option const& _other ) + : nullableValue( _other ? new( storage ) T( *_other ) : NULL ) + {} + + ~Option() { + reset(); + } + + Option& operator= ( Option const& _other ) { + if( &_other != this ) { + reset(); + if( _other ) + nullableValue = new( storage ) T( *_other ); + } + return *this; + } + Option& operator = ( T const& _value ) { + reset(); + nullableValue = new( storage ) T( _value ); + return *this; + } + + void reset() { + if( nullableValue ) + nullableValue->~T(); + nullableValue = NULL; + } + + T& operator*() { return *nullableValue; } + T const& operator*() const { return *nullableValue; } + T* operator->() { return nullableValue; } + const T* operator->() const { return nullableValue; } + + T valueOr( T const& defaultValue ) const { + return nullableValue ? *nullableValue : defaultValue; + } + + bool some() const { return nullableValue != NULL; } + bool none() const { return nullableValue == NULL; } + + bool operator !() const { return nullableValue == NULL; } + operator SafeBool::type() const { + return SafeBool::makeSafe( some() ); + } + + private: + T* nullableValue; + char storage[sizeof(T)]; + }; + +} // end namespace Catch + +namespace Catch { + + struct ITagAliasRegistry { + virtual ~ITagAliasRegistry(); + virtual Option<TagAlias> find( std::string const& alias ) const = 0; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0; + + static ITagAliasRegistry const& get(); + }; + +} // end namespace Catch + +// These files are included here so the single_include script doesn't put them +// in the conditionally compiled sections +// #included from: internal/catch_test_case_info.h +#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED + +#include <string> +#include <set> + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + struct ITestCase; + + struct TestCaseInfo { + enum SpecialProperties{ + None = 0, + IsHidden = 1 << 1, + ShouldFail = 1 << 2, + MayFail = 1 << 3, + Throws = 1 << 4 + }; + + TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::set<std::string> const& _tags, + SourceLineInfo const& _lineInfo ); + + TestCaseInfo( TestCaseInfo const& other ); + + bool isHidden() const; + bool throws() const; + bool okToFail() const; + bool expectedToFail() const; + + std::string name; + std::string className; + std::string description; + std::set<std::string> tags; + std::set<std::string> lcaseTags; + std::string tagsAsString; + SourceLineInfo lineInfo; + SpecialProperties properties; + }; + + class TestCase : public TestCaseInfo { + public: + + TestCase( ITestCase* testCase, TestCaseInfo const& info ); + TestCase( TestCase const& other ); + + TestCase withName( std::string const& _newName ) const; + + void invoke() const; + + TestCaseInfo const& getTestCaseInfo() const; + + void swap( TestCase& other ); + bool operator == ( TestCase const& other ) const; + bool operator < ( TestCase const& other ) const; + TestCase& operator = ( TestCase const& other ); + + private: + Ptr<ITestCase> test; + }; + + TestCase makeTestCase( ITestCase* testCase, + std::string const& className, + std::string const& name, + std::string const& description, + SourceLineInfo const& lineInfo ); +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + + +#ifdef __OBJC__ +// #included from: internal/catch_objc.hpp +#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED + +#import <objc/runtime.h> + +#include <string> + +// NB. Any general catch headers included here must be included +// in catch.hpp first to make sure they are included by the single +// header for non obj-usage + +/////////////////////////////////////////////////////////////////////////////// +// This protocol is really only here for (self) documenting purposes, since +// all its methods are optional. +@protocol OcFixture + +@optional + +-(void) setUp; +-(void) tearDown; + +@end + +namespace Catch { + + class OcMethod : public SharedImpl<ITestCase> { + + public: + OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {} + + virtual void invoke() const { + id obj = [[m_cls alloc] init]; + + performOptionalSelector( obj, @selector(setUp) ); + performOptionalSelector( obj, m_sel ); + performOptionalSelector( obj, @selector(tearDown) ); + + arcSafeRelease( obj ); + } + private: + virtual ~OcMethod() {} + + Class m_cls; + SEL m_sel; + }; + + namespace Detail{ + + inline std::string getAnnotation( Class cls, + std::string const& annotationName, + std::string const& testCaseName ) { + NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()]; + SEL sel = NSSelectorFromString( selStr ); + arcSafeRelease( selStr ); + id value = performOptionalSelector( cls, sel ); + if( value ) + return [(NSString*)value UTF8String]; + return ""; + } + } + + inline size_t registerTestMethods() { + size_t noTestMethods = 0; + int noClasses = objc_getClassList( NULL, 0 ); + + Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); + objc_getClassList( classes, noClasses ); + + for( int c = 0; c < noClasses; c++ ) { + Class cls = classes[c]; + { + u_int count; + Method* methods = class_copyMethodList( cls, &count ); + for( u_int m = 0; m < count ; m++ ) { + SEL selector = method_getName(methods[m]); + std::string methodName = sel_getName(selector); + if( startsWith( methodName, "Catch_TestCase_" ) ) { + std::string testCaseName = methodName.substr( 15 ); + std::string name = Detail::getAnnotation( cls, "Name", testCaseName ); + std::string desc = Detail::getAnnotation( cls, "Description", testCaseName ); + const char* className = class_getName( cls ); + + getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) ); + noTestMethods++; + } + } + free(methods); + } + } + return noTestMethods; + } + + namespace Matchers { + namespace Impl { + namespace NSStringMatchers { + + template<typename MatcherT> + struct StringHolder : MatcherImpl<MatcherT, NSString*>{ + StringHolder( NSString* substr ) : m_substr( [substr copy] ){} + StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){} + StringHolder() { + arcSafeRelease( m_substr ); + } + + NSString* m_substr; + }; + + struct Equals : StringHolder<Equals> { + Equals( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str isEqualToString:m_substr]; + } + + virtual std::string toString() const { + return "equals string: " + Catch::toString( m_substr ); + } + }; + + struct Contains : StringHolder<Contains> { + Contains( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location != NSNotFound; + } + + virtual std::string toString() const { + return "contains string: " + Catch::toString( m_substr ); + } + }; + + struct StartsWith : StringHolder<StartsWith> { + StartsWith( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == 0; + } + + virtual std::string toString() const { + return "starts with: " + Catch::toString( m_substr ); + } + }; + struct EndsWith : StringHolder<EndsWith> { + EndsWith( NSString* substr ) : StringHolder( substr ){} + + virtual bool match( ExpressionType const& str ) const { + return (str != nil || m_substr == nil ) && + [str rangeOfString:m_substr].location == [str length] - [m_substr length]; + } + + virtual std::string toString() const { + return "ends with: " + Catch::toString( m_substr ); + } + }; + + } // namespace NSStringMatchers + } // namespace Impl + + inline Impl::NSStringMatchers::Equals + Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); } + + inline Impl::NSStringMatchers::Contains + Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); } + + inline Impl::NSStringMatchers::StartsWith + StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); } + + inline Impl::NSStringMatchers::EndsWith + EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); } + + } // namespace Matchers + + using namespace Matchers; + +} // namespace Catch + +/////////////////////////////////////////////////////////////////////////////// +#define OC_TEST_CASE( name, desc )\ ++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \ +{\ +return @ name; \ +}\ ++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \ +{ \ +return @ desc; \ +} \ +-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test ) + +#endif + +#ifdef CATCH_IMPL +// #included from: internal/catch_impl.hpp +#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED + +// Collect all the implementation files together here +// These are the equivalent of what would usually be cpp files + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wweak-vtables" +#endif + +// #included from: ../catch_runner.hpp +#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED + +// #included from: internal/catch_commandline.hpp +#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED + +// #included from: catch_config.hpp +#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED + +// #included from: catch_test_spec_parser.hpp +#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +// #included from: catch_test_spec.hpp +#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpadded" +#endif + +#include <string> +#include <vector> + +namespace Catch { + + class TestSpec { + struct Pattern : SharedImpl<> { + virtual ~Pattern(); + virtual bool matches( TestCaseInfo const& testCase ) const = 0; + }; + class NamePattern : public Pattern { + enum WildcardPosition { + NoWildcard = 0, + WildcardAtStart = 1, + WildcardAtEnd = 2, + WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd + }; + + public: + NamePattern( std::string const& name ) : m_name( toLower( name ) ), m_wildcard( NoWildcard ) { + if( startsWith( m_name, "*" ) ) { + m_name = m_name.substr( 1 ); + m_wildcard = WildcardAtStart; + } + if( endsWith( m_name, "*" ) ) { + m_name = m_name.substr( 0, m_name.size()-1 ); + m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd ); + } + } + virtual ~NamePattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { + switch( m_wildcard ) { + case NoWildcard: + return m_name == toLower( testCase.name ); + case WildcardAtStart: + return endsWith( toLower( testCase.name ), m_name ); + case WildcardAtEnd: + return startsWith( toLower( testCase.name ), m_name ); + case WildcardAtBothEnds: + return contains( toLower( testCase.name ), m_name ); + } + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code" +#endif + throw std::logic_error( "Unknown enum" ); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + } + private: + std::string m_name; + WildcardPosition m_wildcard; + }; + class TagPattern : public Pattern { + public: + TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} + virtual ~TagPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { + return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end(); + } + private: + std::string m_tag; + }; + class ExcludedPattern : public Pattern { + public: + ExcludedPattern( Ptr<Pattern> const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} + virtual ~ExcludedPattern(); + virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); } + private: + Ptr<Pattern> m_underlyingPattern; + }; + + struct Filter { + std::vector<Ptr<Pattern> > m_patterns; + + bool matches( TestCaseInfo const& testCase ) const { + // All patterns in a filter must match for the filter to be a match + for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it ) + if( !(*it)->matches( testCase ) ) + return false; + return true; + } + }; + + public: + bool hasFilters() const { + return !m_filters.empty(); + } + bool matches( TestCaseInfo const& testCase ) const { + // A TestSpec matches if any filter matches + for( std::vector<Filter>::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it ) + if( it->matches( testCase ) ) + return true; + return false; + } + + private: + std::vector<Filter> m_filters; + + friend class TestSpecParser; + }; +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +namespace Catch { + + class TestSpecParser { + enum Mode{ None, Name, QuotedName, Tag }; + Mode m_mode; + bool m_exclusion; + std::size_t m_start, m_pos; + std::string m_arg; + TestSpec::Filter m_currentFilter; + TestSpec m_testSpec; + ITagAliasRegistry const* m_tagAliases; + + public: + TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {} + + TestSpecParser& parse( std::string const& arg ) { + m_mode = None; + m_exclusion = false; + m_start = std::string::npos; + m_arg = m_tagAliases->expandAliases( arg ); + for( m_pos = 0; m_pos < m_arg.size(); ++m_pos ) + visitChar( m_arg[m_pos] ); + if( m_mode == Name ) + addPattern<TestSpec::NamePattern>(); + return *this; + } + TestSpec testSpec() { + addFilter(); + return m_testSpec; + } + private: + void visitChar( char c ) { + if( m_mode == None ) { + switch( c ) { + case ' ': return; + case '~': m_exclusion = true; return; + case '[': return startNewMode( Tag, ++m_pos ); + case '"': return startNewMode( QuotedName, ++m_pos ); + default: startNewMode( Name, m_pos ); break; + } + } + if( m_mode == Name ) { + if( c == ',' ) { + addPattern<TestSpec::NamePattern>(); + addFilter(); + } + else if( c == '[' ) { + if( subString() == "exclude:" ) + m_exclusion = true; + else + addPattern<TestSpec::NamePattern>(); + startNewMode( Tag, ++m_pos ); + } + } + else if( m_mode == QuotedName && c == '"' ) + addPattern<TestSpec::NamePattern>(); + else if( m_mode == Tag && c == ']' ) + addPattern<TestSpec::TagPattern>(); + } + void startNewMode( Mode mode, std::size_t start ) { + m_mode = mode; + m_start = start; + } + std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); } + template<typename T> + void addPattern() { + std::string token = subString(); + if( startsWith( token, "exclude:" ) ) { + m_exclusion = true; + token = token.substr( 8 ); + } + if( !token.empty() ) { + Ptr<TestSpec::Pattern> pattern = new T( token ); + if( m_exclusion ) + pattern = new TestSpec::ExcludedPattern( pattern ); + m_currentFilter.m_patterns.push_back( pattern ); + } + m_exclusion = false; + m_mode = None; + } + void addFilter() { + if( !m_currentFilter.m_patterns.empty() ) { + m_testSpec.m_filters.push_back( m_currentFilter ); + m_currentFilter = TestSpec::Filter(); + } + } + }; + inline TestSpec parseTestSpec( std::string const& arg ) { + return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec(); + } + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +// #included from: catch_interfaces_config.h +#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED + +#include <iostream> +#include <string> +#include <vector> + +namespace Catch { + + struct Verbosity { enum Level { + NoOutput = 0, + Quiet, + Normal + }; }; + + struct WarnAbout { enum What { + Nothing = 0x00, + NoAssertions = 0x01 + }; }; + + struct ShowDurations { enum OrNot { + DefaultForReporter, + Always, + Never + }; }; + struct RunTests { enum InWhatOrder { + InDeclarationOrder, + InLexicographicalOrder, + InRandomOrder + }; }; + + class TestSpec; + + struct IConfig : IShared { + + virtual ~IConfig(); + + virtual bool allowThrows() const = 0; + virtual std::ostream& stream() const = 0; + virtual std::string name() const = 0; + virtual bool includeSuccessfulResults() const = 0; + virtual bool shouldDebugBreak() const = 0; + virtual bool warnAboutMissingAssertions() const = 0; + virtual int abortAfter() const = 0; + virtual bool showInvisibles() const = 0; + virtual ShowDurations::OrNot showDurations() const = 0; + virtual TestSpec const& testSpec() const = 0; + virtual RunTests::InWhatOrder runOrder() const = 0; + virtual unsigned int rngSeed() const = 0; + virtual bool forceColour() const = 0; + }; +} + +// #included from: catch_stream.h +#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED + +#include <streambuf> + +#ifdef __clang__ +#pragma clang diagnostic ignored "-Wpadded" +#endif + +namespace Catch { + + class Stream { + public: + Stream(); + Stream( std::streambuf* _streamBuf, bool _isOwned ); + void release(); + + std::streambuf* streamBuf; + + private: + bool isOwned; + }; + + std::ostream& cout(); + std::ostream& cerr(); +} + +#include <memory> +#include <vector> +#include <string> +#include <iostream> +#include <ctime> + +#ifndef CATCH_CONFIG_CONSOLE_WIDTH +#define CATCH_CONFIG_CONSOLE_WIDTH 80 +#endif + +namespace Catch { + + struct ConfigData { + + ConfigData() + : listTests( false ), + listTags( false ), + listReporters( false ), + listTestNamesOnly( false ), + showSuccessfulTests( false ), + shouldDebugBreak( false ), + noThrow( false ), + showHelp( false ), + showInvisibles( false ), + forceColour( false ), + abortAfter( -1 ), + rngSeed( 0 ), + verbosity( Verbosity::Normal ), + warnings( WarnAbout::Nothing ), + showDurations( ShowDurations::DefaultForReporter ), + runOrder( RunTests::InDeclarationOrder ) + {} + + bool listTests; + bool listTags; + bool listReporters; + bool listTestNamesOnly; + + bool showSuccessfulTests; + bool shouldDebugBreak; + bool noThrow; + bool showHelp; + bool showInvisibles; + bool forceColour; + + int abortAfter; + unsigned int rngSeed; + + Verbosity::Level verbosity; + WarnAbout::What warnings; + ShowDurations::OrNot showDurations; + RunTests::InWhatOrder runOrder; + + std::string reporterName; + std::string outputFilename; + std::string name; + std::string processName; + + std::vector<std::string> testsOrTags; + }; + + class Config : public SharedImpl<IConfig> { + private: + Config( Config const& other ); + Config& operator = ( Config const& other ); + virtual void dummy(); + public: + + Config() + : m_os( Catch::cout().rdbuf() ) + {} + + Config( ConfigData const& data ) + : m_data( data ), + m_os( Catch::cout().rdbuf() ) + { + if( !data.testsOrTags.empty() ) { + TestSpecParser parser( ITagAliasRegistry::get() ); + for( std::size_t i = 0; i < data.testsOrTags.size(); ++i ) + parser.parse( data.testsOrTags[i] ); + m_testSpec = parser.testSpec(); + } + } + + virtual ~Config() { + m_os.rdbuf( Catch::cout().rdbuf() ); + m_stream.release(); + } + + void setFilename( std::string const& filename ) { + m_data.outputFilename = filename; + } + + std::string const& getFilename() const { + return m_data.outputFilename ; + } + + bool listTests() const { return m_data.listTests; } + bool listTestNamesOnly() const { return m_data.listTestNamesOnly; } + bool listTags() const { return m_data.listTags; } + bool listReporters() const { return m_data.listReporters; } + + std::string getProcessName() const { return m_data.processName; } + + bool shouldDebugBreak() const { return m_data.shouldDebugBreak; } + + void setStreamBuf( std::streambuf* buf ) { + m_os.rdbuf( buf ? buf : Catch::cout().rdbuf() ); + } + + void useStream( std::string const& streamName ) { + Stream stream = createStream( streamName ); + setStreamBuf( stream.streamBuf ); + m_stream.release(); + m_stream = stream; + } + + std::string getReporterName() const { return m_data.reporterName; } + + int abortAfter() const { return m_data.abortAfter; } + + TestSpec const& testSpec() const { return m_testSpec; } + + bool showHelp() const { return m_data.showHelp; } + bool showInvisibles() const { return m_data.showInvisibles; } + + // IConfig interface + virtual bool allowThrows() const { return !m_data.noThrow; } + virtual std::ostream& stream() const { return m_os; } + virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } + virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; } + virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } + virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; } + virtual RunTests::InWhatOrder runOrder() const { return m_data.runOrder; } + virtual unsigned int rngSeed() const { return m_data.rngSeed; } + virtual bool forceColour() const { return m_data.forceColour; } + + private: + ConfigData m_data; + + Stream m_stream; + mutable std::ostream m_os; + TestSpec m_testSpec; + }; + +} // end namespace Catch + +// #included from: catch_clara.h +#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED + +// Use Catch's value for console width (store Clara's off to the side, if present) +#ifdef CLARA_CONFIG_CONSOLE_WIDTH +#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH +#undef CLARA_CONFIG_CONSOLE_WIDTH +#endif +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +// Declare Clara inside the Catch namespace +#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch { +// #included from: ../external/clara.h + +// Only use header guard if we are not using an outer namespace +#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE) + +#ifndef STITCH_CLARA_OPEN_NAMESPACE +#define TWOBLUECUBES_CLARA_H_INCLUDED +#define STITCH_CLARA_OPEN_NAMESPACE +#define STITCH_CLARA_CLOSE_NAMESPACE +#else +#define STITCH_CLARA_CLOSE_NAMESPACE } +#endif + +#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE + +// ----------- #included from tbc_text_format.h ----------- + +// Only use header guard if we are not using an outer namespace +#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE) +#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +#define TBC_TEXT_FORMAT_H_INCLUDED +#endif + +#include <string> +#include <vector> +#include <sstream> + +// Use optional outer namespace +#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector<std::string>::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector<std::string> lines; + }; + +} // end namespace Tbc + +#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TBC_TEXT_FORMAT_H_INCLUDED + +// ----------- end of #include from tbc_text_format.h ----------- +// ........... back in /Users/philnash/Dev/OSS/Clara/srcs/clara.h + +#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE + +#include <map> +#include <algorithm> +#include <stdexcept> +#include <memory> + +// Use optional outer namespace +#ifdef STITCH_CLARA_OPEN_NAMESPACE +STITCH_CLARA_OPEN_NAMESPACE +#endif + +namespace Clara { + + struct UnpositionalTag {}; + + extern UnpositionalTag _; + +#ifdef CLARA_CONFIG_MAIN + UnpositionalTag _; +#endif + + namespace Detail { + +#ifdef CLARA_CONSOLE_WIDTH + const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + using namespace Tbc; + + inline bool startsWith( std::string const& str, std::string const& prefix ) { + return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix; + } + + template<typename T> struct RemoveConstRef{ typedef T type; }; + template<typename T> struct RemoveConstRef<T&>{ typedef T type; }; + template<typename T> struct RemoveConstRef<T const&>{ typedef T type; }; + template<typename T> struct RemoveConstRef<T const>{ typedef T type; }; + + template<typename T> struct IsBool { static const bool value = false; }; + template<> struct IsBool<bool> { static const bool value = true; }; + + template<typename T> + void convertInto( std::string const& _source, T& _dest ) { + std::stringstream ss; + ss << _source; + ss >> _dest; + if( ss.fail() ) + throw std::runtime_error( "Unable to convert " + _source + " to destination type" ); + } + inline void convertInto( std::string const& _source, std::string& _dest ) { + _dest = _source; + } + inline void convertInto( std::string const& _source, bool& _dest ) { + std::string sourceLC = _source; + std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower ); + if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" ) + _dest = true; + else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" ) + _dest = false; + else + throw std::runtime_error( "Expected a boolean value but did not recognise:\n '" + _source + "'" ); + } + inline void convertInto( bool _source, bool& _dest ) { + _dest = _source; + } + template<typename T> + inline void convertInto( bool, T& ) { + throw std::runtime_error( "Invalid conversion" ); + } + + template<typename ConfigT> + struct IArgFunction { + virtual ~IArgFunction() {} +# ifdef CATCH_CPP11_OR_GREATER + IArgFunction() = default; + IArgFunction( IArgFunction const& ) = default; +# endif + virtual void set( ConfigT& config, std::string const& value ) const = 0; + virtual void setFlag( ConfigT& config ) const = 0; + virtual bool takesArg() const = 0; + virtual IArgFunction* clone() const = 0; + }; + + template<typename ConfigT> + class BoundArgFunction { + public: + BoundArgFunction() : functionObj( NULL ) {} + BoundArgFunction( IArgFunction<ConfigT>* _functionObj ) : functionObj( _functionObj ) {} + BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : NULL ) {} + BoundArgFunction& operator = ( BoundArgFunction const& other ) { + IArgFunction<ConfigT>* newFunctionObj = other.functionObj ? other.functionObj->clone() : NULL; + delete functionObj; + functionObj = newFunctionObj; + return *this; + } + ~BoundArgFunction() { delete functionObj; } + + void set( ConfigT& config, std::string const& value ) const { + functionObj->set( config, value ); + } + void setFlag( ConfigT& config ) const { + functionObj->setFlag( config ); + } + bool takesArg() const { return functionObj->takesArg(); } + + bool isSet() const { + return functionObj != NULL; + } + private: + IArgFunction<ConfigT>* functionObj; + }; + + template<typename C> + struct NullBinder : IArgFunction<C>{ + virtual void set( C&, std::string const& ) const {} + virtual void setFlag( C& ) const {} + virtual bool takesArg() const { return true; } + virtual IArgFunction<C>* clone() const { return new NullBinder( *this ); } + }; + + template<typename C, typename M> + struct BoundDataMember : IArgFunction<C>{ + BoundDataMember( M C::* _member ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + convertInto( stringValue, p.*member ); + } + virtual void setFlag( C& p ) const { + convertInto( true, p.*member ); + } + virtual bool takesArg() const { return !IsBool<M>::value; } + virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); } + M C::* member; + }; + template<typename C, typename M> + struct BoundUnaryMethod : IArgFunction<C>{ + BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + typename RemoveConstRef<M>::type value; + convertInto( stringValue, value ); + (p.*member)( value ); + } + virtual void setFlag( C& p ) const { + typename RemoveConstRef<M>::type value; + convertInto( true, value ); + (p.*member)( value ); + } + virtual bool takesArg() const { return !IsBool<M>::value; } + virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); } + void (C::*member)( M ); + }; + template<typename C> + struct BoundNullaryMethod : IArgFunction<C>{ + BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {} + virtual void set( C& p, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + (p.*member)(); + } + virtual void setFlag( C& p ) const { + (p.*member)(); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); } + void (C::*member)(); + }; + + template<typename C> + struct BoundUnaryFunction : IArgFunction<C>{ + BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + bool value; + convertInto( stringValue, value ); + if( value ) + function( obj ); + } + virtual void setFlag( C& p ) const { + function( p ); + } + virtual bool takesArg() const { return false; } + virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); } + void (*function)( C& ); + }; + + template<typename C, typename T> + struct BoundBinaryFunction : IArgFunction<C>{ + BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {} + virtual void set( C& obj, std::string const& stringValue ) const { + typename RemoveConstRef<T>::type value; + convertInto( stringValue, value ); + function( obj, value ); + } + virtual void setFlag( C& obj ) const { + typename RemoveConstRef<T>::type value; + convertInto( true, value ); + function( obj, value ); + } + virtual bool takesArg() const { return !IsBool<T>::value; } + virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); } + void (*function)( C&, T ); + }; + + } // namespace Detail + + struct Parser { + Parser() : separators( " \t=:" ) {} + + struct Token { + enum Type { Positional, ShortOpt, LongOpt }; + Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {} + Type type; + std::string data; + }; + + void parseIntoTokens( int argc, char const * const * argv, std::vector<Parser::Token>& tokens ) const { + const std::string doubleDash = "--"; + for( int i = 1; i < argc && argv[i] != doubleDash; ++i ) + parseIntoTokens( argv[i] , tokens); + } + void parseIntoTokens( std::string arg, std::vector<Parser::Token>& tokens ) const { + while( !arg.empty() ) { + Parser::Token token( Parser::Token::Positional, arg ); + arg = ""; + if( token.data[0] == '-' ) { + if( token.data.size() > 1 && token.data[1] == '-' ) { + token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) ); + } + else { + token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) ); + if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) { + arg = "-" + token.data.substr( 1 ); + token.data = token.data.substr( 0, 1 ); + } + } + } + if( token.type != Parser::Token::Positional ) { + std::size_t pos = token.data.find_first_of( separators ); + if( pos != std::string::npos ) { + arg = token.data.substr( pos+1 ); + token.data = token.data.substr( 0, pos ); + } + } + tokens.push_back( token ); + } + } + std::string separators; + }; + + template<typename ConfigT> + struct CommonArgProperties { + CommonArgProperties() {} + CommonArgProperties( Detail::BoundArgFunction<ConfigT> const& _boundField ) : boundField( _boundField ) {} + + Detail::BoundArgFunction<ConfigT> boundField; + std::string description; + std::string detail; + std::string placeholder; // Only value if boundField takes an arg + + bool takesArg() const { + return !placeholder.empty(); + } + void validate() const { + if( !boundField.isSet() ) + throw std::logic_error( "option not bound" ); + } + }; + struct OptionArgProperties { + std::vector<std::string> shortNames; + std::string longName; + + bool hasShortName( std::string const& shortName ) const { + return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end(); + } + bool hasLongName( std::string const& _longName ) const { + return _longName == longName; + } + }; + struct PositionalArgProperties { + PositionalArgProperties() : position( -1 ) {} + int position; // -1 means non-positional (floating) + + bool isFixedPositional() const { + return position != -1; + } + }; + + template<typename ConfigT> + class CommandLine { + + struct Arg : CommonArgProperties<ConfigT>, OptionArgProperties, PositionalArgProperties { + Arg() {} + Arg( Detail::BoundArgFunction<ConfigT> const& _boundField ) : CommonArgProperties<ConfigT>( _boundField ) {} + + using CommonArgProperties<ConfigT>::placeholder; // !TBD + + std::string dbgName() const { + if( !longName.empty() ) + return "--" + longName; + if( !shortNames.empty() ) + return "-" + shortNames[0]; + return "positional args"; + } + std::string commands() const { + std::ostringstream oss; + bool first = true; + std::vector<std::string>::const_iterator it = shortNames.begin(), itEnd = shortNames.end(); + for(; it != itEnd; ++it ) { + if( first ) + first = false; + else + oss << ", "; + oss << "-" << *it; + } + if( !longName.empty() ) { + if( !first ) + oss << ", "; + oss << "--" << longName; + } + if( !placeholder.empty() ) + oss << " <" << placeholder << ">"; + return oss.str(); + } + }; + + // NOTE: std::auto_ptr is deprecated in c++11/c++0x +#if defined(__cplusplus) && __cplusplus > 199711L + typedef std::unique_ptr<Arg> ArgAutoPtr; +#else + typedef std::auto_ptr<Arg> ArgAutoPtr; +#endif + + friend void addOptName( Arg& arg, std::string const& optName ) + { + if( optName.empty() ) + return; + if( Detail::startsWith( optName, "--" ) ) { + if( !arg.longName.empty() ) + throw std::logic_error( "Only one long opt may be specified. '" + + arg.longName + + "' already specified, now attempting to add '" + + optName + "'" ); + arg.longName = optName.substr( 2 ); + } + else if( Detail::startsWith( optName, "-" ) ) + arg.shortNames.push_back( optName.substr( 1 ) ); + else + throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" ); + } + friend void setPositionalArg( Arg& arg, int position ) + { + arg.position = position; + } + + class ArgBuilder { + public: + ArgBuilder( Arg* arg ) : m_arg( arg ) {} + + // Bind a non-boolean data member (requires placeholder string) + template<typename C, typename M> + void bind( M C::* field, std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundDataMember<C,M>( field ); + m_arg->placeholder = placeholder; + } + // Bind a boolean data member (no placeholder required) + template<typename C> + void bind( bool C::* field ) { + m_arg->boundField = new Detail::BoundDataMember<C,bool>( field ); + } + + // Bind a method taking a single, non-boolean argument (requires a placeholder string) + template<typename C, typename M> + void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundUnaryMethod<C,M>( unaryMethod ); + m_arg->placeholder = placeholder; + } + + // Bind a method taking a single, boolean argument (no placeholder string required) + template<typename C> + void bind( void (C::* unaryMethod)( bool ) ) { + m_arg->boundField = new Detail::BoundUnaryMethod<C,bool>( unaryMethod ); + } + + // Bind a method that takes no arguments (will be called if opt is present) + template<typename C> + void bind( void (C::* nullaryMethod)() ) { + m_arg->boundField = new Detail::BoundNullaryMethod<C>( nullaryMethod ); + } + + // Bind a free function taking a single argument - the object to operate on (no placeholder string required) + template<typename C> + void bind( void (* unaryFunction)( C& ) ) { + m_arg->boundField = new Detail::BoundUnaryFunction<C>( unaryFunction ); + } + + // Bind a free function taking a single argument - the object to operate on (requires a placeholder string) + template<typename C, typename T> + void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) { + m_arg->boundField = new Detail::BoundBinaryFunction<C, T>( binaryFunction ); + m_arg->placeholder = placeholder; + } + + ArgBuilder& describe( std::string const& description ) { + m_arg->description = description; + return *this; + } + ArgBuilder& detail( std::string const& detail ) { + m_arg->detail = detail; + return *this; + } + + protected: + Arg* m_arg; + }; + + class OptBuilder : public ArgBuilder { + public: + OptBuilder( Arg* arg ) : ArgBuilder( arg ) {} + OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {} + + OptBuilder& operator[]( std::string const& optName ) { + addOptName( *ArgBuilder::m_arg, optName ); + return *this; + } + }; + + public: + + CommandLine() + : m_boundProcessName( new Detail::NullBinder<ConfigT>() ), + m_highestSpecifiedArgPosition( 0 ), + m_throwOnUnrecognisedTokens( false ) + {} + CommandLine( CommandLine const& other ) + : m_boundProcessName( other.m_boundProcessName ), + m_options ( other.m_options ), + m_positionalArgs( other.m_positionalArgs ), + m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ), + m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens ) + { + if( other.m_floatingArg.get() ) + m_floatingArg.reset( new Arg( *other.m_floatingArg ) ); + } + + CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) { + m_throwOnUnrecognisedTokens = shouldThrow; + return *this; + } + + OptBuilder operator[]( std::string const& optName ) { + m_options.push_back( Arg() ); + addOptName( m_options.back(), optName ); + OptBuilder builder( &m_options.back() ); + return builder; + } + + ArgBuilder operator[]( int position ) { + m_positionalArgs.insert( std::make_pair( position, Arg() ) ); + if( position > m_highestSpecifiedArgPosition ) + m_highestSpecifiedArgPosition = position; + setPositionalArg( m_positionalArgs[position], position ); + ArgBuilder builder( &m_positionalArgs[position] ); + return builder; + } + + // Invoke this with the _ instance + ArgBuilder operator[]( UnpositionalTag ) { + if( m_floatingArg.get() ) + throw std::logic_error( "Only one unpositional argument can be added" ); + m_floatingArg.reset( new Arg() ); + ArgBuilder builder( m_floatingArg.get() ); + return builder; + } + + template<typename C, typename M> + void bindProcessName( M C::* field ) { + m_boundProcessName = new Detail::BoundDataMember<C,M>( field ); + } + template<typename C, typename M> + void bindProcessName( void (C::*_unaryMethod)( M ) ) { + m_boundProcessName = new Detail::BoundUnaryMethod<C,M>( _unaryMethod ); + } + + void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const { + typename std::vector<Arg>::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it; + std::size_t maxWidth = 0; + for( it = itBegin; it != itEnd; ++it ) + maxWidth = (std::max)( maxWidth, it->commands().size() ); + + for( it = itBegin; it != itEnd; ++it ) { + Detail::Text usage( it->commands(), Detail::TextAttributes() + .setWidth( maxWidth+indent ) + .setIndent( indent ) ); + Detail::Text desc( it->description, Detail::TextAttributes() + .setWidth( width - maxWidth - 3 ) ); + + for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { + std::string usageCol = i < usage.size() ? usage[i] : ""; + os << usageCol; + + if( i < desc.size() && !desc[i].empty() ) + os << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' ) + << desc[i]; + os << "\n"; + } + } + } + std::string optUsage() const { + std::ostringstream oss; + optUsage( oss ); + return oss.str(); + } + + void argSynopsis( std::ostream& os ) const { + for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) { + if( i > 1 ) + os << " "; + typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( i ); + if( it != m_positionalArgs.end() ) + os << "<" << it->second.placeholder << ">"; + else if( m_floatingArg.get() ) + os << "<" << m_floatingArg->placeholder << ">"; + else + throw std::logic_error( "non consecutive positional arguments with no floating args" ); + } + // !TBD No indication of mandatory args + if( m_floatingArg.get() ) { + if( m_highestSpecifiedArgPosition > 1 ) + os << " "; + os << "[<" << m_floatingArg->placeholder << "> ...]"; + } + } + std::string argSynopsis() const { + std::ostringstream oss; + argSynopsis( oss ); + return oss.str(); + } + + void usage( std::ostream& os, std::string const& procName ) const { + validate(); + os << "usage:\n " << procName << " "; + argSynopsis( os ); + if( !m_options.empty() ) { + os << " [options]\n\nwhere options are: \n"; + optUsage( os, 2 ); + } + os << "\n"; + } + std::string usage( std::string const& procName ) const { + std::ostringstream oss; + usage( oss, procName ); + return oss.str(); + } + + ConfigT parse( int argc, char const * const * argv ) const { + ConfigT config; + parseInto( argc, argv, config ); + return config; + } + + std::vector<Parser::Token> parseInto( int argc, char const * const * argv, ConfigT& config ) const { + std::string processName = argv[0]; + std::size_t lastSlash = processName.find_last_of( "/\\" ); + if( lastSlash != std::string::npos ) + processName = processName.substr( lastSlash+1 ); + m_boundProcessName.set( config, processName ); + std::vector<Parser::Token> tokens; + Parser parser; + parser.parseIntoTokens( argc, argv, tokens ); + return populate( tokens, config ); + } + + std::vector<Parser::Token> populate( std::vector<Parser::Token> const& tokens, ConfigT& config ) const { + validate(); + std::vector<Parser::Token> unusedTokens = populateOptions( tokens, config ); + unusedTokens = populateFixedArgs( unusedTokens, config ); + unusedTokens = populateFloatingArgs( unusedTokens, config ); + return unusedTokens; + } + + std::vector<Parser::Token> populateOptions( std::vector<Parser::Token> const& tokens, ConfigT& config ) const { + std::vector<Parser::Token> unusedTokens; + std::vector<std::string> errors; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::vector<Arg>::const_iterator it = m_options.begin(), itEnd = m_options.end(); + for(; it != itEnd; ++it ) { + Arg const& arg = *it; + + try { + if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) || + ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) { + if( arg.takesArg() ) { + if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional ) + errors.push_back( "Expected argument to option: " + token.data ); + else + arg.boundField.set( config, tokens[++i].data ); + } + else { + arg.boundField.setFlag( config ); + } + break; + } + } + catch( std::exception& ex ) { + errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" ); + } + } + if( it == itEnd ) { + if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens ) + unusedTokens.push_back( token ); + else if( errors.empty() && m_throwOnUnrecognisedTokens ) + errors.push_back( "unrecognised option: " + token.data ); + } + } + if( !errors.empty() ) { + std::ostringstream oss; + for( std::vector<std::string>::const_iterator it = errors.begin(), itEnd = errors.end(); + it != itEnd; + ++it ) { + if( it != errors.begin() ) + oss << "\n"; + oss << *it; + } + throw std::runtime_error( oss.str() ); + } + return unusedTokens; + } + std::vector<Parser::Token> populateFixedArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const { + std::vector<Parser::Token> unusedTokens; + int position = 1; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( position ); + if( it != m_positionalArgs.end() ) + it->second.boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + if( token.type == Parser::Token::Positional ) + position++; + } + return unusedTokens; + } + std::vector<Parser::Token> populateFloatingArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const { + if( !m_floatingArg.get() ) + return tokens; + std::vector<Parser::Token> unusedTokens; + for( std::size_t i = 0; i < tokens.size(); ++i ) { + Parser::Token const& token = tokens[i]; + if( token.type == Parser::Token::Positional ) + m_floatingArg->boundField.set( config, token.data ); + else + unusedTokens.push_back( token ); + } + return unusedTokens; + } + + void validate() const + { + if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() ) + throw std::logic_error( "No options or arguments specified" ); + + for( typename std::vector<Arg>::const_iterator it = m_options.begin(), + itEnd = m_options.end(); + it != itEnd; ++it ) + it->validate(); + } + + private: + Detail::BoundArgFunction<ConfigT> m_boundProcessName; + std::vector<Arg> m_options; + std::map<int, Arg> m_positionalArgs; + ArgAutoPtr m_floatingArg; + int m_highestSpecifiedArgPosition; + bool m_throwOnUnrecognisedTokens; + }; + +} // end namespace Clara + +STITCH_CLARA_CLOSE_NAMESPACE +#undef STITCH_CLARA_OPEN_NAMESPACE +#undef STITCH_CLARA_CLOSE_NAMESPACE + +#endif // TWOBLUECUBES_CLARA_H_INCLUDED +#undef STITCH_CLARA_OPEN_NAMESPACE + +// Restore Clara's value for console width, if present +#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH +#endif + +#include <fstream> + +namespace Catch { + + inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; } + inline void abortAfterX( ConfigData& config, int x ) { + if( x < 1 ) + throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" ); + config.abortAfter = x; + } + inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } + + inline void addWarning( ConfigData& config, std::string const& _warning ) { + if( _warning == "NoAssertions" ) + config.warnings = static_cast<WarnAbout::What>( config.warnings | WarnAbout::NoAssertions ); + else + throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" ); + } + inline void setOrder( ConfigData& config, std::string const& order ) { + if( startsWith( "declared", order ) ) + config.runOrder = RunTests::InDeclarationOrder; + else if( startsWith( "lexical", order ) ) + config.runOrder = RunTests::InLexicographicalOrder; + else if( startsWith( "random", order ) ) + config.runOrder = RunTests::InRandomOrder; + else + throw std::runtime_error( "Unrecognised ordering: '" + order + "'" ); + } + inline void setRngSeed( ConfigData& config, std::string const& seed ) { + if( seed == "time" ) { + config.rngSeed = static_cast<unsigned int>( std::time(0) ); + } + else { + std::stringstream ss; + ss << seed; + ss >> config.rngSeed; + if( ss.fail() ) + throw std::runtime_error( "Argment to --rng-seed should be the word 'time' or a number" ); + } + } + inline void setVerbosity( ConfigData& config, int level ) { + // !TBD: accept strings? + config.verbosity = static_cast<Verbosity::Level>( level ); + } + inline void setShowDurations( ConfigData& config, bool _showDurations ) { + config.showDurations = _showDurations + ? ShowDurations::Always + : ShowDurations::Never; + } + inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) { + std::ifstream f( _filename.c_str() ); + if( !f.is_open() ) + throw std::domain_error( "Unable to load input file: " + _filename ); + + std::string line; + while( std::getline( f, line ) ) { + line = trim(line); + if( !line.empty() && !startsWith( line, "#" ) ) + addTestOrTags( config, "\"" + line + "\"," ); + } + } + + inline Clara::CommandLine<ConfigData> makeCommandLineParser() { + + using namespace Clara; + CommandLine<ConfigData> cli; + + cli.bindProcessName( &ConfigData::processName ); + + cli["-?"]["-h"]["--help"] + .describe( "display usage information" ) + .bind( &ConfigData::showHelp ); + + cli["-l"]["--list-tests"] + .describe( "list all/matching test cases" ) + .bind( &ConfigData::listTests ); + + cli["-t"]["--list-tags"] + .describe( "list all/matching tags" ) + .bind( &ConfigData::listTags ); + + cli["-s"]["--success"] + .describe( "include successful tests in output" ) + .bind( &ConfigData::showSuccessfulTests ); + + cli["-b"]["--break"] + .describe( "break into debugger on failure" ) + .bind( &ConfigData::shouldDebugBreak ); + + cli["-e"]["--nothrow"] + .describe( "skip exception tests" ) + .bind( &ConfigData::noThrow ); + + cli["-i"]["--invisibles"] + .describe( "show invisibles (tabs, newlines)" ) + .bind( &ConfigData::showInvisibles ); + + cli["-o"]["--out"] + .describe( "output filename" ) + .bind( &ConfigData::outputFilename, "filename" ); + + cli["-r"]["--reporter"] +// .placeholder( "name[:filename]" ) + .describe( "reporter to use (defaults to console)" ) + .bind( &ConfigData::reporterName, "name" ); + + cli["-n"]["--name"] + .describe( "suite name" ) + .bind( &ConfigData::name, "name" ); + + cli["-a"]["--abort"] + .describe( "abort at first failure" ) + .bind( &abortAfterFirst ); + + cli["-x"]["--abortx"] + .describe( "abort after x failures" ) + .bind( &abortAfterX, "no. failures" ); + + cli["-w"]["--warn"] + .describe( "enable warnings" ) + .bind( &addWarning, "warning name" ); + +// - needs updating if reinstated +// cli.into( &setVerbosity ) +// .describe( "level of verbosity (0=no output)" ) +// .shortOpt( "v") +// .longOpt( "verbosity" ) +// .placeholder( "level" ); + + cli[_] + .describe( "which test or tests to use" ) + .bind( &addTestOrTags, "test name, pattern or tags" ); + + cli["-d"]["--durations"] + .describe( "show test durations" ) + .bind( &setShowDurations, "yes/no" ); + + cli["-f"]["--input-file"] + .describe( "load test names to run from a file" ) + .bind( &loadTestNamesFromFile, "filename" ); + + // Less common commands which don't have a short form + cli["--list-test-names-only"] + .describe( "list all/matching test cases names only" ) + .bind( &ConfigData::listTestNamesOnly ); + + cli["--list-reporters"] + .describe( "list all reporters" ) + .bind( &ConfigData::listReporters ); + + cli["--order"] + .describe( "test case order (defaults to decl)" ) + .bind( &setOrder, "decl|lex|rand" ); + + cli["--rng-seed"] + .describe( "set a specific seed for random numbers" ) + .bind( &setRngSeed, "'time'|number" ); + + cli["--force-colour"] + .describe( "force colourised output" ) + .bind( &ConfigData::forceColour ); + + return cli; + } + +} // end namespace Catch + +// #included from: internal/catch_list.hpp +#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED + +// #included from: catch_text.h +#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED + +#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH + +#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch +// #included from: ../external/tbc_text_format.h +// Only use header guard if we are not using an outer namespace +#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +# endif +# else +# define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED +# endif +#endif +#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#include <string> +#include <vector> +#include <sstream> + +// Use optional outer namespace +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE { +#endif + +namespace Tbc { + +#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH + const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH; +#else + const unsigned int consoleWidth = 80; +#endif + + struct TextAttributes { + TextAttributes() + : initialIndent( std::string::npos ), + indent( 0 ), + width( consoleWidth-1 ), + tabChar( '\t' ) + {} + + TextAttributes& setInitialIndent( std::size_t _value ) { initialIndent = _value; return *this; } + TextAttributes& setIndent( std::size_t _value ) { indent = _value; return *this; } + TextAttributes& setWidth( std::size_t _value ) { width = _value; return *this; } + TextAttributes& setTabChar( char _value ) { tabChar = _value; return *this; } + + std::size_t initialIndent; // indent of first line, or npos + std::size_t indent; // indent of subsequent lines, or all if initialIndent is npos + std::size_t width; // maximum width of text, including indent. Longer text will wrap + char tabChar; // If this char is seen the indent is changed to current pos + }; + + class Text { + public: + Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() ) + : attr( _attr ) + { + std::string wrappableChars = " [({.,/|\\-"; + std::size_t indent = _attr.initialIndent != std::string::npos + ? _attr.initialIndent + : _attr.indent; + std::string remainder = _str; + + while( !remainder.empty() ) { + if( lines.size() >= 1000 ) { + lines.push_back( "... message truncated due to excessive size" ); + return; + } + std::size_t tabPos = std::string::npos; + std::size_t width = (std::min)( remainder.size(), _attr.width - indent ); + std::size_t pos = remainder.find_first_of( '\n' ); + if( pos <= width ) { + width = pos; + } + pos = remainder.find_last_of( _attr.tabChar, width ); + if( pos != std::string::npos ) { + tabPos = pos; + if( remainder[width] == '\n' ) + width--; + remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 ); + } + + if( width == remainder.size() ) { + spliceLine( indent, remainder, width ); + } + else if( remainder[width] == '\n' ) { + spliceLine( indent, remainder, width ); + if( width <= 1 || remainder.size() != 1 ) + remainder = remainder.substr( 1 ); + indent = _attr.indent; + } + else { + pos = remainder.find_last_of( wrappableChars, width ); + if( pos != std::string::npos && pos > 0 ) { + spliceLine( indent, remainder, pos ); + if( remainder[0] == ' ' ) + remainder = remainder.substr( 1 ); + } + else { + spliceLine( indent, remainder, width-1 ); + lines.back() += "-"; + } + if( lines.size() == 1 ) + indent = _attr.indent; + if( tabPos != std::string::npos ) + indent += tabPos; + } + } + } + + void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) { + lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) ); + _remainder = _remainder.substr( _pos ); + } + + typedef std::vector<std::string>::const_iterator const_iterator; + + const_iterator begin() const { return lines.begin(); } + const_iterator end() const { return lines.end(); } + std::string const& last() const { return lines.back(); } + std::size_t size() const { return lines.size(); } + std::string const& operator[]( std::size_t _index ) const { return lines[_index]; } + std::string toString() const { + std::ostringstream oss; + oss << *this; + return oss.str(); + } + + inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) { + for( Text::const_iterator it = _text.begin(), itEnd = _text.end(); + it != itEnd; ++it ) { + if( it != _text.begin() ) + _stream << "\n"; + _stream << *it; + } + return _stream; + } + + private: + std::string str; + TextAttributes attr; + std::vector<std::string> lines; + }; + +} // end namespace Tbc + +#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE +} // end outer namespace +#endif + +#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED +#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE + +namespace Catch { + using Tbc::Text; + using Tbc::TextAttributes; +} + +// #included from: catch_console_colour.hpp +#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED + +namespace Catch { + + struct Colour { + enum Code { + None = 0, + + White, + Red, + Green, + Blue, + Cyan, + Yellow, + Grey, + + Bright = 0x10, + + BrightRed = Bright | Red, + BrightGreen = Bright | Green, + LightGrey = Bright | Grey, + BrightWhite = Bright | White, + + // By intention + FileName = Grey, + Warning = Yellow, + ResultError = BrightRed, + ResultSuccess = BrightGreen, + ResultExpectedFailure = Warning, + + Error = BrightRed, + Success = Green, + + OriginalExpression = Cyan, + ReconstructedExpression = Blue, + + SecondaryText = Grey, + Headers = White + }; + + // Use constructed object for RAII guard + Colour( Code _colourCode ); + Colour( Colour const& other ); + ~Colour(); + + // Use static method for one-shot changes + static void use( Code _colourCode ); + + private: + bool m_moved; + }; + + inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; } + +} // end namespace Catch + +// #included from: catch_interfaces_reporter.h +#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED + +#include <string> +#include <ostream> +#include <map> +#include <assert.h> + +namespace Catch +{ + struct ReporterConfig { + explicit ReporterConfig( Ptr<IConfig> const& _fullConfig ) + : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} + + ReporterConfig( Ptr<IConfig> const& _fullConfig, std::ostream& _stream ) + : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} + + std::ostream& stream() const { return *m_stream; } + Ptr<IConfig> fullConfig() const { return m_fullConfig; } + + private: + std::ostream* m_stream; + Ptr<IConfig> m_fullConfig; + }; + + struct ReporterPreferences { + ReporterPreferences() + : shouldRedirectStdOut( false ) + {} + + bool shouldRedirectStdOut; + }; + + template<typename T> + struct LazyStat : Option<T> { + LazyStat() : used( false ) {} + LazyStat& operator=( T const& _value ) { + Option<T>::operator=( _value ); + used = false; + return *this; + } + void reset() { + Option<T>::reset(); + used = false; + } + bool used; + }; + + struct TestRunInfo { + TestRunInfo( std::string const& _name ) : name( _name ) {} + std::string name; + }; + struct GroupInfo { + GroupInfo( std::string const& _name, + std::size_t _groupIndex, + std::size_t _groupsCount ) + : name( _name ), + groupIndex( _groupIndex ), + groupsCounts( _groupsCount ) + {} + + std::string name; + std::size_t groupIndex; + std::size_t groupsCounts; + }; + + struct AssertionStats { + AssertionStats( AssertionResult const& _assertionResult, + std::vector<MessageInfo> const& _infoMessages, + Totals const& _totals ) + : assertionResult( _assertionResult ), + infoMessages( _infoMessages ), + totals( _totals ) + { + if( assertionResult.hasMessage() ) { + // Copy message into messages list. + // !TBD This should have been done earlier, somewhere + MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() ); + builder << assertionResult.getMessage(); + builder.m_info.message = builder.m_stream.str(); + + infoMessages.push_back( builder.m_info ); + } + } + virtual ~AssertionStats(); + +# ifdef CATCH_CPP11_OR_GREATER + AssertionStats( AssertionStats const& ) = default; + AssertionStats( AssertionStats && ) = default; + AssertionStats& operator = ( AssertionStats const& ) = default; + AssertionStats& operator = ( AssertionStats && ) = default; +# endif + + AssertionResult assertionResult; + std::vector<MessageInfo> infoMessages; + Totals totals; + }; + + struct SectionStats { + SectionStats( SectionInfo const& _sectionInfo, + Counts const& _assertions, + double _durationInSeconds, + bool _missingAssertions ) + : sectionInfo( _sectionInfo ), + assertions( _assertions ), + durationInSeconds( _durationInSeconds ), + missingAssertions( _missingAssertions ) + {} + virtual ~SectionStats(); +# ifdef CATCH_CPP11_OR_GREATER + SectionStats( SectionStats const& ) = default; + SectionStats( SectionStats && ) = default; + SectionStats& operator = ( SectionStats const& ) = default; + SectionStats& operator = ( SectionStats && ) = default; +# endif + + SectionInfo sectionInfo; + Counts assertions; + double durationInSeconds; + bool missingAssertions; + }; + + struct TestCaseStats { + TestCaseStats( TestCaseInfo const& _testInfo, + Totals const& _totals, + std::string const& _stdOut, + std::string const& _stdErr, + bool _aborting ) + : testInfo( _testInfo ), + totals( _totals ), + stdOut( _stdOut ), + stdErr( _stdErr ), + aborting( _aborting ) + {} + virtual ~TestCaseStats(); + +# ifdef CATCH_CPP11_OR_GREATER + TestCaseStats( TestCaseStats const& ) = default; + TestCaseStats( TestCaseStats && ) = default; + TestCaseStats& operator = ( TestCaseStats const& ) = default; + TestCaseStats& operator = ( TestCaseStats && ) = default; +# endif + + TestCaseInfo testInfo; + Totals totals; + std::string stdOut; + std::string stdErr; + bool aborting; + }; + + struct TestGroupStats { + TestGroupStats( GroupInfo const& _groupInfo, + Totals const& _totals, + bool _aborting ) + : groupInfo( _groupInfo ), + totals( _totals ), + aborting( _aborting ) + {} + TestGroupStats( GroupInfo const& _groupInfo ) + : groupInfo( _groupInfo ), + aborting( false ) + {} + virtual ~TestGroupStats(); + +# ifdef CATCH_CPP11_OR_GREATER + TestGroupStats( TestGroupStats const& ) = default; + TestGroupStats( TestGroupStats && ) = default; + TestGroupStats& operator = ( TestGroupStats const& ) = default; + TestGroupStats& operator = ( TestGroupStats && ) = default; +# endif + + GroupInfo groupInfo; + Totals totals; + bool aborting; + }; + + struct TestRunStats { + TestRunStats( TestRunInfo const& _runInfo, + Totals const& _totals, + bool _aborting ) + : runInfo( _runInfo ), + totals( _totals ), + aborting( _aborting ) + {} + virtual ~TestRunStats(); + +# ifndef CATCH_CPP11_OR_GREATER + TestRunStats( TestRunStats const& _other ) + : runInfo( _other.runInfo ), + totals( _other.totals ), + aborting( _other.aborting ) + {} +# else + TestRunStats( TestRunStats const& ) = default; + TestRunStats( TestRunStats && ) = default; + TestRunStats& operator = ( TestRunStats const& ) = default; + TestRunStats& operator = ( TestRunStats && ) = default; +# endif + + TestRunInfo runInfo; + Totals totals; + bool aborting; + }; + + struct IStreamingReporter : IShared { + virtual ~IStreamingReporter(); + + // Implementing class must also provide the following static method: + // static std::string getDescription(); + + virtual ReporterPreferences getPreferences() const = 0; + + virtual void noMatchingTestCases( std::string const& spec ) = 0; + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0; + virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0; + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0; + virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0; + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0; + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; + virtual void sectionEnded( SectionStats const& sectionStats ) = 0; + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; + virtual void testRunEnded( TestRunStats const& testRunStats ) = 0; + + virtual void skipTest( TestCaseInfo const& testInfo ) = 0; + }; + + struct IReporterFactory { + virtual ~IReporterFactory(); + virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; + virtual std::string getDescription() const = 0; + }; + + struct IReporterRegistry { + typedef std::map<std::string, IReporterFactory*> FactoryMap; + + virtual ~IReporterRegistry(); + virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig> const& config ) const = 0; + virtual FactoryMap const& getFactories() const = 0; + }; + +} + +#include <limits> +#include <algorithm> + +namespace Catch { + + inline std::size_t listTests( Config const& config ) { + + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + Catch::cout() << "Matching test cases:\n"; + else { + Catch::cout() << "All available test cases:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + } + + std::size_t matchedTests = 0; + TextAttributes nameAttr, tagsAttr; + nameAttr.setInitialIndent( 2 ).setIndent( 4 ); + tagsAttr.setIndent( 6 ); + + std::vector<TestCase> matchedTestCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); + for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + Colour::Code colour = testCaseInfo.isHidden() + ? Colour::SecondaryText + : Colour::None; + Colour colourGuard( colour ); + + Catch::cout() << Text( testCaseInfo.name, nameAttr ) << std::endl; + if( !testCaseInfo.tags.empty() ) + Catch::cout() << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl; + } + + if( !config.testSpec().hasFilters() ) + Catch::cout() << pluralise( matchedTests, "test case" ) << "\n" << std::endl; + else + Catch::cout() << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl; + return matchedTests; + } + + inline std::size_t listTestsNamesOnly( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( !config.testSpec().hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + std::size_t matchedTests = 0; + std::vector<TestCase> matchedTestCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); + for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + matchedTests++; + TestCaseInfo const& testCaseInfo = it->getTestCaseInfo(); + Catch::cout() << testCaseInfo.name << std::endl; + } + return matchedTests; + } + + struct TagInfo { + TagInfo() : count ( 0 ) {} + void add( std::string const& spelling ) { + ++count; + spellings.insert( spelling ); + } + std::string all() const { + std::string out; + for( std::set<std::string>::const_iterator it = spellings.begin(), itEnd = spellings.end(); + it != itEnd; + ++it ) + out += "[" + *it + "]"; + return out; + } + std::set<std::string> spellings; + std::size_t count; + }; + + inline std::size_t listTags( Config const& config ) { + TestSpec testSpec = config.testSpec(); + if( config.testSpec().hasFilters() ) + Catch::cout() << "Tags for matching test cases:\n"; + else { + Catch::cout() << "All available tags:\n"; + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); + } + + std::map<std::string, TagInfo> tagCounts; + + std::vector<TestCase> matchedTestCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); + for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); + it != itEnd; + ++it ) { + for( std::set<std::string>::const_iterator tagIt = it->getTestCaseInfo().tags.begin(), + tagItEnd = it->getTestCaseInfo().tags.end(); + tagIt != tagItEnd; + ++tagIt ) { + std::string tagName = *tagIt; + std::string lcaseTagName = toLower( tagName ); + std::map<std::string, TagInfo>::iterator countIt = tagCounts.find( lcaseTagName ); + if( countIt == tagCounts.end() ) + countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first; + countIt->second.add( tagName ); + } + } + + for( std::map<std::string, TagInfo>::const_iterator countIt = tagCounts.begin(), + countItEnd = tagCounts.end(); + countIt != countItEnd; + ++countIt ) { + std::ostringstream oss; + oss << " " << std::setw(2) << countIt->second.count << " "; + Text wrapper( countIt->second.all(), TextAttributes() + .setInitialIndent( 0 ) + .setIndent( oss.str().size() ) + .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) ); + Catch::cout() << oss.str() << wrapper << "\n"; + } + Catch::cout() << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl; + return tagCounts.size(); + } + + inline std::size_t listReporters( Config const& /*config*/ ) { + Catch::cout() << "Available reporters:\n"; + IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); + IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it; + std::size_t maxNameLen = 0; + for(it = itBegin; it != itEnd; ++it ) + maxNameLen = (std::max)( maxNameLen, it->first.size() ); + + for(it = itBegin; it != itEnd; ++it ) { + Text wrapper( it->second->getDescription(), TextAttributes() + .setInitialIndent( 0 ) + .setIndent( 7+maxNameLen ) + .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) ); + Catch::cout() << " " + << it->first + << ":" + << std::string( maxNameLen - it->first.size() + 2, ' ' ) + << wrapper << "\n"; + } + Catch::cout() << std::endl; + return factories.size(); + } + + inline Option<std::size_t> list( Config const& config ) { + Option<std::size_t> listedCount; + if( config.listTests() ) + listedCount = listedCount.valueOr(0) + listTests( config ); + if( config.listTestNamesOnly() ) + listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config ); + if( config.listTags() ) + listedCount = listedCount.valueOr(0) + listTags( config ); + if( config.listReporters() ) + listedCount = listedCount.valueOr(0) + listReporters( config ); + return listedCount; + } + +} // end namespace Catch + +// #included from: internal/catch_runner_impl.hpp +#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED + +// #included from: catch_test_case_tracker.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED + +#include <map> +#include <string> +#include <assert.h> + +namespace Catch { +namespace SectionTracking { + + class TrackedSection { + + typedef std::map<std::string, TrackedSection> TrackedSections; + + public: + enum RunState { + NotStarted, + Executing, + ExecutingChildren, + Completed + }; + + TrackedSection( std::string const& name, TrackedSection* parent ) + : m_name( name ), m_runState( NotStarted ), m_parent( parent ) + {} + + RunState runState() const { return m_runState; } + + TrackedSection* findChild( std::string const& childName ) { + TrackedSections::iterator it = m_children.find( childName ); + return it != m_children.end() + ? &it->second + : NULL; + } + TrackedSection* acquireChild( std::string const& childName ) { + if( TrackedSection* child = findChild( childName ) ) + return child; + m_children.insert( std::make_pair( childName, TrackedSection( childName, this ) ) ); + return findChild( childName ); + } + void enter() { + if( m_runState == NotStarted ) + m_runState = Executing; + } + void leave() { + for( TrackedSections::const_iterator it = m_children.begin(), itEnd = m_children.end(); + it != itEnd; + ++it ) + if( it->second.runState() != Completed ) { + m_runState = ExecutingChildren; + return; + } + m_runState = Completed; + } + TrackedSection* getParent() { + return m_parent; + } + bool hasChildren() const { + return !m_children.empty(); + } + + private: + std::string m_name; + RunState m_runState; + TrackedSections m_children; + TrackedSection* m_parent; + + }; + + class TestCaseTracker { + public: + TestCaseTracker( std::string const& testCaseName ) + : m_testCase( testCaseName, NULL ), + m_currentSection( &m_testCase ), + m_completedASectionThisRun( false ) + {} + + bool enterSection( std::string const& name ) { + TrackedSection* child = m_currentSection->acquireChild( name ); + if( m_completedASectionThisRun || child->runState() == TrackedSection::Completed ) + return false; + + m_currentSection = child; + m_currentSection->enter(); + return true; + } + void leaveSection() { + m_currentSection->leave(); + m_currentSection = m_currentSection->getParent(); + assert( m_currentSection != NULL ); + m_completedASectionThisRun = true; + } + + bool currentSectionHasChildren() const { + return m_currentSection->hasChildren(); + } + bool isCompleted() const { + return m_testCase.runState() == TrackedSection::Completed; + } + + class Guard { + public: + Guard( TestCaseTracker& tracker ) : m_tracker( tracker ) { + m_tracker.enterTestCase(); + } + ~Guard() { + m_tracker.leaveTestCase(); + } + private: + Guard( Guard const& ); + void operator = ( Guard const& ); + TestCaseTracker& m_tracker; + }; + + private: + void enterTestCase() { + m_currentSection = &m_testCase; + m_completedASectionThisRun = false; + m_testCase.enter(); + } + void leaveTestCase() { + m_testCase.leave(); + } + + TrackedSection m_testCase; + TrackedSection* m_currentSection; + bool m_completedASectionThisRun; + }; + +} // namespace SectionTracking + +using SectionTracking::TestCaseTracker; + +} // namespace Catch + +// #included from: catch_fatal_condition.hpp +#define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED + +namespace Catch { + + // Report the error condition then exit the process + inline void fatal( std::string const& message, int exitCode ) { + IContext& context = Catch::getCurrentContext(); + IResultCapture* resultCapture = context.getResultCapture(); + resultCapture->handleFatalErrorCondition( message ); + + if( Catch::alwaysTrue() ) // avoids "no return" warnings + exit( exitCode ); + } + +} // namespace Catch + +#if defined ( CATCH_PLATFORM_WINDOWS ) ///////////////////////////////////////// + +namespace Catch { + + struct FatalConditionHandler { + void reset() {} + }; + +} // namespace Catch + +#else // Not Windows - assumed to be POSIX compatible ////////////////////////// + +#include <signal.h> + +namespace Catch { + + struct SignalDefs { int id; const char* name; }; + extern SignalDefs signalDefs[]; + SignalDefs signalDefs[] = { + { SIGINT, "SIGINT - Terminal interrupt signal" }, + { SIGILL, "SIGILL - Illegal instruction signal" }, + { SIGFPE, "SIGFPE - Floating point error signal" }, + { SIGSEGV, "SIGSEGV - Segmentation violation signal" }, + { SIGTERM, "SIGTERM - Termination request signal" }, + { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } + }; + + struct FatalConditionHandler { + + static void handleSignal( int sig ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + if( sig == signalDefs[i].id ) + fatal( signalDefs[i].name, -sig ); + fatal( "<unknown signal>", -sig ); + } + + FatalConditionHandler() : m_isSet( true ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + signal( signalDefs[i].id, handleSignal ); + } + ~FatalConditionHandler() { + reset(); + } + void reset() { + if( m_isSet ) { + for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) + signal( signalDefs[i].id, SIG_DFL ); + m_isSet = false; + } + } + + bool m_isSet; + }; + +} // namespace Catch + +#endif // not Windows + +#include <set> +#include <string> + +namespace Catch { + + class StreamRedirect { + + public: + StreamRedirect( std::ostream& stream, std::string& targetString ) + : m_stream( stream ), + m_prevBuf( stream.rdbuf() ), + m_targetString( targetString ) + { + stream.rdbuf( m_oss.rdbuf() ); + } + + ~StreamRedirect() { + m_targetString += m_oss.str(); + m_stream.rdbuf( m_prevBuf ); + } + + private: + std::ostream& m_stream; + std::streambuf* m_prevBuf; + std::ostringstream m_oss; + std::string& m_targetString; + }; + + /////////////////////////////////////////////////////////////////////////// + + class RunContext : public IResultCapture, public IRunner { + + RunContext( RunContext const& ); + void operator =( RunContext const& ); + + public: + + explicit RunContext( Ptr<IConfig const> const& config, Ptr<IStreamingReporter> const& reporter ) + : m_runInfo( config->name() ), + m_context( getCurrentMutableContext() ), + m_activeTestCase( NULL ), + m_config( config ), + m_reporter( reporter ), + m_prevRunner( m_context.getRunner() ), + m_prevResultCapture( m_context.getResultCapture() ), + m_prevConfig( m_context.getConfig() ) + { + m_context.setRunner( this ); + m_context.setConfig( m_config ); + m_context.setResultCapture( this ); + m_reporter->testRunStarting( m_runInfo ); + } + + virtual ~RunContext() { + m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); + m_context.setRunner( m_prevRunner ); + m_context.setConfig( NULL ); + m_context.setResultCapture( m_prevResultCapture ); + m_context.setConfig( m_prevConfig ); + } + + void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) ); + } + void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) { + m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) ); + } + + Totals runTest( TestCase const& testCase ) { + Totals prevTotals = m_totals; + + std::string redirectedCout; + std::string redirectedCerr; + + TestCaseInfo testInfo = testCase.getTestCaseInfo(); + + m_reporter->testCaseStarting( testInfo ); + + m_activeTestCase = &testCase; + m_testCaseTracker = TestCaseTracker( testInfo.name ); + + do { + do { + runCurrentTest( redirectedCout, redirectedCerr ); + } + while( !m_testCaseTracker->isCompleted() && !aborting() ); + } + while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); + + Totals deltaTotals = m_totals.delta( prevTotals ); + m_totals.testCases += deltaTotals.testCases; + m_reporter->testCaseEnded( TestCaseStats( testInfo, + deltaTotals, + redirectedCout, + redirectedCerr, + aborting() ) ); + + m_activeTestCase = NULL; + m_testCaseTracker.reset(); + + return deltaTotals; + } + + Ptr<IConfig const> config() const { + return m_config; + } + + private: // IResultCapture + + virtual void assertionEnded( AssertionResult const& result ) { + if( result.getResultType() == ResultWas::Ok ) { + m_totals.assertions.passed++; + } + else if( !result.isOk() ) { + m_totals.assertions.failed++; + } + + if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) ) + m_messages.clear(); + + // Reset working state + m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition ); + m_lastResult = result; + } + + virtual bool sectionStarted ( + SectionInfo const& sectionInfo, + Counts& assertions + ) + { + std::ostringstream oss; + oss << sectionInfo.name << "@" << sectionInfo.lineInfo; + + if( !m_testCaseTracker->enterSection( oss.str() ) ) + return false; + + m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; + + m_reporter->sectionStarting( sectionInfo ); + + assertions = m_totals.assertions; + + return true; + } + bool testForMissingAssertions( Counts& assertions ) { + if( assertions.total() != 0 || + !m_config->warnAboutMissingAssertions() || + m_testCaseTracker->currentSectionHasChildren() ) + return false; + m_totals.assertions.failed++; + assertions.failed++; + return true; + } + + virtual void sectionEnded( SectionInfo const& info, Counts const& prevAssertions, double _durationInSeconds ) { + if( std::uncaught_exception() ) { + m_unfinishedSections.push_back( UnfinishedSections( info, prevAssertions, _durationInSeconds ) ); + return; + } + + Counts assertions = m_totals.assertions - prevAssertions; + bool missingAssertions = testForMissingAssertions( assertions ); + + m_testCaseTracker->leaveSection(); + + m_reporter->sectionEnded( SectionStats( info, assertions, _durationInSeconds, missingAssertions ) ); + m_messages.clear(); + } + + virtual void pushScopedMessage( MessageInfo const& message ) { + m_messages.push_back( message ); + } + + virtual void popScopedMessage( MessageInfo const& message ) { + m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() ); + } + + virtual std::string getCurrentTestName() const { + return m_activeTestCase + ? m_activeTestCase->getTestCaseInfo().name + : ""; + } + + virtual const AssertionResult* getLastResult() const { + return &m_lastResult; + } + + virtual void handleFatalErrorCondition( std::string const& message ) { + ResultBuilder resultBuilder = makeUnexpectedResultBuilder(); + resultBuilder.setResultType( ResultWas::FatalErrorCondition ); + resultBuilder << message; + resultBuilder.captureExpression(); + + handleUnfinishedSections(); + + // Recreate section for test case (as we will lose the one that was in scope) + TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + + Counts assertions; + assertions.failed = 1; + SectionStats testCaseSectionStats( testCaseSection, assertions, 0, false ); + m_reporter->sectionEnded( testCaseSectionStats ); + + TestCaseInfo testInfo = m_activeTestCase->getTestCaseInfo(); + + Totals deltaTotals; + deltaTotals.testCases.failed = 1; + m_reporter->testCaseEnded( TestCaseStats( testInfo, + deltaTotals, + "", + "", + false ) ); + m_totals.testCases.failed++; + testGroupEnded( "", m_totals, 1, 1 ); + m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, false ) ); + } + + public: + // !TBD We need to do this another way! + bool aborting() const { + return m_totals.assertions.failed == static_cast<std::size_t>( m_config->abortAfter() ); + } + + private: + + void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) { + TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo(); + SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description ); + m_reporter->sectionStarting( testCaseSection ); + Counts prevAssertions = m_totals.assertions; + double duration = 0; + try { + m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); + TestCaseTracker::Guard guard( *m_testCaseTracker ); + + Timer timer; + timer.start(); + if( m_reporter->getPreferences().shouldRedirectStdOut ) { + StreamRedirect coutRedir( Catch::cout(), redirectedCout ); + StreamRedirect cerrRedir( Catch::cerr(), redirectedCerr ); + invokeActiveTestCase(); + } + else { + invokeActiveTestCase(); + } + duration = timer.getElapsedSeconds(); + } + catch( TestFailureException& ) { + // This just means the test was aborted due to failure + } + catch(...) { + makeUnexpectedResultBuilder().useActiveException(); + } + handleUnfinishedSections(); + m_messages.clear(); + + Counts assertions = m_totals.assertions - prevAssertions; + bool missingAssertions = testForMissingAssertions( assertions ); + + if( testCaseInfo.okToFail() ) { + std::swap( assertions.failedButOk, assertions.failed ); + m_totals.assertions.failed -= assertions.failedButOk; + m_totals.assertions.failedButOk += assertions.failedButOk; + } + + SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions ); + m_reporter->sectionEnded( testCaseSectionStats ); + } + + void invokeActiveTestCase() { + FatalConditionHandler fatalConditionHandler; // Handle signals + m_activeTestCase->invoke(); + fatalConditionHandler.reset(); + } + + private: + + ResultBuilder makeUnexpectedResultBuilder() const { + return ResultBuilder( m_lastAssertionInfo.macroName.c_str(), + m_lastAssertionInfo.lineInfo, + m_lastAssertionInfo.capturedExpression.c_str(), + m_lastAssertionInfo.resultDisposition ); + } + + void handleUnfinishedSections() { + // If sections ended prematurely due to an exception we stored their + // infos here so we can tear them down outside the unwind process. + for( std::vector<UnfinishedSections>::const_reverse_iterator it = m_unfinishedSections.rbegin(), + itEnd = m_unfinishedSections.rend(); + it != itEnd; + ++it ) + sectionEnded( it->info, it->prevAssertions, it->durationInSeconds ); + m_unfinishedSections.clear(); + } + + struct UnfinishedSections { + UnfinishedSections( SectionInfo const& _info, Counts const& _prevAssertions, double _durationInSeconds ) + : info( _info ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) + {} + + SectionInfo info; + Counts prevAssertions; + double durationInSeconds; + }; + + TestRunInfo m_runInfo; + IMutableContext& m_context; + TestCase const* m_activeTestCase; + Option<TestCaseTracker> m_testCaseTracker; + AssertionResult m_lastResult; + + Ptr<IConfig const> m_config; + Totals m_totals; + Ptr<IStreamingReporter> m_reporter; + std::vector<MessageInfo> m_messages; + IRunner* m_prevRunner; + IResultCapture* m_prevResultCapture; + Ptr<IConfig const> m_prevConfig; + AssertionInfo m_lastAssertionInfo; + std::vector<UnfinishedSections> m_unfinishedSections; + }; + + IResultCapture& getResultCapture() { + if( IResultCapture* capture = getCurrentContext().getResultCapture() ) + return *capture; + else + throw std::logic_error( "No result capture instance" ); + } + +} // end namespace Catch + +// #included from: internal/catch_version.h +#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED + +namespace Catch { + + // Versioning information + struct Version { + Version( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _buildNumber, + char const* const _branchName ) + : majorVersion( _majorVersion ), + minorVersion( _minorVersion ), + buildNumber( _buildNumber ), + branchName( _branchName ) + {} + + unsigned int const majorVersion; + unsigned int const minorVersion; + unsigned int const buildNumber; + char const* const branchName; + + private: + void operator=( Version const& ); + }; + + extern Version libraryVersion; +} + +#include <fstream> +#include <stdlib.h> +#include <limits> + +namespace Catch { + + class Runner { + + public: + Runner( Ptr<Config> const& config ) + : m_config( config ) + { + openStream(); + makeReporter(); + } + + Totals runTests() { + + RunContext context( m_config.get(), m_reporter ); + + Totals totals; + + context.testGroupStarting( "all tests", 1, 1 ); // deprecated? + + TestSpec testSpec = m_config->testSpec(); + if( !testSpec.hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests + + std::vector<TestCase> testCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, testCases ); + + int testsRunForGroup = 0; + for( std::vector<TestCase>::const_iterator it = testCases.begin(), itEnd = testCases.end(); + it != itEnd; + ++it ) { + testsRunForGroup++; + if( m_testsAlreadyRun.find( *it ) == m_testsAlreadyRun.end() ) { + + if( context.aborting() ) + break; + + totals += context.runTest( *it ); + m_testsAlreadyRun.insert( *it ); + } + } + std::vector<TestCase> skippedTestCases; + getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, skippedTestCases, true ); + + for( std::vector<TestCase>::const_iterator it = skippedTestCases.begin(), itEnd = skippedTestCases.end(); + it != itEnd; + ++it ) + m_reporter->skipTest( *it ); + + context.testGroupEnded( "all tests", totals, 1, 1 ); + return totals; + } + + private: + void openStream() { + // Open output file, if specified + if( !m_config->getFilename().empty() ) { + m_ofs.open( m_config->getFilename().c_str() ); + if( m_ofs.fail() ) { + std::ostringstream oss; + oss << "Unable to open file: '" << m_config->getFilename() << "'"; + throw std::domain_error( oss.str() ); + } + m_config->setStreamBuf( m_ofs.rdbuf() ); + } + } + void makeReporter() { + std::string reporterName = m_config->getReporterName().empty() + ? "console" + : m_config->getReporterName(); + + m_reporter = getRegistryHub().getReporterRegistry().create( reporterName, m_config.get() ); + if( !m_reporter ) { + std::ostringstream oss; + oss << "No reporter registered with name: '" << reporterName << "'"; + throw std::domain_error( oss.str() ); + } + } + + private: + Ptr<Config> m_config; + std::ofstream m_ofs; + Ptr<IStreamingReporter> m_reporter; + std::set<TestCase> m_testsAlreadyRun; + }; + + class Session : NonCopyable { + static bool alreadyInstantiated; + + public: + + struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; }; + + Session() + : m_cli( makeCommandLineParser() ) { + if( alreadyInstantiated ) { + std::string msg = "Only one instance of Catch::Session can ever be used"; + Catch::cerr() << msg << std::endl; + throw std::logic_error( msg ); + } + alreadyInstantiated = true; + } + ~Session() { + Catch::cleanUp(); + } + + void showHelp( std::string const& processName ) { + Catch::cout() << "\nCatch v" << libraryVersion.majorVersion << "." + << libraryVersion.minorVersion << " build " + << libraryVersion.buildNumber; + if( libraryVersion.branchName != std::string( "master" ) ) + Catch::cout() << " (" << libraryVersion.branchName << " branch)"; + Catch::cout() << "\n"; + + m_cli.usage( Catch::cout(), processName ); + Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; + } + + int applyCommandLine( int argc, char* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { + try { + m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); + m_unusedTokens = m_cli.parseInto( argc, argv, m_configData ); + if( m_configData.showHelp ) + showHelp( m_configData.processName ); + m_config.reset(); + } + catch( std::exception& ex ) { + { + Colour colourGuard( Colour::Red ); + Catch::cerr() << "\nError(s) in input:\n" + << Text( ex.what(), TextAttributes().setIndent(2) ) + << "\n\n"; + } + m_cli.usage( Catch::cout(), m_configData.processName ); + return (std::numeric_limits<int>::max)(); + } + return 0; + } + + void useConfigData( ConfigData const& _configData ) { + m_configData = _configData; + m_config.reset(); + } + + int run( int argc, char* const argv[] ) { + + int returnCode = applyCommandLine( argc, argv ); + if( returnCode == 0 ) + returnCode = run(); + return returnCode; + } + + int run() { + if( m_configData.showHelp ) + return 0; + + try + { + config(); // Force config to be constructed + + std::srand( m_configData.rngSeed ); + + Runner runner( m_config ); + + // Handle list request + if( Option<std::size_t> listed = list( config() ) ) + return static_cast<int>( *listed ); + + return static_cast<int>( runner.runTests().assertions.failed ); + } + catch( std::exception& ex ) { + Catch::cerr() << ex.what() << std::endl; + return (std::numeric_limits<int>::max)(); + } + } + + Clara::CommandLine<ConfigData> const& cli() const { + return m_cli; + } + std::vector<Clara::Parser::Token> const& unusedTokens() const { + return m_unusedTokens; + } + ConfigData& configData() { + return m_configData; + } + Config& config() { + if( !m_config ) + m_config = new Config( m_configData ); + return *m_config; + } + + private: + Clara::CommandLine<ConfigData> m_cli; + std::vector<Clara::Parser::Token> m_unusedTokens; + ConfigData m_configData; + Ptr<Config> m_config; + }; + + bool Session::alreadyInstantiated = false; + +} // end namespace Catch + +// #included from: catch_registry_hub.hpp +#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED + +// #included from: catch_test_case_registry_impl.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED + +#include <vector> +#include <set> +#include <sstream> +#include <iostream> +#include <algorithm> + +namespace Catch { + + class TestRegistry : public ITestCaseRegistry { + struct LexSort { + bool operator() (TestCase i,TestCase j) const { return (i<j);} + }; + struct RandomNumberGenerator { + int operator()( int n ) const { return std::rand() % n; } + }; + + public: + TestRegistry() : m_unnamedCount( 0 ) {} + virtual ~TestRegistry(); + + virtual void registerTest( TestCase const& testCase ) { + std::string name = testCase.getTestCaseInfo().name; + if( name == "" ) { + std::ostringstream oss; + oss << "Anonymous test case " << ++m_unnamedCount; + return registerTest( testCase.withName( oss.str() ) ); + } + + if( m_functions.find( testCase ) == m_functions.end() ) { + m_functions.insert( testCase ); + m_functionsInOrder.push_back( testCase ); + if( !testCase.isHidden() ) + m_nonHiddenFunctions.push_back( testCase ); + } + else { + TestCase const& prev = *m_functions.find( testCase ); + { + Colour colourGuard( Colour::Red ); + Catch::cerr() << "error: TEST_CASE( \"" << name << "\" ) already defined.\n" + << "\tFirst seen at " << prev.getTestCaseInfo().lineInfo << "\n" + << "\tRedefined at " << testCase.getTestCaseInfo().lineInfo << std::endl; + } + exit(1); + } + } + + virtual std::vector<TestCase> const& getAllTests() const { + return m_functionsInOrder; + } + + virtual std::vector<TestCase> const& getAllNonHiddenTests() const { + return m_nonHiddenFunctions; + } + + virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector<TestCase>& matchingTestCases, bool negated = false ) const { + + for( std::vector<TestCase>::const_iterator it = m_functionsInOrder.begin(), + itEnd = m_functionsInOrder.end(); + it != itEnd; + ++it ) { + bool includeTest = testSpec.matches( *it ) && ( config.allowThrows() || !it->throws() ); + if( includeTest != negated ) + matchingTestCases.push_back( *it ); + } + sortTests( config, matchingTestCases ); + } + + private: + + static void sortTests( IConfig const& config, std::vector<TestCase>& matchingTestCases ) { + + switch( config.runOrder() ) { + case RunTests::InLexicographicalOrder: + std::sort( matchingTestCases.begin(), matchingTestCases.end(), LexSort() ); + break; + case RunTests::InRandomOrder: + { + RandomNumberGenerator rng; + std::random_shuffle( matchingTestCases.begin(), matchingTestCases.end(), rng ); + } + break; + case RunTests::InDeclarationOrder: + // already in declaration order + break; + } + } + std::set<TestCase> m_functions; + std::vector<TestCase> m_functionsInOrder; + std::vector<TestCase> m_nonHiddenFunctions; + size_t m_unnamedCount; + }; + + /////////////////////////////////////////////////////////////////////////// + + class FreeFunctionTestCase : public SharedImpl<ITestCase> { + public: + + FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {} + + virtual void invoke() const { + m_fun(); + } + + private: + virtual ~FreeFunctionTestCase(); + + TestFunction m_fun; + }; + + inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) { + std::string className = classOrQualifiedMethodName; + if( startsWith( className, "&" ) ) + { + std::size_t lastColons = className.rfind( "::" ); + std::size_t penultimateColons = className.rfind( "::", lastColons-1 ); + if( penultimateColons == std::string::npos ) + penultimateColons = 1; + className = className.substr( penultimateColons, lastColons-penultimateColons ); + } + return className; + } + + /////////////////////////////////////////////////////////////////////////// + + AutoReg::AutoReg( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); + } + + AutoReg::~AutoReg() {} + + void AutoReg::registerTestCase( ITestCase* testCase, + char const* classOrQualifiedMethodName, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { + + getMutableRegistryHub().registerTest + ( makeTestCase( testCase, + extractClassName( classOrQualifiedMethodName ), + nameAndDesc.name, + nameAndDesc.description, + lineInfo ) ); + } + +} // end namespace Catch + +// #included from: catch_reporter_registry.hpp +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED + +#include <map> + +namespace Catch { + + class ReporterRegistry : public IReporterRegistry { + + public: + + virtual ~ReporterRegistry() { + deleteAllValues( m_factories ); + } + + virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig> const& config ) const { + FactoryMap::const_iterator it = m_factories.find( name ); + if( it == m_factories.end() ) + return NULL; + return it->second->create( ReporterConfig( config ) ); + } + + void registerReporter( std::string const& name, IReporterFactory* factory ) { + m_factories.insert( std::make_pair( name, factory ) ); + } + + FactoryMap const& getFactories() const { + return m_factories; + } + + private: + FactoryMap m_factories; + }; +} + +// #included from: catch_exception_translator_registry.hpp +#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED + +#ifdef __OBJC__ +#import "Foundation/Foundation.h" +#endif + +namespace Catch { + + class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry { + public: + ~ExceptionTranslatorRegistry() { + deleteAll( m_translators ); + } + + virtual void registerTranslator( const IExceptionTranslator* translator ) { + m_translators.push_back( translator ); + } + + virtual std::string translateActiveException() const { + try { +#ifdef __OBJC__ + // In Objective-C try objective-c exceptions first + @try { + throw; + } + @catch (NSException *exception) { + return Catch::toString( [exception description] ); + } +#else + throw; +#endif + } + catch( TestFailureException& ) { + throw; + } + catch( std::exception& ex ) { + return ex.what(); + } + catch( std::string& msg ) { + return msg; + } + catch( const char* msg ) { + return msg; + } + catch(...) { + return tryTranslators( m_translators.begin() ); + } + } + + std::string tryTranslators( std::vector<const IExceptionTranslator*>::const_iterator it ) const { + if( it == m_translators.end() ) + return "Unknown exception"; + + try { + return (*it)->translate(); + } + catch(...) { + return tryTranslators( it+1 ); + } + } + + private: + std::vector<const IExceptionTranslator*> m_translators; + }; +} + +namespace Catch { + + namespace { + + class RegistryHub : public IRegistryHub, public IMutableRegistryHub { + + RegistryHub( RegistryHub const& ); + void operator=( RegistryHub const& ); + + public: // IRegistryHub + RegistryHub() { + } + virtual IReporterRegistry const& getReporterRegistry() const { + return m_reporterRegistry; + } + virtual ITestCaseRegistry const& getTestCaseRegistry() const { + return m_testCaseRegistry; + } + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() { + return m_exceptionTranslatorRegistry; + } + + public: // IMutableRegistryHub + virtual void registerReporter( std::string const& name, IReporterFactory* factory ) { + m_reporterRegistry.registerReporter( name, factory ); + } + virtual void registerTest( TestCase const& testInfo ) { + m_testCaseRegistry.registerTest( testInfo ); + } + virtual void registerTranslator( const IExceptionTranslator* translator ) { + m_exceptionTranslatorRegistry.registerTranslator( translator ); + } + + private: + TestRegistry m_testCaseRegistry; + ReporterRegistry m_reporterRegistry; + ExceptionTranslatorRegistry m_exceptionTranslatorRegistry; + }; + + // Single, global, instance + inline RegistryHub*& getTheRegistryHub() { + static RegistryHub* theRegistryHub = NULL; + if( !theRegistryHub ) + theRegistryHub = new RegistryHub(); + return theRegistryHub; + } + } + + IRegistryHub& getRegistryHub() { + return *getTheRegistryHub(); + } + IMutableRegistryHub& getMutableRegistryHub() { + return *getTheRegistryHub(); + } + void cleanUp() { + delete getTheRegistryHub(); + getTheRegistryHub() = NULL; + cleanUpContext(); + } + std::string translateActiveException() { + return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException(); + } + +} // end namespace Catch + +// #included from: catch_notimplemented_exception.hpp +#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED + +#include <ostream> + +namespace Catch { + + NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo ) + : m_lineInfo( lineInfo ) { + std::ostringstream oss; + oss << lineInfo << ": function "; + oss << "not implemented"; + m_what = oss.str(); + } + + const char* NotImplementedException::what() const CATCH_NOEXCEPT { + return m_what.c_str(); + } + +} // end namespace Catch + +// #included from: catch_context_impl.hpp +#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED + +// #included from: catch_stream.hpp +#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED + +// #included from: catch_streambuf.h +#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED + +#include <streambuf> + +namespace Catch { + + class StreamBufBase : public std::streambuf { + public: + virtual ~StreamBufBase() CATCH_NOEXCEPT; + }; +} + +#include <stdexcept> +#include <cstdio> +#include <iostream> + +namespace Catch { + + template<typename WriterF, size_t bufferSize=256> + class StreamBufImpl : public StreamBufBase { + char data[bufferSize]; + WriterF m_writer; + + public: + StreamBufImpl() { + setp( data, data + sizeof(data) ); + } + + ~StreamBufImpl() CATCH_NOEXCEPT { + sync(); + } + + private: + int overflow( int c ) { + sync(); + + if( c != EOF ) { + if( pbase() == epptr() ) + m_writer( std::string( 1, static_cast<char>( c ) ) ); + else + sputc( static_cast<char>( c ) ); + } + return 0; + } + + int sync() { + if( pbase() != pptr() ) { + m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) ); + setp( pbase(), epptr() ); + } + return 0; + } + }; + + /////////////////////////////////////////////////////////////////////////// + + struct OutputDebugWriter { + + void operator()( std::string const&str ) { + writeToDebugConsole( str ); + } + }; + + Stream::Stream() + : streamBuf( NULL ), isOwned( false ) + {} + + Stream::Stream( std::streambuf* _streamBuf, bool _isOwned ) + : streamBuf( _streamBuf ), isOwned( _isOwned ) + {} + + void Stream::release() { + if( isOwned ) { + delete streamBuf; + streamBuf = NULL; + isOwned = false; + } + } + +#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement this functions + std::ostream& cout() { + return std::cout; + } + std::ostream& cerr() { + return std::cerr; + } +#endif +} + +namespace Catch { + + class Context : public IMutableContext { + + Context() : m_config( NULL ), m_runner( NULL ), m_resultCapture( NULL ) {} + Context( Context const& ); + void operator=( Context const& ); + + public: // IContext + virtual IResultCapture* getResultCapture() { + return m_resultCapture; + } + virtual IRunner* getRunner() { + return m_runner; + } + virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) { + return getGeneratorsForCurrentTest() + .getGeneratorInfo( fileInfo, totalSize ) + .getCurrentIndex(); + } + virtual bool advanceGeneratorsForCurrentTest() { + IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); + return generators && generators->moveNext(); + } + + virtual Ptr<IConfig const> getConfig() const { + return m_config; + } + + public: // IMutableContext + virtual void setResultCapture( IResultCapture* resultCapture ) { + m_resultCapture = resultCapture; + } + virtual void setRunner( IRunner* runner ) { + m_runner = runner; + } + virtual void setConfig( Ptr<IConfig const> const& config ) { + m_config = config; + } + + friend IMutableContext& getCurrentMutableContext(); + + private: + IGeneratorsForTest* findGeneratorsForCurrentTest() { + std::string testName = getResultCapture()->getCurrentTestName(); + + std::map<std::string, IGeneratorsForTest*>::const_iterator it = + m_generatorsByTestName.find( testName ); + return it != m_generatorsByTestName.end() + ? it->second + : NULL; + } + + IGeneratorsForTest& getGeneratorsForCurrentTest() { + IGeneratorsForTest* generators = findGeneratorsForCurrentTest(); + if( !generators ) { + std::string testName = getResultCapture()->getCurrentTestName(); + generators = createGeneratorsForTest(); + m_generatorsByTestName.insert( std::make_pair( testName, generators ) ); + } + return *generators; + } + + private: + Ptr<IConfig const> m_config; + IRunner* m_runner; + IResultCapture* m_resultCapture; + std::map<std::string, IGeneratorsForTest*> m_generatorsByTestName; + }; + + namespace { + Context* currentContext = NULL; + } + IMutableContext& getCurrentMutableContext() { + if( !currentContext ) + currentContext = new Context(); + return *currentContext; + } + IContext& getCurrentContext() { + return getCurrentMutableContext(); + } + + Stream createStream( std::string const& streamName ) { + if( streamName == "stdout" ) return Stream( Catch::cout().rdbuf(), false ); + if( streamName == "stderr" ) return Stream( Catch::cerr().rdbuf(), false ); + if( streamName == "debug" ) return Stream( new StreamBufImpl<OutputDebugWriter>, true ); + + throw std::domain_error( "Unknown stream: " + streamName ); + } + + void cleanUpContext() { + delete currentContext; + currentContext = NULL; + } +} + +// #included from: catch_console_colour_impl.hpp +#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED + +namespace Catch { + namespace { + + struct IColourImpl { + virtual ~IColourImpl() {} + virtual void use( Colour::Code _colourCode ) = 0; + }; + + struct NoColourImpl : IColourImpl { + void use( Colour::Code ) {} + + static IColourImpl* instance() { + static NoColourImpl s_instance; + return &s_instance; + } + }; + + } // anon namespace +} // namespace Catch + +#if !defined( CATCH_CONFIG_COLOUR_NONE ) && !defined( CATCH_CONFIG_COLOUR_WINDOWS ) && !defined( CATCH_CONFIG_COLOUR_ANSI ) +# ifdef CATCH_PLATFORM_WINDOWS +# define CATCH_CONFIG_COLOUR_WINDOWS +# else +# define CATCH_CONFIG_COLOUR_ANSI +# endif +#endif + +#if defined ( CATCH_CONFIG_COLOUR_WINDOWS ) ///////////////////////////////////////// + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#ifdef __AFXDLL +#include <AfxWin.h> +#else +#include <windows.h> +#endif + +namespace Catch { +namespace { + + class Win32ColourImpl : public IColourImpl { + public: + Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) ) + { + CONSOLE_SCREEN_BUFFER_INFO csbiInfo; + GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); + originalAttributes = csbiInfo.wAttributes; + } + + virtual void use( Colour::Code _colourCode ) { + switch( _colourCode ) { + case Colour::None: return setTextAttribute( originalAttributes ); + case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + case Colour::Red: return setTextAttribute( FOREGROUND_RED ); + case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); + case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE ); + case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN ); + case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN ); + case Colour::Grey: return setTextAttribute( 0 ); + + case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY ); + case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED ); + case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN ); + case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); + + case Colour::Bright: throw std::logic_error( "not a colour" ); + } + } + + private: + void setTextAttribute( WORD _textAttribute ) { + SetConsoleTextAttribute( stdoutHandle, _textAttribute ); + } + HANDLE stdoutHandle; + WORD originalAttributes; + }; + + IColourImpl* platformColourInstance() { + static Win32ColourImpl s_instance; + return &s_instance; + } + +} // end anon namespace +} // end namespace Catch + +#elif defined( CATCH_CONFIG_COLOUR_ANSI ) ////////////////////////////////////// + +#include <unistd.h> + +namespace Catch { +namespace { + + // use POSIX/ ANSI console terminal codes + // Thanks to Adam Strzelecki for original contribution + // (http://github.com/nanoant) + // https://github.com/philsquared/Catch/pull/131 + class PosixColourImpl : public IColourImpl { + public: + virtual void use( Colour::Code _colourCode ) { + switch( _colourCode ) { + case Colour::None: + case Colour::White: return setColour( "[0m" ); + case Colour::Red: return setColour( "[0;31m" ); + case Colour::Green: return setColour( "[0;32m" ); + case Colour::Blue: return setColour( "[0;34m" ); + case Colour::Cyan: return setColour( "[0;36m" ); + case Colour::Yellow: return setColour( "[0;33m" ); + case Colour::Grey: return setColour( "[1;30m" ); + + case Colour::LightGrey: return setColour( "[0;37m" ); + case Colour::BrightRed: return setColour( "[1;31m" ); + case Colour::BrightGreen: return setColour( "[1;32m" ); + case Colour::BrightWhite: return setColour( "[1;37m" ); + + case Colour::Bright: throw std::logic_error( "not a colour" ); + } + } + static IColourImpl* instance() { + static PosixColourImpl s_instance; + return &s_instance; + } + + private: + void setColour( const char* _escapeCode ) { + Catch::cout() << '\033' << _escapeCode; + } + }; + + IColourImpl* platformColourInstance() { + Ptr<IConfig const> config = getCurrentContext().getConfig(); + return (config && config->forceColour()) || isatty(STDOUT_FILENO) + ? PosixColourImpl::instance() + : NoColourImpl::instance(); + } + +} // end anon namespace +} // end namespace Catch + +#else // not Windows or ANSI /////////////////////////////////////////////// + +namespace Catch { + + static IColourImpl* platformColourInstance() { return NoColourImpl::instance(); } + +} // end namespace Catch + +#endif // Windows/ ANSI/ None + +namespace Catch { + + Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); } + Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast<Colour&>( _other ).m_moved = true; } + Colour::~Colour(){ if( !m_moved ) use( None ); } + + void Colour::use( Code _colourCode ) { + static IColourImpl* impl = isDebuggerActive() + ? NoColourImpl::instance() + : platformColourInstance(); + impl->use( _colourCode ); + } + +} // end namespace Catch + +// #included from: catch_generators_impl.hpp +#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED + +#include <vector> +#include <string> +#include <map> + +namespace Catch { + + struct GeneratorInfo : IGeneratorInfo { + + GeneratorInfo( std::size_t size ) + : m_size( size ), + m_currentIndex( 0 ) + {} + + bool moveNext() { + if( ++m_currentIndex == m_size ) { + m_currentIndex = 0; + return false; + } + return true; + } + + std::size_t getCurrentIndex() const { + return m_currentIndex; + } + + std::size_t m_size; + std::size_t m_currentIndex; + }; + + /////////////////////////////////////////////////////////////////////////// + + class GeneratorsForTest : public IGeneratorsForTest { + + public: + ~GeneratorsForTest() { + deleteAll( m_generatorsInOrder ); + } + + IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) { + std::map<std::string, IGeneratorInfo*>::const_iterator it = m_generatorsByName.find( fileInfo ); + if( it == m_generatorsByName.end() ) { + IGeneratorInfo* info = new GeneratorInfo( size ); + m_generatorsByName.insert( std::make_pair( fileInfo, info ) ); + m_generatorsInOrder.push_back( info ); + return *info; + } + return *it->second; + } + + bool moveNext() { + std::vector<IGeneratorInfo*>::const_iterator it = m_generatorsInOrder.begin(); + std::vector<IGeneratorInfo*>::const_iterator itEnd = m_generatorsInOrder.end(); + for(; it != itEnd; ++it ) { + if( (*it)->moveNext() ) + return true; + } + return false; + } + + private: + std::map<std::string, IGeneratorInfo*> m_generatorsByName; + std::vector<IGeneratorInfo*> m_generatorsInOrder; + }; + + IGeneratorsForTest* createGeneratorsForTest() + { + return new GeneratorsForTest(); + } + +} // end namespace Catch + +// #included from: catch_assertionresult.hpp +#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED + +namespace Catch { + + AssertionInfo::AssertionInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + std::string const& _capturedExpression, + ResultDisposition::Flags _resultDisposition ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + capturedExpression( _capturedExpression ), + resultDisposition( _resultDisposition ) + {} + + AssertionResult::AssertionResult() {} + + AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data ) + : m_info( info ), + m_resultData( data ) + {} + + AssertionResult::~AssertionResult() {} + + // Result was a success + bool AssertionResult::succeeded() const { + return Catch::isOk( m_resultData.resultType ); + } + + // Result was a success, or failure is suppressed + bool AssertionResult::isOk() const { + return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition ); + } + + ResultWas::OfType AssertionResult::getResultType() const { + return m_resultData.resultType; + } + + bool AssertionResult::hasExpression() const { + return !m_info.capturedExpression.empty(); + } + + bool AssertionResult::hasMessage() const { + return !m_resultData.message.empty(); + } + + std::string AssertionResult::getExpression() const { + if( isFalseTest( m_info.resultDisposition ) ) + return "!" + m_info.capturedExpression; + else + return m_info.capturedExpression; + } + std::string AssertionResult::getExpressionInMacro() const { + if( m_info.macroName.empty() ) + return m_info.capturedExpression; + else + return m_info.macroName + "( " + m_info.capturedExpression + " )"; + } + + bool AssertionResult::hasExpandedExpression() const { + return hasExpression() && getExpandedExpression() != getExpression(); + } + + std::string AssertionResult::getExpandedExpression() const { + return m_resultData.reconstructedExpression; + } + + std::string AssertionResult::getMessage() const { + return m_resultData.message; + } + SourceLineInfo AssertionResult::getSourceInfo() const { + return m_info.lineInfo; + } + + std::string AssertionResult::getTestMacroName() const { + return m_info.macroName; + } + +} // end namespace Catch + +// #included from: catch_test_case_info.hpp +#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED + +namespace Catch { + + inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) { + if( startsWith( tag, "." ) || + tag == "hide" || + tag == "!hide" ) + return TestCaseInfo::IsHidden; + else if( tag == "!throws" ) + return TestCaseInfo::Throws; + else if( tag == "!shouldfail" ) + return TestCaseInfo::ShouldFail; + else if( tag == "!mayfail" ) + return TestCaseInfo::MayFail; + else + return TestCaseInfo::None; + } + inline bool isReservedTag( std::string const& tag ) { + return TestCaseInfo::None && tag.size() > 0 && !isalnum( tag[0] ); + } + inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) { + if( isReservedTag( tag ) ) { + { + Colour colourGuard( Colour::Red ); + Catch::cerr() + << "Tag name [" << tag << "] not allowed.\n" + << "Tag names starting with non alpha-numeric characters are reserved\n"; + } + { + Colour colourGuard( Colour::FileName ); + Catch::cerr() << _lineInfo << std::endl; + } + exit(1); + } + } + + TestCase makeTestCase( ITestCase* _testCase, + std::string const& _className, + std::string const& _name, + std::string const& _descOrTags, + SourceLineInfo const& _lineInfo ) + { + bool isHidden( startsWith( _name, "./" ) ); // Legacy support + + // Parse out tags + std::set<std::string> tags; + std::string desc, tag; + bool inTag = false; + for( std::size_t i = 0; i < _descOrTags.size(); ++i ) { + char c = _descOrTags[i]; + if( !inTag ) { + if( c == '[' ) + inTag = true; + else + desc += c; + } + else { + if( c == ']' ) { + TestCaseInfo::SpecialProperties prop = parseSpecialTag( tag ); + if( prop == TestCaseInfo::IsHidden ) + isHidden = true; + else if( prop == TestCaseInfo::None ) + enforceNotReservedTag( tag, _lineInfo ); + + tags.insert( tag ); + tag.clear(); + inTag = false; + } + else + tag += c; + } + } + if( isHidden ) { + tags.insert( "hide" ); + tags.insert( "." ); + } + + TestCaseInfo info( _name, _className, desc, tags, _lineInfo ); + return TestCase( _testCase, info ); + } + + TestCaseInfo::TestCaseInfo( std::string const& _name, + std::string const& _className, + std::string const& _description, + std::set<std::string> const& _tags, + SourceLineInfo const& _lineInfo ) + : name( _name ), + className( _className ), + description( _description ), + tags( _tags ), + lineInfo( _lineInfo ), + properties( None ) + { + std::ostringstream oss; + for( std::set<std::string>::const_iterator it = _tags.begin(), itEnd = _tags.end(); it != itEnd; ++it ) { + oss << "[" << *it << "]"; + std::string lcaseTag = toLower( *it ); + properties = static_cast<SpecialProperties>( properties | parseSpecialTag( lcaseTag ) ); + lcaseTags.insert( lcaseTag ); + } + tagsAsString = oss.str(); + } + + TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) + : name( other.name ), + className( other.className ), + description( other.description ), + tags( other.tags ), + lcaseTags( other.lcaseTags ), + tagsAsString( other.tagsAsString ), + lineInfo( other.lineInfo ), + properties( other.properties ) + {} + + bool TestCaseInfo::isHidden() const { + return ( properties & IsHidden ) != 0; + } + bool TestCaseInfo::throws() const { + return ( properties & Throws ) != 0; + } + bool TestCaseInfo::okToFail() const { + return ( properties & (ShouldFail | MayFail ) ) != 0; + } + bool TestCaseInfo::expectedToFail() const { + return ( properties & (ShouldFail ) ) != 0; + } + + TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {} + + TestCase::TestCase( TestCase const& other ) + : TestCaseInfo( other ), + test( other.test ) + {} + + TestCase TestCase::withName( std::string const& _newName ) const { + TestCase other( *this ); + other.name = _newName; + return other; + } + + void TestCase::swap( TestCase& other ) { + test.swap( other.test ); + name.swap( other.name ); + className.swap( other.className ); + description.swap( other.description ); + tags.swap( other.tags ); + lcaseTags.swap( other.lcaseTags ); + tagsAsString.swap( other.tagsAsString ); + std::swap( TestCaseInfo::properties, static_cast<TestCaseInfo&>( other ).properties ); + std::swap( lineInfo, other.lineInfo ); + } + + void TestCase::invoke() const { + test->invoke(); + } + + bool TestCase::operator == ( TestCase const& other ) const { + return test.get() == other.test.get() && + name == other.name && + className == other.className; + } + + bool TestCase::operator < ( TestCase const& other ) const { + return name < other.name; + } + TestCase& TestCase::operator = ( TestCase const& other ) { + TestCase temp( other ); + swap( temp ); + return *this; + } + + TestCaseInfo const& TestCase::getTestCaseInfo() const + { + return *this; + } + +} // end namespace Catch + +// #included from: catch_version.hpp +#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED + +namespace Catch { + + // These numbers are maintained by a script + Version libraryVersion( 1, 1, 14, "develop" ); +} + +// #included from: catch_message.hpp +#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED + +namespace Catch { + + MessageInfo::MessageInfo( std::string const& _macroName, + SourceLineInfo const& _lineInfo, + ResultWas::OfType _type ) + : macroName( _macroName ), + lineInfo( _lineInfo ), + type( _type ), + sequence( ++globalCount ) + {} + + // This may need protecting if threading support is added + unsigned int MessageInfo::globalCount = 0; + + //////////////////////////////////////////////////////////////////////////// + + ScopedMessage::ScopedMessage( MessageBuilder const& builder ) + : m_info( builder.m_info ) + { + m_info.message = builder.m_stream.str(); + getResultCapture().pushScopedMessage( m_info ); + } + ScopedMessage::ScopedMessage( ScopedMessage const& other ) + : m_info( other.m_info ) + {} + + ScopedMessage::~ScopedMessage() { + getResultCapture().popScopedMessage( m_info ); + } + +} // end namespace Catch + +// #included from: catch_legacy_reporter_adapter.hpp +#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED + +// #included from: catch_legacy_reporter_adapter.h +#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED + +namespace Catch +{ + // Deprecated + struct IReporter : IShared { + virtual ~IReporter(); + + virtual bool shouldRedirectStdout() const = 0; + + virtual void StartTesting() = 0; + virtual void EndTesting( Totals const& totals ) = 0; + virtual void StartGroup( std::string const& groupName ) = 0; + virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0; + virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0; + virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0; + virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0; + virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0; + virtual void NoAssertionsInSection( std::string const& sectionName ) = 0; + virtual void NoAssertionsInTestCase( std::string const& testName ) = 0; + virtual void Aborted() = 0; + virtual void Result( AssertionResult const& result ) = 0; + }; + + class LegacyReporterAdapter : public SharedImpl<IStreamingReporter> + { + public: + LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter ); + virtual ~LegacyReporterAdapter(); + + virtual ReporterPreferences getPreferences() const; + virtual void noMatchingTestCases( std::string const& ); + virtual void testRunStarting( TestRunInfo const& ); + virtual void testGroupStarting( GroupInfo const& groupInfo ); + virtual void testCaseStarting( TestCaseInfo const& testInfo ); + virtual void sectionStarting( SectionInfo const& sectionInfo ); + virtual void assertionStarting( AssertionInfo const& ); + virtual bool assertionEnded( AssertionStats const& assertionStats ); + virtual void sectionEnded( SectionStats const& sectionStats ); + virtual void testCaseEnded( TestCaseStats const& testCaseStats ); + virtual void testGroupEnded( TestGroupStats const& testGroupStats ); + virtual void testRunEnded( TestRunStats const& testRunStats ); + virtual void skipTest( TestCaseInfo const& ); + + private: + Ptr<IReporter> m_legacyReporter; + }; +} + +namespace Catch +{ + LegacyReporterAdapter::LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter ) + : m_legacyReporter( legacyReporter ) + {} + LegacyReporterAdapter::~LegacyReporterAdapter() {} + + ReporterPreferences LegacyReporterAdapter::getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout(); + return prefs; + } + + void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {} + void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) { + m_legacyReporter->StartTesting(); + } + void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) { + m_legacyReporter->StartGroup( groupInfo.name ); + } + void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) { + m_legacyReporter->StartTestCase( testInfo ); + } + void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) { + m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description ); + } + void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) { + // Not on legacy interface + } + + bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) { + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); + it != itEnd; + ++it ) { + if( it->type == ResultWas::Info ) { + ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal ); + rb << it->message; + rb.setResultType( ResultWas::Info ); + AssertionResult result = rb.build(); + m_legacyReporter->Result( result ); + } + } + } + m_legacyReporter->Result( assertionStats.assertionResult ); + return true; + } + void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) { + if( sectionStats.missingAssertions ) + m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name ); + m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions ); + } + void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) { + m_legacyReporter->EndTestCase + ( testCaseStats.testInfo, + testCaseStats.totals, + testCaseStats.stdOut, + testCaseStats.stdErr ); + } + void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) { + if( testGroupStats.aborting ) + m_legacyReporter->Aborted(); + m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals ); + } + void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) { + m_legacyReporter->EndTesting( testRunStats.totals ); + } + void LegacyReporterAdapter::skipTest( TestCaseInfo const& ) { + } +} + +// #included from: catch_timer.hpp + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wc++11-long-long" +#endif + +#ifdef CATCH_PLATFORM_WINDOWS +#include <windows.h> +#else +#include <sys/time.h> +#endif + +namespace Catch { + + namespace { +#ifdef CATCH_PLATFORM_WINDOWS + uint64_t getCurrentTicks() { + static uint64_t hz=0, hzo=0; + if (!hz) { + QueryPerformanceFrequency((LARGE_INTEGER*)&hz); + QueryPerformanceCounter((LARGE_INTEGER*)&hzo); + } + uint64_t t; + QueryPerformanceCounter((LARGE_INTEGER*)&t); + return ((t-hzo)*1000000)/hz; + } +#else + uint64_t getCurrentTicks() { + timeval t; + gettimeofday(&t,NULL); + return static_cast<uint64_t>( t.tv_sec ) * 1000000ull + static_cast<uint64_t>( t.tv_usec ); + } +#endif + } + + void Timer::start() { + m_ticks = getCurrentTicks(); + } + unsigned int Timer::getElapsedMicroseconds() const { + return static_cast<unsigned int>(getCurrentTicks() - m_ticks); + } + unsigned int Timer::getElapsedMilliseconds() const { + return static_cast<unsigned int>(getElapsedMicroseconds()/1000); + } + double Timer::getElapsedSeconds() const { + return getElapsedMicroseconds()/1000000.0; + } + +} // namespace Catch + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif +// #included from: catch_common.hpp +#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED + +namespace Catch { + + bool startsWith( std::string const& s, std::string const& prefix ) { + return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix; + } + bool endsWith( std::string const& s, std::string const& suffix ) { + return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix; + } + bool contains( std::string const& s, std::string const& infix ) { + return s.find( infix ) != std::string::npos; + } + void toLowerInPlace( std::string& s ) { + std::transform( s.begin(), s.end(), s.begin(), ::tolower ); + } + std::string toLower( std::string const& s ) { + std::string lc = s; + toLowerInPlace( lc ); + return lc; + } + std::string trim( std::string const& str ) { + static char const* whitespaceChars = "\n\r\t "; + std::string::size_type start = str.find_first_not_of( whitespaceChars ); + std::string::size_type end = str.find_last_not_of( whitespaceChars ); + + return start != std::string::npos ? str.substr( start, 1+end-start ) : ""; + } + + bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) { + bool replaced = false; + std::size_t i = str.find( replaceThis ); + while( i != std::string::npos ) { + replaced = true; + str = str.substr( 0, i ) + withThis + str.substr( i+replaceThis.size() ); + if( i < str.size()-withThis.size() ) + i = str.find( replaceThis, i+withThis.size() ); + else + i = std::string::npos; + } + return replaced; + } + + pluralise::pluralise( std::size_t count, std::string const& label ) + : m_count( count ), + m_label( label ) + {} + + std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) { + os << pluraliser.m_count << " " << pluraliser.m_label; + if( pluraliser.m_count != 1 ) + os << "s"; + return os; + } + + SourceLineInfo::SourceLineInfo() : line( 0 ){} + SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line ) + : file( _file ), + line( _line ) + {} + SourceLineInfo::SourceLineInfo( SourceLineInfo const& other ) + : file( other.file ), + line( other.line ) + {} + bool SourceLineInfo::empty() const { + return file.empty(); + } + bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const { + return line == other.line && file == other.file; + } + bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const { + return line < other.line || ( line == other.line && file < other.file ); + } + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { +#ifndef __GNUG__ + os << info.file << "(" << info.line << ")"; +#else + os << info.file << ":" << info.line; +#endif + return os; + } + + void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) { + std::ostringstream oss; + oss << locationInfo << ": Internal Catch error: '" << message << "'"; + if( alwaysTrue() ) + throw std::logic_error( oss.str() ); + } +} + +// #included from: catch_section.hpp +#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED + +namespace Catch { + + SectionInfo::SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description ) + : name( _name ), + description( _description ), + lineInfo( _lineInfo ) + {} + + Section::Section( SectionInfo const& info ) + : m_info( info ), + m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) ) + { + m_timer.start(); + } + + Section::~Section() { + if( m_sectionIncluded ) + getResultCapture().sectionEnded( m_info, m_assertions, m_timer.getElapsedSeconds() ); + } + + // This indicates whether the section should be executed or not + Section::operator bool() const { + return m_sectionIncluded; + } + +} // end namespace Catch + +// #included from: catch_debugger.hpp +#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED + +#include <iostream> + +#ifdef CATCH_PLATFORM_MAC + + #include <assert.h> + #include <stdbool.h> + #include <sys/types.h> + #include <unistd.h> + #include <sys/sysctl.h> + + namespace Catch{ + + // The following function is taken directly from the following technical note: + // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html + + // Returns true if the current process is being debugged (either + // running under the debugger or has a debugger attached post facto). + bool isDebuggerActive(){ + + int mib[4]; + struct kinfo_proc info; + size_t size; + + // Initialize the flags so that, if sysctl fails for some bizarre + // reason, we get a predictable result. + + info.kp_proc.p_flag = 0; + + // Initialize mib, which tells sysctl the info we want, in this case + // we're looking for information about a specific process ID. + + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + + // Call sysctl. + + size = sizeof(info); + if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0) != 0 ) { + Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; + return false; + } + + // We're being debugged if the P_TRACED flag is set. + + return ( (info.kp_proc.p_flag & P_TRACED) != 0 ); + } + } // namespace Catch + +#elif defined(_MSC_VER) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#elif defined(__MINGW32__) + extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); + namespace Catch { + bool isDebuggerActive() { + return IsDebuggerPresent() != 0; + } + } +#else + namespace Catch { + inline bool isDebuggerActive() { return false; } + } +#endif // Platform + +#ifdef CATCH_PLATFORM_WINDOWS + extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* ); + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + ::OutputDebugStringA( text.c_str() ); + } + } +#else + namespace Catch { + void writeToDebugConsole( std::string const& text ) { + // !TBD: Need a version for Mac/ XCode and other IDEs + Catch::cout() << text; + } + } +#endif // Platform + +// #included from: catch_tostring.hpp +#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED + +namespace Catch { + +namespace Detail { + + std::string unprintableString = "{?}"; + + namespace { + struct Endianness { + enum Arch { Big, Little }; + + static Arch which() { + union _{ + int asInt; + char asChar[sizeof (int)]; + } u; + + u.asInt = 1; + return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little; + } + }; + } + + std::string rawMemoryToString( const void *object, std::size_t size ) + { + // Reverse order for little endian architectures + int i = 0, end = static_cast<int>( size ), inc = 1; + if( Endianness::which() == Endianness::Little ) { + i = end-1; + end = inc = -1; + } + + unsigned char const *bytes = static_cast<unsigned char const *>(object); + std::ostringstream os; + os << "0x" << std::setfill('0') << std::hex; + for( ; i != end; i += inc ) + os << std::setw(2) << static_cast<unsigned>(bytes[i]); + return os.str(); + } +} + +std::string toString( std::string const& value ) { + std::string s = value; + if( getCurrentContext().getConfig()->showInvisibles() ) { + for(size_t i = 0; i < s.size(); ++i ) { + std::string subs; + switch( s[i] ) { + case '\n': subs = "\\n"; break; + case '\t': subs = "\\t"; break; + default: break; + } + if( !subs.empty() ) { + s = s.substr( 0, i ) + subs + s.substr( i+1 ); + ++i; + } + } + } + return "\"" + s + "\""; +} +std::string toString( std::wstring const& value ) { + + std::string s; + s.reserve( value.size() ); + for(size_t i = 0; i < value.size(); ++i ) + s += value[i] <= 0xff ? static_cast<char>( value[i] ) : '?'; + return Catch::toString( s ); +} + +std::string toString( const char* const value ) { + return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" ); +} + +std::string toString( char* const value ) { + return Catch::toString( static_cast<const char*>( value ) ); +} + +std::string toString( const wchar_t* const value ) +{ + return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" ); +} + +std::string toString( wchar_t* const value ) +{ + return Catch::toString( static_cast<const wchar_t*>( value ) ); +} + +std::string toString( int value ) { + std::ostringstream oss; + if( value > 8192 ) + oss << "0x" << std::hex << value; + else + oss << value; + return oss.str(); +} + +std::string toString( unsigned long value ) { + std::ostringstream oss; + if( value > 8192 ) + oss << "0x" << std::hex << value; + else + oss << value; + return oss.str(); +} + +std::string toString( unsigned int value ) { + return Catch::toString( static_cast<unsigned long>( value ) ); +} + +template<typename T> +std::string fpToString( T value, int precision ) { + std::ostringstream oss; + oss << std::setprecision( precision ) + << std::fixed + << value; + std::string d = oss.str(); + std::size_t i = d.find_last_not_of( '0' ); + if( i != std::string::npos && i != d.size()-1 ) { + if( d[i] == '.' ) + i++; + d = d.substr( 0, i+1 ); + } + return d; +} + +std::string toString( const double value ) { + return fpToString( value, 10 ); +} +std::string toString( const float value ) { + return fpToString( value, 5 ) + "f"; +} + +std::string toString( bool value ) { + return value ? "true" : "false"; +} + +std::string toString( char value ) { + return value < ' ' + ? toString( static_cast<unsigned int>( value ) ) + : Detail::makeString( value ); +} + +std::string toString( signed char value ) { + return toString( static_cast<char>( value ) ); +} + +std::string toString( unsigned char value ) { + return toString( static_cast<char>( value ) ); +} + +#ifdef CATCH_CONFIG_CPP11_NULLPTR +std::string toString( std::nullptr_t ) { + return "nullptr"; +} +#endif + +#ifdef __OBJC__ + std::string toString( NSString const * const& nsstring ) { + if( !nsstring ) + return "nil"; + return "@" + toString([nsstring UTF8String]); + } + std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) { + if( !nsstring ) + return "nil"; + return "@" + toString([nsstring UTF8String]); + } + std::string toString( NSObject* const& nsObject ) { + return toString( [nsObject description] ); + } +#endif + +} // end namespace Catch + +// #included from: catch_result_builder.hpp +#define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED + +namespace Catch { + + ResultBuilder::ResultBuilder( char const* macroName, + SourceLineInfo const& lineInfo, + char const* capturedExpression, + ResultDisposition::Flags resultDisposition ) + : m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition ), + m_shouldDebugBreak( false ), + m_shouldThrow( false ) + {} + + ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) { + m_data.resultType = result; + return *this; + } + ResultBuilder& ResultBuilder::setResultType( bool result ) { + m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed; + return *this; + } + ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) { + m_exprComponents.lhs = lhs; + return *this; + } + ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) { + m_exprComponents.rhs = rhs; + return *this; + } + ResultBuilder& ResultBuilder::setOp( std::string const& op ) { + m_exprComponents.op = op; + return *this; + } + + void ResultBuilder::endExpression() { + m_exprComponents.testFalse = isFalseTest( m_assertionInfo.resultDisposition ); + captureExpression(); + } + + void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) { + m_assertionInfo.resultDisposition = resultDisposition; + m_stream.oss << Catch::translateActiveException(); + captureResult( ResultWas::ThrewException ); + } + + void ResultBuilder::captureResult( ResultWas::OfType resultType ) { + setResultType( resultType ); + captureExpression(); + } + + void ResultBuilder::captureExpression() { + AssertionResult result = build(); + getResultCapture().assertionEnded( result ); + + if( !result.isOk() ) { + if( getCurrentContext().getConfig()->shouldDebugBreak() ) + m_shouldDebugBreak = true; + if( getCurrentContext().getRunner()->aborting() || m_assertionInfo.resultDisposition == ResultDisposition::Normal ) + m_shouldThrow = true; + } + } + void ResultBuilder::react() { + if( m_shouldThrow ) + throw Catch::TestFailureException(); + } + + bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; } + bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); } + + AssertionResult ResultBuilder::build() const + { + assert( m_data.resultType != ResultWas::Unknown ); + + AssertionResultData data = m_data; + + // Flip bool results if testFalse is set + if( m_exprComponents.testFalse ) { + if( data.resultType == ResultWas::Ok ) + data.resultType = ResultWas::ExpressionFailed; + else if( data.resultType == ResultWas::ExpressionFailed ) + data.resultType = ResultWas::Ok; + } + + data.message = m_stream.oss.str(); + data.reconstructedExpression = reconstructExpression(); + if( m_exprComponents.testFalse ) { + if( m_exprComponents.op == "" ) + data.reconstructedExpression = "!" + data.reconstructedExpression; + else + data.reconstructedExpression = "!(" + data.reconstructedExpression + ")"; + } + return AssertionResult( m_assertionInfo, data ); + } + std::string ResultBuilder::reconstructExpression() const { + if( m_exprComponents.op == "" ) + return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + m_exprComponents.lhs; + else if( m_exprComponents.op == "matches" ) + return m_exprComponents.lhs + " " + m_exprComponents.rhs; + else if( m_exprComponents.op != "!" ) { + if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 && + m_exprComponents.lhs.find("\n") == std::string::npos && + m_exprComponents.rhs.find("\n") == std::string::npos ) + return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs; + else + return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs; + } + else + return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}"; + } + +} // end namespace Catch + +// #included from: catch_tag_alias_registry.hpp +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED + +// #included from: catch_tag_alias_registry.h +#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED + +#include <map> + +namespace Catch { + + class TagAliasRegistry : public ITagAliasRegistry { + public: + virtual ~TagAliasRegistry(); + virtual Option<TagAlias> find( std::string const& alias ) const; + virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const; + void add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + static TagAliasRegistry& get(); + + private: + std::map<std::string, TagAlias> m_registry; + }; + +} // end namespace Catch + +#include <map> +#include <iostream> + +namespace Catch { + + TagAliasRegistry::~TagAliasRegistry() {} + + Option<TagAlias> TagAliasRegistry::find( std::string const& alias ) const { + std::map<std::string, TagAlias>::const_iterator it = m_registry.find( alias ); + if( it != m_registry.end() ) + return it->second; + else + return Option<TagAlias>(); + } + + std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const { + std::string expandedTestSpec = unexpandedTestSpec; + for( std::map<std::string, TagAlias>::const_iterator it = m_registry.begin(), itEnd = m_registry.end(); + it != itEnd; + ++it ) { + std::size_t pos = expandedTestSpec.find( it->first ); + if( pos != std::string::npos ) { + expandedTestSpec = expandedTestSpec.substr( 0, pos ) + + it->second.tag + + expandedTestSpec.substr( pos + it->first.size() ); + } + } + return expandedTestSpec; + } + + void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { + + if( !startsWith( alias, "[@" ) || !endsWith( alias, "]" ) ) { + std::ostringstream oss; + oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo; + throw std::domain_error( oss.str().c_str() ); + } + if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) { + std::ostringstream oss; + oss << "error: tag alias, \"" << alias << "\" already registered.\n" + << "\tFirst seen at " << find(alias)->lineInfo << "\n" + << "\tRedefined at " << lineInfo; + throw std::domain_error( oss.str().c_str() ); + } + } + + TagAliasRegistry& TagAliasRegistry::get() { + static TagAliasRegistry instance; + return instance; + + } + + ITagAliasRegistry::~ITagAliasRegistry() {} + ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); } + + RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) { + try { + TagAliasRegistry::get().add( alias, tag, lineInfo ); + } + catch( std::exception& ex ) { + Colour colourGuard( Colour::Red ); + Catch::cerr() << ex.what() << std::endl; + exit(1); + } + } + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_xml.hpp +#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED + +// #included from: catch_reporter_bases.hpp +#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED + +#include <cstring> + +namespace Catch { + + struct StreamingReporterBase : SharedImpl<IStreamingReporter> { + + StreamingReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + {} + + virtual ~StreamingReporterBase(); + + virtual void noMatchingTestCases( std::string const& ) {} + + virtual void testRunStarting( TestRunInfo const& _testRunInfo ) { + currentTestRunInfo = _testRunInfo; + } + virtual void testGroupStarting( GroupInfo const& _groupInfo ) { + currentGroupInfo = _groupInfo; + } + + virtual void testCaseStarting( TestCaseInfo const& _testInfo ) { + currentTestCaseInfo = _testInfo; + } + virtual void sectionStarting( SectionInfo const& _sectionInfo ) { + m_sectionStack.push_back( _sectionInfo ); + } + + virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) { + m_sectionStack.pop_back(); + } + virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) { + currentTestCaseInfo.reset(); + } + virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) { + currentGroupInfo.reset(); + } + virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) { + currentTestCaseInfo.reset(); + currentGroupInfo.reset(); + currentTestRunInfo.reset(); + } + + virtual void skipTest( TestCaseInfo const& ) { + // Don't do anything with this by default. + // It can optionally be overridden in the derived class. + } + + Ptr<IConfig> m_config; + std::ostream& stream; + + LazyStat<TestRunInfo> currentTestRunInfo; + LazyStat<GroupInfo> currentGroupInfo; + LazyStat<TestCaseInfo> currentTestCaseInfo; + + std::vector<SectionInfo> m_sectionStack; + }; + + struct CumulativeReporterBase : SharedImpl<IStreamingReporter> { + template<typename T, typename ChildNodeT> + struct Node : SharedImpl<> { + explicit Node( T const& _value ) : value( _value ) {} + virtual ~Node() {} + + typedef std::vector<Ptr<ChildNodeT> > ChildNodes; + T value; + ChildNodes children; + }; + struct SectionNode : SharedImpl<> { + explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {} + virtual ~SectionNode(); + + bool operator == ( SectionNode const& other ) const { + return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo; + } + bool operator == ( Ptr<SectionNode> const& other ) const { + return operator==( *other ); + } + + SectionStats stats; + typedef std::vector<Ptr<SectionNode> > ChildSections; + typedef std::vector<AssertionStats> Assertions; + ChildSections childSections; + Assertions assertions; + std::string stdOut; + std::string stdErr; + }; + + struct BySectionInfo { + BySectionInfo( SectionInfo const& other ) : m_other( other ) {} + BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {} + bool operator() ( Ptr<SectionNode> const& node ) const { + return node->stats.sectionInfo.lineInfo == m_other.lineInfo; + } + private: + void operator=( BySectionInfo const& ); + SectionInfo const& m_other; + }; + + typedef Node<TestCaseStats, SectionNode> TestCaseNode; + typedef Node<TestGroupStats, TestCaseNode> TestGroupNode; + typedef Node<TestRunStats, TestGroupNode> TestRunNode; + + CumulativeReporterBase( ReporterConfig const& _config ) + : m_config( _config.fullConfig() ), + stream( _config.stream() ) + {} + ~CumulativeReporterBase(); + + virtual void testRunStarting( TestRunInfo const& ) {} + virtual void testGroupStarting( GroupInfo const& ) {} + + virtual void testCaseStarting( TestCaseInfo const& ) {} + + virtual void sectionStarting( SectionInfo const& sectionInfo ) { + SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); + Ptr<SectionNode> node; + if( m_sectionStack.empty() ) { + if( !m_rootSection ) + m_rootSection = new SectionNode( incompleteStats ); + node = m_rootSection; + } + else { + SectionNode& parentNode = *m_sectionStack.back(); + SectionNode::ChildSections::const_iterator it = + std::find_if( parentNode.childSections.begin(), + parentNode.childSections.end(), + BySectionInfo( sectionInfo ) ); + if( it == parentNode.childSections.end() ) { + node = new SectionNode( incompleteStats ); + parentNode.childSections.push_back( node ); + } + else + node = *it; + } + m_sectionStack.push_back( node ); + m_deepestSection = node; + } + + virtual void assertionStarting( AssertionInfo const& ) {} + + virtual bool assertionEnded( AssertionStats const& assertionStats ) { + assert( !m_sectionStack.empty() ); + SectionNode& sectionNode = *m_sectionStack.back(); + sectionNode.assertions.push_back( assertionStats ); + return true; + } + virtual void sectionEnded( SectionStats const& sectionStats ) { + assert( !m_sectionStack.empty() ); + SectionNode& node = *m_sectionStack.back(); + node.stats = sectionStats; + m_sectionStack.pop_back(); + } + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + Ptr<TestCaseNode> node = new TestCaseNode( testCaseStats ); + assert( m_sectionStack.size() == 0 ); + node->children.push_back( m_rootSection ); + m_testCases.push_back( node ); + m_rootSection.reset(); + + assert( m_deepestSection ); + m_deepestSection->stdOut = testCaseStats.stdOut; + m_deepestSection->stdErr = testCaseStats.stdErr; + } + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + Ptr<TestGroupNode> node = new TestGroupNode( testGroupStats ); + node->children.swap( m_testCases ); + m_testGroups.push_back( node ); + } + virtual void testRunEnded( TestRunStats const& testRunStats ) { + Ptr<TestRunNode> node = new TestRunNode( testRunStats ); + node->children.swap( m_testGroups ); + m_testRuns.push_back( node ); + testRunEndedCumulative(); + } + virtual void testRunEndedCumulative() = 0; + + virtual void skipTest( TestCaseInfo const& ) {} + + Ptr<IConfig> m_config; + std::ostream& stream; + std::vector<AssertionStats> m_assertions; + std::vector<std::vector<Ptr<SectionNode> > > m_sections; + std::vector<Ptr<TestCaseNode> > m_testCases; + std::vector<Ptr<TestGroupNode> > m_testGroups; + + std::vector<Ptr<TestRunNode> > m_testRuns; + + Ptr<SectionNode> m_rootSection; + Ptr<SectionNode> m_deepestSection; + std::vector<Ptr<SectionNode> > m_sectionStack; + + }; + + template<char C> + char const* getLineOfChars() { + static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0}; + if( !*line ) { + memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 ); + line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0; + } + return line; + } + +} // end namespace Catch + +// #included from: ../internal/catch_reporter_registrars.hpp +#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED + +namespace Catch { + + template<typename T> + class LegacyReporterRegistrar { + + class ReporterFactory : public IReporterFactory { + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new LegacyReporterAdapter( new T( config ) ); + } + + virtual std::string getDescription() const { + return T::getDescription(); + } + }; + + public: + + LegacyReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); + } + }; + + template<typename T> + class ReporterRegistrar { + + class ReporterFactory : public IReporterFactory { + + // *** Please Note ***: + // - If you end up here looking at a compiler error because it's trying to register + // your custom reporter class be aware that the native reporter interface has changed + // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via + // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter. + // However please consider updating to the new interface as the old one is now + // deprecated and will probably be removed quite soon! + // Please contact me via github if you have any questions at all about this. + // In fact, ideally, please contact me anyway to let me know you've hit this - as I have + // no idea who is actually using custom reporters at all (possibly no-one!). + // The new interface is designed to minimise exposure to interface changes in the future. + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new T( config ); + } + + virtual std::string getDescription() const { + return T::getDescription(); + } + }; + + public: + + ReporterRegistrar( std::string const& name ) { + getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); + } + }; +} + +#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \ + namespace{ Catch::LegacyReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } +#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ + namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); } + +// #included from: ../internal/catch_xmlwriter.hpp +#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED + +#include <sstream> +#include <string> +#include <vector> + +namespace Catch { + + class XmlWriter { + public: + + class ScopedElement { + public: + ScopedElement( XmlWriter* writer ) + : m_writer( writer ) + {} + + ScopedElement( ScopedElement const& other ) + : m_writer( other.m_writer ){ + other.m_writer = NULL; + } + + ~ScopedElement() { + if( m_writer ) + m_writer->endElement(); + } + + ScopedElement& writeText( std::string const& text, bool indent = true ) { + m_writer->writeText( text, indent ); + return *this; + } + + template<typename T> + ScopedElement& writeAttribute( std::string const& name, T const& attribute ) { + m_writer->writeAttribute( name, attribute ); + return *this; + } + + private: + mutable XmlWriter* m_writer; + }; + + XmlWriter() + : m_tagIsOpen( false ), + m_needsNewline( false ), + m_os( &Catch::cout() ) + {} + + XmlWriter( std::ostream& os ) + : m_tagIsOpen( false ), + m_needsNewline( false ), + m_os( &os ) + {} + + ~XmlWriter() { + while( !m_tags.empty() ) + endElement(); + } + +//# ifndef CATCH_CPP11_OR_GREATER +// XmlWriter& operator = ( XmlWriter const& other ) { +// XmlWriter temp( other ); +// swap( temp ); +// return *this; +// } +//# else +// XmlWriter( XmlWriter const& ) = default; +// XmlWriter( XmlWriter && ) = default; +// XmlWriter& operator = ( XmlWriter const& ) = default; +// XmlWriter& operator = ( XmlWriter && ) = default; +//# endif +// +// void swap( XmlWriter& other ) { +// std::swap( m_tagIsOpen, other.m_tagIsOpen ); +// std::swap( m_needsNewline, other.m_needsNewline ); +// std::swap( m_tags, other.m_tags ); +// std::swap( m_indent, other.m_indent ); +// std::swap( m_os, other.m_os ); +// } + + XmlWriter& startElement( std::string const& name ) { + ensureTagClosed(); + newlineIfNecessary(); + stream() << m_indent << "<" << name; + m_tags.push_back( name ); + m_indent += " "; + m_tagIsOpen = true; + return *this; + } + + ScopedElement scopedElement( std::string const& name ) { + ScopedElement scoped( this ); + startElement( name ); + return scoped; + } + + XmlWriter& endElement() { + newlineIfNecessary(); + m_indent = m_indent.substr( 0, m_indent.size()-2 ); + if( m_tagIsOpen ) { + stream() << "/>\n"; + m_tagIsOpen = false; + } + else { + stream() << m_indent << "</" << m_tags.back() << ">\n"; + } + m_tags.pop_back(); + return *this; + } + + XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { + if( !name.empty() && !attribute.empty() ) { + stream() << " " << name << "=\""; + writeEncodedText( attribute ); + stream() << "\""; + } + return *this; + } + + XmlWriter& writeAttribute( std::string const& name, bool attribute ) { + stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\""; + return *this; + } + + template<typename T> + XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { + if( !name.empty() ) + stream() << " " << name << "=\"" << attribute << "\""; + return *this; + } + + XmlWriter& writeText( std::string const& text, bool indent = true ) { + if( !text.empty() ){ + bool tagWasOpen = m_tagIsOpen; + ensureTagClosed(); + if( tagWasOpen && indent ) + stream() << m_indent; + writeEncodedText( text ); + m_needsNewline = true; + } + return *this; + } + + XmlWriter& writeComment( std::string const& text ) { + ensureTagClosed(); + stream() << m_indent << "<!--" << text << "-->"; + m_needsNewline = true; + return *this; + } + + XmlWriter& writeBlankLine() { + ensureTagClosed(); + stream() << "\n"; + return *this; + } + + void setStream( std::ostream& os ) { + m_os = &os; + } + + private: + XmlWriter( XmlWriter const& ); + void operator=( XmlWriter const& ); + + std::ostream& stream() { + return *m_os; + } + + void ensureTagClosed() { + if( m_tagIsOpen ) { + stream() << ">\n"; + m_tagIsOpen = false; + } + } + + void newlineIfNecessary() { + if( m_needsNewline ) { + stream() << "\n"; + m_needsNewline = false; + } + } + + void writeEncodedText( std::string const& text ) { + static const char* charsToEncode = "<&\""; + std::string mtext = text; + std::string::size_type pos = mtext.find_first_of( charsToEncode ); + while( pos != std::string::npos ) { + stream() << mtext.substr( 0, pos ); + + switch( mtext[pos] ) { + case '<': + stream() << "<"; + break; + case '&': + stream() << "&"; + break; + case '\"': + stream() << """; + break; + } + mtext = mtext.substr( pos+1 ); + pos = mtext.find_first_of( charsToEncode ); + } + stream() << mtext; + } + + bool m_tagIsOpen; + bool m_needsNewline; + std::vector<std::string> m_tags; + std::string m_indent; + std::ostream* m_os; + }; + +} +namespace Catch { + class XmlReporter : public StreamingReporterBase { + public: + XmlReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_sectionDepth( 0 ) + {} + + virtual ~XmlReporter(); + + static std::string getDescription() { + return "Reports test results as an XML document"; + } + + public: // StreamingReporterBase + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = true; + return prefs; + } + + virtual void noMatchingTestCases( std::string const& s ) { + StreamingReporterBase::noMatchingTestCases( s ); + } + + virtual void testRunStarting( TestRunInfo const& testInfo ) { + StreamingReporterBase::testRunStarting( testInfo ); + m_xml.setStream( stream ); + m_xml.startElement( "Catch" ); + if( !m_config->name().empty() ) + m_xml.writeAttribute( "name", m_config->name() ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) { + StreamingReporterBase::testGroupStarting( groupInfo ); + m_xml.startElement( "Group" ) + .writeAttribute( "name", groupInfo.name ); + } + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) { + StreamingReporterBase::testCaseStarting(testInfo); + m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); + + if ( m_config->showDurations() == ShowDurations::Always ) + m_testCaseTimer.start(); + } + + virtual void sectionStarting( SectionInfo const& sectionInfo ) { + StreamingReporterBase::sectionStarting( sectionInfo ); + if( m_sectionDepth++ > 0 ) { + m_xml.startElement( "Section" ) + .writeAttribute( "name", trim( sectionInfo.name ) ) + .writeAttribute( "description", sectionInfo.description ); + } + } + + virtual void assertionStarting( AssertionInfo const& ) { } + + virtual bool assertionEnded( AssertionStats const& assertionStats ) { + const AssertionResult& assertionResult = assertionStats.assertionResult; + + // Print any info messages in <Info> tags. + if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) { + for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end(); + it != itEnd; + ++it ) { + if( it->type == ResultWas::Info ) { + m_xml.scopedElement( "Info" ) + .writeText( it->message ); + } else if ( it->type == ResultWas::Warning ) { + m_xml.scopedElement( "Warning" ) + .writeText( it->message ); + } + } + } + + // Drop out if result was successful but we're not printing them. + if( !m_config->includeSuccessfulResults() && isOk(assertionResult.getResultType()) ) + return true; + + // Print the expression if there is one. + if( assertionResult.hasExpression() ) { + m_xml.startElement( "Expression" ) + .writeAttribute( "success", assertionResult.succeeded() ) + .writeAttribute( "type", assertionResult.getTestMacroName() ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ); + + m_xml.scopedElement( "Original" ) + .writeText( assertionResult.getExpression() ); + m_xml.scopedElement( "Expanded" ) + .writeText( assertionResult.getExpandedExpression() ); + } + + // And... Print a result applicable to each result type. + switch( assertionResult.getResultType() ) { + case ResultWas::ThrewException: + m_xml.scopedElement( "Exception" ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::FatalErrorCondition: + m_xml.scopedElement( "Fatal Error Condition" ) + .writeAttribute( "filename", assertionResult.getSourceInfo().file ) + .writeAttribute( "line", assertionResult.getSourceInfo().line ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::Info: + m_xml.scopedElement( "Info" ) + .writeText( assertionResult.getMessage() ); + break; + case ResultWas::Warning: + // Warning will already have been written + break; + case ResultWas::ExplicitFailure: + m_xml.scopedElement( "Failure" ) + .writeText( assertionResult.getMessage() ); + break; + default: + break; + } + + if( assertionResult.hasExpression() ) + m_xml.endElement(); + + return true; + } + + virtual void sectionEnded( SectionStats const& sectionStats ) { + StreamingReporterBase::sectionEnded( sectionStats ); + if( --m_sectionDepth > 0 ) { + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); + e.writeAttribute( "successes", sectionStats.assertions.passed ); + e.writeAttribute( "failures", sectionStats.assertions.failed ); + e.writeAttribute( "expectedFailures", sectionStats.assertions.failedButOk ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", sectionStats.durationInSeconds ); + + m_xml.endElement(); + } + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + StreamingReporterBase::testCaseEnded( testCaseStats ); + XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); + e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); + + if ( m_config->showDurations() == ShowDurations::Always ) + e.writeAttribute( "durationInSeconds", m_testCaseTimer.getElapsedSeconds() ); + + m_xml.endElement(); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + StreamingReporterBase::testGroupEnded( testGroupStats ); + // TODO: Check testGroupStats.aborting and act accordingly. + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) + .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + virtual void testRunEnded( TestRunStats const& testRunStats ) { + StreamingReporterBase::testRunEnded( testRunStats ); + m_xml.scopedElement( "OverallResults" ) + .writeAttribute( "successes", testRunStats.totals.assertions.passed ) + .writeAttribute( "failures", testRunStats.totals.assertions.failed ) + .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); + m_xml.endElement(); + } + + private: + Timer m_testCaseTimer; + XmlWriter m_xml; + int m_sectionDepth; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "xml", XmlReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_junit.hpp +#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED + +#include <assert.h> + +namespace Catch { + + class JunitReporter : public CumulativeReporterBase { + public: + JunitReporter( ReporterConfig const& _config ) + : CumulativeReporterBase( _config ), + xml( _config.stream() ) + {} + + ~JunitReporter(); + + static std::string getDescription() { + return "Reports test results in an XML format that looks like Ant's junitreport target"; + } + + virtual void noMatchingTestCases( std::string const& /*spec*/ ) {} + + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = true; + return prefs; + } + + virtual void testRunStarting( TestRunInfo const& runInfo ) { + CumulativeReporterBase::testRunStarting( runInfo ); + xml.startElement( "testsuites" ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) { + suiteTimer.start(); + stdOutForSuite.str(""); + stdErrForSuite.str(""); + unexpectedExceptions = 0; + CumulativeReporterBase::testGroupStarting( groupInfo ); + } + + virtual bool assertionEnded( AssertionStats const& assertionStats ) { + if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException ) + unexpectedExceptions++; + return CumulativeReporterBase::assertionEnded( assertionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + stdOutForSuite << testCaseStats.stdOut; + stdErrForSuite << testCaseStats.stdErr; + CumulativeReporterBase::testCaseEnded( testCaseStats ); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + double suiteTime = suiteTimer.getElapsedSeconds(); + CumulativeReporterBase::testGroupEnded( testGroupStats ); + writeGroup( *m_testGroups.back(), suiteTime ); + } + + virtual void testRunEndedCumulative() { + xml.endElement(); + } + + void writeGroup( TestGroupNode const& groupNode, double suiteTime ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" ); + TestGroupStats const& stats = groupNode.value; + xml.writeAttribute( "name", stats.groupInfo.name ); + xml.writeAttribute( "errors", unexpectedExceptions ); + xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions ); + xml.writeAttribute( "tests", stats.totals.assertions.total() ); + xml.writeAttribute( "hostname", "tbd" ); // !TBD + if( m_config->showDurations() == ShowDurations::Never ) + xml.writeAttribute( "time", "" ); + else + xml.writeAttribute( "time", suiteTime ); + xml.writeAttribute( "timestamp", "tbd" ); // !TBD + + // Write test cases + for( TestGroupNode::ChildNodes::const_iterator + it = groupNode.children.begin(), itEnd = groupNode.children.end(); + it != itEnd; + ++it ) + writeTestCase( **it ); + + xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false ); + xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false ); + } + + void writeTestCase( TestCaseNode const& testCaseNode ) { + TestCaseStats const& stats = testCaseNode.value; + + // All test cases have exactly one section - which represents the + // test case itself. That section may have 0-n nested sections + assert( testCaseNode.children.size() == 1 ); + SectionNode const& rootSection = *testCaseNode.children.front(); + + std::string className = stats.testInfo.className; + + if( className.empty() ) { + if( rootSection.childSections.empty() ) + className = "global"; + } + writeSection( className, "", rootSection ); + } + + void writeSection( std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode ) { + std::string name = trim( sectionNode.stats.sectionInfo.name ); + if( !rootName.empty() ) + name = rootName + "/" + name; + + if( !sectionNode.assertions.empty() || + !sectionNode.stdOut.empty() || + !sectionNode.stdErr.empty() ) { + XmlWriter::ScopedElement e = xml.scopedElement( "testcase" ); + if( className.empty() ) { + xml.writeAttribute( "classname", name ); + xml.writeAttribute( "name", "root" ); + } + else { + xml.writeAttribute( "classname", className ); + xml.writeAttribute( "name", name ); + } + xml.writeAttribute( "time", Catch::toString( sectionNode.stats.durationInSeconds ) ); + + writeAssertions( sectionNode ); + + if( !sectionNode.stdOut.empty() ) + xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false ); + if( !sectionNode.stdErr.empty() ) + xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false ); + } + for( SectionNode::ChildSections::const_iterator + it = sectionNode.childSections.begin(), + itEnd = sectionNode.childSections.end(); + it != itEnd; + ++it ) + if( className.empty() ) + writeSection( name, "", **it ); + else + writeSection( className, name, **it ); + } + + void writeAssertions( SectionNode const& sectionNode ) { + for( SectionNode::Assertions::const_iterator + it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end(); + it != itEnd; + ++it ) + writeAssertion( *it ); + } + void writeAssertion( AssertionStats const& stats ) { + AssertionResult const& result = stats.assertionResult; + if( !result.isOk() ) { + std::string elementName; + switch( result.getResultType() ) { + case ResultWas::ThrewException: + case ResultWas::FatalErrorCondition: + elementName = "error"; + break; + case ResultWas::ExplicitFailure: + elementName = "failure"; + break; + case ResultWas::ExpressionFailed: + elementName = "failure"; + break; + case ResultWas::DidntThrowException: + elementName = "failure"; + break; + + // We should never see these here: + case ResultWas::Info: + case ResultWas::Warning: + case ResultWas::Ok: + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + elementName = "internalError"; + break; + } + + XmlWriter::ScopedElement e = xml.scopedElement( elementName ); + + xml.writeAttribute( "message", result.getExpandedExpression() ); + xml.writeAttribute( "type", result.getTestMacroName() ); + + std::ostringstream oss; + if( !result.getMessage().empty() ) + oss << result.getMessage() << "\n"; + for( std::vector<MessageInfo>::const_iterator + it = stats.infoMessages.begin(), + itEnd = stats.infoMessages.end(); + it != itEnd; + ++it ) + if( it->type == ResultWas::Info ) + oss << it->message << "\n"; + + oss << "at " << result.getSourceInfo(); + xml.writeText( oss.str(), false ); + } + } + + XmlWriter xml; + Timer suiteTimer; + std::ostringstream stdOutForSuite; + std::ostringstream stdErrForSuite; + unsigned int unexpectedExceptions; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_console.hpp +#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED + +namespace Catch { + + struct ConsoleReporter : StreamingReporterBase { + ConsoleReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ), + m_headerPrinted( false ) + {} + + virtual ~ConsoleReporter(); + static std::string getDescription() { + return "Reports test results as plain lines of text"; + } + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = false; + return prefs; + } + + virtual void noMatchingTestCases( std::string const& spec ) { + stream << "No test cases matched '" << spec << "'" << std::endl; + } + + virtual void assertionStarting( AssertionInfo const& ) { + } + + virtual bool assertionEnded( AssertionStats const& _assertionStats ) { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + lazyPrint(); + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + stream << std::endl; + return true; + } + + virtual void sectionStarting( SectionInfo const& _sectionInfo ) { + m_headerPrinted = false; + StreamingReporterBase::sectionStarting( _sectionInfo ); + } + virtual void sectionEnded( SectionStats const& _sectionStats ) { + if( _sectionStats.missingAssertions ) { + lazyPrint(); + Colour colour( Colour::ResultError ); + if( m_sectionStack.size() > 1 ) + stream << "\nNo assertions in section"; + else + stream << "\nNo assertions in test case"; + stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; + } + if( m_headerPrinted ) { + if( m_config->showDurations() == ShowDurations::Always ) + stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl; + m_headerPrinted = false; + } + else { + if( m_config->showDurations() == ShowDurations::Always ) + stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << "s" << std::endl; + } + StreamingReporterBase::sectionEnded( _sectionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) { + StreamingReporterBase::testCaseEnded( _testCaseStats ); + m_headerPrinted = false; + } + virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) { + if( currentGroupInfo.used ) { + printSummaryDivider(); + stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; + printTotals( _testGroupStats.totals ); + stream << "\n" << std::endl; + } + StreamingReporterBase::testGroupEnded( _testGroupStats ); + } + virtual void testRunEnded( TestRunStats const& _testRunStats ) { + printTotalsDivider( _testRunStats.totals ); + printTotals( _testRunStats.totals ); + stream << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + private: + + class AssertionPrinter { + void operator= ( AssertionPrinter const& ); + public: + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) + : stream( _stream ), + stats( _stats ), + result( _stats.assertionResult ), + colour( Colour::None ), + message( result.getMessage() ), + messages( _stats.infoMessages ), + printInfoMessages( _printInfoMessages ) + { + switch( result.getResultType() ) { + case ResultWas::Ok: + colour = Colour::Success; + passOrFail = "PASSED"; + //if( result.hasMessage() ) + if( _stats.infoMessages.size() == 1 ) + messageLabel = "with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "with messages"; + break; + case ResultWas::ExpressionFailed: + if( result.isOk() ) { + colour = Colour::Success; + passOrFail = "FAILED - but was ok"; + } + else { + colour = Colour::Error; + passOrFail = "FAILED"; + } + if( _stats.infoMessages.size() == 1 ) + messageLabel = "with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "with messages"; + break; + case ResultWas::ThrewException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to unexpected exception with message"; + break; + case ResultWas::FatalErrorCondition: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "due to a fatal error condition"; + break; + case ResultWas::DidntThrowException: + colour = Colour::Error; + passOrFail = "FAILED"; + messageLabel = "because no exception was thrown where one was expected"; + break; + case ResultWas::Info: + messageLabel = "info"; + break; + case ResultWas::Warning: + messageLabel = "warning"; + break; + case ResultWas::ExplicitFailure: + passOrFail = "FAILED"; + colour = Colour::Error; + if( _stats.infoMessages.size() == 1 ) + messageLabel = "explicitly with message"; + if( _stats.infoMessages.size() > 1 ) + messageLabel = "explicitly with messages"; + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + passOrFail = "** internal error **"; + colour = Colour::Error; + break; + } + } + + void print() const { + printSourceInfo(); + if( stats.totals.assertions.total() > 0 ) { + if( result.isOk() ) + stream << "\n"; + printResultType(); + printOriginalExpression(); + printReconstructedExpression(); + } + else { + stream << "\n"; + } + printMessage(); + } + + private: + void printResultType() const { + if( !passOrFail.empty() ) { + Colour colourGuard( colour ); + stream << passOrFail << ":\n"; + } + } + void printOriginalExpression() const { + if( result.hasExpression() ) { + Colour colourGuard( Colour::OriginalExpression ); + stream << " "; + stream << result.getExpressionInMacro(); + stream << "\n"; + } + } + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + stream << "with expansion:\n"; + Colour colourGuard( Colour::ReconstructedExpression ); + stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << "\n"; + } + } + void printMessage() const { + if( !messageLabel.empty() ) + stream << messageLabel << ":" << "\n"; + for( std::vector<MessageInfo>::const_iterator it = messages.begin(), itEnd = messages.end(); + it != itEnd; + ++it ) { + // If this assertion is a warning ignore any INFO messages + if( printInfoMessages || it->type != ResultWas::Info ) + stream << Text( it->message, TextAttributes().setIndent(2) ) << "\n"; + } + } + void printSourceInfo() const { + Colour colourGuard( Colour::FileName ); + stream << result.getSourceInfo() << ": "; + } + + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + Colour::Code colour; + std::string passOrFail; + std::string messageLabel; + std::string message; + std::vector<MessageInfo> messages; + bool printInfoMessages; + }; + + void lazyPrint() { + + if( !currentTestRunInfo.used ) + lazyPrintRunInfo(); + if( !currentGroupInfo.used ) + lazyPrintGroupInfo(); + + if( !m_headerPrinted ) { + printTestCaseAndSectionHeader(); + m_headerPrinted = true; + } + } + void lazyPrintRunInfo() { + stream << "\n" << getLineOfChars<'~'>() << "\n"; + Colour colour( Colour::SecondaryText ); + stream << currentTestRunInfo->name + << " is a Catch v" << libraryVersion.majorVersion << "." + << libraryVersion.minorVersion << " b" + << libraryVersion.buildNumber; + if( libraryVersion.branchName != std::string( "master" ) ) + stream << " (" << libraryVersion.branchName << ")"; + stream << " host application.\n" + << "Run with -? for options\n\n"; + + if( m_config->rngSeed() != 0 ) + stream << "Randomness seeded to: " << m_config->rngSeed() << "\n\n"; + + currentTestRunInfo.used = true; + } + void lazyPrintGroupInfo() { + if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) { + printClosedHeader( "Group: " + currentGroupInfo->name ); + currentGroupInfo.used = true; + } + } + void printTestCaseAndSectionHeader() { + assert( !m_sectionStack.empty() ); + printOpenHeader( currentTestCaseInfo->name ); + + if( m_sectionStack.size() > 1 ) { + Colour colourGuard( Colour::Headers ); + + std::vector<SectionInfo>::const_iterator + it = m_sectionStack.begin()+1, // Skip first section (test case) + itEnd = m_sectionStack.end(); + for( ; it != itEnd; ++it ) + printHeaderString( it->name, 2 ); + } + + SourceLineInfo lineInfo = m_sectionStack.front().lineInfo; + + if( !lineInfo.empty() ){ + stream << getLineOfChars<'-'>() << "\n"; + Colour colourGuard( Colour::FileName ); + stream << lineInfo << "\n"; + } + stream << getLineOfChars<'.'>() << "\n" << std::endl; + } + + void printClosedHeader( std::string const& _name ) { + printOpenHeader( _name ); + stream << getLineOfChars<'.'>() << "\n"; + } + void printOpenHeader( std::string const& _name ) { + stream << getLineOfChars<'-'>() << "\n"; + { + Colour colourGuard( Colour::Headers ); + printHeaderString( _name ); + } + } + + // if string has a : in first line will set indent to follow it on + // subsequent lines + void printHeaderString( std::string const& _string, std::size_t indent = 0 ) { + std::size_t i = _string.find( ": " ); + if( i != std::string::npos ) + i+=2; + else + i = 0; + stream << Text( _string, TextAttributes() + .setIndent( indent+i) + .setInitialIndent( indent ) ) << "\n"; + } + + struct SummaryColumn { + + SummaryColumn( std::string const& _label, Colour::Code _colour ) + : label( _label ), + colour( _colour ) + {} + SummaryColumn addRow( std::size_t count ) { + std::ostringstream oss; + oss << count; + std::string row = oss.str(); + for( std::vector<std::string>::iterator it = rows.begin(); it != rows.end(); ++it ) { + while( it->size() < row.size() ) + *it = " " + *it; + while( it->size() > row.size() ) + row = " " + row; + } + rows.push_back( row ); + return *this; + } + + std::string label; + Colour::Code colour; + std::vector<std::string> rows; + + }; + + void printTotals( Totals const& totals ) { + if( totals.testCases.total() == 0 ) { + stream << Colour( Colour::Warning ) << "No tests ran\n"; + } + else if( totals.assertions.total() > 0 && totals.assertions.allPassed() ) { + stream << Colour( Colour::ResultSuccess ) << "All tests passed"; + stream << " (" + << pluralise( totals.assertions.passed, "assertion" ) << " in " + << pluralise( totals.testCases.passed, "test case" ) << ")" + << "\n"; + } + else { + + std::vector<SummaryColumn> columns; + columns.push_back( SummaryColumn( "", Colour::None ) + .addRow( totals.testCases.total() ) + .addRow( totals.assertions.total() ) ); + columns.push_back( SummaryColumn( "passed", Colour::Success ) + .addRow( totals.testCases.passed ) + .addRow( totals.assertions.passed ) ); + columns.push_back( SummaryColumn( "failed", Colour::ResultError ) + .addRow( totals.testCases.failed ) + .addRow( totals.assertions.failed ) ); + columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure ) + .addRow( totals.testCases.failedButOk ) + .addRow( totals.assertions.failedButOk ) ); + + printSummaryRow( "test cases", columns, 0 ); + printSummaryRow( "assertions", columns, 1 ); + } + } + void printSummaryRow( std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row ) { + for( std::vector<SummaryColumn>::const_iterator it = cols.begin(); it != cols.end(); ++it ) { + std::string value = it->rows[row]; + if( it->label.empty() ) { + stream << label << ": "; + if( value != "0" ) + stream << value; + else + stream << Colour( Colour::Warning ) << "- none -"; + } + else if( value != "0" ) { + stream << Colour( Colour::LightGrey ) << " | "; + stream << Colour( it->colour ) + << value << " " << it->label; + } + } + stream << "\n"; + } + + static std::size_t makeRatio( std::size_t number, std::size_t total ) { + std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0; + return ( ratio == 0 && number > 0 ) ? 1 : ratio; + } + static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) { + if( i > j && i > k ) + return i; + else if( j > k ) + return j; + else + return k; + } + + void printTotalsDivider( Totals const& totals ) { + if( totals.testCases.total() > 0 ) { + std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() ); + std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() ); + std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() ); + while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 ) + findMax( failedRatio, failedButOkRatio, passedRatio )++; + while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 ) + findMax( failedRatio, failedButOkRatio, passedRatio )--; + + stream << Colour( Colour::Error ) << std::string( failedRatio, '=' ); + stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' ); + if( totals.testCases.allPassed() ) + stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' ); + else + stream << Colour( Colour::Success ) << std::string( passedRatio, '=' ); + } + else { + stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' ); + } + stream << "\n"; + } + void printSummaryDivider() { + stream << getLineOfChars<'-'>() << "\n"; + } + + private: + bool m_headerPrinted; + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter ) + +} // end namespace Catch + +// #included from: ../reporters/catch_reporter_compact.hpp +#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED + +namespace Catch { + + struct CompactReporter : StreamingReporterBase { + + CompactReporter( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} + + virtual ~CompactReporter(); + + static std::string getDescription() { + return "Reports test results on a single line, suitable for IDEs"; + } + + virtual ReporterPreferences getPreferences() const { + ReporterPreferences prefs; + prefs.shouldRedirectStdOut = false; + return prefs; + } + + virtual void noMatchingTestCases( std::string const& spec ) { + stream << "No test cases matched '" << spec << "'" << std::endl; + } + + virtual void assertionStarting( AssertionInfo const& ) { + } + + virtual bool assertionEnded( AssertionStats const& _assertionStats ) { + AssertionResult const& result = _assertionStats.assertionResult; + + bool printInfoMessages = true; + + // Drop out if result was successful and we're not printing those + if( !m_config->includeSuccessfulResults() && result.isOk() ) { + if( result.getResultType() != ResultWas::Warning ) + return false; + printInfoMessages = false; + } + + AssertionPrinter printer( stream, _assertionStats, printInfoMessages ); + printer.print(); + + stream << std::endl; + return true; + } + + virtual void testRunEnded( TestRunStats const& _testRunStats ) { + printTotals( _testRunStats.totals ); + stream << "\n" << std::endl; + StreamingReporterBase::testRunEnded( _testRunStats ); + } + + private: + class AssertionPrinter { + void operator= ( AssertionPrinter const& ); + public: + AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages ) + : stream( _stream ) + , stats( _stats ) + , result( _stats.assertionResult ) + , messages( _stats.infoMessages ) + , itMessage( _stats.infoMessages.begin() ) + , printInfoMessages( _printInfoMessages ) + {} + + void print() { + printSourceInfo(); + + itMessage = messages.begin(); + + switch( result.getResultType() ) { + case ResultWas::Ok: + printResultType( Colour::ResultSuccess, passedString() ); + printOriginalExpression(); + printReconstructedExpression(); + if ( ! result.hasExpression() ) + printRemainingMessages( Colour::None ); + else + printRemainingMessages(); + break; + case ResultWas::ExpressionFailed: + if( result.isOk() ) + printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) ); + else + printResultType( Colour::Error, failedString() ); + printOriginalExpression(); + printReconstructedExpression(); + printRemainingMessages(); + break; + case ResultWas::ThrewException: + printResultType( Colour::Error, failedString() ); + printIssue( "unexpected exception with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::FatalErrorCondition: + printResultType( Colour::Error, failedString() ); + printIssue( "fatal error condition with message:" ); + printMessage(); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::DidntThrowException: + printResultType( Colour::Error, failedString() ); + printIssue( "expected exception, got none" ); + printExpressionWas(); + printRemainingMessages(); + break; + case ResultWas::Info: + printResultType( Colour::None, "info" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::Warning: + printResultType( Colour::None, "warning" ); + printMessage(); + printRemainingMessages(); + break; + case ResultWas::ExplicitFailure: + printResultType( Colour::Error, failedString() ); + printIssue( "explicitly" ); + printRemainingMessages( Colour::None ); + break; + // These cases are here to prevent compiler warnings + case ResultWas::Unknown: + case ResultWas::FailureBit: + case ResultWas::Exception: + printResultType( Colour::Error, "** internal error **" ); + break; + } + } + + private: + // Colour::LightGrey + + static Colour::Code dimColour() { return Colour::FileName; } + +#ifdef CATCH_PLATFORM_MAC + static const char* failedString() { return "FAILED"; } + static const char* passedString() { return "PASSED"; } +#else + static const char* failedString() { return "failed"; } + static const char* passedString() { return "passed"; } +#endif + + void printSourceInfo() const { + Colour colourGuard( Colour::FileName ); + stream << result.getSourceInfo() << ":"; + } + + void printResultType( Colour::Code colour, std::string passOrFail ) const { + if( !passOrFail.empty() ) { + { + Colour colourGuard( colour ); + stream << " " << passOrFail; + } + stream << ":"; + } + } + + void printIssue( std::string issue ) const { + stream << " " << issue; + } + + void printExpressionWas() { + if( result.hasExpression() ) { + stream << ";"; + { + Colour colour( dimColour() ); + stream << " expression was:"; + } + printOriginalExpression(); + } + } + + void printOriginalExpression() const { + if( result.hasExpression() ) { + stream << " " << result.getExpression(); + } + } + + void printReconstructedExpression() const { + if( result.hasExpandedExpression() ) { + { + Colour colour( dimColour() ); + stream << " for: "; + } + stream << result.getExpandedExpression(); + } + } + + void printMessage() { + if ( itMessage != messages.end() ) { + stream << " '" << itMessage->message << "'"; + ++itMessage; + } + } + + void printRemainingMessages( Colour::Code colour = dimColour() ) { + if ( itMessage == messages.end() ) + return; + + // using messages.end() directly yields compilation error: + std::vector<MessageInfo>::const_iterator itEnd = messages.end(); + const std::size_t N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) ); + + { + Colour colourGuard( colour ); + stream << " with " << pluralise( N, "message" ) << ":"; + } + + for(; itMessage != itEnd; ) { + // If this assertion is a warning ignore any INFO messages + if( printInfoMessages || itMessage->type != ResultWas::Info ) { + stream << " '" << itMessage->message << "'"; + if ( ++itMessage != itEnd ) { + Colour colourGuard( dimColour() ); + stream << " and"; + } + } + } + } + + private: + std::ostream& stream; + AssertionStats const& stats; + AssertionResult const& result; + std::vector<MessageInfo> messages; + std::vector<MessageInfo>::const_iterator itMessage; + bool printInfoMessages; + }; + + // Colour, message variants: + // - white: No tests ran. + // - red: Failed [both/all] N test cases, failed [both/all] M assertions. + // - white: Passed [both/all] N test cases (no assertions). + // - red: Failed N tests cases, failed M assertions. + // - green: Passed [both/all] N tests cases with M assertions. + + std::string bothOrAll( std::size_t count ) const { + return count == 1 ? "" : count == 2 ? "both " : "all " ; + } + + void printTotals( const Totals& totals ) const { + if( totals.testCases.total() == 0 ) { + stream << "No tests ran."; + } + else if( totals.testCases.failed == totals.testCases.total() ) { + Colour colour( Colour::ResultError ); + const std::string qualify_assertions_failed = + totals.assertions.failed == totals.assertions.total() ? + bothOrAll( totals.assertions.failed ) : ""; + stream << + "Failed " << bothOrAll( totals.testCases.failed ) + << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << qualify_assertions_failed << + pluralise( totals.assertions.failed, "assertion" ) << "."; + } + else if( totals.assertions.total() == 0 ) { + stream << + "Passed " << bothOrAll( totals.testCases.total() ) + << pluralise( totals.testCases.total(), "test case" ) + << " (no assertions)."; + } + else if( totals.assertions.failed ) { + Colour colour( Colour::ResultError ); + stream << + "Failed " << pluralise( totals.testCases.failed, "test case" ) << ", " + "failed " << pluralise( totals.assertions.failed, "assertion" ) << "."; + } + else { + Colour colour( Colour::ResultSuccess ); + stream << + "Passed " << bothOrAll( totals.testCases.passed ) + << pluralise( totals.testCases.passed, "test case" ) << + " with " << pluralise( totals.assertions.passed, "assertion" ) << "."; + } + } + }; + + INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter ) + +} // end namespace Catch + +namespace Catch { + NonCopyable::~NonCopyable() {} + IShared::~IShared() {} + StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} + IContext::~IContext() {} + IResultCapture::~IResultCapture() {} + ITestCase::~ITestCase() {} + ITestCaseRegistry::~ITestCaseRegistry() {} + IRegistryHub::~IRegistryHub() {} + IMutableRegistryHub::~IMutableRegistryHub() {} + IExceptionTranslator::~IExceptionTranslator() {} + IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {} + IReporter::~IReporter() {} + IReporterFactory::~IReporterFactory() {} + IReporterRegistry::~IReporterRegistry() {} + IStreamingReporter::~IStreamingReporter() {} + AssertionStats::~AssertionStats() {} + SectionStats::~SectionStats() {} + TestCaseStats::~TestCaseStats() {} + TestGroupStats::~TestGroupStats() {} + TestRunStats::~TestRunStats() {} + CumulativeReporterBase::SectionNode::~SectionNode() {} + CumulativeReporterBase::~CumulativeReporterBase() {} + + StreamingReporterBase::~StreamingReporterBase() {} + ConsoleReporter::~ConsoleReporter() {} + CompactReporter::~CompactReporter() {} + IRunner::~IRunner() {} + IMutableContext::~IMutableContext() {} + IConfig::~IConfig() {} + XmlReporter::~XmlReporter() {} + JunitReporter::~JunitReporter() {} + TestRegistry::~TestRegistry() {} + FreeFunctionTestCase::~FreeFunctionTestCase() {} + IGeneratorInfo::~IGeneratorInfo() {} + IGeneratorsForTest::~IGeneratorsForTest() {} + TestSpec::Pattern::~Pattern() {} + TestSpec::NamePattern::~NamePattern() {} + TestSpec::TagPattern::~TagPattern() {} + TestSpec::ExcludedPattern::~ExcludedPattern() {} + + Matchers::Impl::StdString::Equals::~Equals() {} + Matchers::Impl::StdString::Contains::~Contains() {} + Matchers::Impl::StdString::StartsWith::~StartsWith() {} + Matchers::Impl::StdString::EndsWith::~EndsWith() {} + + void Config::dummy() {} +} + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +#endif + +#ifdef CATCH_CONFIG_MAIN +// #included from: internal/catch_default_main.hpp +#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED + +#ifndef __OBJC__ + +// Standard C/C++ main entry point +int main (int argc, char * const argv[]) { + return Catch::Session().run( argc, argv ); +} + +#else // __OBJC__ + +// Objective-C entry point +int main (int argc, char * const argv[]) { +#if !CATCH_ARC_ENABLED + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; +#endif + + Catch::registerTestMethods(); + int result = Catch::Session().run( argc, (char* const*)argv ); + +#if !CATCH_ARC_ENABLED + [pool drain]; +#endif + + return result; +} + +#endif // __OBJC__ + +#endif + +#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED +# undef CLARA_CONFIG_MAIN +#endif + +////// + +// If this config identifier is defined then all CATCH macros are prefixed with CATCH_ +#ifdef CATCH_CONFIG_PREFIX_ALL + +#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" ) +#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" ) + +#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS" ) +#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" ) +#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" ) + +#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" ) +#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE" ) +#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" ) +#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" ) +#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" ) + +#define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" ) +#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" ) +#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" ) + +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" ) +#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" ) + +#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) +#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg ) +#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" ) +#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) +#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" ) + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) + #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) + #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) + #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ ) + #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ ) +#else + #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) + #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) + #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) + #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg ) + #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg ) +#endif +#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) + +#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) +#define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) + +#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) + +// "BDD-style" convenience wrappers +#ifdef CATCH_CONFIG_VARIADIC_MACROS +#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#else +#define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags ) +#define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) +#endif +#define CATCH_GIVEN( desc ) CATCH_SECTION( "Given: " desc, "" ) +#define CATCH_WHEN( desc ) CATCH_SECTION( " When: " desc, "" ) +#define CATCH_AND_WHEN( desc ) CATCH_SECTION( " And: " desc, "" ) +#define CATCH_THEN( desc ) CATCH_SECTION( " Then: " desc, "" ) +#define CATCH_AND_THEN( desc ) CATCH_SECTION( " And: " desc, "" ) + +// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required +#else + +#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" ) +#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" ) + +#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "REQUIRE_THROWS" ) +#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" ) +#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" ) + +#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" ) +#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE" ) +#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" ) +#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" ) +#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" ) + +#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS" ) +#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" ) +#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" ) + +#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" ) +#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" ) + +#define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) +#define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg ) +#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" ) +#define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) +#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" ) + +#ifdef CATCH_CONFIG_VARIADIC_MACROS + #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) + #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) + #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) + #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ ) + #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ ) +#else + #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) + #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) + #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) + #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg ) + #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg ) +#endif +#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" ) + +#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) +#define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) + +#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr ) + +#endif + +#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) + +// "BDD-style" convenience wrappers +#ifdef CATCH_CONFIG_VARIADIC_MACROS +#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ ) +#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ ) +#else +#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) +#define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) +#endif +#define GIVEN( desc ) SECTION( " Given: " desc, "" ) +#define WHEN( desc ) SECTION( " When: " desc, "" ) +#define AND_WHEN( desc ) SECTION( "And when: " desc, "" ) +#define THEN( desc ) SECTION( " Then: " desc, "" ) +#define AND_THEN( desc ) SECTION( " And: " desc, "" ) + +using Catch::Detail::Approx; + +// #included from: internal/catch_reenable_warnings.h + +#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(pop) +# else +# pragma clang diagnostic pop +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic pop +#endif + +#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED + diff --git a/vendor/CppQuickCheck-2018-03-28/test/compact-check-tests.cpp b/vendor/CppQuickCheck-2018-03-28/test/compact-check-tests.cpp new file mode 100644 index 00000000..910bc7b0 --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/test/compact-check-tests.cpp @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2016, Philipp Classen All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cppqc/Arbitrary.h" +#include "catch.hpp" +#include "cppqc/CompactCheck.h" + +using namespace cppqc; + +TEST_CASE("minimal passing example in compact check representation", + "[functional][compact]") +{ + const Result result = cppqc::gen<bool>() + .property("Dummy check (always passing)", + [](const bool &v) + { + return true; + }) + .testWithOutput(); + + REQUIRE(result.result == QC_SUCCESS); +} + +TEST_CASE("minimal failing example in compact check representation", + "[functional][compact]") +{ + const Result result = cppqc::gen<bool>() + .property("Dummy check (always failing)", + [](const bool &v) + { + return false; // Intended to fail + }) + .testWithOutput(); + + REQUIRE(result.result == QC_FAILURE); +} + +TEST_CASE("non-trivial example with std::sort should pass all tests", + "[functional][compact]") +{ + const Result result = cppqc::gen<std::vector<int>>() + .property("Should be sorted after calling std::sort", + [](const std::vector<int> &v) + { + std::vector<int> v_copy(v); + std::sort(std::begin(v_copy), std::end(v_copy)); + return std::is_sorted(std::begin(v_copy), std::end(v_copy)); + }) + .classify([](const std::vector<int> &v) + { + return std::to_string(v.size()); + }) + .trivial([](const std::vector<int> &v) + { + return v.empty() || v.size() == 1; + }) + .testWithOutput(); + + REQUIRE(result.result == QC_SUCCESS); +} diff --git a/vendor/CppQuickCheck-2018-03-28/test/functional-tests.cpp b/vendor/CppQuickCheck-2018-03-28/test/functional-tests.cpp new file mode 100644 index 00000000..25661bbb --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/test/functional-tests.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2016, Philipp Classen All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cppqc.h" +#include "catch.hpp" + +using namespace cppqc; + +namespace FunctionalTestsFixtures { + +struct MinimalPassingProperty : cppqc::Property<bool> +{ + bool check(const bool &v) const override + { + return true; + } + std::string name() const override + { + return "Dummy check (will always pass)"; + } +}; + +struct MinimalFailingProperty : cppqc::Property<bool> +{ + bool check(const bool &v) const override + { + return false; // fails intentionally + } + std::string name() const override + { + return "Dummy check (will always fail)"; + } +}; + +struct NontriviallyFailingProperty : cppqc::Property<std::vector<int>> +{ + bool check(const std::vector<int> &v) const override + { + if (v.size() >= 1 && (v[0] % 99) == 1) { + return false; + } + + return true; + } +}; + +} // end FunctionalTestsFixtures + +TEST_CASE("minimal passing example", + "[functional]") +{ + const Result result = + quickCheckOutput(FunctionalTestsFixtures::MinimalPassingProperty{}); + + REQUIRE(result.result == QC_SUCCESS); +} + +TEST_CASE("minimal failing example", + "[functional]") +{ + const Result result = + quickCheckOutput(FunctionalTestsFixtures::MinimalFailingProperty{}); + + REQUIRE(result.result == QC_FAILURE); +} + +TEST_CASE("tests with fixed seeds must be repeatible", + "[functional][seed]") +{ + for (int i = 0; i < 100; i++) { + const auto seed = static_cast<SeedType>(i); + + std::ostringstream output1; + const Result run1 = + quickCheckOutput(FunctionalTestsFixtures::NontriviallyFailingProperty{}, + output1, 100, 0, 0, DISABLE_SHRINK_TIMEOUT, seed); + REQUIRE(run1.seed == seed); + + std::ostringstream output2; + const Result run2 = + quickCheckOutput(FunctionalTestsFixtures::NontriviallyFailingProperty{}, + output2, 100, 0, 0, DISABLE_SHRINK_TIMEOUT, seed); + REQUIRE(run2.seed == seed); + + REQUIRE(run1.result == run2.result); + REQUIRE(output1.str() == output2.str()); + } +} diff --git a/vendor/CppQuickCheck-2018-03-28/test/shrink-explosion-protection.cpp b/vendor/CppQuickCheck-2018-03-28/test/shrink-explosion-protection.cpp new file mode 100644 index 00000000..d66b52e8 --- /dev/null +++ b/vendor/CppQuickCheck-2018-03-28/test/shrink-explosion-protection.cpp @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2016, Philipp Classen All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cppqc/Arbitrary.h" +#include "catch.hpp" + +#include "cppqc/cxx-prettyprint.h" + +using namespace cppqc; + +// Shrinking one value should eventually end, and the +// intermediate state should not contain too many entries. +template <typename T, typename ShrinkFunction, + int MAX_EXPECTED_RUNS = 1000, int MAX_EXPECTED_ENTRIES = 1000> +void checkShrinkExplosions(T initialValue, ShrinkFunction shrinkFunction) +{ + std::vector<T> current = shrinkFunction(initialValue); + for (int i = 0; i < MAX_EXPECTED_RUNS; i++) { + std::vector<T> worstCase; + for (const auto& x : current) { + auto newValues = shrinkFunction(x); + REQUIRE(newValues.size() < MAX_EXPECTED_ENTRIES); + + if (newValues.size() > worstCase.size()) { + worstCase = std::move(newValues); + } + } + + current = std::move(worstCase); + if (current.empty()) { + return; // test passed + } + // std::cout << "current=" << current << '\n'; + } + FAIL("should not be reached"); +} + +template <typename RealType> +void checkShrinkExplosions_Real() +{ + for(RealType x : { RealType(0.0), RealType(0.5), RealType(1.0), RealType(-1.0), + RealType(1.75), RealType(100.0), RealType(-100.0), RealType(NAN), + std::numeric_limits<RealType>::min(), + std::numeric_limits<RealType>::max(), + std::numeric_limits<RealType>::infinity(), + -std::numeric_limits<RealType>::infinity() }) + { + checkShrinkExplosions<RealType>(x, [](RealType x) { return shrinkReal(x); }); + } +} + +TEST_CASE("Number of elements should not explode during shrinking (float)", + "[shrinkReal][float]") +{ + checkShrinkExplosions_Real<float>(); +} + +TEST_CASE("Number of elements should not explode during shrinking (double)", + "[shrinkReal][double]") +{ + checkShrinkExplosions_Real<double>(); +} + +TEST_CASE("Number of elements should not explode during shrinking (long double)", + "[shrinkReal][long double]") +{ + checkShrinkExplosions_Real<long double>(); +} + +template <typename IntegralType> +void checkShrinkExplosions_IntegralType() +{ + for (IntegralType x : { IntegralType(0), IntegralType(1), IntegralType(-1), + IntegralType(3), IntegralType(-3), + IntegralType(100), IntegralType(5555), IntegralType(-5555), + std::numeric_limits<IntegralType>::min(), + std::numeric_limits<IntegralType>::max() }) + { + + checkShrinkExplosions<IntegralType>(x, [](IntegralType x) + { + return shrinkIntegral(x); + }); + } +} + +TEST_CASE("Number of elements should not explode during shrinking (char)", + "[shrinkIntegral][char]") +{ + checkShrinkExplosions_IntegralType<char>(); +} + +TEST_CASE("Number of elements should not explode during shrinking (signed char)", + "[shrinkIntegral][signed char]") +{ + checkShrinkExplosions_IntegralType<signed char>(); +} + +TEST_CASE("Number of elements should not explode during shrinking (unsigned char)", + "[shrinkIntegral][unsigned char]") +{ + checkShrinkExplosions_IntegralType<unsigned char>(); +} + +TEST_CASE("Number of elements should not explode during shrinking (short)", + "[shrinkIntegral][short]") +{ + checkShrinkExplosions_IntegralType<short>(); +} + +TEST_CASE("Number of elements should not explode during shrinking (unsigned short)", + "[shrinkIntegral][unsigned short]") +{ + checkShrinkExplosions_IntegralType<unsigned short>(); +} + +TEST_CASE("Number of elements should not explode during shrinking (int)", + "[shrinkIntegral][int]") +{ + checkShrinkExplosions_IntegralType<int>(); +} + +TEST_CASE("Number of elements should not explode during shrinking (unsigned int)", + "[shrinkIntegral][unsigned int]") +{ + checkShrinkExplosions_IntegralType<unsigned int>(); +} + +TEST_CASE("Number of elements should not explode during shrinking (long)", + "[shrinkIntegral][long]") +{ + checkShrinkExplosions_IntegralType<long>(); +} + +TEST_CASE("Number of elements should not explode during shrinking (unsigned long)", + "[shrinkIntegral][unsigned long]") +{ + checkShrinkExplosions_IntegralType<unsigned long>(); +} + +TEST_CASE("Number of elements should not explode during shrinking (long long)", + "[shrinkIntegral][long long]") +{ + checkShrinkExplosions_IntegralType<long long>(); +} + +TEST_CASE("Number of elements should not explode during shrinking (unsigned long long)", + "[shrinkIntegral][unsigned long long]") +{ + checkShrinkExplosions_IntegralType<unsigned long long>(); +} @@ -1 +1 @@ -fmt-3.0.1
\ No newline at end of file +fmt-4.1.0
\ No newline at end of file diff --git a/vendor/fmt-3.0.1/fmt/format.cc b/vendor/fmt-3.0.1/fmt/format.cc deleted file mode 100644 index 2bd774e4..00000000 --- a/vendor/fmt-3.0.1/fmt/format.cc +++ /dev/null @@ -1,940 +0,0 @@ -/* - Formatting library for C++ - - Copyright (c) 2012 - 2016, Victor Zverovich - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - - 1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "format.h" - -#include <string.h> - -#include <cctype> -#include <cerrno> -#include <climits> -#include <cmath> -#include <cstdarg> -#include <cstddef> // for std::ptrdiff_t - -#if defined(_WIN32) && defined(__MINGW32__) -# include <cstring> -#endif - -#if FMT_USE_WINDOWS_H -# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX) -# include <windows.h> -# else -# define NOMINMAX -# include <windows.h> -# undef NOMINMAX -# endif -#endif - -using fmt::internal::Arg; - -#if FMT_EXCEPTIONS -# define FMT_TRY try -# define FMT_CATCH(x) catch (x) -#else -# define FMT_TRY if (true) -# define FMT_CATCH(x) if (false) -#endif - -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4127) // conditional expression is constant -# pragma warning(disable: 4702) // unreachable code -// Disable deprecation warning for strerror. The latter is not called but -// MSVC fails to detect it. -# pragma warning(disable: 4996) -#endif - -// Dummy implementations of strerror_r and strerror_s called if corresponding -// system functions are not available. -static inline fmt::internal::Null<> strerror_r(int, char *, ...) { - return fmt::internal::Null<>(); -} -static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) { - return fmt::internal::Null<>(); -} - -namespace fmt { - -FMT_FUNC internal::RuntimeError::~RuntimeError() throw() {} -FMT_FUNC FormatError::~FormatError() throw() {} -FMT_FUNC SystemError::~SystemError() throw() {} - -namespace { - -#ifndef _MSC_VER -# define FMT_SNPRINTF snprintf -#else // _MSC_VER -inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) { - va_list args; - va_start(args, format); - int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args); - va_end(args); - return result; -} -# define FMT_SNPRINTF fmt_snprintf -#endif // _MSC_VER - -#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) -# define FMT_SWPRINTF snwprintf -#else -# define FMT_SWPRINTF swprintf -#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) - -// Checks if a value fits in int - used to avoid warnings about comparing -// signed and unsigned integers. -template <bool IsSigned> -struct IntChecker { - template <typename T> - static bool fits_in_int(T value) { - unsigned max = INT_MAX; - return value <= max; - } - static bool fits_in_int(bool) { return true; } -}; - -template <> -struct IntChecker<true> { - template <typename T> - static bool fits_in_int(T value) { - return value >= INT_MIN && value <= INT_MAX; - } - static bool fits_in_int(int) { return true; } -}; - -const char RESET_COLOR[] = "\x1b[0m"; - -typedef void (*FormatFunc)(Writer &, int, StringRef); - -// Portable thread-safe version of strerror. -// Sets buffer to point to a string describing the error code. -// This can be either a pointer to a string stored in buffer, -// or a pointer to some static immutable string. -// Returns one of the following values: -// 0 - success -// ERANGE - buffer is not large enough to store the error message -// other - failure -// Buffer should be at least of size 1. -int safe_strerror( - int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT { - FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer"); - - class StrError { - private: - int error_code_; - char *&buffer_; - std::size_t buffer_size_; - - // A noop assignment operator to avoid bogus warnings. - void operator=(const StrError &) {} - - // Handle the result of XSI-compliant version of strerror_r. - int handle(int result) { - // glibc versions before 2.13 return result in errno. - return result == -1 ? errno : result; - } - - // Handle the result of GNU-specific version of strerror_r. - int handle(char *message) { - // If the buffer is full then the message is probably truncated. - if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1) - return ERANGE; - buffer_ = message; - return 0; - } - - // Handle the case when strerror_r is not available. - int handle(internal::Null<>) { - return fallback(strerror_s(buffer_, buffer_size_, error_code_)); - } - - // Fallback to strerror_s when strerror_r is not available. - int fallback(int result) { - // If the buffer is full then the message is probably truncated. - return result == 0 && strlen(buffer_) == buffer_size_ - 1 ? - ERANGE : result; - } - - // Fallback to strerror if strerror_r and strerror_s are not available. - int fallback(internal::Null<>) { - errno = 0; - buffer_ = strerror(error_code_); - return errno; - } - - public: - StrError(int err_code, char *&buf, std::size_t buf_size) - : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {} - - int run() { - strerror_r(0, 0, ""); // Suppress a warning about unused strerror_r. - return handle(strerror_r(error_code_, buffer_, buffer_size_)); - } - }; - return StrError(error_code, buffer, buffer_size).run(); -} - -void format_error_code(Writer &out, int error_code, - StringRef message) FMT_NOEXCEPT { - // Report error code making sure that the output fits into - // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential - // bad_alloc. - out.clear(); - static const char SEP[] = ": "; - static const char ERROR_STR[] = "error "; - // Subtract 2 to account for terminating null characters in SEP and ERROR_STR. - std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2; - typedef internal::IntTraits<int>::MainType MainType; - MainType abs_value = static_cast<MainType>(error_code); - if (internal::is_negative(error_code)) { - abs_value = 0 - abs_value; - ++error_code_size; - } - error_code_size += internal::count_digits(abs_value); - if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size) - out << message << SEP; - out << ERROR_STR << error_code; - assert(out.size() <= internal::INLINE_BUFFER_SIZE); -} - -void report_error(FormatFunc func, int error_code, - StringRef message) FMT_NOEXCEPT { - MemoryWriter full_message; - func(full_message, error_code, message); - // Use Writer::data instead of Writer::c_str to avoid potential memory - // allocation. - std::fwrite(full_message.data(), full_message.size(), 1, stderr); - std::fputc('\n', stderr); -} - -// IsZeroInt::visit(arg) returns true iff arg is a zero integer. -class IsZeroInt : public ArgVisitor<IsZeroInt, bool> { - public: - template <typename T> - bool visit_any_int(T value) { return value == 0; } -}; - -// Checks if an argument is a valid printf width specifier and sets -// left alignment if it is negative. -class WidthHandler : public ArgVisitor<WidthHandler, unsigned> { - private: - FormatSpec &spec_; - - FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler); - - public: - explicit WidthHandler(FormatSpec &spec) : spec_(spec) {} - - void report_unhandled_arg() { - FMT_THROW(FormatError("width is not integer")); - } - - template <typename T> - unsigned visit_any_int(T value) { - typedef typename internal::IntTraits<T>::MainType UnsignedType; - UnsignedType width = static_cast<UnsignedType>(value); - if (internal::is_negative(value)) { - spec_.align_ = ALIGN_LEFT; - width = 0 - width; - } - if (width > INT_MAX) - FMT_THROW(FormatError("number is too big")); - return static_cast<unsigned>(width); - } -}; - -class PrecisionHandler : public ArgVisitor<PrecisionHandler, int> { - public: - void report_unhandled_arg() { - FMT_THROW(FormatError("precision is not integer")); - } - - template <typename T> - int visit_any_int(T value) { - if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value)) - FMT_THROW(FormatError("number is too big")); - return static_cast<int>(value); - } -}; - -template <typename T, typename U> -struct is_same { - enum { value = 0 }; -}; - -template <typename T> -struct is_same<T, T> { - enum { value = 1 }; -}; - -// An argument visitor that converts an integer argument to T for printf, -// if T is an integral type. If T is void, the argument is converted to -// corresponding signed or unsigned type depending on the type specifier: -// 'd' and 'i' - signed, other - unsigned) -template <typename T = void> -class ArgConverter : public ArgVisitor<ArgConverter<T>, void> { - private: - internal::Arg &arg_; - wchar_t type_; - - FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter); - - public: - ArgConverter(internal::Arg &arg, wchar_t type) - : arg_(arg), type_(type) {} - - void visit_bool(bool value) { - if (type_ != 's') - visit_any_int(value); - } - - template <typename U> - void visit_any_int(U value) { - bool is_signed = type_ == 'd' || type_ == 'i'; - using internal::Arg; - typedef typename internal::Conditional< - is_same<T, void>::value, U, T>::type TargetType; - if (sizeof(TargetType) <= sizeof(int)) { - // Extra casts are used to silence warnings. - if (is_signed) { - arg_.type = Arg::INT; - arg_.int_value = static_cast<int>(static_cast<TargetType>(value)); - } else { - arg_.type = Arg::UINT; - typedef typename internal::MakeUnsigned<TargetType>::Type Unsigned; - arg_.uint_value = static_cast<unsigned>(static_cast<Unsigned>(value)); - } - } else { - if (is_signed) { - arg_.type = Arg::LONG_LONG; - // glibc's printf doesn't sign extend arguments of smaller types: - // std::printf("%lld", -42); // prints "4294967254" - // but we don't have to do the same because it's a UB. - arg_.long_long_value = static_cast<LongLong>(value); - } else { - arg_.type = Arg::ULONG_LONG; - arg_.ulong_long_value = - static_cast<typename internal::MakeUnsigned<U>::Type>(value); - } - } - } -}; - -// Converts an integer argument to char for printf. -class CharConverter : public ArgVisitor<CharConverter, void> { - private: - internal::Arg &arg_; - - FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter); - - public: - explicit CharConverter(internal::Arg &arg) : arg_(arg) {} - - template <typename T> - void visit_any_int(T value) { - arg_.type = internal::Arg::CHAR; - arg_.int_value = static_cast<char>(value); - } -}; -} // namespace - -namespace internal { - -template <typename Char> -class PrintfArgFormatter : - public ArgFormatterBase<PrintfArgFormatter<Char>, Char> { - - void write_null_pointer() { - this->spec().type_ = 0; - this->write("(nil)"); - } - - typedef ArgFormatterBase<PrintfArgFormatter<Char>, Char> Base; - - public: - PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s) - : ArgFormatterBase<PrintfArgFormatter<Char>, Char>(w, s) {} - - void visit_bool(bool value) { - FormatSpec &fmt_spec = this->spec(); - if (fmt_spec.type_ != 's') - return this->visit_any_int(value); - fmt_spec.type_ = 0; - this->write(value); - } - - void visit_char(int value) { - const FormatSpec &fmt_spec = this->spec(); - BasicWriter<Char> &w = this->writer(); - if (fmt_spec.type_ && fmt_spec.type_ != 'c') - w.write_int(value, fmt_spec); - typedef typename BasicWriter<Char>::CharPtr CharPtr; - CharPtr out = CharPtr(); - if (fmt_spec.width_ > 1) { - Char fill = ' '; - out = w.grow_buffer(fmt_spec.width_); - if (fmt_spec.align_ != ALIGN_LEFT) { - std::fill_n(out, fmt_spec.width_ - 1, fill); - out += fmt_spec.width_ - 1; - } else { - std::fill_n(out + 1, fmt_spec.width_ - 1, fill); - } - } else { - out = w.grow_buffer(1); - } - *out = static_cast<Char>(value); - } - - void visit_cstring(const char *value) { - if (value) - Base::visit_cstring(value); - else if (this->spec().type_ == 'p') - write_null_pointer(); - else - this->write("(null)"); - } - - void visit_pointer(const void *value) { - if (value) - return Base::visit_pointer(value); - this->spec().type_ = 0; - write_null_pointer(); - } - - void visit_custom(Arg::CustomValue c) { - BasicFormatter<Char> formatter(ArgList(), this->writer()); - const Char format_str[] = {'}', 0}; - const Char *format = format_str; - c.format(&formatter, c.value, &format); - } -}; -} // namespace internal -} // namespace fmt - -FMT_FUNC void fmt::SystemError::init( - int err_code, CStringRef format_str, ArgList args) { - error_code_ = err_code; - MemoryWriter w; - internal::format_system_error(w, err_code, format(format_str, args)); - std::runtime_error &base = *this; - base = std::runtime_error(w.str()); -} - -template <typename T> -int fmt::internal::CharTraits<char>::format_float( - char *buffer, std::size_t size, const char *format, - unsigned width, int precision, T value) { - if (width == 0) { - return precision < 0 ? - FMT_SNPRINTF(buffer, size, format, value) : - FMT_SNPRINTF(buffer, size, format, precision, value); - } - return precision < 0 ? - FMT_SNPRINTF(buffer, size, format, width, value) : - FMT_SNPRINTF(buffer, size, format, width, precision, value); -} - -template <typename T> -int fmt::internal::CharTraits<wchar_t>::format_float( - wchar_t *buffer, std::size_t size, const wchar_t *format, - unsigned width, int precision, T value) { - if (width == 0) { - return precision < 0 ? - FMT_SWPRINTF(buffer, size, format, value) : - FMT_SWPRINTF(buffer, size, format, precision, value); - } - return precision < 0 ? - FMT_SWPRINTF(buffer, size, format, width, value) : - FMT_SWPRINTF(buffer, size, format, width, precision, value); -} - -template <typename T> -const char fmt::internal::BasicData<T>::DIGITS[] = - "0001020304050607080910111213141516171819" - "2021222324252627282930313233343536373839" - "4041424344454647484950515253545556575859" - "6061626364656667686970717273747576777879" - "8081828384858687888990919293949596979899"; - -#define FMT_POWERS_OF_10(factor) \ - factor * 10, \ - factor * 100, \ - factor * 1000, \ - factor * 10000, \ - factor * 100000, \ - factor * 1000000, \ - factor * 10000000, \ - factor * 100000000, \ - factor * 1000000000 - -template <typename T> -const uint32_t fmt::internal::BasicData<T>::POWERS_OF_10_32[] = { - 0, FMT_POWERS_OF_10(1) -}; - -template <typename T> -const uint64_t fmt::internal::BasicData<T>::POWERS_OF_10_64[] = { - 0, - FMT_POWERS_OF_10(1), - FMT_POWERS_OF_10(fmt::ULongLong(1000000000)), - // Multiply several constants instead of using a single long long constant - // to avoid warnings about C++98 not supporting long long. - fmt::ULongLong(1000000000) * fmt::ULongLong(1000000000) * 10 -}; - -FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) { - (void)type; - if (std::isprint(static_cast<unsigned char>(code))) { - FMT_THROW(fmt::FormatError( - fmt::format("unknown format code '{}' for {}", code, type))); - } - FMT_THROW(fmt::FormatError( - fmt::format("unknown format code '\\x{:02x}' for {}", - static_cast<unsigned>(code), type))); -} - -#if FMT_USE_WINDOWS_H - -FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) { - static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16"; - if (s.size() > INT_MAX) - FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG)); - int s_size = static_cast<int>(s.size()); - int length = MultiByteToWideChar( - CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, 0, 0); - if (length == 0) - FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); - buffer_.resize(length + 1); - length = MultiByteToWideChar( - CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length); - if (length == 0) - FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); - buffer_[length] = 0; -} - -FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) { - if (int error_code = convert(s)) { - FMT_THROW(WindowsError(error_code, - "cannot convert string from UTF-16 to UTF-8")); - } -} - -FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) { - if (s.size() > INT_MAX) - return ERROR_INVALID_PARAMETER; - int s_size = static_cast<int>(s.size()); - int length = WideCharToMultiByte(CP_UTF8, 0, s.data(), s_size, 0, 0, 0, 0); - if (length == 0) - return GetLastError(); - buffer_.resize(length + 1); - length = WideCharToMultiByte( - CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, 0, 0); - if (length == 0) - return GetLastError(); - buffer_[length] = 0; - return 0; -} - -FMT_FUNC void fmt::WindowsError::init( - int err_code, CStringRef format_str, ArgList args) { - error_code_ = err_code; - MemoryWriter w; - internal::format_windows_error(w, err_code, format(format_str, args)); - std::runtime_error &base = *this; - base = std::runtime_error(w.str()); -} - -FMT_FUNC void fmt::internal::format_windows_error( - fmt::Writer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT { - FMT_TRY { - MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer; - buffer.resize(INLINE_BUFFER_SIZE); - for (;;) { - wchar_t *system_message = &buffer[0]; - int result = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - 0, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - system_message, static_cast<uint32_t>(buffer.size()), 0); - if (result != 0) { - UTF16ToUTF8 utf8_message; - if (utf8_message.convert(system_message) == ERROR_SUCCESS) { - out << message << ": " << utf8_message; - return; - } - break; - } - if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) - break; // Can't get error message, report error code instead. - buffer.resize(buffer.size() * 2); - } - } FMT_CATCH(...) {} - fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. -} - -#endif // FMT_USE_WINDOWS_H - -FMT_FUNC void fmt::internal::format_system_error( - fmt::Writer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT { - FMT_TRY { - MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer; - buffer.resize(INLINE_BUFFER_SIZE); - for (;;) { - char *system_message = &buffer[0]; - int result = safe_strerror(error_code, system_message, buffer.size()); - if (result == 0) { - out << message << ": " << system_message; - return; - } - if (result != ERANGE) - break; // Can't get error message, report error code instead. - buffer.resize(buffer.size() * 2); - } - } FMT_CATCH(...) {} - fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. -} - -template <typename Char> -void fmt::internal::ArgMap<Char>::init(const ArgList &args) { - if (!map_.empty()) - return; - typedef internal::NamedArg<Char> NamedArg; - const NamedArg *named_arg = 0; - bool use_values = - args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE; - if (use_values) { - for (unsigned i = 0;/*nothing*/; ++i) { - internal::Arg::Type arg_type = args.type(i); - switch (arg_type) { - case internal::Arg::NONE: - return; - case internal::Arg::NAMED_ARG: - named_arg = static_cast<const NamedArg*>(args.values_[i].pointer); - map_.push_back(Pair(named_arg->name, *named_arg)); - break; - default: - /*nothing*/; - } - } - return; - } - for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) { - internal::Arg::Type arg_type = args.type(i); - if (arg_type == internal::Arg::NAMED_ARG) { - named_arg = static_cast<const NamedArg*>(args.args_[i].pointer); - map_.push_back(Pair(named_arg->name, *named_arg)); - } - } - for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) { - switch (args.args_[i].type) { - case internal::Arg::NONE: - return; - case internal::Arg::NAMED_ARG: - named_arg = static_cast<const NamedArg*>(args.args_[i].pointer); - map_.push_back(Pair(named_arg->name, *named_arg)); - break; - default: - /*nothing*/; - } - } -} - -template <typename Char> -void fmt::internal::FixedBuffer<Char>::grow(std::size_t) { - FMT_THROW(std::runtime_error("buffer overflow")); -} - -FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg( - unsigned arg_index, const char *&error) { - Arg arg = args_[arg_index]; - switch (arg.type) { - case Arg::NONE: - error = "argument index out of range"; - break; - case Arg::NAMED_ARG: - arg = *static_cast<const internal::Arg*>(arg.pointer); - break; - default: - /*nothing*/; - } - return arg; -} - -template <typename Char> -void fmt::internal::PrintfFormatter<Char>::parse_flags( - FormatSpec &spec, const Char *&s) { - for (;;) { - switch (*s++) { - case '-': - spec.align_ = ALIGN_LEFT; - break; - case '+': - spec.flags_ |= SIGN_FLAG | PLUS_FLAG; - break; - case '0': - spec.fill_ = '0'; - break; - case ' ': - spec.flags_ |= SIGN_FLAG; - break; - case '#': - spec.flags_ |= HASH_FLAG; - break; - default: - --s; - return; - } - } -} - -template <typename Char> -Arg fmt::internal::PrintfFormatter<Char>::get_arg( - const Char *s, unsigned arg_index) { - (void)s; - const char *error = 0; - Arg arg = arg_index == UINT_MAX ? - next_arg(error) : FormatterBase::get_arg(arg_index - 1, error); - if (error) - FMT_THROW(FormatError(!*s ? "invalid format string" : error)); - return arg; -} - -template <typename Char> -unsigned fmt::internal::PrintfFormatter<Char>::parse_header( - const Char *&s, FormatSpec &spec) { - unsigned arg_index = UINT_MAX; - Char c = *s; - if (c >= '0' && c <= '9') { - // Parse an argument index (if followed by '$') or a width possibly - // preceded with '0' flag(s). - unsigned value = parse_nonnegative_int(s); - if (*s == '$') { // value is an argument index - ++s; - arg_index = value; - } else { - if (c == '0') - spec.fill_ = '0'; - if (value != 0) { - // Nonzero value means that we parsed width and don't need to - // parse it or flags again, so return now. - spec.width_ = value; - return arg_index; - } - } - } - parse_flags(spec, s); - // Parse width. - if (*s >= '0' && *s <= '9') { - spec.width_ = parse_nonnegative_int(s); - } else if (*s == '*') { - ++s; - spec.width_ = WidthHandler(spec).visit(get_arg(s)); - } - return arg_index; -} - -template <typename Char> -void fmt::internal::PrintfFormatter<Char>::format( - BasicWriter<Char> &writer, BasicCStringRef<Char> format_str) { - const Char *start = format_str.c_str(); - const Char *s = start; - while (*s) { - Char c = *s++; - if (c != '%') continue; - if (*s == c) { - write(writer, start, s); - start = ++s; - continue; - } - write(writer, start, s - 1); - - FormatSpec spec; - spec.align_ = ALIGN_RIGHT; - - // Parse argument index, flags and width. - unsigned arg_index = parse_header(s, spec); - - // Parse precision. - if (*s == '.') { - ++s; - if ('0' <= *s && *s <= '9') { - spec.precision_ = static_cast<int>(parse_nonnegative_int(s)); - } else if (*s == '*') { - ++s; - spec.precision_ = PrecisionHandler().visit(get_arg(s)); - } - } - - Arg arg = get_arg(s, arg_index); - if (spec.flag(HASH_FLAG) && IsZeroInt().visit(arg)) - spec.flags_ &= ~to_unsigned<int>(HASH_FLAG); - if (spec.fill_ == '0') { - if (arg.type <= Arg::LAST_NUMERIC_TYPE) - spec.align_ = ALIGN_NUMERIC; - else - spec.fill_ = ' '; // Ignore '0' flag for non-numeric types. - } - - // Parse length and convert the argument to the required type. - switch (*s++) { - case 'h': - if (*s == 'h') - ArgConverter<signed char>(arg, *++s).visit(arg); - else - ArgConverter<short>(arg, *s).visit(arg); - break; - case 'l': - if (*s == 'l') - ArgConverter<fmt::LongLong>(arg, *++s).visit(arg); - else - ArgConverter<long>(arg, *s).visit(arg); - break; - case 'j': - ArgConverter<intmax_t>(arg, *s).visit(arg); - break; - case 'z': - ArgConverter<std::size_t>(arg, *s).visit(arg); - break; - case 't': - ArgConverter<std::ptrdiff_t>(arg, *s).visit(arg); - break; - case 'L': - // printf produces garbage when 'L' is omitted for long double, no - // need to do the same. - break; - default: - --s; - ArgConverter<void>(arg, *s).visit(arg); - } - - // Parse type. - if (!*s) - FMT_THROW(FormatError("invalid format string")); - spec.type_ = static_cast<char>(*s++); - if (arg.type <= Arg::LAST_INTEGER_TYPE) { - // Normalize type. - switch (spec.type_) { - case 'i': case 'u': - spec.type_ = 'd'; - break; - case 'c': - // TODO: handle wchar_t - CharConverter(arg).visit(arg); - break; - } - } - - start = s; - - // Format argument. - internal::PrintfArgFormatter<Char>(writer, spec).visit(arg); - } - write(writer, start, s); -} - -FMT_FUNC void fmt::report_system_error( - int error_code, fmt::StringRef message) FMT_NOEXCEPT { - // 'fmt::' is for bcc32. - fmt::report_error(internal::format_system_error, error_code, message); -} - -#if FMT_USE_WINDOWS_H -FMT_FUNC void fmt::report_windows_error( - int error_code, fmt::StringRef message) FMT_NOEXCEPT { - // 'fmt::' is for bcc32. - fmt::report_error(internal::format_windows_error, error_code, message); -} -#endif - -FMT_FUNC void fmt::print(std::FILE *f, CStringRef format_str, ArgList args) { - MemoryWriter w; - w.write(format_str, args); - std::fwrite(w.data(), 1, w.size(), f); -} - -FMT_FUNC void fmt::print(CStringRef format_str, ArgList args) { - print(stdout, format_str, args); -} - -FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) { - char escape[] = "\x1b[30m"; - escape[3] = static_cast<char>('0' + c); - std::fputs(escape, stdout); - print(format, args); - std::fputs(RESET_COLOR, stdout); -} - -FMT_FUNC int fmt::fprintf(std::FILE *f, CStringRef format, ArgList args) { - MemoryWriter w; - printf(w, format, args); - std::size_t size = w.size(); - return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size); -} - -#ifndef FMT_HEADER_ONLY - -template struct fmt::internal::BasicData<void>; - -// Explicit instantiations for char. - -template void fmt::internal::FixedBuffer<char>::grow(std::size_t); - -template void fmt::internal::ArgMap<char>::init(const fmt::ArgList &args); - -template void fmt::internal::PrintfFormatter<char>::format( - BasicWriter<char> &writer, CStringRef format); - -template int fmt::internal::CharTraits<char>::format_float( - char *buffer, std::size_t size, const char *format, - unsigned width, int precision, double value); - -template int fmt::internal::CharTraits<char>::format_float( - char *buffer, std::size_t size, const char *format, - unsigned width, int precision, long double value); - -// Explicit instantiations for wchar_t. - -template void fmt::internal::FixedBuffer<wchar_t>::grow(std::size_t); - -template void fmt::internal::ArgMap<wchar_t>::init(const fmt::ArgList &args); - -template void fmt::internal::PrintfFormatter<wchar_t>::format( - BasicWriter<wchar_t> &writer, WCStringRef format); - -template int fmt::internal::CharTraits<wchar_t>::format_float( - wchar_t *buffer, std::size_t size, const wchar_t *format, - unsigned width, int precision, double value); - -template int fmt::internal::CharTraits<wchar_t>::format_float( - wchar_t *buffer, std::size_t size, const wchar_t *format, - unsigned width, int precision, long double value); - -#endif // FMT_HEADER_ONLY - -#ifdef _MSC_VER -# pragma warning(pop) -#endif diff --git a/vendor/fmt-3.0.1/fmt/time.h b/vendor/fmt-3.0.1/fmt/time.h deleted file mode 100644 index 10225c03..00000000 --- a/vendor/fmt-3.0.1/fmt/time.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - Formatting library for C++ - time formatting - - Copyright (c) 2012 - 2016, Victor Zverovich - All rights reserved. - - For the license information refer to format.h. - */ - -#ifndef FMT_TIME_H_ -#define FMT_TIME_H_ - -#include "format.h" -#include <ctime> - -namespace fmt { -template <typename ArgFormatter> -void format(BasicFormatter<char, ArgFormatter> &f, - const char *&format_str, const std::tm &tm) { - if (*format_str == ':') - ++format_str; - const char *end = format_str; - while (*end && *end != '}') - ++end; - if (*end != '}') - FMT_THROW(FormatError("missing '}' in format string")); - internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> format; - format.append(format_str, end + 1); - format[format.size() - 1] = '\0'; - Buffer<char> &buffer = f.writer().buffer(); - std::size_t start = buffer.size(); - for (;;) { - std::size_t size = buffer.capacity() - start; - std::size_t count = std::strftime(&buffer[start], size, &format[0], &tm); - if (count != 0) { - buffer.resize(start + count); - break; - } - if (size >= format.size() * 256) { - // If the buffer is 256 times larger than the format string, assume - // that `strftime` gives an empty result. There doesn't seem to be a - // better way to distinguish the two cases: - // https://github.com/fmtlib/fmt/issues/367 - break; - } - const std::size_t MIN_GROWTH = 10; - buffer.reserve(buffer.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH)); - } - format_str = end + 1; -} -} - -#endif // FMT_TIME_H_ diff --git a/vendor/fmt-3.0.1/fmt/CMakeLists.txt b/vendor/fmt-4.1.0/fmt/CMakeLists.txt index 89ef1f35..3259d788 100644 --- a/vendor/fmt-3.0.1/fmt/CMakeLists.txt +++ b/vendor/fmt-4.1.0/fmt/CMakeLists.txt @@ -1,21 +1,19 @@ # Define the fmt library, its includes and the needed defines. -# format.cc is added to FMT_HEADERS for the header-only configuration. -set(FMT_HEADERS format.h format.cc ostream.h ostream.cc time.h) +# *.cc are added to FMT_HEADERS for the header-only configuration. +set(FMT_HEADERS container.h format.h format.cc ostream.h ostream.cc printf.h + printf.cc string.h time.h) if (HAVE_OPEN) set(FMT_HEADERS ${FMT_HEADERS} posix.h) set(FMT_SOURCES ${FMT_SOURCES} posix.cc) endif () -add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} ../ChangeLog.rst) - -option(FMT_CPPFORMAT "Build cppformat library for backward compatibility." OFF) -if (FMT_CPPFORMAT) - message(WARNING "The cppformat library is deprecated, use fmt instead.") - add_library(cppformat ${FMT_SOURCES} ${FMT_HEADERS}) -endif () +add_library(fmt ${FMT_SOURCES} ${FMT_HEADERS} ../README.rst ../ChangeLog.rst) +add_library(fmt::fmt ALIAS fmt) # Starting with cmake 3.1 the CXX_STANDARD property can be used instead. -target_compile_options(fmt PUBLIC ${CPP11_FLAG}) +# Note: Don't make -std=c++11 public or interface, since it breaks projects +# that use C++14. +target_compile_options(fmt PRIVATE ${CPP11_FLAG}) if (FMT_PEDANTIC) target_compile_options(fmt PRIVATE ${PEDANTIC_COMPILE_FLAGS}) endif () @@ -40,6 +38,7 @@ endif () # additionally define a header only library when cmake is new enough if (CMAKE_VERSION VERSION_GREATER 3.1.0 OR CMAKE_VERSION VERSION_EQUAL 3.1.0) add_library(fmt-header-only INTERFACE) + add_library(fmt::fmt-header-only ALIAS fmt-header-only) target_compile_definitions(fmt-header-only INTERFACE FMT_HEADER_ONLY=1) @@ -50,8 +49,9 @@ endif () # Install targets. if (FMT_INSTALL) + include(GNUInstallDirs) include(CMakePackageConfigHelpers) - set(FMT_CMAKE_DIR lib/cmake/fmt CACHE STRING + set(FMT_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/fmt CACHE STRING "Installation directory for cmake files, relative to ${CMAKE_INSTALL_PREFIX}.") set(version_config ${PROJECT_BINARY_DIR}/fmt-config-version.cmake) set(project_config ${PROJECT_BINARY_DIR}/fmt-config.cmake) @@ -62,9 +62,12 @@ if (FMT_INSTALL) set(INSTALL_TARGETS ${INSTALL_TARGETS} fmt-header-only) endif () - set(FMT_LIB_DIR lib CACHE STRING + set(FMT_LIB_DIR ${CMAKE_INSTALL_LIBDIR} CACHE STRING "Installation directory for libraries, relative to ${CMAKE_INSTALL_PREFIX}.") + set(FMT_INC_DIR ${CMAKE_INSTALL_INCLUDEDIR}/fmt CACHE STRING + "Installation directory for include files, relative to ${CMAKE_INSTALL_PREFIX}.") + # Generate the version, config and target files into the build directory. write_basic_package_version_file( ${version_config} @@ -74,20 +77,18 @@ if (FMT_INSTALL) ${PROJECT_SOURCE_DIR}/support/cmake/fmt-config.cmake.in ${project_config} INSTALL_DESTINATION ${FMT_CMAKE_DIR}) - export(TARGETS ${INSTALL_TARGETS} + export(TARGETS ${INSTALL_TARGETS} NAMESPACE fmt:: FILE ${PROJECT_BINARY_DIR}/${targets_export_name}.cmake) # Install version, config and target files. install( FILES ${project_config} ${version_config} DESTINATION ${FMT_CMAKE_DIR}) - install(EXPORT ${targets_export_name} DESTINATION ${FMT_CMAKE_DIR}) + install(EXPORT ${targets_export_name} DESTINATION ${FMT_CMAKE_DIR} + NAMESPACE fmt::) # Install the library and headers. install(TARGETS ${INSTALL_TARGETS} EXPORT ${targets_export_name} DESTINATION ${FMT_LIB_DIR}) - install(FILES ${FMT_HEADERS} DESTINATION include/fmt) - if (FMT_CPPFORMAT) - install(TARGETS cppformat DESTINATION ${FMT_LIB_DIR}) - endif () + install(FILES ${FMT_HEADERS} DESTINATION ${FMT_INC_DIR}) endif () diff --git a/vendor/fmt-4.1.0/fmt/container.h b/vendor/fmt-4.1.0/fmt/container.h new file mode 100644 index 00000000..cb6303fb --- /dev/null +++ b/vendor/fmt-4.1.0/fmt/container.h @@ -0,0 +1,82 @@ +/* + Formatting library for C++ - standard container utilities + + Copyright (c) 2012 - 2016, Victor Zverovich + All rights reserved. + + For the license information refer to format.h. + */ + +#ifndef FMT_CONTAINER_H_ +#define FMT_CONTAINER_H_ + +#include "format.h" + +namespace fmt { + +namespace internal { + +/** + \rst + A "buffer" that appends data to a standard container (e.g. typically a + ``std::vector`` or ``std::basic_string``). + \endrst + */ +template <typename Container> +class ContainerBuffer : public Buffer<typename Container::value_type> { + private: + Container& container_; + + protected: + virtual void grow(std::size_t size) FMT_OVERRIDE { + container_.resize(size); + this->ptr_ = &container_[0]; + this->capacity_ = size; + } + + public: + explicit ContainerBuffer(Container& container) : container_(container) { + this->size_ = container_.size(); + if (this->size_ > 0) { + this->ptr_ = &container_[0]; + this->capacity_ = this->size_; + } + } +}; +} // namespace internal + +/** + \rst + This class template provides operations for formatting and appending data + to a standard *container* like ``std::vector`` or ``std::basic_string``. + + **Example**:: + + void vecformat(std::vector<char>& dest, fmt::BasicCStringRef<char> format, + fmt::ArgList args) { + fmt::BasicContainerWriter<std::vector<char> > appender(dest); + appender.write(format, args); + } + FMT_VARIADIC(void, vecformat, std::vector<char>&, + fmt::BasicCStringRef<char>); + \endrst + */ +template <class Container> +class BasicContainerWriter + : public BasicWriter<typename Container::value_type> { + private: + internal::ContainerBuffer<Container> buffer_; + + public: + /** + \rst + Constructs a :class:`fmt::BasicContainerWriter` object. + \endrst + */ + explicit BasicContainerWriter(Container& dest) + : BasicWriter<typename Container::value_type>(buffer_), buffer_(dest) {} +}; + +} // namespace fmt + +#endif // FMT_CONTAINER_H_ diff --git a/vendor/fmt-4.1.0/fmt/format.cc b/vendor/fmt-4.1.0/fmt/format.cc new file mode 100644 index 00000000..2d236bc6 --- /dev/null +++ b/vendor/fmt-4.1.0/fmt/format.cc @@ -0,0 +1,495 @@ +/* + Formatting library for C++ + + Copyright (c) 2012 - 2016, Victor Zverovich + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "format.h" + +#include <string.h> + +#include <cctype> +#include <cerrno> +#include <climits> +#include <cmath> +#include <cstdarg> +#include <cstddef> // for std::ptrdiff_t + +#if defined(_WIN32) && defined(__MINGW32__) +# include <cstring> +#endif + +#if FMT_USE_WINDOWS_H +# if !defined(FMT_HEADER_ONLY) && !defined(WIN32_LEAN_AND_MEAN) +# define WIN32_LEAN_AND_MEAN +# endif +# if defined(NOMINMAX) || defined(FMT_WIN_MINMAX) +# include <windows.h> +# else +# define NOMINMAX +# include <windows.h> +# undef NOMINMAX +# endif +#endif + +#if FMT_EXCEPTIONS +# define FMT_TRY try +# define FMT_CATCH(x) catch (x) +#else +# define FMT_TRY if (true) +# define FMT_CATCH(x) if (false) +#endif + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4127) // conditional expression is constant +# pragma warning(disable: 4702) // unreachable code +// Disable deprecation warning for strerror. The latter is not called but +// MSVC fails to detect it. +# pragma warning(disable: 4996) +#endif + +// Dummy implementations of strerror_r and strerror_s called if corresponding +// system functions are not available. +FMT_MAYBE_UNUSED +static inline fmt::internal::Null<> strerror_r(int, char *, ...) { + return fmt::internal::Null<>(); +} +FMT_MAYBE_UNUSED +static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) { + return fmt::internal::Null<>(); +} + +namespace fmt { + +FMT_FUNC internal::RuntimeError::~RuntimeError() FMT_DTOR_NOEXCEPT {} +FMT_FUNC FormatError::~FormatError() FMT_DTOR_NOEXCEPT {} +FMT_FUNC SystemError::~SystemError() FMT_DTOR_NOEXCEPT {} + +namespace { + +#ifndef _MSC_VER +# define FMT_SNPRINTF snprintf +#else // _MSC_VER +inline int fmt_snprintf(char *buffer, size_t size, const char *format, ...) { + va_list args; + va_start(args, format); + int result = vsnprintf_s(buffer, size, _TRUNCATE, format, args); + va_end(args); + return result; +} +# define FMT_SNPRINTF fmt_snprintf +#endif // _MSC_VER + +#if defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) +# define FMT_SWPRINTF snwprintf +#else +# define FMT_SWPRINTF swprintf +#endif // defined(_WIN32) && defined(__MINGW32__) && !defined(__NO_ISOCEXT) + +const char RESET_COLOR[] = "\x1b[0m"; + +typedef void (*FormatFunc)(Writer &, int, StringRef); + +// Portable thread-safe version of strerror. +// Sets buffer to point to a string describing the error code. +// This can be either a pointer to a string stored in buffer, +// or a pointer to some static immutable string. +// Returns one of the following values: +// 0 - success +// ERANGE - buffer is not large enough to store the error message +// other - failure +// Buffer should be at least of size 1. +int safe_strerror( + int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT { + FMT_ASSERT(buffer != FMT_NULL && buffer_size != 0, "invalid buffer"); + + class StrError { + private: + int error_code_; + char *&buffer_; + std::size_t buffer_size_; + + // A noop assignment operator to avoid bogus warnings. + void operator=(const StrError &) {} + + // Handle the result of XSI-compliant version of strerror_r. + int handle(int result) { + // glibc versions before 2.13 return result in errno. + return result == -1 ? errno : result; + } + + // Handle the result of GNU-specific version of strerror_r. + int handle(char *message) { + // If the buffer is full then the message is probably truncated. + if (message == buffer_ && strlen(buffer_) == buffer_size_ - 1) + return ERANGE; + buffer_ = message; + return 0; + } + + // Handle the case when strerror_r is not available. + int handle(internal::Null<>) { + return fallback(strerror_s(buffer_, buffer_size_, error_code_)); + } + + // Fallback to strerror_s when strerror_r is not available. + int fallback(int result) { + // If the buffer is full then the message is probably truncated. + return result == 0 && strlen(buffer_) == buffer_size_ - 1 ? + ERANGE : result; + } + +#ifdef __c2__ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif + + // Fallback to strerror if strerror_r and strerror_s are not available. + int fallback(internal::Null<>) { + errno = 0; + buffer_ = strerror(error_code_); + return errno; + } + +#ifdef __c2__ +# pragma clang diagnostic pop +#endif + + public: + StrError(int err_code, char *&buf, std::size_t buf_size) + : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {} + + int run() { + return handle(strerror_r(error_code_, buffer_, buffer_size_)); + } + }; + return StrError(error_code, buffer, buffer_size).run(); +} + +void format_error_code(Writer &out, int error_code, + StringRef message) FMT_NOEXCEPT { + // Report error code making sure that the output fits into + // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential + // bad_alloc. + out.clear(); + static const char SEP[] = ": "; + static const char ERROR_STR[] = "error "; + // Subtract 2 to account for terminating null characters in SEP and ERROR_STR. + std::size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2; + typedef internal::IntTraits<int>::MainType MainType; + MainType abs_value = static_cast<MainType>(error_code); + if (internal::is_negative(error_code)) { + abs_value = 0 - abs_value; + ++error_code_size; + } + error_code_size += internal::count_digits(abs_value); + if (message.size() <= internal::INLINE_BUFFER_SIZE - error_code_size) + out << message << SEP; + out << ERROR_STR << error_code; + assert(out.size() <= internal::INLINE_BUFFER_SIZE); +} + +void report_error(FormatFunc func, int error_code, + StringRef message) FMT_NOEXCEPT { + MemoryWriter full_message; + func(full_message, error_code, message); + // Use Writer::data instead of Writer::c_str to avoid potential memory + // allocation. + std::fwrite(full_message.data(), full_message.size(), 1, stderr); + std::fputc('\n', stderr); +} +} // namespace + +FMT_FUNC void SystemError::init( + int err_code, CStringRef format_str, ArgList args) { + error_code_ = err_code; + MemoryWriter w; + format_system_error(w, err_code, format(format_str, args)); + std::runtime_error &base = *this; + base = std::runtime_error(w.str()); +} + +template <typename T> +int internal::CharTraits<char>::format_float( + char *buffer, std::size_t size, const char *format, + unsigned width, int precision, T value) { + if (width == 0) { + return precision < 0 ? + FMT_SNPRINTF(buffer, size, format, value) : + FMT_SNPRINTF(buffer, size, format, precision, value); + } + return precision < 0 ? + FMT_SNPRINTF(buffer, size, format, width, value) : + FMT_SNPRINTF(buffer, size, format, width, precision, value); +} + +template <typename T> +int internal::CharTraits<wchar_t>::format_float( + wchar_t *buffer, std::size_t size, const wchar_t *format, + unsigned width, int precision, T value) { + if (width == 0) { + return precision < 0 ? + FMT_SWPRINTF(buffer, size, format, value) : + FMT_SWPRINTF(buffer, size, format, precision, value); + } + return precision < 0 ? + FMT_SWPRINTF(buffer, size, format, width, value) : + FMT_SWPRINTF(buffer, size, format, width, precision, value); +} + +template <typename T> +const char internal::BasicData<T>::DIGITS[] = + "0001020304050607080910111213141516171819" + "2021222324252627282930313233343536373839" + "4041424344454647484950515253545556575859" + "6061626364656667686970717273747576777879" + "8081828384858687888990919293949596979899"; + +#define FMT_POWERS_OF_10(factor) \ + factor * 10, \ + factor * 100, \ + factor * 1000, \ + factor * 10000, \ + factor * 100000, \ + factor * 1000000, \ + factor * 10000000, \ + factor * 100000000, \ + factor * 1000000000 + +template <typename T> +const uint32_t internal::BasicData<T>::POWERS_OF_10_32[] = { + 0, FMT_POWERS_OF_10(1) +}; + +template <typename T> +const uint64_t internal::BasicData<T>::POWERS_OF_10_64[] = { + 0, + FMT_POWERS_OF_10(1), + FMT_POWERS_OF_10(ULongLong(1000000000)), + // Multiply several constants instead of using a single long long constant + // to avoid warnings about C++98 not supporting long long. + ULongLong(1000000000) * ULongLong(1000000000) * 10 +}; + +FMT_FUNC void internal::report_unknown_type(char code, const char *type) { + (void)type; + if (std::isprint(static_cast<unsigned char>(code))) { + FMT_THROW(FormatError( + format("unknown format code '{}' for {}", code, type))); + } + FMT_THROW(FormatError( + format("unknown format code '\\x{:02x}' for {}", + static_cast<unsigned>(code), type))); +} + +#if FMT_USE_WINDOWS_H + +FMT_FUNC internal::UTF8ToUTF16::UTF8ToUTF16(StringRef s) { + static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16"; + if (s.size() > INT_MAX) + FMT_THROW(WindowsError(ERROR_INVALID_PARAMETER, ERROR_MSG)); + int s_size = static_cast<int>(s.size()); + int length = MultiByteToWideChar( + CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, FMT_NULL, 0); + if (length == 0) + FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); + buffer_.resize(length + 1); + length = MultiByteToWideChar( + CP_UTF8, MB_ERR_INVALID_CHARS, s.data(), s_size, &buffer_[0], length); + if (length == 0) + FMT_THROW(WindowsError(GetLastError(), ERROR_MSG)); + buffer_[length] = 0; +} + +FMT_FUNC internal::UTF16ToUTF8::UTF16ToUTF8(WStringRef s) { + if (int error_code = convert(s)) { + FMT_THROW(WindowsError(error_code, + "cannot convert string from UTF-16 to UTF-8")); + } +} + +FMT_FUNC int internal::UTF16ToUTF8::convert(WStringRef s) { + if (s.size() > INT_MAX) + return ERROR_INVALID_PARAMETER; + int s_size = static_cast<int>(s.size()); + int length = WideCharToMultiByte( + CP_UTF8, 0, s.data(), s_size, FMT_NULL, 0, FMT_NULL, FMT_NULL); + if (length == 0) + return GetLastError(); + buffer_.resize(length + 1); + length = WideCharToMultiByte( + CP_UTF8, 0, s.data(), s_size, &buffer_[0], length, FMT_NULL, FMT_NULL); + if (length == 0) + return GetLastError(); + buffer_[length] = 0; + return 0; +} + +FMT_FUNC void WindowsError::init( + int err_code, CStringRef format_str, ArgList args) { + error_code_ = err_code; + MemoryWriter w; + internal::format_windows_error(w, err_code, format(format_str, args)); + std::runtime_error &base = *this; + base = std::runtime_error(w.str()); +} + +FMT_FUNC void internal::format_windows_error( + Writer &out, int error_code, StringRef message) FMT_NOEXCEPT { + FMT_TRY { + MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer; + buffer.resize(INLINE_BUFFER_SIZE); + for (;;) { + wchar_t *system_message = &buffer[0]; + int result = FormatMessageW( + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + FMT_NULL, error_code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + system_message, static_cast<uint32_t>(buffer.size()), FMT_NULL); + if (result != 0) { + UTF16ToUTF8 utf8_message; + if (utf8_message.convert(system_message) == ERROR_SUCCESS) { + out << message << ": " << utf8_message; + return; + } + break; + } + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) + break; // Can't get error message, report error code instead. + buffer.resize(buffer.size() * 2); + } + } FMT_CATCH(...) {} + fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. +} + +#endif // FMT_USE_WINDOWS_H + +FMT_FUNC void format_system_error( + Writer &out, int error_code, StringRef message) FMT_NOEXCEPT { + FMT_TRY { + internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> buffer; + buffer.resize(internal::INLINE_BUFFER_SIZE); + for (;;) { + char *system_message = &buffer[0]; + int result = safe_strerror(error_code, system_message, buffer.size()); + if (result == 0) { + out << message << ": " << system_message; + return; + } + if (result != ERANGE) + break; // Can't get error message, report error code instead. + buffer.resize(buffer.size() * 2); + } + } FMT_CATCH(...) {} + fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. +} + +template <typename Char> +void internal::FixedBuffer<Char>::grow(std::size_t) { + FMT_THROW(std::runtime_error("buffer overflow")); +} + +FMT_FUNC internal::Arg internal::FormatterBase::do_get_arg( + unsigned arg_index, const char *&error) { + internal::Arg arg = args_[arg_index]; + switch (arg.type) { + case internal::Arg::NONE: + error = "argument index out of range"; + break; + case internal::Arg::NAMED_ARG: + arg = *static_cast<const internal::Arg*>(arg.pointer); + break; + default: + /*nothing*/; + } + return arg; +} + +FMT_FUNC void report_system_error( + int error_code, fmt::StringRef message) FMT_NOEXCEPT { + // 'fmt::' is for bcc32. + report_error(format_system_error, error_code, message); +} + +#if FMT_USE_WINDOWS_H +FMT_FUNC void report_windows_error( + int error_code, fmt::StringRef message) FMT_NOEXCEPT { + // 'fmt::' is for bcc32. + report_error(internal::format_windows_error, error_code, message); +} +#endif + +FMT_FUNC void print(std::FILE *f, CStringRef format_str, ArgList args) { + MemoryWriter w; + w.write(format_str, args); + std::fwrite(w.data(), 1, w.size(), f); +} + +FMT_FUNC void print(CStringRef format_str, ArgList args) { + print(stdout, format_str, args); +} + +FMT_FUNC void print_colored(Color c, CStringRef format, ArgList args) { + char escape[] = "\x1b[30m"; + escape[3] = static_cast<char>('0' + c); + std::fputs(escape, stdout); + print(format, args); + std::fputs(RESET_COLOR, stdout); +} + +#ifndef FMT_HEADER_ONLY + +template struct internal::BasicData<void>; + +// Explicit instantiations for char. + +template void internal::FixedBuffer<char>::grow(std::size_t); + +template FMT_API int internal::CharTraits<char>::format_float( + char *buffer, std::size_t size, const char *format, + unsigned width, int precision, double value); + +template FMT_API int internal::CharTraits<char>::format_float( + char *buffer, std::size_t size, const char *format, + unsigned width, int precision, long double value); + +// Explicit instantiations for wchar_t. + +template void internal::FixedBuffer<wchar_t>::grow(std::size_t); + +template FMT_API int internal::CharTraits<wchar_t>::format_float( + wchar_t *buffer, std::size_t size, const wchar_t *format, + unsigned width, int precision, double value); + +template FMT_API int internal::CharTraits<wchar_t>::format_float( + wchar_t *buffer, std::size_t size, const wchar_t *format, + unsigned width, int precision, long double value); + +#endif // FMT_HEADER_ONLY + +} // namespace fmt + +#ifdef _MSC_VER +# pragma warning(pop) +#endif diff --git a/vendor/fmt-3.0.1/fmt/format.h b/vendor/fmt-4.1.0/fmt/format.h index f8ce147c..561a9e07 100644 --- a/vendor/fmt-3.0.1/fmt/format.h +++ b/vendor/fmt-4.1.0/fmt/format.h @@ -28,6 +28,7 @@ #ifndef FMT_FORMAT_H_ #define FMT_FORMAT_H_ +#define FMT_INCLUDE #include <cassert> #include <clocale> #include <cmath> @@ -38,9 +39,27 @@ #include <stdexcept> #include <string> #include <vector> -#include <utility> +#include <utility> // for std::pair +#undef FMT_INCLUDE -#ifdef _SECURE_SCL +// The fmt library version in the form major * 10000 + minor * 100 + patch. +#define FMT_VERSION 40100 + +#if defined(__has_include) +# define FMT_HAS_INCLUDE(x) __has_include(x) +#else +# define FMT_HAS_INCLUDE(x) 0 +#endif + +#if (FMT_HAS_INCLUDE(<string_view>) && __cplusplus > 201402L) || \ + (defined(_MSVC_LANG) && _MSVC_LANG > 201402L && _MSC_VER >= 1910) +# include <string_view> +# define FMT_HAS_STRING_VIEW 1 +#else +# define FMT_HAS_STRING_VIEW 0 +#endif + +#if defined _SECURE_SCL && _SECURE_SCL # define FMT_SECURE_SCL _SECURE_SCL #else # define FMT_SECURE_SCL 0 @@ -94,7 +113,9 @@ typedef __int64 intmax_t; # define FMT_HAS_GXX_CXX11 1 # endif #else +# define FMT_GCC_VERSION 0 # define FMT_GCC_EXTENSION +# define FMT_HAS_GXX_CXX11 0 #endif #if defined(__INTEL_COMPILER) @@ -104,6 +125,7 @@ typedef __int64 intmax_t; #endif #if defined(__clang__) && !defined(FMT_ICC_VERSION) +# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wdocumentation-unknown-command" # pragma clang diagnostic ignored "-Wpadded" @@ -131,6 +153,32 @@ typedef __int64 intmax_t; # define FMT_HAS_CPP_ATTRIBUTE(x) 0 #endif +#if FMT_HAS_CPP_ATTRIBUTE(maybe_unused) +# define FMT_HAS_CXX17_ATTRIBUTE_MAYBE_UNUSED +// VC++ 1910 support /std: option and that will set _MSVC_LANG macro +// Clang with Microsoft CodeGen doesn't define _MSVC_LANG macro +#elif defined(_MSVC_LANG) && _MSVC_LANG > 201402 && _MSC_VER >= 1910 +# define FMT_HAS_CXX17_ATTRIBUTE_MAYBE_UNUSED +#endif + +#ifdef FMT_HAS_CXX17_ATTRIBUTE_MAYBE_UNUSED +# define FMT_MAYBE_UNUSED [[maybe_unused]] +// g++/clang++ also support [[gnu::unused]]. However, we don't use it. +#elif defined(__GNUC__) +# define FMT_MAYBE_UNUSED __attribute__((unused)) +#else +# define FMT_MAYBE_UNUSED +#endif + +// Use the compiler's attribute noreturn +#if defined(__MINGW32__) || defined(__MINGW64__) +# define FMT_NORETURN __attribute__((noreturn)) +#elif FMT_HAS_CPP_ATTRIBUTE(noreturn) && __cplusplus >= 201103L +# define FMT_NORETURN [[noreturn]] +#else +# define FMT_NORETURN +#endif + #ifndef FMT_USE_VARIADIC_TEMPLATES // Variadic templates are available in GCC since version 4.4 // (http://gcc.gnu.org/projects/cxx0x.html) and in Visual C++ @@ -152,8 +200,10 @@ typedef __int64 intmax_t; # endif #endif -#if FMT_USE_RVALUE_REFERENCES -# include <utility> // for std::move +#if __cplusplus >= 201103L || FMT_MSC_VER >= 1700 +# define FMT_USE_ALLOCATOR_TRAITS 1 +#else +# define FMT_USE_ALLOCATOR_TRAITS 0 #endif // Check if exceptions are disabled. @@ -180,22 +230,32 @@ typedef __int64 intmax_t; # define FMT_USE_NOEXCEPT 0 #endif -#ifndef FMT_NOEXCEPT -# if FMT_EXCEPTIONS -# if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ +#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \ FMT_MSC_VER >= 1900 -# define FMT_NOEXCEPT noexcept -# else -# define FMT_NOEXCEPT throw() -# endif +# define FMT_DETECTED_NOEXCEPT noexcept +#else +# define FMT_DETECTED_NOEXCEPT throw() +#endif + +#ifndef FMT_NOEXCEPT +# if FMT_EXCEPTIONS +# define FMT_NOEXCEPT FMT_DETECTED_NOEXCEPT # else # define FMT_NOEXCEPT # endif #endif +// This is needed because GCC still uses throw() in its headers when exceptions +// are disabled. +#if FMT_GCC_VERSION +# define FMT_DTOR_NOEXCEPT FMT_DETECTED_NOEXCEPT +#else +# define FMT_DTOR_NOEXCEPT FMT_NOEXCEPT +#endif + #ifndef FMT_OVERRIDE -# if FMT_USE_OVERRIDE || FMT_HAS_FEATURE(cxx_override) || \ +# if (defined(FMT_USE_OVERRIDE) && FMT_USE_OVERRIDE) || FMT_HAS_FEATURE(cxx_override) || \ (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \ FMT_MSC_VER >= 1900 # define FMT_OVERRIDE override @@ -204,6 +264,15 @@ typedef __int64 intmax_t; # endif #endif +#ifndef FMT_NULL +# if FMT_HAS_FEATURE(cxx_nullptr) || \ + (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \ + FMT_MSC_VER >= 1600 +# define FMT_NULL nullptr +# else +# define FMT_NULL NULL +# endif +#endif // A macro to disallow the copy constructor and operator= functions // This should be used in the private: declarations for a class @@ -224,40 +293,75 @@ typedef __int64 intmax_t; TypeName& operator=(const TypeName&) #endif +#ifndef FMT_USE_DEFAULTED_FUNCTIONS +# define FMT_USE_DEFAULTED_FUNCTIONS 0 +#endif + +#ifndef FMT_DEFAULTED_COPY_CTOR +# if FMT_USE_DEFAULTED_FUNCTIONS || FMT_HAS_FEATURE(cxx_defaulted_functions) || \ + (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1800 +# define FMT_DEFAULTED_COPY_CTOR(TypeName) \ + TypeName(const TypeName&) = default; +# else +# define FMT_DEFAULTED_COPY_CTOR(TypeName) +# endif +#endif + #ifndef FMT_USE_USER_DEFINED_LITERALS // All compilers which support UDLs also support variadic templates. This // makes the fmt::literals implementation easier. However, an explicit check // for variadic templates is added here just in case. // For Intel's compiler both it and the system gcc/msc must support UDLs. -# define FMT_USE_USER_DEFINED_LITERALS \ - FMT_USE_VARIADIC_TEMPLATES && FMT_USE_RVALUE_REFERENCES && \ +# if FMT_USE_VARIADIC_TEMPLATES && FMT_USE_RVALUE_REFERENCES && \ (FMT_HAS_FEATURE(cxx_user_literals) || \ (FMT_GCC_VERSION >= 407 && FMT_HAS_GXX_CXX11) || FMT_MSC_VER >= 1900) && \ (!defined(FMT_ICC_VERSION) || FMT_ICC_VERSION >= 1500) +# define FMT_USE_USER_DEFINED_LITERALS 1 +# else +# define FMT_USE_USER_DEFINED_LITERALS 0 +# endif +#endif + +#ifndef FMT_USE_EXTERN_TEMPLATES +# define FMT_USE_EXTERN_TEMPLATES \ + (FMT_CLANG_VERSION >= 209 || (FMT_GCC_VERSION >= 303 && FMT_HAS_GXX_CXX11)) +#endif + +#ifdef FMT_HEADER_ONLY +// If header only do not use extern templates. +# undef FMT_USE_EXTERN_TEMPLATES +# define FMT_USE_EXTERN_TEMPLATES 0 #endif #ifndef FMT_ASSERT # define FMT_ASSERT(condition, message) assert((condition) && message) #endif -#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz) -# define FMT_BUILTIN_CLZ(n) __builtin_clz(n) -#endif +// __builtin_clz is broken in clang with Microsoft CodeGen: +// https://github.com/fmtlib/fmt/issues/519 +#ifndef _MSC_VER +# if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz) +# define FMT_BUILTIN_CLZ(n) __builtin_clz(n) +# endif -#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll) -# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) +# if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll) +# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) +# endif #endif // Some compilers masquerade as both MSVC and GCC-likes or // otherwise support __builtin_clz and __builtin_clzll, so // only define FMT_BUILTIN_CLZ using the MSVC intrinsics // if the clz and clzll builtins are not available. -#if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL) +#if FMT_MSC_VER && !defined(FMT_BUILTIN_CLZLL) && !defined(_MANAGED) # include <intrin.h> // _BitScanReverse, _BitScanReverse64 namespace fmt { namespace internal { -# pragma intrinsic(_BitScanReverse) +// avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning +# ifndef __clang__ +# pragma intrinsic(_BitScanReverse) +# endif inline uint32_t clz(uint32_t x) { unsigned long r = 0; _BitScanReverse(&r, x); @@ -271,7 +375,8 @@ inline uint32_t clz(uint32_t x) { } # define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n) -# ifdef _WIN64 +// avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning +# if defined(_WIN64) && !defined(__clang__) # pragma intrinsic(_BitScanReverse64) # endif @@ -360,8 +465,10 @@ class numeric_limits<fmt::internal::DummyInt> : // Portable version of signbit. static bool isnegative(double x) { using namespace fmt::internal; - if (const_check(sizeof(signbit(x)) == sizeof(int))) + if (const_check(sizeof(signbit(x)) == sizeof(bool) || + sizeof(signbit(x)) == sizeof(int))) { return signbit(x) != 0; + } if (x < 0) return true; if (!isnotanumber(x)) return false; int dec = 0, sign = 0; @@ -392,13 +499,19 @@ typedef BasicWriter<wchar_t> WWriter; template <typename Char> class ArgFormatter; +struct FormatSpec; + +template <typename Impl, typename Char, typename Spec = fmt::FormatSpec> +class BasicPrintfArgFormatter; + template <typename CharType, typename ArgFormatter = fmt::ArgFormatter<CharType> > class BasicFormatter; /** \rst - A string reference. It can be constructed from a C string or ``std::string``. + A string reference. It can be constructed from a C string or + ``std::basic_string``. You can use one of the following typedefs for common character types: @@ -441,12 +554,34 @@ class BasicStringRef { /** \rst - Constructs a string reference from an ``std::string`` object. + Constructs a string reference from a ``std::basic_string`` object. \endrst */ - BasicStringRef(const std::basic_string<Char> &s) + template <typename Allocator> + BasicStringRef( + const std::basic_string<Char, std::char_traits<Char>, Allocator> &s) : data_(s.c_str()), size_(s.size()) {} +#if FMT_HAS_STRING_VIEW + /** + \rst + Constructs a string reference from a ``std::basic_string_view`` object. + \endrst + */ + BasicStringRef( + const std::basic_string_view<Char, std::char_traits<Char>> &s) + : data_(s.data()), size_(s.size()) {} + + /** + \rst + Converts a string reference to an ``std::string_view`` object. + \endrst + */ + explicit operator std::basic_string_view<Char>() const FMT_NOEXCEPT { + return std::basic_string_view<Char>(data_, size_); + } +#endif + /** \rst Converts a string reference to an ``std::string`` object. @@ -497,7 +632,7 @@ typedef BasicStringRef<wchar_t> WStringRef; /** \rst A reference to a null terminated string. It can be constructed from a C - string or ``std::string``. + string or ``std::basic_string``. You can use one of the following typedefs for common character types: @@ -530,10 +665,13 @@ class BasicCStringRef { /** \rst - Constructs a string reference from an ``std::string`` object. + Constructs a string reference from a ``std::basic_string`` object. \endrst */ - BasicCStringRef(const std::basic_string<Char> &s) : data_(s.c_str()) {} + template <typename Allocator> + BasicCStringRef( + const std::basic_string<Char, std::char_traits<Char>, Allocator> &s) + : data_(s.c_str()) {} /** Returns the pointer to a C string. */ const Char *c_str() const { return data_; } @@ -547,7 +685,8 @@ class FormatError : public std::runtime_error { public: explicit FormatError(CStringRef message) : std::runtime_error(message.c_str()) {} - ~FormatError() throw(); + FormatError(const FormatError &ferr) : std::runtime_error(ferr) {} + FMT_API ~FormatError() FMT_DTOR_NOEXCEPT FMT_OVERRIDE; }; namespace internal { @@ -605,7 +744,7 @@ class Buffer { std::size_t size_; std::size_t capacity_; - Buffer(T *ptr = 0, std::size_t capacity = 0) + Buffer(T *ptr = FMT_NULL, std::size_t capacity = 0) : ptr_(ptr), size_(0), capacity_(capacity) {} /** @@ -663,7 +802,8 @@ class Buffer { template <typename T> template <typename U> void Buffer<T>::append(const U *begin, const U *end) { - std::size_t new_size = size_ + internal::to_unsigned(end - begin); + FMT_ASSERT(end >= begin, "negative value"); + std::size_t new_size = size_ + static_cast<std::size_t>(end - begin); if (new_size > capacity_) grow(new_size); std::uninitialized_copy(begin, end, @@ -691,7 +831,7 @@ class MemoryBuffer : private Allocator, public Buffer<T> { public: explicit MemoryBuffer(const Allocator &alloc = Allocator()) : Allocator(alloc), Buffer<T>(data_, SIZE) {} - ~MemoryBuffer() { deallocate(); } + ~MemoryBuffer() FMT_OVERRIDE { deallocate(); } #if FMT_USE_RVALUE_REFERENCES private: @@ -735,7 +875,12 @@ void MemoryBuffer<T, SIZE, Allocator>::grow(std::size_t size) { std::size_t new_capacity = this->capacity_ + this->capacity_ / 2; if (size > new_capacity) new_capacity = size; - T *new_ptr = this->allocate(new_capacity); +#if FMT_USE_ALLOCATOR_TRAITS + T *new_ptr = + std::allocator_traits<Allocator>::allocate(*this, new_capacity, FMT_NULL); +#else + T *new_ptr = this->allocate(new_capacity, FMT_NULL); +#endif // The following code doesn't throw, so the raw pointer above doesn't leak. std::uninitialized_copy(this->ptr_, this->ptr_ + this->size_, make_ptr(new_ptr, new_capacity)); @@ -757,7 +902,7 @@ class FixedBuffer : public fmt::Buffer<Char> { FixedBuffer(Char *array, std::size_t size) : fmt::Buffer<Char>(array, size) {} protected: - FMT_API void grow(std::size_t size); + FMT_API void grow(std::size_t size) FMT_OVERRIDE; }; template <typename Char> @@ -789,6 +934,15 @@ class CharTraits<char> : public BasicCharTraits<char> { const char *format, unsigned width, int precision, T value); }; +#if FMT_USE_EXTERN_TEMPLATES +extern template int CharTraits<char>::format_float<double> + (char *buffer, std::size_t size, + const char* format, unsigned width, int precision, double value); +extern template int CharTraits<char>::format_float<long double> + (char *buffer, std::size_t size, + const char* format, unsigned width, int precision, long double value); +#endif + template <> class CharTraits<wchar_t> : public BasicCharTraits<wchar_t> { public: @@ -800,6 +954,15 @@ class CharTraits<wchar_t> : public BasicCharTraits<wchar_t> { const wchar_t *format, unsigned width, int precision, T value); }; +#if FMT_USE_EXTERN_TEMPLATES +extern template int CharTraits<wchar_t>::format_float<double> + (wchar_t *buffer, std::size_t size, + const wchar_t* format, unsigned width, int precision, double value); +extern template int CharTraits<wchar_t>::format_float<long double> + (wchar_t *buffer, std::size_t size, + const wchar_t* format, unsigned width, int precision, long double value); +#endif + // Checks if a number is negative - used to avoid warnings. template <bool IsSigned> struct SignChecker { @@ -835,7 +998,7 @@ struct IntTraits { TypeSelector<std::numeric_limits<T>::digits <= 32>::Type MainType; }; -FMT_API void report_unknown_type(char code, const char *type); +FMT_API FMT_NORETURN void report_unknown_type(char code, const char *type); // Static data is placed in this class template to allow header-only // configuration. @@ -846,13 +1009,7 @@ struct FMT_API BasicData { static const char DIGITS[]; }; -#ifndef FMT_USE_EXTERN_TEMPLATES -// Clang doesn't have a feature check for extern templates so we check -// for variadic templates which were introduced in the same version. -# define FMT_USE_EXTERN_TEMPLATES (__clang__ && FMT_USE_VARIADIC_TEMPLATES) -#endif - -#if FMT_USE_EXTERN_TEMPLATES && !defined(FMT_HEADER_ONLY) +#if FMT_USE_EXTERN_TEMPLATES extern template struct BasicData<void>; #endif @@ -950,7 +1107,8 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits, template <typename UInt, typename Char> inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) { - return format_decimal(buffer, value, num_digits, NoThousandsSep()); + format_decimal(buffer, value, num_digits, NoThousandsSep()); + return; } #ifndef _WIN32 @@ -1000,9 +1158,6 @@ FMT_API void format_windows_error(fmt::Writer &out, int error_code, fmt::StringRef message) FMT_NOEXCEPT; #endif -FMT_API void format_system_error(fmt::Writer &out, int error_code, - fmt::StringRef message) FMT_NOEXCEPT; - // A formatting argument value. struct Value { template <typename Char> @@ -1052,6 +1207,8 @@ struct Arg : Value { template <typename Char> struct NamedArg; +template <typename Char, typename T> +struct NamedArgWithType; template <typename T = void> struct Null {}; @@ -1080,17 +1237,17 @@ T &get(); Yes &convert(fmt::ULongLong); No &convert(...); -template<typename T, bool ENABLE_CONVERSION> +template <typename T, bool ENABLE_CONVERSION> struct ConvertToIntImpl { enum { value = ENABLE_CONVERSION }; }; -template<typename T, bool ENABLE_CONVERSION> +template <typename T, bool ENABLE_CONVERSION> struct ConvertToIntImpl2 { enum { value = false }; }; -template<typename T> +template <typename T> struct ConvertToIntImpl2<T, true> { enum { // Don't convert numeric types. @@ -1098,9 +1255,11 @@ struct ConvertToIntImpl2<T, true> { }; }; -template<typename T> +template <typename T> struct ConvertToInt { - enum { enable_conversion = sizeof(convert(get<T>())) == sizeof(Yes) }; + enum { + enable_conversion = sizeof(fmt::internal::convert(get<T>())) == sizeof(Yes) + }; enum { value = ConvertToIntImpl2<T, enable_conversion>::value }; }; @@ -1113,26 +1272,29 @@ FMT_DISABLE_CONVERSION_TO_INT(float); FMT_DISABLE_CONVERSION_TO_INT(double); FMT_DISABLE_CONVERSION_TO_INT(long double); -template<bool B, class T = void> +template <bool B, class T = void> struct EnableIf {}; -template<class T> +template <class T> struct EnableIf<true, T> { typedef T type; }; -template<bool B, class T, class F> +template <bool B, class T, class F> struct Conditional { typedef T type; }; -template<class T, class F> +template <class T, class F> struct Conditional<false, T, F> { typedef F type; }; // For bcc32 which doesn't understand ! in template arguments. -template<bool> +template <bool> struct Not { enum { value = 0 }; }; -template<> +template <> struct Not<false> { enum { value = 1 }; }; -template<typename T, T> struct LConvCheck { +template <typename T> +struct FalseType { enum { value = 0 }; }; + +template <typename T, T> struct LConvCheck { LConvCheck(int) {} }; @@ -1147,6 +1309,35 @@ inline StringRef thousands_sep( inline fmt::StringRef thousands_sep(...) { return ""; } +#define FMT_CONCAT(a, b) a##b + +#if FMT_GCC_VERSION >= 303 +# define FMT_UNUSED __attribute__((unused)) +#else +# define FMT_UNUSED +#endif + +#ifndef FMT_USE_STATIC_ASSERT +# define FMT_USE_STATIC_ASSERT 0 +#endif + +#if FMT_USE_STATIC_ASSERT || FMT_HAS_FEATURE(cxx_static_assert) || \ + (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600 +# define FMT_STATIC_ASSERT(cond, message) static_assert(cond, message) +#else +# define FMT_CONCAT_(a, b) FMT_CONCAT(a, b) +# define FMT_STATIC_ASSERT(cond, message) \ + typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED +#endif + +template <typename Formatter> +void format_arg(Formatter&, ...) { + FMT_STATIC_ASSERT(FalseType<Formatter>::value, + "Cannot format argument. To enable the use of ostream " + "operator<< include fmt/ostream.h. Otherwise provide " + "an overload of format_arg."); +} + // Makes an Arg object from any type. template <typename Formatter> class MakeValue : public Arg { @@ -1174,6 +1365,9 @@ class MakeValue : public Arg { MakeValue(typename WCharHelper<wchar_t *, Char>::Unsupported); MakeValue(typename WCharHelper<const wchar_t *, Char>::Unsupported); MakeValue(typename WCharHelper<const std::wstring &, Char>::Unsupported); +#if FMT_HAS_STRING_VIEW + MakeValue(typename WCharHelper<const std::wstring_view &, Char>::Unsupported); +#endif MakeValue(typename WCharHelper<WStringRef, Char>::Unsupported); void set_string(StringRef str) { @@ -1190,9 +1384,9 @@ class MakeValue : public Arg { template <typename T> static void format_custom_arg( void *formatter, const void *arg, void *format_str_ptr) { - format(*static_cast<Formatter*>(formatter), - *static_cast<const Char**>(format_str_ptr), - *static_cast<const T*>(arg)); + format_arg(*static_cast<Formatter*>(formatter), + *static_cast<const Char**>(format_str_ptr), + *static_cast<const T*>(arg)); } public: @@ -1243,6 +1437,20 @@ class MakeValue : public Arg { FMT_MAKE_VALUE(unsigned char, uint_value, UINT) FMT_MAKE_VALUE(char, int_value, CHAR) +#if __cplusplus >= 201103L + template < + typename T, + typename = typename std::enable_if< + std::is_enum<T>::value && ConvertToInt<T>::value>::type> + MakeValue(T value) { int_value = value; } + + template < + typename T, + typename = typename std::enable_if< + std::is_enum<T>::value && ConvertToInt<T>::value>::type> + static uint64_t type(T) { return Arg::INT; } +#endif + #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) MakeValue(typename WCharHelper<wchar_t, Char>::Supported value) { int_value = value; @@ -1261,6 +1469,9 @@ class MakeValue : public Arg { FMT_MAKE_VALUE(unsigned char *, ustring.value, CSTRING) FMT_MAKE_VALUE(const unsigned char *, ustring.value, CSTRING) FMT_MAKE_STR_VALUE(const std::string &, STRING) +#if FMT_HAS_STRING_VIEW + FMT_MAKE_STR_VALUE(const std::string_view &, STRING) +#endif FMT_MAKE_STR_VALUE(StringRef, STRING) FMT_MAKE_VALUE_(CStringRef, string.value, CSTRING, value.c_str()) @@ -1273,6 +1484,9 @@ class MakeValue : public Arg { FMT_MAKE_WSTR_VALUE(wchar_t *, WSTRING) FMT_MAKE_WSTR_VALUE(const wchar_t *, WSTRING) FMT_MAKE_WSTR_VALUE(const std::wstring &, WSTRING) +#if FMT_HAS_STRING_VIEW + FMT_MAKE_WSTR_VALUE(const std::wstring_view &, WSTRING) +#endif FMT_MAKE_WSTR_VALUE(WStringRef, WSTRING) FMT_MAKE_VALUE(void *, pointer, POINTER) @@ -1287,23 +1501,22 @@ class MakeValue : public Arg { } template <typename T> - MakeValue(const T &value, - typename EnableIf<ConvertToInt<T>::value, int>::type = 0) { - int_value = value; - } - - template <typename T> - static uint64_t type(const T &) { - return ConvertToInt<T>::value ? Arg::INT : Arg::CUSTOM; + static typename EnableIf<Not<ConvertToInt<T>::value>::value, uint64_t>::type + type(const T &) { + return Arg::CUSTOM; } // Additional template param `Char_` is needed here because make_type always // uses char. template <typename Char_> MakeValue(const NamedArg<Char_> &value) { pointer = &value; } + template <typename Char_, typename T> + MakeValue(const NamedArgWithType<Char_, T> &value) { pointer = &value; } template <typename Char_> static uint64_t type(const NamedArg<Char_> &) { return Arg::NAMED_ARG; } + template <typename Char_, typename T> + static uint64_t type(const NamedArgWithType<Char_, T> &) { return Arg::NAMED_ARG; } }; template <typename Formatter> @@ -1329,16 +1542,20 @@ struct NamedArg : Arg { : Arg(MakeArg< BasicFormatter<Char> >(value)), name(argname) {} }; +template <typename Char, typename T> +struct NamedArgWithType : NamedArg<Char> { + NamedArgWithType(BasicStringRef<Char> argname, const T &value) + : NamedArg<Char>(argname, value) {} +}; + class RuntimeError : public std::runtime_error { protected: RuntimeError() : std::runtime_error("") {} - ~RuntimeError() throw(); + RuntimeError(const RuntimeError &rerr) : std::runtime_error(rerr) {} + FMT_API ~RuntimeError() FMT_DTOR_NOEXCEPT FMT_OVERRIDE; }; template <typename Char> -class PrintfArgFormatter; - -template <typename Char> class ArgMap; } // namespace internal @@ -1359,10 +1576,7 @@ class ArgList { }; internal::Arg::Type type(unsigned index) const { - unsigned shift = index * 4; - uint64_t mask = 0xf; - return static_cast<internal::Arg::Type>( - (types_ & (mask << shift)) >> shift); + return type(types_, index); } template <typename Char> @@ -1379,6 +1593,8 @@ class ArgList { ArgList(ULongLong types, const internal::Arg *args) : types_(types), args_(args) {} + uint64_t types() const { return types_; } + /** Returns the argument at specified index. */ internal::Arg operator[](unsigned index) const { using internal::Arg; @@ -1404,6 +1620,13 @@ class ArgList { } return args_[index]; } + + static internal::Arg::Type type(uint64_t types, unsigned index) { + unsigned shift = index * 4; + uint64_t mask = 0xf; + return static_cast<internal::Arg::Type>( + (types & (mask << shift)) >> shift); + } }; #define FMT_DISPATCH(call) static_cast<Impl*>(this)->call @@ -1588,6 +1811,7 @@ struct TypeSpec : EmptySpec { int precision() const { return -1; } bool flag(unsigned) const { return false; } char type() const { return TYPE; } + char type_prefix() const { return TYPE; } char fill() const { return ' '; } }; @@ -1623,6 +1847,7 @@ struct AlignTypeSpec : AlignSpec { bool flag(unsigned) const { return false; } char type() const { return TYPE; } + char type_prefix() const { return TYPE; } }; // A full format specifier. @@ -1638,6 +1863,7 @@ struct FormatSpec : AlignSpec { bool flag(unsigned f) const { return (flags_ & f) != 0; } int precision() const { return precision_; } char type() const { return type_; } + char type_prefix() const { return type_; } }; // An integer format specifier. @@ -1800,24 +2026,69 @@ class ArgMap { MapType map_; public: - FMT_API void init(const ArgList &args); + void init(const ArgList &args); - const internal::Arg* find(const fmt::BasicStringRef<Char> &name) const { + const internal::Arg *find(const fmt::BasicStringRef<Char> &name) const { // The list is unsorted, so just return the first matching name. for (typename MapType::const_iterator it = map_.begin(), end = map_.end(); it != end; ++it) { if (it->first == name) return &it->second; } - return 0; + return FMT_NULL; } }; -template <typename Impl, typename Char> +template <typename Char> +void ArgMap<Char>::init(const ArgList &args) { + if (!map_.empty()) + return; + typedef internal::NamedArg<Char> NamedArg; + const NamedArg *named_arg = FMT_NULL; + bool use_values = + args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE; + if (use_values) { + for (unsigned i = 0;/*nothing*/; ++i) { + internal::Arg::Type arg_type = args.type(i); + switch (arg_type) { + case internal::Arg::NONE: + return; + case internal::Arg::NAMED_ARG: + named_arg = static_cast<const NamedArg*>(args.values_[i].pointer); + map_.push_back(Pair(named_arg->name, *named_arg)); + break; + default: + /*nothing*/; + } + } + return; + } + for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) { + internal::Arg::Type arg_type = args.type(i); + if (arg_type == internal::Arg::NAMED_ARG) { + named_arg = static_cast<const NamedArg*>(args.args_[i].pointer); + map_.push_back(Pair(named_arg->name, *named_arg)); + } + } + for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) { + switch (args.args_[i].type) { + case internal::Arg::NONE: + return; + case internal::Arg::NAMED_ARG: + named_arg = static_cast<const NamedArg*>(args.args_[i].pointer); + map_.push_back(Pair(named_arg->name, *named_arg)); + break; + default: + /*nothing*/; + } + } +} + +template <typename Impl, typename Char, typename Spec = fmt::FormatSpec> class ArgFormatterBase : public ArgVisitor<Impl, void> { private: BasicWriter<Char> &writer_; - FormatSpec &spec_; + Spec &spec_; FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatterBase); @@ -1827,9 +2098,12 @@ class ArgFormatterBase : public ArgVisitor<Impl, void> { writer_.write_int(reinterpret_cast<uintptr_t>(p), spec_); } + // workaround MSVC two-phase lookup issue + typedef internal::Arg Arg; + protected: BasicWriter<Char> &writer() { return writer_; } - FormatSpec &spec() { return spec_; } + Spec &spec() { return spec_; } void write(bool value) { const char *str_value = value ? "true" : "false"; @@ -1838,12 +2112,14 @@ class ArgFormatterBase : public ArgVisitor<Impl, void> { } void write(const char *value) { - Arg::StringValue<char> str = {value, value != 0 ? std::strlen(value) : 0}; + Arg::StringValue<char> str = {value, value ? std::strlen(value) : 0}; writer_.write_str(str, spec_); } public: - ArgFormatterBase(BasicWriter<Char> &w, FormatSpec &s) + typedef Spec SpecType; + + ArgFormatterBase(BasicWriter<Char> &w, Spec &s) : writer_(w), spec_(s) {} template <typename T> @@ -1853,8 +2129,10 @@ class ArgFormatterBase : public ArgVisitor<Impl, void> { void visit_any_double(T value) { writer_.write_double(value, spec_); } void visit_bool(bool value) { - if (spec_.type_) - return visit_any_int(value); + if (spec_.type_) { + visit_any_int(value); + return; + } write(value); } @@ -1894,13 +2172,14 @@ class ArgFormatterBase : public ArgVisitor<Impl, void> { write(value); } - void visit_string(Arg::StringValue<char> value) { + // Qualification with "internal" here and below is a workaround for nvcc. + void visit_string(internal::Arg::StringValue<char> value) { writer_.write_str(value, spec_); } using ArgVisitor<Impl, void>::visit_wstring; - void visit_wstring(Arg::StringValue<Char> value) { + void visit_wstring(internal::Arg::StringValue<Char> value) { writer_.write_str(value, spec_); } @@ -1956,26 +2235,6 @@ class FormatterBase { w << BasicStringRef<Char>(start, internal::to_unsigned(end - start)); } }; - -// A printf formatter. -template <typename Char> -class PrintfFormatter : private FormatterBase { - private: - void parse_flags(FormatSpec &spec, const Char *&s); - - // Returns the argument with specified index or, if arg_index is equal - // to the maximum unsigned value, the next argument. - Arg get_arg(const Char *s, - unsigned arg_index = (std::numeric_limits<unsigned>::max)()); - - // Parses argument index, flags and width and returns the argument index. - unsigned parse_header(const Char *&s, FormatSpec &spec); - - public: - explicit PrintfFormatter(const ArgList &args) : FormatterBase(args) {} - FMT_API void format(BasicWriter<Char> &writer, - BasicCStringRef<Char> format_str); -}; } // namespace internal /** @@ -1995,8 +2254,8 @@ class PrintfFormatter : private FormatterBase { will be called. \endrst */ -template <typename Impl, typename Char> -class BasicArgFormatter : public internal::ArgFormatterBase<Impl, Char> { +template <typename Impl, typename Char, typename Spec = fmt::FormatSpec> +class BasicArgFormatter : public internal::ArgFormatterBase<Impl, Char, Spec> { private: BasicFormatter<Char, Impl> &formatter_; const Char *format_; @@ -2011,11 +2270,11 @@ class BasicArgFormatter : public internal::ArgFormatterBase<Impl, Char> { \endrst */ BasicArgFormatter(BasicFormatter<Char, Impl> &formatter, - FormatSpec &spec, const Char *fmt) - : internal::ArgFormatterBase<Impl, Char>(formatter.writer(), spec), + Spec &spec, const Char *fmt) + : internal::ArgFormatterBase<Impl, Char, Spec>(formatter.writer(), spec), formatter_(formatter), format_(fmt) {} - /** Formats argument of a custom (user-defined) type. */ + /** Formats an argument of a custom (user-defined) type. */ void visit_custom(internal::Arg::CustomValue c) { c.format(&formatter_, c.value, &format_); } @@ -2023,12 +2282,14 @@ class BasicArgFormatter : public internal::ArgFormatterBase<Impl, Char> { /** The default argument formatter. */ template <typename Char> -class ArgFormatter : public BasicArgFormatter<ArgFormatter<Char>, Char> { +class ArgFormatter : + public BasicArgFormatter<ArgFormatter<Char>, Char, FormatSpec> { public: /** Constructs an argument formatter object. */ ArgFormatter(BasicFormatter<Char> &formatter, FormatSpec &spec, const Char *fmt) - : BasicArgFormatter<ArgFormatter<Char>, Char>(formatter, spec, fmt) {} + : BasicArgFormatter<ArgFormatter<Char>, + Char, FormatSpec>(formatter, spec, fmt) {} }; /** This template formats data and writes the output to a writer. */ @@ -2104,12 +2365,13 @@ inline uint64_t make_type(const T &arg) { return MakeValue< BasicFormatter<char> >::type(arg); } -template <unsigned N, bool/*IsPacked*/= (N < ArgList::MAX_PACKED_ARGS)> +template <std::size_t N, bool/*IsPacked*/= (N < ArgList::MAX_PACKED_ARGS)> struct ArgArray; -template <unsigned N> +template <std::size_t N> struct ArgArray<N, true/*IsPacked*/> { - typedef Value Type[N > 0 ? N : 1]; + // '+' is used to silence GCC -Wduplicated-branches warning. + typedef Value Type[N > 0 ? N : +1]; template <typename Formatter, typename T> static Value make(const T &value) { @@ -2125,7 +2387,7 @@ struct ArgArray<N, true/*IsPacked*/> { } }; -template <unsigned N> +template <std::size_t N> struct ArgArray<N, false/*IsPacked*/> { typedef Arg Type[N + 1]; // +1 for the list end Arg::NONE @@ -2265,7 +2527,7 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) { */ class SystemError : public internal::RuntimeError { private: - void init(int err_code, CStringRef format_str, ArgList args); + FMT_API void init(int err_code, CStringRef format_str, ArgList args); protected: int error_code_; @@ -2277,17 +2539,10 @@ class SystemError : public internal::RuntimeError { public: /** \rst - Constructs a :class:`fmt::SystemError` object with the description - of the form - - .. parsed-literal:: - *<message>*: *<system-message>* - - where *<message>* is the formatted message and *<system-message>* is - the system message corresponding to the error code. - *error_code* is a system error code as given by ``errno``. - If *error_code* is not a valid error code such as -1, the system message - may look like "Unknown error -1" and is platform-dependent. + Constructs a :class:`fmt::SystemError` object with a description + formatted with `fmt::format_system_error`. *message* and additional + arguments passed into the constructor are formatted similarly to + `fmt::format`. **Example**:: @@ -2303,15 +2558,35 @@ class SystemError : public internal::RuntimeError { SystemError(int error_code, CStringRef message) { init(error_code, message, ArgList()); } + FMT_DEFAULTED_COPY_CTOR(SystemError) FMT_VARIADIC_CTOR(SystemError, init, int, CStringRef) - ~SystemError() throw(); + FMT_API ~SystemError() FMT_DTOR_NOEXCEPT FMT_OVERRIDE; int error_code() const { return error_code_; } }; /** \rst + Formats an error returned by an operating system or a language runtime, + for example a file opening error, and writes it to *out* in the following + form: + + .. parsed-literal:: + *<message>*: *<system-message>* + + where *<message>* is the passed message and *<system-message>* is + the system message corresponding to the error code. + *error_code* is a system error code as given by ``errno``. + If *error_code* is not a valid error code such as -1, the system message + may look like "Unknown error -1" and is platform-dependent. + \endrst + */ +FMT_API void format_system_error(fmt::Writer &out, int error_code, + fmt::StringRef message) FMT_NOEXCEPT; + +/** + \rst This template provides operations for formatting and writing data into a character stream. The output is stored in a buffer provided by a subclass such as :class:`fmt::BasicMemoryWriter`. @@ -2398,16 +2673,16 @@ class BasicWriter { void write_int(T value, Spec spec); // Formats a floating-point number (double or long double). - template <typename T> - void write_double(T value, const FormatSpec &spec); + template <typename T, typename Spec> + void write_double(T value, const Spec &spec); // Writes a formatted string. template <typename StrChar> CharPtr write_str(const StrChar *s, std::size_t size, const AlignSpec &spec); - template <typename StrChar> + template <typename StrChar, typename Spec> void write_str(const internal::Arg::StringValue<StrChar> &str, - const FormatSpec &spec); + const Spec &spec); // This following methods are private to disallow writing wide characters // and strings to a char stream. If you want to print a wide string as a @@ -2426,10 +2701,11 @@ class BasicWriter { template<typename T> void append_float_length(Char *&, T) {} - template <typename Impl, typename Char_> + template <typename Impl, typename Char_, typename Spec_> friend class internal::ArgFormatterBase; - friend class internal::PrintfArgFormatter<Char>; + template <typename Impl, typename Char_, typename Spec_> + friend class BasicPrintfArgFormatter; protected: /** @@ -2625,9 +2901,9 @@ typename BasicWriter<Char>::CharPtr BasicWriter<Char>::write_str( } template <typename Char> -template <typename StrChar> +template <typename StrChar, typename Spec> void BasicWriter<Char>::write_str( - const internal::Arg::StringValue<StrChar> &s, const FormatSpec &spec) { + const internal::Arg::StringValue<StrChar> &s, const Spec &spec) { // Check if StrChar is convertible to Char. internal::CharTraits<Char>::convert(StrChar()); if (spec.type_ && spec.type_ != 's') @@ -2751,7 +3027,7 @@ void BasicWriter<Char>::write_int(T value, Spec spec) { UnsignedType n = abs_value; if (spec.flag(HASH_FLAG)) { prefix[prefix_size++] = '0'; - prefix[prefix_size++] = spec.type(); + prefix[prefix_size++] = spec.type_prefix(); } unsigned num_digits = 0; do { @@ -2771,7 +3047,7 @@ void BasicWriter<Char>::write_int(T value, Spec spec) { UnsignedType n = abs_value; if (spec.flag(HASH_FLAG)) { prefix[prefix_size++] = '0'; - prefix[prefix_size++] = spec.type(); + prefix[prefix_size++] = spec.type_prefix(); } unsigned num_digits = 0; do { @@ -2802,7 +3078,7 @@ void BasicWriter<Char>::write_int(T value, Spec spec) { case 'n': { unsigned num_digits = internal::count_digits(abs_value); fmt::StringRef sep = ""; -#ifndef ANDROID +#if !(defined(ANDROID) || defined(__ANDROID__)) sep = internal::thousands_sep(std::localeconv()); #endif unsigned size = static_cast<unsigned>( @@ -2819,8 +3095,8 @@ void BasicWriter<Char>::write_int(T value, Spec spec) { } template <typename Char> -template <typename T> -void BasicWriter<Char>::write_double(T value, const FormatSpec &spec) { +template <typename T, typename Spec> +void BasicWriter<Char>::write_double(T value, const Spec &spec) { // Check type. char type = spec.type(); bool upper = false; @@ -2921,7 +3197,7 @@ void BasicWriter<Char>::write_double(T value, const FormatSpec &spec) { // Format using snprintf. Char fill = internal::CharTraits<Char>::cast(spec.fill()); unsigned n = 0; - Char *start = 0; + Char *start = FMT_NULL; for (;;) { std::size_t buffer_size = buffer_.capacity() - offset; #if FMT_MSC_VER @@ -3198,56 +3474,6 @@ FMT_API void print(std::FILE *f, CStringRef format_str, ArgList args); */ FMT_API void print(CStringRef format_str, ArgList args); -template <typename Char> -void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args) { - internal::PrintfFormatter<Char>(args).format(w, format); -} - -/** - \rst - Formats arguments and returns the result as a string. - - **Example**:: - - std::string message = fmt::sprintf("The answer is %d", 42); - \endrst -*/ -inline std::string sprintf(CStringRef format, ArgList args) { - MemoryWriter w; - printf(w, format, args); - return w.str(); -} - -inline std::wstring sprintf(WCStringRef format, ArgList args) { - WMemoryWriter w; - printf(w, format, args); - return w.str(); -} - -/** - \rst - Prints formatted data to the file *f*. - - **Example**:: - - fmt::fprintf(stderr, "Don't %s!", "panic"); - \endrst - */ -FMT_API int fprintf(std::FILE *f, CStringRef format, ArgList args); - -/** - \rst - Prints formatted data to ``stdout``. - - **Example**:: - - fmt::printf("Elapsed time: %.2f seconds", 1.23); - \endrst - */ -inline int printf(CStringRef format, ArgList args) { - return fprintf(stdout, format, args); -} - /** Fast integer formatter. */ @@ -3364,13 +3590,13 @@ inline void format_decimal(char *&buffer, T value) { \endrst */ template <typename T> -inline internal::NamedArg<char> arg(StringRef name, const T &arg) { - return internal::NamedArg<char>(name, arg); +inline internal::NamedArgWithType<char, T> arg(StringRef name, const T &arg) { + return internal::NamedArgWithType<char, T>(name, arg); } template <typename T> -inline internal::NamedArg<wchar_t> arg(WStringRef name, const T &arg) { - return internal::NamedArg<wchar_t>(name, arg); +inline internal::NamedArgWithType<wchar_t, T> arg(WStringRef name, const T &arg) { + return internal::NamedArgWithType<wchar_t, T>(name, arg); } // The following two functions are deleted intentionally to disable @@ -3399,7 +3625,6 @@ void arg(WStringRef, const internal::NamedArg<Char>&) FMT_DELETED_OR_UNDEFINED; #define FMT_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N #define FMT_RSEQ_N() 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 -#define FMT_CONCAT(a, b) a##b #define FMT_FOR_EACH_(N, f, ...) \ FMT_EXPAND(FMT_CONCAT(FMT_FOR_EACH, N)(f, __VA_ARGS__)) #define FMT_FOR_EACH(f, ...) \ @@ -3409,10 +3634,10 @@ void arg(WStringRef, const internal::NamedArg<Char>&) FMT_DELETED_OR_UNDEFINED; #define FMT_GET_ARG_NAME(type, index) arg##index #if FMT_USE_VARIADIC_TEMPLATES -# define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \ +# define FMT_VARIADIC_(Const, Char, ReturnType, func, call, ...) \ template <typename... Args> \ ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ - const Args & ... args) { \ + const Args & ... args) Const { \ typedef fmt::internal::ArgArray<sizeof...(Args)> ArgArray; \ typename ArgArray::Type array{ \ ArgArray::template make<fmt::BasicFormatter<Char> >(args)...}; \ @@ -3422,35 +3647,35 @@ void arg(WStringRef, const internal::NamedArg<Char>&) FMT_DELETED_OR_UNDEFINED; #else // Defines a wrapper for a function taking __VA_ARGS__ arguments // and n additional arguments of arbitrary types. -# define FMT_WRAP(Char, ReturnType, func, call, n, ...) \ +# define FMT_WRAP(Const, Char, ReturnType, func, call, n, ...) \ template <FMT_GEN(n, FMT_MAKE_TEMPLATE_ARG)> \ inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__), \ - FMT_GEN(n, FMT_MAKE_ARG)) { \ + FMT_GEN(n, FMT_MAKE_ARG)) Const { \ fmt::internal::ArgArray<n>::Type arr; \ FMT_GEN(n, FMT_ASSIGN_##Char); \ call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList( \ fmt::internal::make_type(FMT_GEN(n, FMT_MAKE_REF2)), arr)); \ } -# define FMT_VARIADIC_(Char, ReturnType, func, call, ...) \ - inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__)) { \ +# define FMT_VARIADIC_(Const, Char, ReturnType, func, call, ...) \ + inline ReturnType func(FMT_FOR_EACH(FMT_ADD_ARG_NAME, __VA_ARGS__)) Const { \ call(FMT_FOR_EACH(FMT_GET_ARG_NAME, __VA_ARGS__), fmt::ArgList()); \ } \ - FMT_WRAP(Char, ReturnType, func, call, 1, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 2, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 3, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 4, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 5, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 6, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 7, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 8, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 9, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 10, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 11, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 12, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 13, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 14, __VA_ARGS__) \ - FMT_WRAP(Char, ReturnType, func, call, 15, __VA_ARGS__) + FMT_WRAP(Const, Char, ReturnType, func, call, 1, __VA_ARGS__) \ + FMT_WRAP(Const, Char, ReturnType, func, call, 2, __VA_ARGS__) \ + FMT_WRAP(Const, Char, ReturnType, func, call, 3, __VA_ARGS__) \ + FMT_WRAP(Const, Char, ReturnType, func, call, 4, __VA_ARGS__) \ + FMT_WRAP(Const, Char, ReturnType, func, call, 5, __VA_ARGS__) \ + FMT_WRAP(Const, Char, ReturnType, func, call, 6, __VA_ARGS__) \ + FMT_WRAP(Const, Char, ReturnType, func, call, 7, __VA_ARGS__) \ + FMT_WRAP(Const, Char, ReturnType, func, call, 8, __VA_ARGS__) \ + FMT_WRAP(Const, Char, ReturnType, func, call, 9, __VA_ARGS__) \ + FMT_WRAP(Const, Char, ReturnType, func, call, 10, __VA_ARGS__) \ + FMT_WRAP(Const, Char, ReturnType, func, call, 11, __VA_ARGS__) \ + FMT_WRAP(Const, Char, ReturnType, func, call, 12, __VA_ARGS__) \ + FMT_WRAP(Const, Char, ReturnType, func, call, 13, __VA_ARGS__) \ + FMT_WRAP(Const, Char, ReturnType, func, call, 14, __VA_ARGS__) \ + FMT_WRAP(Const, Char, ReturnType, func, call, 15, __VA_ARGS__) #endif // FMT_USE_VARIADIC_TEMPLATES /** @@ -3481,10 +3706,16 @@ void arg(WStringRef, const internal::NamedArg<Char>&) FMT_DELETED_OR_UNDEFINED; \endrst */ #define FMT_VARIADIC(ReturnType, func, ...) \ - FMT_VARIADIC_(char, ReturnType, func, return func, __VA_ARGS__) + FMT_VARIADIC_(, char, ReturnType, func, return func, __VA_ARGS__) + +#define FMT_VARIADIC_CONST(ReturnType, func, ...) \ + FMT_VARIADIC_(const, char, ReturnType, func, return func, __VA_ARGS__) #define FMT_VARIADIC_W(ReturnType, func, ...) \ - FMT_VARIADIC_(wchar_t, ReturnType, func, return func, __VA_ARGS__) + FMT_VARIADIC_(, wchar_t, ReturnType, func, return func, __VA_ARGS__) + +#define FMT_VARIADIC_CONST_W(ReturnType, func, ...) \ + FMT_VARIADIC_(const, wchar_t, ReturnType, func, return func, __VA_ARGS__) #define FMT_CAPTURE_ARG_(id, index) ::fmt::arg(#id, id) @@ -3513,12 +3744,7 @@ FMT_VARIADIC(std::string, format, CStringRef) FMT_VARIADIC_W(std::wstring, format, WCStringRef) FMT_VARIADIC(void, print, CStringRef) FMT_VARIADIC(void, print, std::FILE *, CStringRef) - FMT_VARIADIC(void, print_colored, Color, CStringRef) -FMT_VARIADIC(std::string, sprintf, CStringRef) -FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef) -FMT_VARIADIC(int, printf, CStringRef) -FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef) namespace internal { template <typename Char> @@ -3532,17 +3758,19 @@ template <typename Char> unsigned parse_nonnegative_int(const Char *&s) { assert('0' <= *s && *s <= '9'); unsigned value = 0; + // Convert to unsigned to prevent a warning. + unsigned max_int = (std::numeric_limits<int>::max)(); + unsigned big = max_int / 10; do { - unsigned new_value = value * 10 + (*s++ - '0'); - // Check if value wrapped around. - if (new_value < value) { - value = (std::numeric_limits<unsigned>::max)(); + // Check for overflow. + if (value > big) { + value = max_int + 1; break; } - value = new_value; + value = value * 10 + (*s - '0'); + ++s; } while ('0' <= *s && *s <= '9'); // Convert to unsigned to prevent a warning. - unsigned max_int = (std::numeric_limits<int>::max)(); if (value > max_int) FMT_THROW(FormatError("number is too big")); return value; @@ -3583,7 +3811,7 @@ inline internal::Arg BasicFormatter<Char, AF>::get_arg( template <typename Char, typename AF> inline internal::Arg BasicFormatter<Char, AF>::parse_arg_index(const Char *&s) { - const char *error = 0; + const char *error = FMT_NULL; internal::Arg arg = *s < '0' || *s > '9' ? next_arg(error) : get_arg(internal::parse_nonnegative_int(s), error); if (error) { @@ -3601,7 +3829,7 @@ inline internal::Arg BasicFormatter<Char, AF>::parse_arg_name(const Char *&s) { do { c = *++s; } while (internal::is_name_start(c) || ('0' <= c && c <= '9')); - const char *error = 0; + const char *error = FMT_NULL; internal::Arg arg = get_arg(BasicStringRef<Char>(start, s - start), error); if (error) FMT_THROW(FormatError(error)); @@ -3613,7 +3841,7 @@ const Char *BasicFormatter<Char, ArgFormatter>::format( const Char *&format_str, const internal::Arg &arg) { using internal::Arg; const Char *s = format_str; - FormatSpec spec; + typename ArgFormatter::SpecType spec; if (*s == ':') { if (arg.type == Arg::CUSTOM) { arg.custom.format(this, arg.custom.value, &s); @@ -3714,7 +3942,8 @@ const Char *BasicFormatter<Char, ArgFormatter>::format( default: FMT_THROW(FormatError("width is not integer")); } - if (value > (std::numeric_limits<int>::max)()) + unsigned max_int = (std::numeric_limits<int>::max)(); + if (value > max_int) FMT_THROW(FormatError("number is too big")); spec.width_ = static_cast<int>(value); } @@ -3752,7 +3981,8 @@ const Char *BasicFormatter<Char, ArgFormatter>::format( default: FMT_THROW(FormatError("precision is not integer")); } - if (value > (std::numeric_limits<int>::max)()) + unsigned max_int = (std::numeric_limits<int>::max)(); + if (value > max_int) FMT_THROW(FormatError("number is too big")); spec.precision_ = static_cast<int>(value); } else { @@ -3799,6 +4029,66 @@ void BasicFormatter<Char, AF>::format(BasicCStringRef<Char> format_str) { } write(writer_, start, s); } + +template <typename Char, typename It> +struct ArgJoin { + It first; + It last; + BasicCStringRef<Char> sep; + + ArgJoin(It first, It last, const BasicCStringRef<Char>& sep) : + first(first), + last(last), + sep(sep) {} +}; + +template <typename It> +ArgJoin<char, It> join(It first, It last, const BasicCStringRef<char>& sep) { + return ArgJoin<char, It>(first, last, sep); +} + +template <typename It> +ArgJoin<wchar_t, It> join(It first, It last, const BasicCStringRef<wchar_t>& sep) { + return ArgJoin<wchar_t, It>(first, last, sep); +} + +#if FMT_HAS_GXX_CXX11 +template <typename Range> +auto join(const Range& range, const BasicCStringRef<char>& sep) + -> ArgJoin<char, decltype(std::begin(range))> { + return join(std::begin(range), std::end(range), sep); +} + +template <typename Range> +auto join(const Range& range, const BasicCStringRef<wchar_t>& sep) + -> ArgJoin<wchar_t, decltype(std::begin(range))> { + return join(std::begin(range), std::end(range), sep); +} +#endif + +template <typename ArgFormatter, typename Char, typename It> +void format_arg(fmt::BasicFormatter<Char, ArgFormatter> &f, + const Char *&format_str, const ArgJoin<Char, It>& e) { + const Char* end = format_str; + if (*end == ':') + ++end; + while (*end && *end != '}') + ++end; + if (*end != '}') + FMT_THROW(FormatError("missing '}' in format string")); + + It it = e.first; + if (it != e.last) { + const Char* save = format_str; + f.format(format_str, internal::MakeArg<fmt::BasicFormatter<Char, ArgFormatter> >(*it++)); + while (it != e.last) { + f.writer().write(e.sep); + format_str = save; + f.format(format_str, internal::MakeArg<fmt::BasicFormatter<Char, ArgFormatter> >(*it++)); + } + } + format_str = end + 1; +} } // namespace fmt #if FMT_USE_USER_DEFINED_LITERALS @@ -3821,7 +4111,7 @@ struct UdlArg { const Char *str; template <typename T> - NamedArg<Char> operator=(T &&value) const { + NamedArgWithType<Char, T> operator=(T &&value) const { return {str, std::forward<T>(value)}; } }; diff --git a/vendor/fmt-3.0.1/fmt/ostream.cc b/vendor/fmt-4.1.0/fmt/ostream.cc index bcb67fe1..2d443f73 100644 --- a/vendor/fmt-3.0.1/fmt/ostream.cc +++ b/vendor/fmt-4.1.0/fmt/ostream.cc @@ -11,9 +11,8 @@ namespace fmt { -namespace { -// Write the content of w to os. -void write(std::ostream &os, Writer &w) { +namespace internal { +FMT_FUNC void write(std::ostream &os, Writer &w) { const char *data = w.data(); typedef internal::MakeUnsigned<std::streamsize>::Type UnsignedStreamSize; UnsignedStreamSize size = w.size(); @@ -31,13 +30,6 @@ void write(std::ostream &os, Writer &w) { FMT_FUNC void print(std::ostream &os, CStringRef format_str, ArgList args) { MemoryWriter w; w.write(format_str, args); - write(os, w); -} - -FMT_FUNC int fprintf(std::ostream &os, CStringRef format, ArgList args) { - MemoryWriter w; - printf(w, format, args); - write(os, w); - return static_cast<int>(w.size()); + internal::write(os, w); } } // namespace fmt diff --git a/vendor/fmt-3.0.1/fmt/ostream.h b/vendor/fmt-4.1.0/fmt/ostream.h index 29483c1b..6848aac2 100644 --- a/vendor/fmt-3.0.1/fmt/ostream.h +++ b/vendor/fmt-4.1.0/fmt/ostream.h @@ -24,28 +24,27 @@ class FormatBuf : public std::basic_streambuf<Char> { typedef typename std::basic_streambuf<Char>::traits_type traits_type; Buffer<Char> &buffer_; - Char *start_; public: - FormatBuf(Buffer<Char> &buffer) : buffer_(buffer), start_(&buffer[0]) { - this->setp(start_, start_ + buffer_.capacity()); - } - - int_type overflow(int_type ch = traits_type::eof()) { - if (!traits_type::eq_int_type(ch, traits_type::eof())) { - size_t buf_size = size(); - buffer_.resize(buf_size); - buffer_.reserve(buf_size * 2); - - start_ = &buffer_[0]; - start_[buf_size] = traits_type::to_char_type(ch); - this->setp(start_+ buf_size + 1, start_ + buf_size * 2); - } + FormatBuf(Buffer<Char> &buffer) : buffer_(buffer) {} + + protected: + // The put-area is actually always empty. This makes the implementation + // simpler and has the advantage that the streambuf and the buffer are always + // in sync and sputc never writes into uninitialized memory. The obvious + // disadvantage is that each call to sputc always results in a (virtual) call + // to overflow. There is no disadvantage here for sputn since this always + // results in a call to xsputn. + + int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE { + if (!traits_type::eq_int_type(ch, traits_type::eof())) + buffer_.push_back(static_cast<Char>(ch)); return ch; } - size_t size() const { - return to_unsigned(this->pptr() - start_); + std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE { + buffer_.append(s, s + count); + return count; } }; @@ -53,32 +52,38 @@ Yes &convert(std::ostream &); struct DummyStream : std::ostream { DummyStream(); // Suppress a bogus warning in MSVC. + // Hide all operator<< overloads from std::ostream. - void operator<<(Null<>); + template <typename T> + typename EnableIf<sizeof(T) == 0>::type operator<<(const T &); }; No &operator<<(std::ostream &, int); -template<typename T> +template <typename T> struct ConvertToIntImpl<T, true> { // Convert to int only if T doesn't have an overloaded operator<<. enum { value = sizeof(convert(get<DummyStream>() << get<T>())) == sizeof(No) }; }; + +// Write the content of w to os. +FMT_API void write(std::ostream &os, Writer &w); } // namespace internal // Formats a value. -template <typename Char, typename ArgFormatter, typename T> -void format(BasicFormatter<Char, ArgFormatter> &f, - const Char *&format_str, const T &value) { +template <typename Char, typename ArgFormatter_, typename T> +void format_arg(BasicFormatter<Char, ArgFormatter_> &f, + const Char *&format_str, const T &value) { internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE> buffer; internal::FormatBuf<Char> format_buf(buffer); std::basic_ostream<Char> output(&format_buf); + output.exceptions(std::ios_base::failbit | std::ios_base::badbit); output << value; - BasicStringRef<Char> str(&buffer[0], format_buf.size()); + BasicStringRef<Char> str(&buffer[0], buffer.size()); typedef internal::MakeArg< BasicFormatter<Char> > MakeArg; format_str = f.format(format_str, MakeArg(str)); } @@ -94,18 +99,6 @@ void format(BasicFormatter<Char, ArgFormatter> &f, */ FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args); FMT_VARIADIC(void, print, std::ostream &, CStringRef) - -/** - \rst - Prints formatted data to the stream *os*. - - **Example**:: - - fprintf(cerr, "Don't %s!", "panic"); - \endrst - */ -FMT_API int fprintf(std::ostream &os, CStringRef format_str, ArgList args); -FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef) } // namespace fmt #ifdef FMT_HEADER_ONLY diff --git a/vendor/fmt-3.0.1/fmt/posix.cc b/vendor/fmt-4.1.0/fmt/posix.cc index 76eb7f05..356668c1 100644 --- a/vendor/fmt-3.0.1/fmt/posix.cc +++ b/vendor/fmt-4.1.0/fmt/posix.cc @@ -21,6 +21,9 @@ #ifndef _WIN32 # include <unistd.h> #else +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif # include <windows.h> # include <io.h> @@ -79,7 +82,7 @@ void fmt::BufferedFile::close() { if (!file_) return; int result = FMT_SYSTEM(fclose(file_)); - file_ = 0; + file_ = FMT_NULL; if (result != 0) FMT_THROW(SystemError(errno, "cannot close file")); } diff --git a/vendor/fmt-3.0.1/fmt/posix.h b/vendor/fmt-4.1.0/fmt/posix.h index be1286c4..88512de5 100644 --- a/vendor/fmt-3.0.1/fmt/posix.h +++ b/vendor/fmt-4.1.0/fmt/posix.h @@ -51,25 +51,6 @@ # endif #endif -#if FMT_GCC_VERSION >= 407 -# define FMT_UNUSED __attribute__((unused)) -#else -# define FMT_UNUSED -#endif - -#ifndef FMT_USE_STATIC_ASSERT -# define FMT_USE_STATIC_ASSERT 0 -#endif - -#if FMT_USE_STATIC_ASSERT || FMT_HAS_FEATURE(cxx_static_assert) || \ - (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600 -# define FMT_STATIC_ASSERT(cond, message) static_assert(cond, message) -#else -# define FMT_CONCAT_(a, b) FMT_CONCAT(a, b) -# define FMT_STATIC_ASSERT(cond, message) \ - typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED -#endif - // Retries the expression while it evaluates to error_result and errno // equals to EINTR. #ifndef _WIN32 @@ -107,10 +88,10 @@ class BufferedFile { public: // Constructs a BufferedFile object which doesn't represent any file. - BufferedFile() FMT_NOEXCEPT : file_(0) {} + BufferedFile() FMT_NOEXCEPT : file_(FMT_NULL) {} // Destroys the object closing the file it represents if any. - ~BufferedFile() FMT_NOEXCEPT; + FMT_API ~BufferedFile() FMT_NOEXCEPT; #if !FMT_USE_RVALUE_REFERENCES // Emulate a move constructor and a move assignment operator if rvalue @@ -129,7 +110,7 @@ public: // A "move constructor" for moving from an lvalue. BufferedFile(BufferedFile &f) FMT_NOEXCEPT : file_(f.file_) { - f.file_ = 0; + f.file_ = FMT_NULL; } // A "move assignment operator" for moving from a temporary. @@ -143,7 +124,7 @@ public: BufferedFile &operator=(BufferedFile &other) { close(); file_ = other.file_; - other.file_ = 0; + other.file_ = FMT_NULL; return *this; } @@ -151,7 +132,7 @@ public: // BufferedFile file = BufferedFile(...); operator Proxy() FMT_NOEXCEPT { Proxy p = {file_}; - file_ = 0; + file_ = FMT_NULL; return p; } @@ -161,29 +142,29 @@ public: public: BufferedFile(BufferedFile &&other) FMT_NOEXCEPT : file_(other.file_) { - other.file_ = 0; + other.file_ = FMT_NULL; } BufferedFile& operator=(BufferedFile &&other) { close(); file_ = other.file_; - other.file_ = 0; + other.file_ = FMT_NULL; return *this; } #endif // Opens a file. - BufferedFile(CStringRef filename, CStringRef mode); + FMT_API BufferedFile(CStringRef filename, CStringRef mode); // Closes the file. - void close(); + FMT_API void close(); // Returns the pointer to a FILE object representing this file. FILE *get() const FMT_NOEXCEPT { return file_; } // We place parentheses around fileno to workaround a bug in some versions // of MinGW that define fileno as a macro. - int (fileno)() const; + FMT_API int (fileno)() const; void print(CStringRef format_str, const ArgList &args) { fmt::print(file_, format_str, args); @@ -216,7 +197,7 @@ class File { File() FMT_NOEXCEPT : fd_(-1) {} // Opens a file and constructs a File object representing this file. - File(CStringRef path, int oflag); + FMT_API File(CStringRef path, int oflag); #if !FMT_USE_RVALUE_REFERENCES // Emulate a move constructor and a move assignment operator if rvalue @@ -279,43 +260,43 @@ class File { #endif // Destroys the object closing the file it represents if any. - ~File() FMT_NOEXCEPT; + FMT_API ~File() FMT_NOEXCEPT; // Returns the file descriptor. int descriptor() const FMT_NOEXCEPT { return fd_; } // Closes the file. - void close(); + FMT_API void close(); // Returns the file size. The size has signed type for consistency with // stat::st_size. - LongLong size() const; + FMT_API LongLong size() const; // Attempts to read count bytes from the file into the specified buffer. - std::size_t read(void *buffer, std::size_t count); + FMT_API std::size_t read(void *buffer, std::size_t count); // Attempts to write count bytes from the specified buffer to the file. - std::size_t write(const void *buffer, std::size_t count); + FMT_API std::size_t write(const void *buffer, std::size_t count); // Duplicates a file descriptor with the dup function and returns // the duplicate as a file object. - static File dup(int fd); + FMT_API static File dup(int fd); // Makes fd be the copy of this file descriptor, closing fd first if // necessary. - void dup2(int fd); + FMT_API void dup2(int fd); // Makes fd be the copy of this file descriptor, closing fd first if // necessary. - void dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT; + FMT_API void dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT; // Creates a pipe setting up read_end and write_end file objects for reading // and writing respectively. - static void pipe(File &read_end, File &write_end); + FMT_API static void pipe(File &read_end, File &write_end); // Creates a BufferedFile object associated with this file and detaches // this File object from the file. - BufferedFile fdopen(const char *mode); + FMT_API BufferedFile fdopen(const char *mode); }; // Returns the memory page size. @@ -355,7 +336,7 @@ class Locale { public: typedef locale_t Type; - Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", NULL)) { + Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL)) { if (!locale_) FMT_THROW(fmt::SystemError(errno, "cannot create locale")); } @@ -366,7 +347,7 @@ class Locale { // Converts string to floating-point number and advances str past the end // of the parsed input. double strtod(const char *&str) const { - char *end = 0; + char *end = FMT_NULL; double result = strtod_l(str, &end, locale_); str = end; return result; diff --git a/vendor/fmt-4.1.0/fmt/printf.cc b/vendor/fmt-4.1.0/fmt/printf.cc new file mode 100644 index 00000000..95d7a36a --- /dev/null +++ b/vendor/fmt-4.1.0/fmt/printf.cc @@ -0,0 +1,32 @@ +/* + Formatting library for C++ + + Copyright (c) 2012 - 2016, Victor Zverovich + All rights reserved. + + For the license information refer to format.h. + */ + +#include "format.h" +#include "printf.h" + +namespace fmt { + +template <typename Char> +void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args); + +FMT_FUNC int fprintf(std::FILE *f, CStringRef format, ArgList args) { + MemoryWriter w; + printf(w, format, args); + std::size_t size = w.size(); + return std::fwrite(w.data(), 1, size, f) < size ? -1 : static_cast<int>(size); +} + +#ifndef FMT_HEADER_ONLY + +template void PrintfFormatter<char>::format(CStringRef format); +template void PrintfFormatter<wchar_t>::format(WCStringRef format); + +#endif // FMT_HEADER_ONLY + +} // namespace fmt diff --git a/vendor/fmt-4.1.0/fmt/printf.h b/vendor/fmt-4.1.0/fmt/printf.h new file mode 100644 index 00000000..46205a78 --- /dev/null +++ b/vendor/fmt-4.1.0/fmt/printf.h @@ -0,0 +1,603 @@ +/* + Formatting library for C++ + + Copyright (c) 2012 - 2016, Victor Zverovich + All rights reserved. + + For the license information refer to format.h. + */ + +#ifndef FMT_PRINTF_H_ +#define FMT_PRINTF_H_ + +#include <algorithm> // std::fill_n +#include <limits> // std::numeric_limits + +#include "ostream.h" + +namespace fmt { +namespace internal { + +// Checks if a value fits in int - used to avoid warnings about comparing +// signed and unsigned integers. +template <bool IsSigned> +struct IntChecker { + template <typename T> + static bool fits_in_int(T value) { + unsigned max = std::numeric_limits<int>::max(); + return value <= max; + } + static bool fits_in_int(bool) { return true; } +}; + +template <> +struct IntChecker<true> { + template <typename T> + static bool fits_in_int(T value) { + return value >= std::numeric_limits<int>::min() && + value <= std::numeric_limits<int>::max(); + } + static bool fits_in_int(int) { return true; } +}; + +class PrecisionHandler : public ArgVisitor<PrecisionHandler, int> { + public: + void report_unhandled_arg() { + FMT_THROW(FormatError("precision is not integer")); + } + + template <typename T> + int visit_any_int(T value) { + if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value)) + FMT_THROW(FormatError("number is too big")); + return static_cast<int>(value); + } +}; + +// IsZeroInt::visit(arg) returns true iff arg is a zero integer. +class IsZeroInt : public ArgVisitor<IsZeroInt, bool> { + public: + template <typename T> + bool visit_any_int(T value) { return value == 0; } +}; + +// returns the default type for format specific "%s" +class DefaultType : public ArgVisitor<DefaultType, char> { + public: + char visit_char(int) { return 'c'; } + + char visit_bool(bool) { return 's'; } + + char visit_pointer(const void *) { return 'p'; } + + template <typename T> + char visit_any_int(T) { return 'd'; } + + template <typename T> + char visit_any_double(T) { return 'g'; } + + char visit_unhandled_arg() { return 's'; } +}; + +template <typename T, typename U> +struct is_same { + enum { value = 0 }; +}; + +template <typename T> +struct is_same<T, T> { + enum { value = 1 }; +}; + +// An argument visitor that converts an integer argument to T for printf, +// if T is an integral type. If T is void, the argument is converted to +// corresponding signed or unsigned type depending on the type specifier: +// 'd' and 'i' - signed, other - unsigned) +template <typename T = void> +class ArgConverter : public ArgVisitor<ArgConverter<T>, void> { + private: + internal::Arg &arg_; + wchar_t type_; + + FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter); + + public: + ArgConverter(internal::Arg &arg, wchar_t type) + : arg_(arg), type_(type) {} + + void visit_bool(bool value) { + if (type_ != 's') + visit_any_int(value); + } + + void visit_char(int value) { + if (type_ != 's') + visit_any_int(value); + } + + template <typename U> + void visit_any_int(U value) { + bool is_signed = type_ == 'd' || type_ == 'i'; + if (type_ == 's') { + is_signed = std::numeric_limits<U>::is_signed; + } + + using internal::Arg; + typedef typename internal::Conditional< + is_same<T, void>::value, U, T>::type TargetType; + if (const_check(sizeof(TargetType) <= sizeof(int))) { + // Extra casts are used to silence warnings. + if (is_signed) { + arg_.type = Arg::INT; + arg_.int_value = static_cast<int>(static_cast<TargetType>(value)); + } else { + arg_.type = Arg::UINT; + typedef typename internal::MakeUnsigned<TargetType>::Type Unsigned; + arg_.uint_value = static_cast<unsigned>(static_cast<Unsigned>(value)); + } + } else { + if (is_signed) { + arg_.type = Arg::LONG_LONG; + // glibc's printf doesn't sign extend arguments of smaller types: + // std::printf("%lld", -42); // prints "4294967254" + // but we don't have to do the same because it's a UB. + arg_.long_long_value = static_cast<LongLong>(value); + } else { + arg_.type = Arg::ULONG_LONG; + arg_.ulong_long_value = + static_cast<typename internal::MakeUnsigned<U>::Type>(value); + } + } + } +}; + +// Converts an integer argument to char for printf. +class CharConverter : public ArgVisitor<CharConverter, void> { + private: + internal::Arg &arg_; + + FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter); + + public: + explicit CharConverter(internal::Arg &arg) : arg_(arg) {} + + template <typename T> + void visit_any_int(T value) { + arg_.type = internal::Arg::CHAR; + arg_.int_value = static_cast<char>(value); + } +}; + +// Checks if an argument is a valid printf width specifier and sets +// left alignment if it is negative. +class WidthHandler : public ArgVisitor<WidthHandler, unsigned> { + private: + FormatSpec &spec_; + + FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler); + + public: + explicit WidthHandler(FormatSpec &spec) : spec_(spec) {} + + void report_unhandled_arg() { + FMT_THROW(FormatError("width is not integer")); + } + + template <typename T> + unsigned visit_any_int(T value) { + typedef typename internal::IntTraits<T>::MainType UnsignedType; + UnsignedType width = static_cast<UnsignedType>(value); + if (internal::is_negative(value)) { + spec_.align_ = ALIGN_LEFT; + width = 0 - width; + } + unsigned int_max = std::numeric_limits<int>::max(); + if (width > int_max) + FMT_THROW(FormatError("number is too big")); + return static_cast<unsigned>(width); + } +}; +} // namespace internal + +/** + \rst + A ``printf`` argument formatter based on the `curiously recurring template + pattern <http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern>`_. + + To use `~fmt::BasicPrintfArgFormatter` define a subclass that implements some + or all of the visit methods with the same signatures as the methods in + `~fmt::ArgVisitor`, for example, `~fmt::ArgVisitor::visit_int()`. + Pass the subclass as the *Impl* template parameter. When a formatting + function processes an argument, it will dispatch to a visit method + specific to the argument type. For example, if the argument type is + ``double`` then the `~fmt::ArgVisitor::visit_double()` method of a subclass + will be called. If the subclass doesn't contain a method with this signature, + then a corresponding method of `~fmt::BasicPrintfArgFormatter` or its + superclass will be called. + \endrst + */ +template <typename Impl, typename Char, typename Spec> +class BasicPrintfArgFormatter : + public internal::ArgFormatterBase<Impl, Char, Spec> { + private: + void write_null_pointer() { + this->spec().type_ = 0; + this->write("(nil)"); + } + + typedef internal::ArgFormatterBase<Impl, Char, Spec> Base; + + public: + /** + \rst + Constructs an argument formatter object. + *writer* is a reference to the output writer and *spec* contains format + specifier information for standard argument types. + \endrst + */ + BasicPrintfArgFormatter(BasicWriter<Char> &w, Spec &s) + : internal::ArgFormatterBase<Impl, Char, Spec>(w, s) {} + + /** Formats an argument of type ``bool``. */ + void visit_bool(bool value) { + Spec &fmt_spec = this->spec(); + if (fmt_spec.type_ != 's') + return this->visit_any_int(value); + fmt_spec.type_ = 0; + this->write(value); + } + + /** Formats a character. */ + void visit_char(int value) { + const Spec &fmt_spec = this->spec(); + BasicWriter<Char> &w = this->writer(); + if (fmt_spec.type_ && fmt_spec.type_ != 'c') + w.write_int(value, fmt_spec); + typedef typename BasicWriter<Char>::CharPtr CharPtr; + CharPtr out = CharPtr(); + if (fmt_spec.width_ > 1) { + Char fill = ' '; + out = w.grow_buffer(fmt_spec.width_); + if (fmt_spec.align_ != ALIGN_LEFT) { + std::fill_n(out, fmt_spec.width_ - 1, fill); + out += fmt_spec.width_ - 1; + } else { + std::fill_n(out + 1, fmt_spec.width_ - 1, fill); + } + } else { + out = w.grow_buffer(1); + } + *out = static_cast<Char>(value); + } + + /** Formats a null-terminated C string. */ + void visit_cstring(const char *value) { + if (value) + Base::visit_cstring(value); + else if (this->spec().type_ == 'p') + write_null_pointer(); + else + this->write("(null)"); + } + + /** Formats a pointer. */ + void visit_pointer(const void *value) { + if (value) + return Base::visit_pointer(value); + this->spec().type_ = 0; + write_null_pointer(); + } + + /** Formats an argument of a custom (user-defined) type. */ + void visit_custom(internal::Arg::CustomValue c) { + BasicFormatter<Char> formatter(ArgList(), this->writer()); + const Char format_str[] = {'}', 0}; + const Char *format = format_str; + c.format(&formatter, c.value, &format); + } +}; + +/** The default printf argument formatter. */ +template <typename Char> +class PrintfArgFormatter : + public BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char, FormatSpec> { + public: + /** Constructs an argument formatter object. */ + PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s) + : BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char, FormatSpec>(w, s) {} +}; + +/** This template formats data and writes the output to a writer. */ +template <typename Char, typename ArgFormatter = PrintfArgFormatter<Char> > +class PrintfFormatter : private internal::FormatterBase { + private: + BasicWriter<Char> &writer_; + + void parse_flags(FormatSpec &spec, const Char *&s); + + // Returns the argument with specified index or, if arg_index is equal + // to the maximum unsigned value, the next argument. + internal::Arg get_arg( + const Char *s, + unsigned arg_index = (std::numeric_limits<unsigned>::max)()); + + // Parses argument index, flags and width and returns the argument index. + unsigned parse_header(const Char *&s, FormatSpec &spec); + + public: + /** + \rst + Constructs a ``PrintfFormatter`` object. References to the arguments and + the writer are stored in the formatter object so make sure they have + appropriate lifetimes. + \endrst + */ + explicit PrintfFormatter(const ArgList &al, BasicWriter<Char> &w) + : FormatterBase(al), writer_(w) {} + + /** Formats stored arguments and writes the output to the writer. */ + void format(BasicCStringRef<Char> format_str); +}; + +template <typename Char, typename AF> +void PrintfFormatter<Char, AF>::parse_flags(FormatSpec &spec, const Char *&s) { + for (;;) { + switch (*s++) { + case '-': + spec.align_ = ALIGN_LEFT; + break; + case '+': + spec.flags_ |= SIGN_FLAG | PLUS_FLAG; + break; + case '0': + spec.fill_ = '0'; + break; + case ' ': + spec.flags_ |= SIGN_FLAG; + break; + case '#': + spec.flags_ |= HASH_FLAG; + break; + default: + --s; + return; + } + } +} + +template <typename Char, typename AF> +internal::Arg PrintfFormatter<Char, AF>::get_arg(const Char *s, + unsigned arg_index) { + (void)s; + const char *error = FMT_NULL; + internal::Arg arg = arg_index == std::numeric_limits<unsigned>::max() ? + next_arg(error) : FormatterBase::get_arg(arg_index - 1, error); + if (error) + FMT_THROW(FormatError(!*s ? "invalid format string" : error)); + return arg; +} + +template <typename Char, typename AF> +unsigned PrintfFormatter<Char, AF>::parse_header( + const Char *&s, FormatSpec &spec) { + unsigned arg_index = std::numeric_limits<unsigned>::max(); + Char c = *s; + if (c >= '0' && c <= '9') { + // Parse an argument index (if followed by '$') or a width possibly + // preceded with '0' flag(s). + unsigned value = internal::parse_nonnegative_int(s); + if (*s == '$') { // value is an argument index + ++s; + arg_index = value; + } else { + if (c == '0') + spec.fill_ = '0'; + if (value != 0) { + // Nonzero value means that we parsed width and don't need to + // parse it or flags again, so return now. + spec.width_ = value; + return arg_index; + } + } + } + parse_flags(spec, s); + // Parse width. + if (*s >= '0' && *s <= '9') { + spec.width_ = internal::parse_nonnegative_int(s); + } else if (*s == '*') { + ++s; + spec.width_ = internal::WidthHandler(spec).visit(get_arg(s)); + } + return arg_index; +} + +template <typename Char, typename AF> +void PrintfFormatter<Char, AF>::format(BasicCStringRef<Char> format_str) { + const Char *start = format_str.c_str(); + const Char *s = start; + while (*s) { + Char c = *s++; + if (c != '%') continue; + if (*s == c) { + write(writer_, start, s); + start = ++s; + continue; + } + write(writer_, start, s - 1); + + FormatSpec spec; + spec.align_ = ALIGN_RIGHT; + + // Parse argument index, flags and width. + unsigned arg_index = parse_header(s, spec); + + // Parse precision. + if (*s == '.') { + ++s; + if ('0' <= *s && *s <= '9') { + spec.precision_ = static_cast<int>(internal::parse_nonnegative_int(s)); + } else if (*s == '*') { + ++s; + spec.precision_ = internal::PrecisionHandler().visit(get_arg(s)); + } else { + spec.precision_ = 0; + } + } + + using internal::Arg; + Arg arg = get_arg(s, arg_index); + if (spec.flag(HASH_FLAG) && internal::IsZeroInt().visit(arg)) + spec.flags_ &= ~internal::to_unsigned<int>(HASH_FLAG); + if (spec.fill_ == '0') { + if (arg.type <= Arg::LAST_NUMERIC_TYPE) + spec.align_ = ALIGN_NUMERIC; + else + spec.fill_ = ' '; // Ignore '0' flag for non-numeric types. + } + + // Parse length and convert the argument to the required type. + using internal::ArgConverter; + switch (*s++) { + case 'h': + if (*s == 'h') + ArgConverter<signed char>(arg, *++s).visit(arg); + else + ArgConverter<short>(arg, *s).visit(arg); + break; + case 'l': + if (*s == 'l') + ArgConverter<fmt::LongLong>(arg, *++s).visit(arg); + else + ArgConverter<long>(arg, *s).visit(arg); + break; + case 'j': + ArgConverter<intmax_t>(arg, *s).visit(arg); + break; + case 'z': + ArgConverter<std::size_t>(arg, *s).visit(arg); + break; + case 't': + ArgConverter<std::ptrdiff_t>(arg, *s).visit(arg); + break; + case 'L': + // printf produces garbage when 'L' is omitted for long double, no + // need to do the same. + break; + default: + --s; + ArgConverter<void>(arg, *s).visit(arg); + } + + // Parse type. + if (!*s) + FMT_THROW(FormatError("invalid format string")); + spec.type_ = static_cast<char>(*s++); + + if (spec.type_ == 's') { + // set the format type to the default if 's' is specified + spec.type_ = internal::DefaultType().visit(arg); + } + + if (arg.type <= Arg::LAST_INTEGER_TYPE) { + // Normalize type. + switch (spec.type_) { + case 'i': case 'u': + spec.type_ = 'd'; + break; + case 'c': + // TODO: handle wchar_t + internal::CharConverter(arg).visit(arg); + break; + } + } + + start = s; + + // Format argument. + AF(writer_, spec).visit(arg); + } + write(writer_, start, s); +} + +inline void printf(Writer &w, CStringRef format, ArgList args) { + PrintfFormatter<char>(args, w).format(format); +} +FMT_VARIADIC(void, printf, Writer &, CStringRef) + +inline void printf(WWriter &w, WCStringRef format, ArgList args) { + PrintfFormatter<wchar_t>(args, w).format(format); +} +FMT_VARIADIC(void, printf, WWriter &, WCStringRef) + +/** + \rst + Formats arguments and returns the result as a string. + + **Example**:: + + std::string message = fmt::sprintf("The answer is %d", 42); + \endrst +*/ +inline std::string sprintf(CStringRef format, ArgList args) { + MemoryWriter w; + printf(w, format, args); + return w.str(); +} +FMT_VARIADIC(std::string, sprintf, CStringRef) + +inline std::wstring sprintf(WCStringRef format, ArgList args) { + WMemoryWriter w; + printf(w, format, args); + return w.str(); +} +FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef) + +/** + \rst + Prints formatted data to the file *f*. + + **Example**:: + + fmt::fprintf(stderr, "Don't %s!", "panic"); + \endrst + */ +FMT_API int fprintf(std::FILE *f, CStringRef format, ArgList args); +FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef) + +/** + \rst + Prints formatted data to ``stdout``. + + **Example**:: + + fmt::printf("Elapsed time: %.2f seconds", 1.23); + \endrst + */ +inline int printf(CStringRef format, ArgList args) { + return fprintf(stdout, format, args); +} +FMT_VARIADIC(int, printf, CStringRef) + +/** + \rst + Prints formatted data to the stream *os*. + + **Example**:: + + fprintf(cerr, "Don't %s!", "panic"); + \endrst + */ +inline int fprintf(std::ostream &os, CStringRef format_str, ArgList args) { + MemoryWriter w; + printf(w, format_str, args); + internal::write(os, w); + return static_cast<int>(w.size()); +} +FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef) +} // namespace fmt + +#ifdef FMT_HEADER_ONLY +# include "printf.cc" +#endif + +#endif // FMT_PRINTF_H_ diff --git a/vendor/fmt-4.1.0/fmt/string.h b/vendor/fmt-4.1.0/fmt/string.h new file mode 100644 index 00000000..05996eb5 --- /dev/null +++ b/vendor/fmt-4.1.0/fmt/string.h @@ -0,0 +1,148 @@ +/* + Formatting library for C++ - string utilities + + Copyright (c) 2012 - 2016, Victor Zverovich + All rights reserved. + + For the license information refer to format.h. + */ + +#ifdef FMT_INCLUDE +# error "Add the fmt's parent directory and not fmt itself to includes." +#endif + +#ifndef FMT_STRING_H_ +#define FMT_STRING_H_ + +#include "format.h" + +namespace fmt { + +namespace internal { + +// A buffer that stores data in ``std::basic_string``. +template <typename Char, typename Allocator = std::allocator<Char> > +class StringBuffer : public Buffer<Char> { + public: + typedef std::basic_string<Char, std::char_traits<Char>, Allocator> StringType; + + private: + StringType data_; + + protected: + virtual void grow(std::size_t size) FMT_OVERRIDE { + data_.resize(size); + this->ptr_ = &data_[0]; + this->capacity_ = size; + } + + public: + explicit StringBuffer(const Allocator &allocator = Allocator()) + : data_(allocator) {} + + // Moves the data to ``str`` clearing the buffer. + void move_to(StringType &str) { + data_.resize(this->size_); + str.swap(data_); + this->capacity_ = this->size_ = 0; + this->ptr_ = FMT_NULL; + } +}; +} // namespace internal + +/** + \rst + This class template provides operations for formatting and writing data + into a character stream. The output is stored in a ``std::basic_string`` + that grows dynamically. + + You can use one of the following typedefs for common character types + and the standard allocator: + + +---------------+----------------------------+ + | Type | Definition | + +===============+============================+ + | StringWriter | BasicStringWriter<char> | + +---------------+----------------------------+ + | WStringWriter | BasicStringWriter<wchar_t> | + +---------------+----------------------------+ + + **Example**:: + + StringWriter out; + out << "The answer is " << 42 << "\n"; + + This will write the following output to the ``out`` object: + + .. code-block:: none + + The answer is 42 + + The output can be moved to a ``std::basic_string`` with ``out.move_to()``. + \endrst + */ +template <typename Char, typename Allocator = std::allocator<Char> > +class BasicStringWriter : public BasicWriter<Char> { + private: + internal::StringBuffer<Char, Allocator> buffer_; + + public: + /** + \rst + Constructs a :class:`fmt::BasicStringWriter` object. + \endrst + */ + explicit BasicStringWriter(const Allocator &allocator = Allocator()) + : BasicWriter<Char>(buffer_), buffer_(allocator) {} + + /** + \rst + Moves the buffer content to *str* clearing the buffer. + \endrst + */ + void move_to(std::basic_string<Char, std::char_traits<Char>, Allocator> &str) { + buffer_.move_to(str); + } +}; + +typedef BasicStringWriter<char> StringWriter; +typedef BasicStringWriter<wchar_t> WStringWriter; + +/** + \rst + Converts *value* to ``std::string`` using the default format for type *T*. + + **Example**:: + + #include "fmt/string.h" + + std::string answer = fmt::to_string(42); + \endrst + */ +template <typename T> +std::string to_string(const T &value) { + fmt::MemoryWriter w; + w << value; + return w.str(); +} + +/** + \rst + Converts *value* to ``std::wstring`` using the default format for type *T*. + + **Example**:: + + #include "fmt/string.h" + + std::wstring answer = fmt::to_wstring(42); + \endrst + */ +template <typename T> +std::wstring to_wstring(const T &value) { + fmt::WMemoryWriter w; + w << value; + return w.str(); +} +} + +#endif // FMT_STRING_H_ diff --git a/vendor/fmt-4.1.0/fmt/time.h b/vendor/fmt-4.1.0/fmt/time.h new file mode 100644 index 00000000..c98b0e01 --- /dev/null +++ b/vendor/fmt-4.1.0/fmt/time.h @@ -0,0 +1,143 @@ +/* + Formatting library for C++ - time formatting + + Copyright (c) 2012 - 2016, Victor Zverovich + All rights reserved. + + For the license information refer to format.h. + */ + +#ifndef FMT_TIME_H_ +#define FMT_TIME_H_ + +#include "format.h" +#include <ctime> + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4702) // unreachable code +# pragma warning(disable: 4996) // "deprecated" functions +#endif + +namespace fmt { +template <typename ArgFormatter> +void format_arg(BasicFormatter<char, ArgFormatter> &f, + const char *&format_str, const std::tm &tm) { + if (*format_str == ':') + ++format_str; + const char *end = format_str; + while (*end && *end != '}') + ++end; + if (*end != '}') + FMT_THROW(FormatError("missing '}' in format string")); + internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> format; + format.append(format_str, end + 1); + format[format.size() - 1] = '\0'; + Buffer<char> &buffer = f.writer().buffer(); + std::size_t start = buffer.size(); + for (;;) { + std::size_t size = buffer.capacity() - start; + std::size_t count = std::strftime(&buffer[start], size, &format[0], &tm); + if (count != 0) { + buffer.resize(start + count); + break; + } + if (size >= format.size() * 256) { + // If the buffer is 256 times larger than the format string, assume + // that `strftime` gives an empty result. There doesn't seem to be a + // better way to distinguish the two cases: + // https://github.com/fmtlib/fmt/issues/367 + break; + } + const std::size_t MIN_GROWTH = 10; + buffer.reserve(buffer.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH)); + } + format_str = end + 1; +} + +namespace internal{ +inline Null<> localtime_r(...) { return Null<>(); } +inline Null<> localtime_s(...) { return Null<>(); } +inline Null<> gmtime_r(...) { return Null<>(); } +inline Null<> gmtime_s(...) { return Null<>(); } +} + +// Thread-safe replacement for std::localtime +inline std::tm localtime(std::time_t time) { + struct LocalTime { + std::time_t time_; + std::tm tm_; + + LocalTime(std::time_t t): time_(t) {} + + bool run() { + using namespace fmt::internal; + return handle(localtime_r(&time_, &tm_)); + } + + bool handle(std::tm *tm) { return tm != FMT_NULL; } + + bool handle(internal::Null<>) { + using namespace fmt::internal; + return fallback(localtime_s(&tm_, &time_)); + } + + bool fallback(int res) { return res == 0; } + + bool fallback(internal::Null<>) { + using namespace fmt::internal; + std::tm *tm = std::localtime(&time_); + if (tm) tm_ = *tm; + return tm != FMT_NULL; + } + }; + LocalTime lt(time); + if (lt.run()) + return lt.tm_; + // Too big time values may be unsupported. + FMT_THROW(fmt::FormatError("time_t value out of range")); + return std::tm(); +} + +// Thread-safe replacement for std::gmtime +inline std::tm gmtime(std::time_t time) { + struct GMTime { + std::time_t time_; + std::tm tm_; + + GMTime(std::time_t t): time_(t) {} + + bool run() { + using namespace fmt::internal; + return handle(gmtime_r(&time_, &tm_)); + } + + bool handle(std::tm *tm) { return tm != FMT_NULL; } + + bool handle(internal::Null<>) { + using namespace fmt::internal; + return fallback(gmtime_s(&tm_, &time_)); + } + + bool fallback(int res) { return res == 0; } + + bool fallback(internal::Null<>) { + std::tm *tm = std::gmtime(&time_); + if (tm != FMT_NULL) tm_ = *tm; + return tm != FMT_NULL; + } + }; + GMTime gt(time); + if (gt.run()) + return gt.tm_; + // Too big time values may be unsupported. + FMT_THROW(fmt::FormatError("time_t value out of range")); + return std::tm(); +} +} //namespace fmt + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif // FMT_TIME_H_ diff --git a/vendor/jsoncons b/vendor/jsoncons index 0f3415d8..33696c54 120000 --- a/vendor/jsoncons +++ b/vendor/jsoncons @@ -1 +1 @@ -jsoncons-0.99.2
\ No newline at end of file +jsoncons-0.104.0
\ No newline at end of file diff --git a/vendor/jsoncons-0.104.0/jsoncons/detail/heap_only_string.hpp b/vendor/jsoncons-0.104.0/jsoncons/detail/heap_only_string.hpp new file mode 100644 index 00000000..5348b436 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/detail/heap_only_string.hpp @@ -0,0 +1,155 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_DETAIL_HEAPONLYSTRING_HPP +#define JSONCONS_DETAIL_HEAPONLYSTRING_HPP + +#include <stdexcept> +#include <string> +#include <cstdlib> +#include <exception> +#include <ostream> +#include <jsoncons/jsoncons_config.hpp> + +namespace jsoncons { namespace detail { + +template <class Allocator> +class heap_only_string_base +{ + Allocator allocator_; +public: + Allocator& get_allocator() + { + return allocator_; + } + + const Allocator& get_allocator() const + { + return allocator_; + } +protected: + heap_only_string_base(const Allocator& allocator) + : allocator_(allocator) + { + } + + ~heap_only_string_base() {} +}; + +template <class CharT,class Allocator> +class heap_only_string_factory; + +template <class CharT, class Allocator> +class heap_only_string : public heap_only_string_base<Allocator> +{ + typedef typename std::allocator_traits<Allocator>::template rebind_alloc<CharT> allocator_type; + typedef std::allocator_traits<allocator_type> allocator_traits_type; + typedef typename allocator_traits_type::pointer pointer; + + friend class heap_only_string_factory<CharT, Allocator>; +public: + typedef CharT char_type; + typedef heap_only_string<CharT,Allocator> value_type; + + ~heap_only_string() {} + + const char_type* c_str() const { return to_plain_pointer(p_); } + const char_type* data() const { return to_plain_pointer(p_); } + size_t length() const { return length_; } + + using heap_only_string_base<Allocator>::get_allocator; + + + friend std::basic_ostream<CharT>& operator<<(std::basic_ostream<CharT>& os, const heap_only_string& s) + { + os.write(s.data(),s.length()); + return os; + } +private: + heap_only_string() + : heap_only_string_base<Allocator>(Allocator()) + { + + } + heap_only_string(const Allocator& allocator) + : heap_only_string_base<Allocator>(allocator) + { + + } + + pointer p_; + size_t length_; + + heap_only_string(const heap_only_string&) = delete; + heap_only_string& operator=(const heap_only_string&) = delete; + +}; + +template <class CharT, class Allocator> +class heap_only_string_factory +{ + typedef CharT char_type; + typedef typename std::allocator_traits<Allocator>::template rebind_alloc<char> byte_allocator_type; + typedef std::allocator_traits<byte_allocator_type> byte_allocator_traits_type; + typedef typename byte_allocator_traits_type::pointer byte_pointer; + typedef typename heap_only_string<CharT,Allocator>::pointer pointer; +public: + + typedef typename std::allocator_traits<Allocator>::template rebind_alloc<heap_only_string<CharT,Allocator>> string_allocator_type; + typedef std::allocator_traits<string_allocator_type> string_allocator_traits_type; + typedef typename string_allocator_traits_type::pointer string_pointer; + + typedef heap_only_string<char_type,Allocator>* raw_string_pointer_type; + + struct string_storage + { + heap_only_string<CharT,Allocator> data; + char_type c[1]; + }; + typedef typename std::aligned_storage<sizeof(string_storage), JSONCONS_ALIGNOF(string_storage)>::type storage_type; + + static size_t aligned_size(size_t n) + { + return sizeof(storage_type) + n; + } +public: + static string_pointer create(const char_type* s, size_t length) + { + return create(s, length, Allocator()); + } + static string_pointer create(const char_type* s, size_t length, const Allocator& allocator) + { + size_t mem_size = aligned_size(length*sizeof(char_type)); + + byte_allocator_type alloc(allocator); + byte_pointer ptr = alloc.allocate(mem_size); + + char* storage = to_plain_pointer(ptr); + raw_string_pointer_type ps = new(storage)heap_only_string<char_type,Allocator>(alloc); + auto psa = reinterpret_cast<string_storage*>(storage); + + CharT* p = new(&psa->c)char_type[length + 1]; + memcpy(p, s, length*sizeof(char_type)); + p[length] = 0; + ps->p_ = std::pointer_traits<pointer>::pointer_to(*p); + ps->length_ = length; + return std::pointer_traits<string_pointer>::pointer_to(*ps); + } + + static void destroy(string_pointer ptr) + { + raw_string_pointer_type rawp = to_plain_pointer(ptr); + char* p = reinterpret_cast<char*>(rawp); + size_t mem_size = aligned_size(ptr->length_*sizeof(char_type)); + byte_allocator_type alloc(ptr->get_allocator()); + alloc.deallocate(p,mem_size); + } +}; + + +}} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/detail/number_parsers.hpp b/vendor/jsoncons-0.104.0/jsoncons/detail/number_parsers.hpp new file mode 100644 index 00000000..1a8fc0a9 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/detail/number_parsers.hpp @@ -0,0 +1,266 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_DETAIL_NUMBERPARSERS_HPP +#define JSONCONS_DETAIL_NUMBERPARSERS_HPP + +#include <stdexcept> +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <ostream> +#include <iomanip> +#include <cstdlib> +#include <cstdarg> +#include <locale> +#include <limits> +#include <type_traits> +#include <algorithm> +#include <exception> +#include <jsoncons/jsoncons_config.hpp> + +namespace jsoncons { namespace detail { + +struct to_integer_result +{ + int64_t value; + bool overflow; +}; + +// Precondition: s satisfies + +// digit +// digit1-digits +// - digit +// - digit1-digits + +template <class CharT> +to_integer_result to_integer(const CharT* s, size_t length) +{ + JSONCONS_ASSERT(length > 0); + + int64_t n = 0; + bool overflow = false; + const CharT* end = s + length; + if (*s == '-') + { + static const int64_t min_value = (std::numeric_limits<int64_t>::min)(); + static const int64_t min_value_div_10 = min_value / 10; + ++s; + for (; s < end; ++s) + { + int64_t x = *s - '0'; + if (n < min_value_div_10) + { + overflow = true; + break; + } + n = n * 10; + if (n < min_value + x) + { + overflow = true; + break; + } + + n -= x; + } + } + else + { + static const int64_t max_value = (std::numeric_limits<int64_t>::max)(); + static const int64_t max_value_div_10 = max_value / 10; + for (; s < end; ++s) + { + int64_t x = *s - '0'; + if (n > max_value_div_10) + { + overflow = true; + break; + } + n = n * 10; + if (n > max_value - x) + { + overflow = true; + break; + } + + n += x; + } + } + + return to_integer_result({ n,overflow }); +} + +struct to_uinteger_result +{ + uint64_t value; + bool overflow; +}; + +// Precondition: s satisfies + +// digit +// digit1-digits +// - digit +// - digit1-digits + +template <class CharT> +to_uinteger_result to_uinteger(const CharT* s, size_t length) +{ + JSONCONS_ASSERT(length > 0); + + static const uint64_t max_value = (std::numeric_limits<uint64_t>::max)(); + static const uint64_t max_value_div_10 = max_value / 10; + uint64_t n = 0; + bool overflow = false; + + const CharT* end = s + length; + for (; s < end; ++s) + { + uint64_t x = *s - '0'; + if (n > max_value_div_10) + { + overflow = true; + break; + } + n = n * 10; + if (n > max_value - x) + { + overflow = true; + break; + } + + n += x; + } + return to_uinteger_result{ n,overflow }; +} + +#if defined(JSONCONS_HAS_MSC__STRTOD_L) + +class string_to_double +{ +private: + _locale_t locale_; +public: + string_to_double() + { + locale_ = _create_locale(LC_NUMERIC, "C"); + } + ~string_to_double() + { + _free_locale(locale_); + } + + char get_decimal_point() const + { + return '.'; + } + + double operator()(const char* s, size_t) const + { + const char *begin = s; + char *end = nullptr; + double val = _strtod_l(begin, &end, locale_); + if (begin == end) + { + JSONCONS_THROW(json_exception_impl<std::invalid_argument>("Invalid float value")); + } + return val; + } +private: + // noncopyable and nonmoveable + string_to_double(const string_to_double&) = delete; + string_to_double& operator=(const string_to_double&) = delete; +}; + +#elif defined(JSONCONS_HAS_STRTOLD_L) + +class string_to_double +{ +private: + locale_t locale_; +public: + string_to_double() + { + locale_ = newlocale(LC_ALL_MASK, "C", (locale_t) 0); + } + ~string_to_double() + { + freelocale(locale_); + } + + char get_decimal_point() const + { + return '.'; + } + + double operator()(const char* s, size_t length) const + { + const char *begin = s; + char *end = nullptr; + double val = strtold_l(begin, &end, locale_); + if (begin == end) + { + JSONCONS_THROW(json_exception_impl<std::invalid_argument>("Invalid float value")); + } + return val; + } + +private: + // noncopyable and nonmoveable + string_to_double(const string_to_double& fr) = delete; + string_to_double& operator=(const string_to_double& fr) = delete; +}; + +#else +class string_to_double +{ +private: + std::vector<char> buffer_; + char decimal_point_; +public: + string_to_double() + : buffer_() + { + struct lconv * lc = localeconv(); + if (lc != nullptr && lc->decimal_point[0] != 0) + { + decimal_point_ = lc->decimal_point[0]; + } + else + { + decimal_point_ = '.'; + } + buffer_.reserve(100); + } + + char get_decimal_point() const + { + return decimal_point_; + } + + double operator()(const char* s, size_t /*length*/) const + { + char *end = nullptr; + double val = strtod(s, &end); + if (s == end) + { + JSONCONS_THROW(json_exception_impl<std::invalid_argument>("string_to_double failed")); + } + return val; + } + +private: + // noncopyable and nonmoveable + string_to_double(const string_to_double& fr) = delete; + string_to_double& operator=(const string_to_double& fr) = delete; +}; +#endif + +}} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/detail/number_printers.hpp b/vendor/jsoncons-0.104.0/jsoncons/detail/number_printers.hpp new file mode 100644 index 00000000..58779280 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/detail/number_printers.hpp @@ -0,0 +1,374 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_DETAIL_NUMBERPRINTERS_HPP +#define JSONCONS_DETAIL_NUMBERPRINTERS_HPP + +#include <stdexcept> +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <ostream> +#include <iomanip> +#include <cstdlib> +#include <cmath> +#include <cstdarg> +#include <locale> +#include <limits> +#include <algorithm> +#include <exception> +#include <jsoncons/jsoncons_config.hpp> +#include <jsoncons/detail/obufferedstream.hpp> + +namespace jsoncons { namespace detail { + +// print_integer + +template<class Writer> +void print_integer(int64_t value, Writer& os) +{ + typedef typename Writer::char_type char_type; + + char_type buf[255]; + uint64_t u = (value < 0) ? static_cast<uint64_t>(-value) : static_cast<uint64_t>(value); + char_type* p = buf; + do + { + *p++ = static_cast<char_type>(48 + u%10); + } + while (u /= 10); + if (value < 0) + { + os.put('-'); + } + while (--p >= buf) + { + os.put(*p); + } +} + +// print_uinteger + +template<class Writer> +void print_uinteger(uint64_t value, Writer& os) +{ + typedef typename Writer::char_type char_type; + + char_type buf[255]; + char_type* p = buf; + do + { + *p++ = static_cast<char_type>(48 + value % 10); + } while (value /= 10); + while (--p >= buf) + { + os.put(*p); + } +} + +// print_double + +#if defined(JSONCONS_HAS__ECVT_S) + +class print_double +{ +private: + uint8_t precision_override_; +public: + print_double(uint8_t precision) + : precision_override_(precision) + { + } + + template <class Writer> + void operator()(double val, uint8_t precision, Writer& writer) + { + typedef typename Writer::char_type char_type; + + char buf[_CVTBUFSIZE]; + int decimal_point = 0; + int sign = 0; + + int prec; + if (precision_override_ != 0) + { + prec = precision_override_; + } + else if (precision != 0) + { + prec = precision; + } + else + { + prec = std::numeric_limits<double>::digits10; + } + + int err = _ecvt_s(buf, _CVTBUFSIZE, val, prec, &decimal_point, &sign); + if (err != 0) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Failed attempting double to string conversion")); + } + //std::cout << "prec:" << prec << ", buf:" << buf << std::endl; + char* s = buf; + char* se = s + prec; + + int i, k; + int j; + + if (sign) + { + writer.put('-'); + } + if (decimal_point <= -4 || decimal_point > se - s + 5) + { + writer.put(*s++); + if (s < se) + { + writer.put('.'); + while ((se-1) > s && *(se-1) == '0') + { + --se; + } + + while(s < se) + { + writer.put(*s++); + } + } + writer.put('e'); + /* sprintf(b, "%+.2d", decimal_point - 1); */ + if (--decimal_point < 0) { + writer.put('-'); + decimal_point = -decimal_point; + } + else + writer.put('+'); + for(j = 2, k = 10; 10*k <= decimal_point; j++, k *= 10); + for(;;) + { + i = decimal_point / k; + writer.put(static_cast<char_type>(i) + '0'); + if (--j <= 0) + break; + decimal_point -= i*k; + decimal_point *= 10; + } + } + else if (decimal_point <= 0) + { + writer.put('0'); + writer.put('.'); + while ((se-1) > s && *(se-1) == '0') + { + --se; + } + for(; decimal_point < 0; decimal_point++) + { + writer.put('0'); + } + while(s < se) + { + writer.put(*s++); + } + } + else { + while(s < se) + { + writer.put(*s++); + if ((--decimal_point == 0) && s < se) + { + writer.put('.'); + while ((se-1) > s && *(se-1) == '0') + { + --se; + } + } + } + for(; decimal_point > 0; decimal_point--) + { + writer.put('0'); + } + } + } +}; + +#elif defined(JSONCONS_NO_LOCALECONV) + +class print_double +{ +private: + uint8_t precision_override_; + basic_obufferedstream<char> os_; +public: + print_double(uint8_t precision) + : precision_override_(precision) + { + os_.imbue(std::locale::classic()); + os_.precision(precision); + } + + template <class Writer> + void operator()(double val, uint8_t precision, Writer& writer) + { + typedef typename Writer::char_type char_type; + + int prec; + if (precision_override_ != 0) + { + prec = precision_override_; + } + else if (precision != 0) + { + prec = precision; + } + else + { + prec = std::numeric_limits<double>::digits10; + } + + os_.clear_sequence(); + os_.precision(prec); + os_ << val; + + //std::cout << "precision_override_:" << (int)precision_override_ << ", precision:" << (int)precision << ", buf:" << os_.data() << std::endl; + + const char_type* sbeg = os_.data(); + const char_type* send = sbeg + os_.length(); + const char_type* pexp = send; + + if (sbeg != send) + { + bool dot = false; + for (pexp = sbeg; *pexp != 'e' && *pexp != 'E' && pexp < send; ++pexp) + { + } + + const char_type* qend = pexp; + while (qend >= sbeg+2 && *(qend-1) == '0' && *(qend-2) != '.') + { + --qend; + } + if (pexp == send) + { + qend = ((qend >= sbeg+2) && *(qend-2) == '.') ? qend : send; + } + + for (const char_type* q = sbeg; q < qend; ++q) + { + if (*q == '.') + { + dot = true; + } + writer.put(*q); + } + if (!dot) + { + writer.put('.'); + writer.put('0'); + dot = true; + } + for (const char_type* q = pexp; q < send; ++q) + { + writer.put(*q); + } + } + } +}; +#else + +class print_double +{ +private: + uint8_t precision_override_; + char decimal_point_; +public: + print_double(uint8_t precision) + : precision_override_(precision) + { + struct lconv * lc = localeconv(); + if (lc != nullptr && lc->decimal_point[0] != 0) + { + decimal_point_ = lc->decimal_point[0]; + } + else + { + decimal_point_ = '.'; + } + } + + template <class Writer> + void operator()(double val, uint8_t precision, Writer& writer) + { + typedef typename Writer::char_type char_type; + + int prec; + if (precision_override_ != 0) + { + prec = precision_override_; + } + else if (precision != 0) + { + prec = precision; + } + else + { + prec = std::numeric_limits<double>::digits10; + } + + char number_buffer[100]; + int length = snprintf(number_buffer, 100, "%1.*g", prec, val); + if (length < 0) + { + JSONCONS_THROW(json_exception_impl<std::invalid_argument>("print_double failed.")); + } + + const char* sbeg = number_buffer; + const char* send = sbeg + length; + const char* pexp = send; + + if (sbeg != send) + { + bool dot = false; + for (pexp = sbeg; *pexp != 'e' && *pexp != 'E' && pexp < send; ++pexp) + { + } + + for (const char* q = sbeg; q < pexp; ++q) + { + switch (*q) + { + case '-':case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + writer.put(*q); + break; + default: + if (*q == decimal_point_) + { + dot = true; + writer.put('.'); + } + break; + } + } + if (!dot) + { + writer.put('.'); + writer.put('0'); + dot = true; + } + for (const char* q = pexp; q < send; ++q) + { + writer.put(*q); + } + } + } +}; + +#endif + +}} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/detail/obufferedstream.hpp b/vendor/jsoncons-0.104.0/jsoncons/detail/obufferedstream.hpp new file mode 100644 index 00000000..7b499f4b --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/detail/obufferedstream.hpp @@ -0,0 +1,264 @@ +// Copyright 2016 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_DETAIL_OBUFFEREDSTREAM_HPP +#define JSONCONS_DETAIL_OBUFFEREDSTREAM_HPP + +#include <ios> +#include <ostream> +#include <string> +#include <cstddef> +#include <vector> +#include <locale> +#include <jsoncons/jsoncons_config.hpp> + +namespace jsoncons { + +template< + class CharT, + class Traits = std::char_traits<CharT> +> class basic_obufferedstream; + +template<class CharT, class Traits> +class basic_ovectorbuf + : public std::basic_streambuf<CharT, Traits> +{ +private: + std::ios_base::openmode mode_; + std::vector<CharT> buf_; + +public: + typedef CharT char_type; + typedef typename Traits::int_type int_type; + typedef typename Traits::pos_type pos_type; + typedef typename Traits::off_type off_type; + typedef Traits traits_type; + +public: + + explicit basic_ovectorbuf() JSONCONS_NOEXCEPT + : mode_(std::ios_base::out | std::ios_base::binary), + buf_(100u) + { + // Set write position to beginning of buffer. + this->setp(buf_.data(), buf_.data() + buf_.size()); + this->setg(buf_.data(), 0, buf_.data()); + } + + explicit basic_ovectorbuf(std::size_t length) JSONCONS_NOEXCEPT + : mode_(std::ios_base::out | std::ios_base::binary), + buf_(length) + { + // Set write position to beginning of buffer. + this->setp(buf_.data(), buf_.data() + buf_.size()); + this->setg(buf_.data(), 0, buf_.data()); + } + + virtual ~basic_ovectorbuf() JSONCONS_NOEXCEPT {} + + basic_ovectorbuf(const basic_ovectorbuf<CharT,Traits>&) = delete; + + //basic_ovectorbuf(basic_ovectorbuf<CharT,Traits>&&) = default; + + basic_ovectorbuf<CharT,Traits>& operator=(const basic_ovectorbuf<CharT,Traits>&) = delete; + + //basic_ovectorbuf<CharT,Traits>& operator=(basic_ovectorbuf<CharT,Traits>&&) = default; + + const CharT* data() const + { + return buf_.data(); + } + + size_t length() const + { + return this->pptr() - this->pbase(); + } + + virtual int sync() override + { + return EOF; + } + +protected: + int_type underflow() override + { + return this->gptr() != this->egptr() ? + Traits::to_int_type(*this->gptr()) : Traits::eof(); + } + + int_type pbackfail(int_type c = Traits::eof()) override + { + if (this->gptr() != this->eback()) + { + if (!Traits::eq_int_type(c, Traits::eof())) + { + if (Traits::eq(Traits::to_char_type(c), this->gptr()[-1])) + { + this->gbump(-1); + return c; + } + this->gbump(-1); + *this->gptr() = static_cast<CharT>(c); + return c; + } + else + { + this->gbump(-1); + return Traits::not_eof(c); + } + } + else + { + return Traits::eof(); + } + } + + int_type overflow(int_type c = Traits::eof()) override + { + if (!Traits::eq_int_type(c, Traits::eof())) + { + size_t pos = buf_.size()+1; + buf_.resize(pos*2); + this->setp(buf_.data(), buf_.data() + buf_.size()); + this->pubseekpos(pos, std::ios_base::out); + *this->pptr() = Traits::to_char_type(c); + this->pbump(1); + this->pubsync(); + return c; + } + else + { + return Traits::not_eof(c); + } + } + + pos_type seekoff(off_type off, std::ios_base::seekdir dir, + std::ios_base::openmode mode = std::ios_base::out) override + { + (void)mode; // Always out + + std::streamoff newoff; + switch (dir) + { + case std::ios_base::beg: + newoff = 0; + break; + case std::ios_base::end: + newoff = static_cast<std::streamoff>(buf_.size()); + break; + case std::ios_base::cur: + newoff = static_cast<std::streamoff>(this->pptr() - this->pbase()); + break; + default: + return pos_type(off_type(-1)); + } + + off += newoff; + + std::ptrdiff_t n = this->epptr() - this->pbase(); + + if (off < 0 || off > n) return pos_type(off_type(-1)); + else + { + this->setp(this->pbase(), this->pbase() + n); + this->pbump(static_cast<int>(off)); + } + + return pos_type(off); + } + + pos_type seekoff_beg(off_type off) + { + std::ptrdiff_t n = this->epptr() - this->pbase(); + + if (off < 0 || off > n) + { + return pos_type(off_type(-1)); + } + else + { + this->setp(this->pbase(), this->pbase() + n); + this->pbump(static_cast<int>(off)); + } + + return pos_type(off); + } + + pos_type seekpos(pos_type pos, std::ios_base::openmode mode + = std::ios_base::out) override + { + + (void)mode; // Always out + + return seekoff_beg(pos - pos_type(off_type(0))); + } +}; + +template<class CharT, class Traits> +class basic_obufferedstream : + public std::basic_ostream<CharT, Traits> +{ +public: + typedef typename std::basic_ios<CharT, Traits>::char_type char_type; + typedef typename std::basic_ios<char_type, Traits>::int_type int_type; + typedef typename std::basic_ios<char_type, Traits>::pos_type pos_type; + typedef typename std::basic_ios<char_type, Traits>::off_type off_type; + typedef typename std::basic_ios<char_type, Traits>::traits_type traits_type; + +private: + typedef basic_ovectorbuf<CharT, Traits> base_ouputbuf; + typedef std::basic_ios<char_type, Traits> base_ios; + + basic_ovectorbuf<CharT, Traits> buf_; + +public: + basic_obufferedstream() JSONCONS_NOEXCEPT + : std::basic_ostream<CharT, Traits>( (std::basic_streambuf<CharT, Traits>*)(&buf_)), + buf_() + {} + basic_obufferedstream(std::size_t length) JSONCONS_NOEXCEPT + : std::basic_ostream<CharT, Traits>( (std::basic_streambuf<CharT, Traits>*)(&buf_)), + buf_(length) + {} + + basic_obufferedstream(const basic_obufferedstream<CharT,Traits>&) = delete; + + //basic_obufferedstream(basic_obufferedstream<CharT,Traits>&&) = default; + + virtual ~basic_obufferedstream() JSONCONS_NOEXCEPT + { + } + + basic_obufferedstream<CharT,Traits>& operator=(const basic_obufferedstream<CharT,Traits>&) = delete; + + //basic_obufferedstream<CharT,Traits>& operator=(basic_obufferedstream<CharT,Traits>&&) = default; + + const CharT* data() const + { + return buf_.data(); + } + + size_t length() const + { + return buf_.length(); + } + + void set_locale(const std::locale& loc) + { + std::locale result = std::basic_ostream<CharT, Traits>::imbue(loc); + //this->pubimbue(loc); + } + + void clear_sequence() + { + this->clear(); + this->seekp(0, std::ios::beg); + } +}; + +} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/detail/type_traits_helper.hpp b/vendor/jsoncons-0.104.0/jsoncons/detail/type_traits_helper.hpp new file mode 100644 index 00000000..4dce8e63 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/detail/type_traits_helper.hpp @@ -0,0 +1,226 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_DETAIL_TYPETRAITSHELPER_HPP +#define JSONCONS_DETAIL_TYPETRAITSHELPER_HPP + +#include <stdexcept> +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <ostream> +#include <iomanip> +#include <cstdlib> +#include <cmath> +#include <cstdarg> +#include <locale> +#include <limits> +#include <type_traits> +#include <algorithm> +#include <memory> +#include <iterator> +#include <exception> +#include <array> +#include <initializer_list> +#include <jsoncons/jsoncons_config.hpp> +#include <jsoncons/json_exception.hpp> +#include <jsoncons/detail/obufferedstream.hpp> + +namespace jsoncons +{ +// static_max + +template <size_t arg1, size_t ... argn> +struct static_max; + +template <size_t arg> +struct static_max<arg> +{ + static const size_t value = arg; +}; + +template <size_t arg1, size_t arg2, size_t ... argn> +struct static_max<arg1,arg2,argn ...> +{ + static const size_t value = arg1 >= arg2 ? + static_max<arg1,argn...>::value : + static_max<arg2,argn...>::value; +}; + +// type_wrapper + +template <class T> +struct type_wrapper +{ + typedef T* pointer_type; + typedef const T* const_pointer_type; + typedef T value_type; + typedef T& reference; + typedef const T& const_reference; +}; + +template <class T> +struct type_wrapper<const T> +{ + typedef T* pointer_type; + typedef const T* const_pointer_type; + typedef T value_type; + typedef T& reference; + typedef const T& const_reference; +}; + +template <class T> +struct type_wrapper<T&> +{ + typedef T* pointer_type; + typedef const T* const_pointer_type; + typedef T value_type; + typedef T& reference; + typedef const T& const_reference; +}; + +template <class T> +struct type_wrapper<const T&> +{ + typedef T* pointer_type; + typedef const T* const_pointer_type; + typedef T value_type; + typedef T& reference; + typedef const T& const_reference; +}; + +// json_literals + +namespace detail { +JSONCONS_DEFINE_LITERAL(null_literal,"null") +JSONCONS_DEFINE_LITERAL(true_literal,"true") +JSONCONS_DEFINE_LITERAL(false_literal,"false") +} + +inline +unsigned char to_hex_character(unsigned char c) +{ + JSONCONS_ASSERT(c <= 0xF); + + return (c < 10) ? ('0' + c) : ('A' - 10 + c); +} + +inline +bool is_control_character(uint32_t c) +{ + return c <= 0x1F || c == 0x7f; +} + +inline +bool is_non_ascii_codepoint(uint32_t cp) +{ + return cp >= 0x80; +} + +template <typename T> +struct is_stateless + : public std::integral_constant<bool, + (std::is_default_constructible<T>::value && + std::is_empty<T>::value)> +{}; + +// type traits extensions + + +namespace detail { + +// to_plain_pointer + +template<class Pointer> inline +typename std::pointer_traits<Pointer>::element_type* to_plain_pointer(Pointer ptr) +{ + return (std::addressof(*ptr)); +} + +template<class T> inline +T * to_plain_pointer(T * ptr) +{ + return (ptr); +} + +// is_string_like + +template <class T, class Enable=void> +struct is_string_like : std::false_type {}; + +template <class T> +struct is_string_like<T, + typename std::enable_if<!std::is_void<typename T::traits_type>::value +>::type> : std::true_type {}; + +// is_integer_like + +template <class T, class Enable=void> +struct is_integer_like : std::false_type {}; + +template <class T> +struct is_integer_like<T, + typename std::enable_if<std::is_integral<T>::value && + std::is_signed<T>::value && + !std::is_same<T,bool>::value>::type> : std::true_type {}; + +// is_uinteger_like + +template <class T, class Enable=void> +struct is_uinteger_like : std::false_type {}; + +template <class T> +struct is_uinteger_like<T, + typename std::enable_if<std::is_integral<T>::value && + !std::is_signed<T>::value && + !std::is_same<T,bool>::value>::type> : std::true_type {}; + +// is_floating_point_like + +template <class T, class Enable=void> +struct is_floating_point_like : std::false_type {}; + +template <class T> +struct is_floating_point_like<T, + typename std::enable_if<std::is_floating_point<T>::value>::type> : std::true_type {}; + +// is_map_like + +template <class T, class Enable=void> +struct is_map_like : std::false_type {}; + +template <class T> +struct is_map_like<T, + typename std::enable_if<!std::is_void<typename T::mapped_type>::value>::type> + : std::true_type {}; + +// is_array_like +template<class T> +struct is_array_like : std::false_type {}; + +template<class E, size_t N> +struct is_array_like<std::array<E, N>> : std::true_type {}; + +// is_vector_like + +template <class T, class Enable=void> +struct is_vector_like : std::false_type {}; + +template <class T> +struct is_vector_like<T, + typename std::enable_if<!std::is_void<typename T::value_type>::value && + !is_array_like<T>::value && + !is_string_like<T>::value && + !is_map_like<T>::value +>::type> + : std::true_type {}; + +} + +} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/detail/unicode_traits.hpp b/vendor/jsoncons-0.104.0/jsoncons/detail/unicode_traits.hpp new file mode 100644 index 00000000..affbb9b7 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/detail/unicode_traits.hpp @@ -0,0 +1,1463 @@ +// Copyright 2016 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/unicode_traits for latest version + +/* + * Includes code derived from Unicode, Inc decomposition code in ConvertUTF.h and ConvertUTF.c + * http://www.unicode.org/ + * + * "Unicode, Inc. hereby grants the right to freely use the information + * supplied in this file in the creation of products supporting the + * Unicode Standard." +*/ + +#ifndef UNICONS_UNICODE_TRAITS_HPP +#define UNICONS_UNICODE_TRAITS_HPP + +#if defined (__clang__) +#if defined(_GLIBCXX_USE_NOEXCEPT) +#define UNICONS_NOEXCEPT _GLIBCXX_USE_NOEXCEPT +#else +#define UNICONS_NOEXCEPT noexcept +#endif +#elif defined(__GNUC__) +#define UNICONS_NOEXCEPT _GLIBCXX_USE_NOEXCEPT +#elif defined(_MSC_VER) +#if _MSC_VER >= 1900 +#define UNICONS_NOEXCEPT noexcept +#else +#define UNICONS_NOEXCEPT +#endif +#else +#define UNICONS_NOEXCEPT +#endif + +#include <string> +#include <iterator> +#include <type_traits> +#include <system_error> + +namespace unicons { + +/* + * Magic values subtracted from a buffer value during UTF8 conversion. + * This table contains as many values as there might be trailing bytes + * in a UTF-8 sequence. Source: ConvertUTF.c + */ +const uint32_t offsets_from_utf8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, + 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; + +/* + * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed + * into the first byte, depending on how many bytes follow. There are + * as many entries in this table as there are UTF-8 sequence types. + * (I.e., one byte sequence, two byte... etc.). Remember that sequencs + * for *legal* UTF-8 will be 4 or fewer bytes total. Source: ConvertUTF.c + */ +const uint8_t first_byte_mark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + +/* + * Index into the table below with the first byte of a UTF-8 sequence to + * get the number of trailing bytes that are supposed to follow it. + * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is + * left as-is for anyone who may want to do such conversion, which was + * allowed in earlier algorithms. Source: ConvertUTF.c + */ +const uint8_t trailing_bytes_for_utf8[256] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 +}; + +// Some fundamental constants. Source: ConvertUTF.h +const uint32_t replacement_char = 0x0000FFFD; +const uint32_t max_bmp = 0x0000FFFF; +const uint32_t max_utf16 = 0x0010FFFF; +const uint32_t max_utf32 = 0x7FFFFFFF; +const uint32_t max_legal_utf32 = 0x0010FFFF; + +const int half_shift = 10; // used for shifting by 10 bits +const uint32_t half_base = 0x0010000UL; +const uint32_t half_mask = 0x3FFUL; + +const uint16_t sur_high_start = 0xD800; +const uint16_t sur_high_end = 0xDBFF; +const uint16_t sur_low_start = 0xDC00; +const uint16_t sur_low_end = 0xDFFF; + +inline +static bool is_continuation_byte(unsigned char ch) +{ + return (ch & 0xC0) == 0x80; +} + +inline +bool is_high_surrogate(uint32_t ch) UNICONS_NOEXCEPT +{ + return (ch >= sur_high_start && ch <= sur_high_end); +} + +inline +bool is_low_surrogate(uint32_t ch) UNICONS_NOEXCEPT +{ + return (ch >= sur_low_start && ch <= sur_low_end); +} + +inline +bool is_surrogate(uint32_t ch) UNICONS_NOEXCEPT +{ + return (ch >= sur_high_start && ch <= sur_low_end); +} + +enum class conv_flags +{ + strict = 0, + lenient +}; + +// conv_errc + +enum class conv_errc +{ + ok = 0, + over_long_utf8_sequence = 1, // over long utf8 sequence + expected_continuation_byte, // expected continuation byte + unpaired_high_surrogate, // unpaired high surrogate UTF-16 + illegal_surrogate_value, // UTF-16 surrogate values are illegal in UTF-32 + source_exhausted, // partial character in source, but hit end + source_illegal // source sequence is illegal/malformed +}; + +class Unicode_traits_error_category_impl_ + : public std::error_category +{ +public: + virtual const char* name() const UNICONS_NOEXCEPT + { + return "unicons conversion error"; + } + virtual std::string message(int ev) const + { + switch (static_cast<conv_errc>(ev)) + { + case conv_errc::over_long_utf8_sequence: + return "Over long utf8 sequence"; + case conv_errc::expected_continuation_byte: + return "Expected continuation byte"; + case conv_errc::unpaired_high_surrogate: + return "Unpaired high surrogate UTF-16"; + case conv_errc::illegal_surrogate_value: + return "UTF-16 surrogate values are illegal in UTF-32"; + case conv_errc::source_exhausted: + return "Partial character in source, but hit end"; + case conv_errc::source_illegal: + return "Source sequence is illegal/malformed"; + default: + return ""; + break; + } + } +}; + +inline +const std::error_category& unicode_traits_error_category() +{ + static Unicode_traits_error_category_impl_ instance; + return instance; +} + +inline +std::error_code make_error_code(conv_errc result) +{ + return std::error_code(static_cast<int>(result),unicode_traits_error_category()); +} + +// encoding_errc + +enum class encoding_errc +{ + ok = 0, + expected_u8_found_u16 = 1, + expected_u8_found_u32, + expected_u16_found_fffe, + expected_u32_found_fffe +}; + +class Encoding_errc_impl_ + : public std::error_category +{ +public: + virtual const char* name() const UNICONS_NOEXCEPT + { + return "unicons encoding error"; + } + virtual std::string message(int ev) const + { + switch (static_cast<encoding_errc>(ev)) + { + case encoding_errc::expected_u8_found_u16: + return "Expected UTF-8, found UTF-16"; + case encoding_errc::expected_u8_found_u32: + return "Expected UTF-8, found UTF-32"; + case encoding_errc::expected_u16_found_fffe: + return "Expected UTF-16, found non character"; + case encoding_errc::expected_u32_found_fffe: + return "Expected UTF-32, found non character"; + default: + return ""; + break; + } + } +}; + +inline +const std::error_category& encoding_error_category() +{ + static Encoding_errc_impl_ instance; + return instance; +} + +inline +std::error_code make_error_code(encoding_errc result) +{ + return std::error_code(static_cast<int>(result),encoding_error_category()); +} +} + +namespace std { + template<> + struct is_error_code_enum<unicons::conv_errc> : public true_type + { + }; + template<> + struct is_error_code_enum<unicons::encoding_errc> : public true_type + { + }; +} + +namespace unicons { + +// utf8 + +template <class Iterator> +typename std::enable_if<std::is_integral<typename std::iterator_traits<Iterator>::value_type>::value + && sizeof(typename std::iterator_traits<Iterator>::value_type) == sizeof(uint8_t), + conv_errc >::type +is_legal_utf8(Iterator first, size_t length) +{ + uint8_t a; + Iterator srcptr = first+length; + switch (length) { + default: + return conv_errc::over_long_utf8_sequence; + case 4: + if (((a = (*--srcptr))& 0xC0) != 0x80) + return conv_errc::expected_continuation_byte; + // FALLTHRU + case 3: + if (((a = (*--srcptr))& 0xC0) != 0x80) + return conv_errc::expected_continuation_byte; + // FALLTHRU + case 2: + if (((a = (*--srcptr))& 0xC0) != 0x80) + return conv_errc::expected_continuation_byte; + + switch (static_cast<uint8_t>(*first)) + { + /* no fall-through in this inner switch */ + case 0xE0: if (a < 0xA0) return conv_errc::source_illegal; break; + case 0xED: if (a > 0x9F) return conv_errc::source_illegal; break; + case 0xF0: if (a < 0x90) return conv_errc::source_illegal; break; + case 0xF4: if (a > 0x8F) return conv_errc::source_illegal; break; + default: if (a < 0x80) return conv_errc::source_illegal; + } + + // FALLTHRU + case 1: + if (static_cast<uint8_t>(*first) >= 0x80 && static_cast<uint8_t>(*first) < 0xC2) + return conv_errc::source_illegal; + // FALLTHRU + } + if (static_cast<uint8_t>(*first) > 0xF4) + return conv_errc::source_illegal; + + return conv_errc(); +} + +template <class...> using void_t = void; + +template <class, class, class = void> +struct is_output_iterator : std::false_type {}; + +template <class I, class E> +struct is_output_iterator<I, E, void_t< + typename std::iterator_traits<I>::iterator_category, + decltype(*std::declval<I>() = std::declval<E>())>> : std::true_type {}; + +// is_same_size fixes issue with vs2013 + +// primary template +template<class T1, class T2, class Enable = void> +struct is_same_size : std::false_type +{ +}; + +// specialization for non void types +template<class T1, class T2> +struct is_same_size<T1, T2, typename std::enable_if<!std::is_void<T1>::value && !std::is_void<T2>::value>::type> +{ + static const bool value = (sizeof(T1) == sizeof(T2)); +}; + +template<class OutputIt, class CharT, class Enable = void> +struct is_compatible_output_iterator : std::false_type {}; + +template<class OutputIt, class CharT> +struct is_compatible_output_iterator<OutputIt,CharT, + typename std::enable_if<is_output_iterator<OutputIt,CharT>::value + && std::is_void<typename std::iterator_traits<OutputIt>::value_type>::value + && std::is_integral<typename OutputIt::container_type::value_type>::value + && !std::is_void<typename OutputIt::container_type::value_type>::value + && is_same_size<typename OutputIt::container_type::value_type,CharT>::value>::type +> : std::true_type {}; + +template<class OutputIt, class CharT> +struct is_compatible_output_iterator<OutputIt,CharT, + typename std::enable_if<is_output_iterator<OutputIt,CharT>::value + && std::is_integral<typename std::iterator_traits<OutputIt>::value_type>::value + && is_same_size<typename std::iterator_traits<OutputIt>::value_type,CharT>::value>::type +> : std::true_type {}; + +template<class OutputIt, class CharT> +struct is_compatible_output_iterator<OutputIt,CharT, + typename std::enable_if<is_output_iterator<OutputIt,CharT>::value + && std::is_void<typename std::iterator_traits<OutputIt>::value_type>::value + && is_same_size<typename OutputIt::char_type,CharT>::value>::type +> : std::true_type {}; + +// convert + +template <class Iterator> +struct convert_result +{ + Iterator it; + conv_errc ec; +}; + +template <class InputIt,class OutputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint8_t) + && is_compatible_output_iterator<OutputIt,uint8_t>::value,convert_result<InputIt>>::type +convert(InputIt first, InputIt last, OutputIt target, conv_flags flags=conv_flags::strict) +{ + (void)flags; + + conv_errc result = conv_errc(); + while (first != last) + { + size_t length = trailing_bytes_for_utf8[static_cast<uint8_t>(*first)] + 1; + if (length > (size_t)(last - first)) + { + return convert_result<InputIt>{first, conv_errc::source_exhausted}; + } + if ((result=is_legal_utf8(first, length)) != conv_errc()) + { + return convert_result<InputIt>{first,result}; + } + + switch (length) { + case 4: *target++ = (static_cast<uint8_t>(*first++)); + case 3: *target++ = (static_cast<uint8_t>(*first++)); + case 2: *target++ = (static_cast<uint8_t>(*first++)); + case 1: *target++ = (static_cast<uint8_t>(*first++)); + } + } + return convert_result<InputIt>{first,result} ; +} + +template <class InputIt,class OutputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint8_t) + && is_compatible_output_iterator<OutputIt,uint16_t>::value,convert_result<InputIt>>::type +convert(InputIt first, InputIt last, + OutputIt target, + conv_flags flags = conv_flags::strict) +{ + conv_errc result = conv_errc(); + + while (first != last) + { + uint32_t ch = 0; + unsigned short extra_bytes_to_read = trailing_bytes_for_utf8[static_cast<uint8_t>(*first)]; + if (extra_bytes_to_read >= last - first) + { + result = conv_errc::source_exhausted; + break; + } + /* Do this check whether lenient or strict */ + if ((result=is_legal_utf8(first, extra_bytes_to_read+1)) != conv_errc()) + { + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extra_bytes_to_read) { + case 5: ch += static_cast<uint8_t>(*first++); ch <<= 6; /* remember, illegal UTF-8 */ + case 4: ch += static_cast<uint8_t>(*first++); ch <<= 6; /* remember, illegal UTF-8 */ + case 3: ch += static_cast<uint8_t>(*first++); ch <<= 6; + case 2: ch += static_cast<uint8_t>(*first++); ch <<= 6; + case 1: ch += static_cast<uint8_t>(*first++); ch <<= 6; + case 0: ch += static_cast<uint8_t>(*first++); + } + ch -= offsets_from_utf8[extra_bytes_to_read]; + + if (ch <= max_bmp) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (is_surrogate(ch) ) { + if (flags == conv_flags::strict) { + first -= (extra_bytes_to_read+1); /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } else { + *target++ = (replacement_char); + } + } else { + *target++ = ((uint16_t)ch); /* normal case */ + } + } else if (ch > max_utf16) { + if (flags == conv_flags::strict) { + result = conv_errc::source_illegal; + first -= (extra_bytes_to_read+1); /* return to the start */ + break; /* Bail out; shouldn't continue */ + } else { + *target++ = (replacement_char); + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + ch -= half_base; + *target++ = ((uint16_t)((ch >> half_shift) + sur_high_start)); + *target++ = ((uint16_t)((ch & half_mask) + sur_low_start)); + } + } + return convert_result<InputIt>{first,result} ; +} + +template <class InputIt,class OutputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint8_t) + && is_compatible_output_iterator<OutputIt,uint32_t>::value,convert_result<InputIt>>::type +convert(InputIt first, InputIt last, + OutputIt target, + conv_flags flags = conv_flags::strict) +{ + conv_errc result = conv_errc(); + + while (first < last) + { + uint32_t ch = 0; + unsigned short extra_bytes_to_read = trailing_bytes_for_utf8[static_cast<uint8_t>(*first)]; + if (extra_bytes_to_read >= last - first) + { + result = conv_errc::source_exhausted; + break; + } + /* Do this check whether lenient or strict */ + if ((result=is_legal_utf8(first, extra_bytes_to_read+1)) != conv_errc()) { + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extra_bytes_to_read) { + case 5: ch += static_cast<uint8_t>(*first++); ch <<= 6; + case 4: ch += static_cast<uint8_t>(*first++); ch <<= 6; + case 3: ch += static_cast<uint8_t>(*first++); ch <<= 6; + case 2: ch += static_cast<uint8_t>(*first++); ch <<= 6; + case 1: ch += static_cast<uint8_t>(*first++); ch <<= 6; + case 0: ch += static_cast<uint8_t>(*first++); + } + ch -= offsets_from_utf8[extra_bytes_to_read]; + + if (ch <= max_legal_utf32) { + /* + * UTF-16 surrogate values are illegal in UTF-32, and anything + * over Plane 17 (> 0x10FFFF) is illegal. + */ + if (is_surrogate(ch) ) { + if (flags == conv_flags::strict) { + first -= (extra_bytes_to_read+1); /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } else { + *target++ = (replacement_char); + } + } else { + *target++ = (ch); + } + } else { /* i.e., ch > max_legal_utf32 */ + result = conv_errc::source_illegal; + *target++ = (replacement_char); + } + } + return convert_result<InputIt>{first,result} ; +} + +// utf16 + +template <class InputIt,class OutputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint16_t) + && is_compatible_output_iterator<OutputIt,uint8_t>::value,convert_result<InputIt>>::type +convert(InputIt first, InputIt last, + OutputIt target, + conv_flags flags = conv_flags::strict) { + conv_errc result = conv_errc(); + while (first < last) { + unsigned short bytes_to_write = 0; + const uint32_t byteMask = 0xBF; + const uint32_t byteMark = 0x80; + uint32_t ch = *first++; + /* If we have a surrogate pair, convert to uint32_t first. */ + if (is_high_surrogate(ch)) { + /* If the 16 bits following the high surrogate are in the first buffer... */ + if (first < last) { + uint32_t ch2 = *first; + /* If it's a low surrogate, convert to uint32_t. */ + if (ch2 >= sur_low_start && ch2 <= sur_low_end) { + ch = ((ch - sur_high_start) << half_shift) + + (ch2 - sur_low_start) + half_base; + ++first; + } else if (flags == conv_flags::strict) { /* it's an unpaired high surrogate */ + --first; /* return to the illegal value itself */ + result = conv_errc::unpaired_high_surrogate; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --first; /* return to the high surrogate */ + result = conv_errc::source_exhausted; + break; + } + } else if (flags == conv_flags::strict) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (is_low_surrogate(ch)) { + --first; /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } + } + /* Figure out how many bytes the result will require */ + if (ch < (uint32_t)0x80) { + bytes_to_write = 1; + } else if (ch < (uint32_t)0x800) { + bytes_to_write = 2; + } else if (ch < (uint32_t)0x10000) { + bytes_to_write = 3; + } else if (ch < (uint32_t)0x110000) { + bytes_to_write = 4; + } else { + bytes_to_write = 3; + ch = replacement_char; + } + + uint8_t byte1 = 0; + uint8_t byte2 = 0; + uint8_t byte3 = 0; + uint8_t byte4 = 0; + + switch (bytes_to_write) { // note: everything falls through + case 4: byte4 = (uint8_t)((ch | byteMark) & byteMask); ch >>= 6; + case 3: byte3 = (uint8_t)((ch | byteMark) & byteMask); ch >>= 6; + case 2: byte2 = (uint8_t)((ch | byteMark) & byteMask); ch >>= 6; + case 1: byte1 = (uint8_t)(ch | first_byte_mark[bytes_to_write]); + } + switch (bytes_to_write) + { + case 4: + *target++ = (byte1); + *target++ = (byte2); + *target++ = (byte3); + *target++ = (byte4); + break; + case 3: + *target++ = (byte1); + *target++ = (byte2); + *target++ = (byte3); + break; + case 2: + *target++ = (byte1); + *target++ = (byte2); + break; + case 1: + *target++ = (byte1); + break; + } + } + return convert_result<InputIt>{first,result} ; +} + +template <class InputIt,class OutputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint16_t) + && is_compatible_output_iterator<OutputIt,uint16_t>::value,convert_result<InputIt>>::type +convert(InputIt first, InputIt last, + OutputIt target, + conv_flags flags = conv_flags::strict) +{ + conv_errc result = conv_errc(); + + while (first != last) + { + uint32_t ch = *first++; + /* If we have a surrogate pair, convert to uint32_t first. */ + if (is_high_surrogate(ch)) + { + /* If the 16 bits following the high surrogate are in the first buffer... */ + if (first < last) { + uint32_t ch2 = *first; + /* If it's a low surrogate, */ + if (ch2 >= sur_low_start && ch2 <= sur_low_end) { + *target++ = ((uint16_t)ch); + *target++ = ((uint16_t)ch2); + ++first; + } else if (flags == conv_flags::strict) { /* it's an unpaired high surrogate */ + --first; /* return to the illegal value itself */ + result = conv_errc::unpaired_high_surrogate; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --first; /* return to the high surrogate */ + result = conv_errc::source_exhausted; + break; + } + } else if (is_low_surrogate(ch)) + { + // illegal leading low surrogate + if (flags == conv_flags::strict) { + --first; /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } + else + { + *target++ = ((uint16_t)ch); + } + } + else + { + *target++ = ((uint16_t)ch); + } + } + return convert_result<InputIt>{first,result} ; +} + +template <class InputIt,class OutputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint16_t) + && is_compatible_output_iterator<OutputIt,uint32_t>::value,convert_result<InputIt>>::type +convert(InputIt first, InputIt last, + OutputIt target, + conv_flags flags = conv_flags::strict) +{ + conv_errc result = conv_errc(); + + while (first != last) + { + uint32_t ch = *first++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (is_high_surrogate(ch)) { + /* If the 16 bits following the high surrogate are in the first buffer... */ + if (first < last) { + uint32_t ch2 = *first; + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= sur_low_start && ch2 <= sur_low_end ) { + ch = ((ch - sur_high_start) << half_shift) + + (ch2 - sur_low_start) + half_base; + ++first; + } else if (flags == conv_flags::strict) { /* it's an unpaired high surrogate */ + --first; /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --first; /* return to the high surrogate */ + result = conv_errc::source_exhausted; + break; + } + } else if (flags == conv_flags::strict) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (is_low_surrogate(ch) ) { + --first; /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } + } + *target++ = (ch); + } + return convert_result<InputIt>{first,result} ; +} + +// utf32 + +template <class InputIt,class OutputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint32_t) + && is_compatible_output_iterator<OutputIt,uint8_t>::value,convert_result<InputIt>>::type +convert(InputIt first, InputIt last, + OutputIt target, + conv_flags flags = conv_flags::strict) +{ + conv_errc result = conv_errc(); + while (first < last) { + unsigned short bytes_to_write = 0; + const uint32_t byteMask = 0xBF; + const uint32_t byteMark = 0x80; + uint32_t ch = *first++; + if (flags == conv_flags::strict ) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (is_surrogate(ch)) { + --first; /* return to the illegal value itself */ + result = conv_errc::illegal_surrogate_value; + break; + } + } + /* + * Figure out how many bytes the result will require. Turn any + * illegally large UTF32 things (> Plane 17) into replacement chars. + */ + if (ch < (uint32_t)0x80) { bytes_to_write = 1; + } else if (ch < (uint32_t)0x800) { bytes_to_write = 2; + } else if (ch < (uint32_t)0x10000) { bytes_to_write = 3; + } else if (ch <= max_legal_utf32) { bytes_to_write = 4; + } else { + bytes_to_write = 3; + ch = replacement_char; + result = conv_errc::source_illegal; + } + + uint8_t byte1 = 0; + uint8_t byte2 = 0; + uint8_t byte3 = 0; + uint8_t byte4 = 0; + + switch (bytes_to_write) { + case 4: + byte4 = (uint8_t)((ch | byteMark) & byteMask); ch >>= 6; + // FALLTHRU + case 3: + byte3 = (uint8_t)((ch | byteMark) & byteMask); ch >>= 6; + // FALLTHRU + case 2: + byte2 = (uint8_t)((ch | byteMark) & byteMask); ch >>= 6; + // FALLTHRU + case 1: + byte1 = (uint8_t) (ch | first_byte_mark[bytes_to_write]); + } + + switch (bytes_to_write) + { + case 4: + *target++ = (byte1); + *target++ = (byte2); + *target++ = (byte3); + *target++ = (byte4); + break; + case 3: + *target++ = (byte1); + *target++ = (byte2); + *target++ = (byte3); + break; + case 2: + *target++ = (byte1); + *target++ = (byte2); + break; + case 1: + *target++ = (byte1); + break; + } + } + return convert_result<InputIt>{first,result} ; +} + +template <class InputIt,class OutputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint32_t) + && is_compatible_output_iterator<OutputIt,uint16_t>::value,convert_result<InputIt>>::type +convert(InputIt first, InputIt last, + OutputIt target, + conv_flags flags = conv_flags::strict) +{ + conv_errc result = conv_errc(); + + while (first != last) + { + uint32_t ch = *first++; + if (ch <= max_bmp) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */ + if (is_surrogate(ch) ) { + if (flags == conv_flags::strict) { + --first; /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } else { + *target++ = (replacement_char); + } + } else { + *target++ = ((uint16_t)ch); /* normal case */ + } + } else if (ch > max_legal_utf32) { + if (flags == conv_flags::strict) { + result = conv_errc::source_illegal; + } else { + *target++ = (replacement_char); + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + ch -= half_base; + *target++ = ((uint16_t)((ch >> half_shift) + sur_high_start)); + *target++ = ((uint16_t)((ch & half_mask) + sur_low_start)); + } + } + return convert_result<InputIt>{first,result} ; +} + +template <class InputIt,class OutputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint32_t) + && is_compatible_output_iterator<OutputIt,uint32_t>::value,convert_result<InputIt>>::type +convert(InputIt first, InputIt last, + OutputIt target, + conv_flags flags = conv_flags::strict) +{ + conv_errc result = conv_errc(); + + while (first != last) + { + uint32_t ch = *first++; + if (flags == conv_flags::strict ) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (is_surrogate(ch)) { + --first; /* return to the illegal value itself */ + result = conv_errc::illegal_surrogate_value; + break; + } + } + if (ch <= max_legal_utf32) + { + *target++ = (ch); + } + else + { + *target++ = (replacement_char); + result = conv_errc::source_illegal; + } + } + return convert_result<InputIt>{first,result} ; +} + +// validate + +template <class InputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint8_t) + ,convert_result<InputIt>>::type +validate(InputIt first, InputIt last) UNICONS_NOEXCEPT +{ + conv_errc result = conv_errc(); + while (first != last) + { + size_t length = trailing_bytes_for_utf8[static_cast<uint8_t>(*first)] + 1; + if (length > (size_t)(last - first)) + { + return convert_result<InputIt>{first, conv_errc::source_exhausted}; + } + if ((result=is_legal_utf8(first, length)) != conv_errc()) + { + return convert_result<InputIt>{first,result} ; + } + first += length; + } + return convert_result<InputIt>{first,result} ; +} + +// utf16 + +template <class InputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint16_t) + ,convert_result<InputIt>>::type +validate(InputIt first, InputIt last) UNICONS_NOEXCEPT +{ + conv_errc result = conv_errc(); + + while (first != last) + { + uint32_t ch = *first++; + /* If we have a surrogate pair, validate to uint32_t first. */ + if (is_high_surrogate(ch)) + { + /* If the 16 bits following the high surrogate are in the first buffer... */ + if (first < last) { + uint32_t ch2 = *first; + /* If it's a low surrogate, */ + if (ch2 >= sur_low_start && ch2 <= sur_low_end) { + ++first; + } else { + --first; /* return to the illegal value itself */ + result = conv_errc::unpaired_high_surrogate; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --first; /* return to the high surrogate */ + result = conv_errc::source_exhausted; + break; + } + } else if (is_low_surrogate(ch)) + { + /* UTF-16 surrogate values are illegal in UTF-32 */ + --first; /* return to the illegal value itself */ + result = conv_errc::source_illegal; + break; + } + } + return convert_result<InputIt>{first,result} ; +} + + +// utf32 + + +template <class InputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint32_t) + ,convert_result<InputIt>>::type +validate(InputIt first, InputIt last) UNICONS_NOEXCEPT +{ + conv_errc result = conv_errc(); + + while (first != last) + { + uint32_t ch = *first++; + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (is_surrogate(ch)) { + --first; /* return to the illegal value itself */ + result = conv_errc::illegal_surrogate_value; + break; + } + if (!(ch <= max_legal_utf32)) + { + result = conv_errc::source_illegal; + } + } + return convert_result<InputIt>{first,result} ; +} + +// sequence + +template <class Iterator> +class sequence +{ + Iterator first_; + size_t length_; +public: + sequence(Iterator first, size_t length) + : first_(first), length_(length) + { + } + + Iterator begin() const + { + return first_; + } + + size_t length() const + { + return length_; + } + + template <class CharT = typename std::iterator_traits<Iterator>::value_type> + typename std::enable_if<sizeof(CharT) == sizeof(uint8_t),uint32_t>::type + codepoint() const UNICONS_NOEXCEPT + { + uint32_t ch = 0; + Iterator it = first_; + switch (length_) + { + default: + return replacement_char; + break; + case 4: + ch += static_cast<uint8_t>(*it++); ch <<= 6; + // FALLTHRU + case 3: + ch += static_cast<uint8_t>(*it++); ch <<= 6; + // FALLTHRU + case 2: + ch += static_cast<uint8_t>(*it++); ch <<= 6; + // FALLTHRU + case 1: + ch += static_cast<uint8_t>(*it++); + ch -= offsets_from_utf8[length_ - 1]; + break; + } + if (ch <= max_legal_utf32) + { + if (is_surrogate(ch)) + { + ch = replacement_char; + } + } + else // ch > max_legal_utf32 + { + ch = replacement_char; + } + return ch; + } + + template <class CharT = typename std::iterator_traits<Iterator>::value_type> + typename std::enable_if<sizeof(CharT) == sizeof(uint16_t),uint32_t>::type + codepoint() const UNICONS_NOEXCEPT + { + if (length_ == 0) + { + return replacement_char; + } + if (length_ == 2) + { + uint32_t ch = *first_; + uint32_t ch2 = *(first_+ 1); + ch = ((ch - sur_high_start) << half_shift) + + (ch2 - sur_low_start) + half_base; + return ch; + } + else + { + return *first_; + } + } + + template <class CharT = typename std::iterator_traits<Iterator>::value_type> + typename std::enable_if<sizeof(CharT) == sizeof(uint32_t),uint32_t>::type + codepoint() const UNICONS_NOEXCEPT + { + if (length_ == 0) + { + return replacement_char; + } + return *(first_); + } +}; + +// sequence_generator + +template <class Iterator> +class sequence_generator +{ + Iterator begin_; + Iterator last_; + conv_flags flags_; + size_t length_; + conv_errc err_cd_; +public: + typedef sequence<Iterator> sequence_type; + + sequence_generator(Iterator first, Iterator last, + conv_flags flags = conv_flags::strict) UNICONS_NOEXCEPT + : begin_(first), last_(last), flags_(flags), + length_(0), err_cd_(conv_errc()) + { + next(); + } + + bool done() const UNICONS_NOEXCEPT + { + return err_cd_ != conv_errc() || begin_ == last_; + } + + conv_errc status() const UNICONS_NOEXCEPT + { + return err_cd_; + } + + sequence_type get() const UNICONS_NOEXCEPT + { + return sequence<Iterator>(begin_,length_); + } + + template <class CharT = typename std::iterator_traits<Iterator>::value_type> + typename std::enable_if<sizeof(CharT) == sizeof(uint8_t)>::type + next() UNICONS_NOEXCEPT + { + begin_ += length_; + if (begin_ != last_) + { + size_t length = trailing_bytes_for_utf8[static_cast<uint8_t>(*begin_)] + 1; + if (length > (size_t)(last_ - begin_)) + { + err_cd_ = conv_errc::source_exhausted; + } + else if ((err_cd_ = is_legal_utf8(begin_, length)) != conv_errc()) + { + } + else + { + length_ = length; + } + } + } + + template <class CharT = typename std::iterator_traits<Iterator>::value_type> + typename std::enable_if<sizeof(CharT) == sizeof(uint16_t)>::type + next() UNICONS_NOEXCEPT + { + begin_ += length_; + if (begin_ != last_) + { + if (begin_ != last_) + { + + Iterator it = begin_; + + uint32_t ch = *it++; + /* If we have a surrogate pair, validate to uint32_t it. */ + if (is_high_surrogate(ch)) + { + /* If the 16 bits following the high surrogate are in the it buffer... */ + if (it < last_) { + uint32_t ch2 = *it; + /* If it's a low surrogate, */ + if (ch2 >= sur_low_start && ch2 <= sur_low_end) + { + ++it; + length_ = 2; + } + else + { + err_cd_ = conv_errc::unpaired_high_surrogate; + } + } + else + { + // We don't have the 16 bits following the high surrogate. + err_cd_ = conv_errc::source_exhausted; + } + } + else if (is_low_surrogate(ch)) + { + /* leading low surrogate */ + err_cd_ = conv_errc::source_illegal; + } + else + { + length_ = 1; + } + } + } + } + + template <class CharT = typename std::iterator_traits<Iterator>::value_type> + typename std::enable_if<sizeof(CharT) == sizeof(uint32_t)>::type + next() UNICONS_NOEXCEPT + { + begin_ += length_; + length_ = 1; + } +}; + +template <class Iterator> +sequence_generator<Iterator> make_sequence_generator(Iterator first, Iterator last, + conv_flags flags = conv_flags::strict) +{ + return sequence_generator<Iterator>(first, last, flags); +} + +template <class InputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value + && (sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint8_t) || sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint16_t)), + sequence<InputIt>>::type +sequence_at(InputIt first, InputIt last, size_t index) +{ + sequence_generator<InputIt> g(first, last, unicons::conv_flags::strict); + + size_t count = 0; + while (!g.done() && count < index) + { + g.next(); + ++count; + } + return (!g.done() && count == index) ? g.get() : sequence<InputIt>(last,0); +} + +template <class InputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint32_t), + sequence<InputIt>>::type +sequence_at(InputIt first, InputIt last, size_t index) +{ + size_t size = std::distance(first,last); + return index < size ? sequence<InputIt>(first+index,1) : sequence<InputIt>(last,0); +} + +// u8_length + +template <class InputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint8_t),size_t>::type +u8_length(InputIt first, InputIt last) UNICONS_NOEXCEPT +{ + return std::distance(first,last); +} + +// utf16 + +template <class InputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint16_t),size_t>::type +u8_length(InputIt first, InputIt last) UNICONS_NOEXCEPT +{ + conv_flags flags = conv_flags::strict; + size_t count = 0; + for (InputIt p = first; p != last; ++p) + { + uint32_t ch = *p; + if (is_high_surrogate(ch)) { + /* If the 16 bits following the high surrogate are in the p buffer... */ + if (p < last) { + uint32_t ch2 = *(++p); + /* If it's a low surrogate, convert to uint32_t. */ + if (ch2 >= sur_low_start && ch2 <= sur_low_end) { + ch = ((ch - sur_high_start) << half_shift) + + (ch2 - sur_low_start) + half_base; + + } else if (flags == conv_flags::strict) { /* it's an unpaired high surrogate */ + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + break; + } + } else if (flags == conv_flags::strict) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (is_low_surrogate(ch)) { + break; + } + } + if (ch < (uint32_t)0x80) { + ++count; + } else if (ch < (uint32_t)0x800) { + count += 2; + } else if (ch < (uint32_t)0x10000) { + count += 3; + } else if (ch < (uint32_t)0x110000) { + count += 4; + } else { + count += 3; + } + } + return count; +} + + +// utf32 + +template <class InputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint32_t),size_t>::type +u8_length(InputIt first, InputIt last) UNICONS_NOEXCEPT +{ + size_t count = 0; + for (InputIt p = first; p < last; ++p) + { + uint32_t ch = *p; + if (ch < (uint32_t)0x80) { + ++count; + } else if (ch < (uint32_t)0x800) { + count += 2; + } else if (ch < (uint32_t)0x10000) { + count += 3; + } else if (ch <= max_legal_utf32) { + count += 4; + } else { + count += 3; + } + } + return count; +} + +// u32_length + +template <class InputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value + && (sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint8_t) || sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint16_t)), + size_t>::type +u32_length(InputIt first, InputIt last) UNICONS_NOEXCEPT +{ + sequence_generator<InputIt> g(first, last, unicons::conv_flags::strict); + + size_t count = 0; + while (!g.done()) + { + g.next(); + ++count; + } + return count; +} + +template <class InputIt> +typename std::enable_if<std::is_integral<typename std::iterator_traits<InputIt>::value_type>::value && sizeof(typename std::iterator_traits<InputIt>::value_type) == sizeof(uint32_t), + size_t>::type +u32_length(InputIt first, InputIt last) UNICONS_NOEXCEPT +{ + return std::distance(first,last); +} + +enum class encoding {u8,u16le,u16be,u32le,u32be,undetected}; + +template <class Iterator> +struct detect_encoding_result +{ + Iterator it; + encoding ec; +}; + +template <class Iterator> +typename std::enable_if<std::is_integral<typename std::iterator_traits<Iterator>::value_type>::value && sizeof(typename std::iterator_traits<Iterator>::value_type) == sizeof(uint8_t), + detect_encoding_result<Iterator>>::type +detect_encoding(Iterator first, Iterator last) UNICONS_NOEXCEPT +{ + Iterator it1 = first; + if (std::distance(first,last) < 4) + { + if (std::distance(first,last) == 3) + { + Iterator it2 = ++first; + Iterator it3 = ++first; + if (static_cast<uint8_t>(*it1) == 0xEF && static_cast<uint8_t>(*it2) == 0xBB && static_cast<uint8_t>(*it3) == 0xBF) + { + return detect_encoding_result<Iterator>{last,encoding::u8}; + } + } + return detect_encoding_result<Iterator>{it1,encoding::undetected}; + } + else + { + Iterator it2 = ++first; + Iterator it3 = ++first; + Iterator it4 = ++first; + + uint32_t bom = static_cast<uint8_t>(*it1) | (static_cast<uint8_t>(*it2) << 8) | (static_cast<uint8_t>(*it3) << 16) | (static_cast<uint8_t>(*it4) << 24); + if (bom == 0xFFFE0000) + { + return detect_encoding_result<Iterator>{it4++,encoding::u32be}; + } + else if (bom == 0x0000FEFF) + { + return detect_encoding_result<Iterator>{first,encoding::u32le}; + } + else if ((bom & 0xFFFF) == 0xFFFE) + { + return detect_encoding_result<Iterator>{it3,encoding::u16be}; + } + else if ((bom & 0xFFFF) == 0xFEFF) + { + return detect_encoding_result<Iterator>{it3,encoding::u16le}; + } + else if ((bom & 0xFFFFFF) == 0xBFBBEF) + { + return detect_encoding_result<Iterator>{it4,encoding::u8}; + } + else + { + uint32_t pattern = (static_cast<uint8_t>(*it1) ? 1 : 0) | (static_cast<uint8_t>(*it2) ? 2 : 0) | (static_cast<uint8_t>(*it3) ? 4 : 0) | (static_cast<uint8_t>(*it4) ? 8 : 0); + switch (pattern) { + case 0x08: + return detect_encoding_result<Iterator>{it1,encoding::u32be}; + case 0x0A: + return detect_encoding_result<Iterator>{it1,encoding::u16be}; + case 0x01: + return detect_encoding_result<Iterator>{it1,encoding::u32le}; + case 0x05: + return detect_encoding_result<Iterator>{it1,encoding::u16le}; + case 0x0F: + return detect_encoding_result<Iterator>{it1,encoding::u8}; + default: + return detect_encoding_result<Iterator>{it1,encoding::undetected}; + } + } + } +} + +template <class Iterator> +struct skip_bom_result +{ + Iterator it; + encoding_errc ec; +}; + +template <class Iterator> +typename std::enable_if<std::is_integral<typename std::iterator_traits<Iterator>::value_type>::value && sizeof(typename std::iterator_traits<Iterator>::value_type) == sizeof(uint8_t), + skip_bom_result<Iterator>>::type +skip_bom(Iterator first, Iterator last) UNICONS_NOEXCEPT +{ + auto result = unicons::detect_encoding(first,last); + switch (result.ec) + { + case unicons::encoding::u8: + return skip_bom_result<Iterator>{result.it,encoding_errc()}; + break; + case unicons::encoding::u16le: + case unicons::encoding::u16be: + return skip_bom_result<Iterator>{result.it,encoding_errc::expected_u8_found_u16}; + break; + case unicons::encoding::u32le: + case unicons::encoding::u32be: + return skip_bom_result<Iterator>{result.it,encoding_errc::expected_u8_found_u32}; + break; + default: + return skip_bom_result<Iterator>{result.it,encoding_errc()}; + break; + } +} + +template <class Iterator> +typename std::enable_if<std::is_integral<typename std::iterator_traits<Iterator>::value_type>::value && sizeof(typename std::iterator_traits<Iterator>::value_type) == sizeof(uint16_t), + skip_bom_result<Iterator>>::type +skip_bom(Iterator first, Iterator last) UNICONS_NOEXCEPT +{ + if (first == last) + { + return skip_bom_result<Iterator>{first,encoding_errc()}; + } + uint16_t bom = static_cast<uint16_t>(*first); + if (bom == 0xFEFF) + { + return skip_bom_result<Iterator>{++first,encoding_errc()}; + } + else if (bom == 0xFFFE) + { + return skip_bom_result<Iterator>{last,encoding_errc::expected_u16_found_fffe}; + } + else + { + return skip_bom_result<Iterator>{first,encoding_errc()}; + } +} + +template <class Iterator> +typename std::enable_if<std::is_integral<typename std::iterator_traits<Iterator>::value_type>::value && sizeof(typename std::iterator_traits<Iterator>::value_type) == sizeof(uint32_t), + skip_bom_result<Iterator>>::type +skip_bom(Iterator first, Iterator last) UNICONS_NOEXCEPT +{ + if (first == last) + { + return skip_bom_result<Iterator>{first,encoding_errc()}; + } + uint32_t bom = static_cast<uint32_t>(*first); + if (bom == 0xFEFF0000) + { + return skip_bom_result<Iterator>{++first,encoding_errc()}; + } + else if (bom == 0xFFFE0000) + { + return skip_bom_result<Iterator>{last,encoding_errc::expected_u32_found_fffe}; + } + else + { + return skip_bom_result<Iterator>{first,encoding_errc()}; + } +} + +} + +#endif + diff --git a/vendor/jsoncons-0.104.0/jsoncons/detail/writer.hpp b/vendor/jsoncons-0.104.0/jsoncons/detail/writer.hpp new file mode 100644 index 00000000..c832f06f --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/detail/writer.hpp @@ -0,0 +1,155 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_DETAIL_WRITERS_HPP +#define JSONCONS_DETAIL_WRITERS_HPP + +#include <stdexcept> +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <ostream> +#include <iomanip> +#include <cstdlib> +#include <cmath> +#include <cstdarg> +#include <locale> +#include <limits> +#include <type_traits> +#include <algorithm> +#include <exception> +#include <jsoncons/jsoncons_config.hpp> +#include <jsoncons/detail/type_traits_helper.hpp> + +namespace jsoncons { namespace detail { + +template <class CharT> +class ostream_buffered_writer +{ +public: + typedef basic_string_view_ext<CharT> string_view_type; + typedef CharT char_type; + typedef std::basic_ostream<CharT> output_type; +private: + static const size_t default_buffer_length = 16384; + + std::basic_ostream<CharT>& os_; + std::vector<CharT> buffer_; + CharT * begin_buffer_; + const CharT* end_buffer_; + CharT* p_; + + // Noncopyable and nonmoveable + ostream_buffered_writer(const ostream_buffered_writer&) = delete; + ostream_buffered_writer& operator=(const ostream_buffered_writer&) = delete; + +public: + ostream_buffered_writer(std::basic_ostream<CharT>& os) + : os_(os), buffer_(default_buffer_length), begin_buffer_(buffer_.data()), end_buffer_(begin_buffer_+buffer_.size()), p_(begin_buffer_) + { + } + ostream_buffered_writer(std::basic_ostream<CharT>& os, size_t buflen) + : os_(os), buffer_(buflen), begin_buffer_(buffer_.data()), end_buffer_(begin_buffer_+buffer_.size()), p_(begin_buffer_) + { + } + ~ostream_buffered_writer() + { + os_.write(begin_buffer_, buffer_length()); + os_.flush(); + } + + void flush() + { + os_.write(begin_buffer_, buffer_length()); + p_ = buffer_.data(); + } + + void write(const CharT* s, size_t length) + { + size_t diff = end_buffer_ - p_; + if (diff >= length) + { + std::memcpy(p_, s, length*sizeof(CharT)); + p_ += length; + } + else + { + os_.write(begin_buffer_, buffer_length()); + os_.write(s,length); + p_ = begin_buffer_; + } + } + + void write(const string_view_type& s) + { + write(s.data(),s.length()); + } + + void put(CharT ch) + { + if (p_ < end_buffer_) + { + *p_++ = ch; + } + else + { + os_.write(begin_buffer_, buffer_length()); + p_ = begin_buffer_; + put(ch); + } + } +private: + + size_t buffer_length() const + { + return p_ - begin_buffer_; + } +}; + +template <class CharT> +class string_writer +{ +public: + typedef basic_string_view_ext<CharT> string_view_type; + typedef CharT char_type; + typedef std::basic_string<CharT> output_type; +private: + std::basic_string<CharT>& s_; + + // Noncopyable and nonmoveable + string_writer(const string_writer&) = delete; + string_writer& operator=(const string_writer&) = delete; +public: + + string_writer(std::basic_string<CharT>& s) + : s_(s) + { + } + + void flush() + { + } + + void write(const CharT* s, size_t length) + { + s_.append(s,length); + } + + void write(const string_view_type& s) + { + s_.append(s.data(),s.length()); + } + + void put(CharT ch) + { + s_.push_back(ch); + } +}; + +}} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/json.hpp b/vendor/jsoncons-0.104.0/jsoncons/json.hpp new file mode 100644 index 00000000..fe9aec4e --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/json.hpp @@ -0,0 +1,4959 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_HPP +#define JSONCONS_JSON_HPP + +#include <limits> +#include <string> +#include <vector> +#include <exception> +#include <cstdlib> +#include <cstring> +#include <ostream> +#include <memory> +#include <typeinfo> +#include <cstring> +#include <jsoncons/version.hpp> +#include <jsoncons/json_exception.hpp> +#include <jsoncons/jsoncons_utilities.hpp> +#include <jsoncons/json_structures.hpp> +#include <jsoncons/json_output_handler.hpp> +#include <jsoncons/serialization_options.hpp> +#include <jsoncons/json_serializer.hpp> +#include <jsoncons/json_decoder.hpp> +#include <jsoncons/json_reader.hpp> +#include <jsoncons/json_type_traits.hpp> +#include <jsoncons/json_error_category.hpp> +#include <jsoncons/detail/heap_only_string.hpp> + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wswitch" +#endif + +namespace jsoncons { + +struct sorted_policy +{ + static const bool preserve_order = false; + + template <class T,class Allocator> + using object_storage = std::vector<T,Allocator>; + + template <class T,class Allocator> + using array_storage = std::vector<T,Allocator>; + + template <class CharT, class CharTraits, class Allocator> + using key_storage = std::basic_string<CharT, CharTraits,Allocator>; + + template <class CharT, class CharTraits, class Allocator> + using string_storage = std::basic_string<CharT, CharTraits,Allocator>; + + typedef default_parse_error_handler parse_error_handler_type; +}; + +struct preserve_order_policy : public sorted_policy +{ + static const bool preserve_order = true; +}; + +template <typename IteratorT> +class range +{ + IteratorT first_; + IteratorT last_; +public: + range(const IteratorT& first, const IteratorT& last) + : first_(first), last_(last) + { + } + +public: + IteratorT begin() + { + return first_; + } + IteratorT end() + { + return last_; + } +}; + +enum class json_type_tag : uint8_t +{ + null_t = 0, + empty_object_t, + bool_t, + integer_t, + uinteger_t, + double_t, + small_string_t, + string_t, + byte_string_t, + array_t, + object_t +}; + +template <class CharT, + class ImplementationPolicy = sorted_policy, + class Allocator = std::allocator<CharT>> +class basic_json +{ +public: + + typedef Allocator allocator_type; + + typedef ImplementationPolicy implementation_policy; + + typedef typename ImplementationPolicy::parse_error_handler_type parse_error_handler_type; + + typedef CharT char_type; + typedef typename std::char_traits<char_type> char_traits_type; + + typedef basic_string_view_ext<char_type,char_traits_type> string_view_type; + + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<char_type> char_allocator_type; + using string_storage_type = typename implementation_policy::template string_storage<CharT,char_traits_type,char_allocator_type>; + using key_storage_type = typename implementation_policy::template key_storage<CharT,char_traits_type,char_allocator_type>; + + // string_type is for interface only, not storage + typedef std::basic_string<CharT,char_traits_type,char_allocator_type> string_type; + + typedef basic_json<CharT,ImplementationPolicy,Allocator> value_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef key_value_pair<key_storage_type,value_type> key_value_pair_type; + +#if !defined(JSONCONS_NO_DEPRECATED) + typedef value_type json_type; + typedef key_value_pair_type kvp_type; + typedef key_value_pair_type member_type; + typedef jsoncons::null_type null_type; +#endif + + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<basic_json> val_allocator_type; + using array_storage_type = typename implementation_policy::template array_storage<basic_json, val_allocator_type>; + + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<uint8_t> byte_allocator_type; + using byte_string_storage_type = typename implementation_policy::template array_storage<uint8_t, byte_allocator_type>; + + typedef json_array<basic_json> array; + + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<key_value_pair_type> kvp_allocator_type; + + using object_storage_type = typename implementation_policy::template object_storage<key_value_pair_type , kvp_allocator_type>; + typedef json_object<key_storage_type,basic_json,implementation_policy::preserve_order> object; + + typedef typename std::allocator_traits<Allocator>:: template rebind_alloc<array> array_allocator; + typedef typename std::allocator_traits<Allocator>:: template rebind_alloc<object> object_allocator; + + typedef typename object::iterator object_iterator; + typedef typename object::const_iterator const_object_iterator; + typedef typename array::iterator array_iterator; + typedef typename array::const_iterator const_array_iterator; + + struct variant + { + struct data_base + { + json_type_tag type_id_; + + data_base(json_type_tag id) + : type_id_(id) + {} + }; + + class null_data final : public data_base + { + public: + null_data() + : data_base(json_type_tag::null_t) + { + } + }; + + class empty_object_data final : public data_base + { + public: + empty_object_data() + : data_base(json_type_tag::empty_object_t) + { + } + }; + + class bool_data final : public data_base + { + bool val_; + public: + bool_data(bool val) + : data_base(json_type_tag::bool_t),val_(val) + { + } + + bool_data(const bool_data& val) + : data_base(json_type_tag::bool_t),val_(val.val_) + { + } + + bool value() const + { + return val_; + } + + }; + + class integer_data final : public data_base + { + int64_t val_; + public: + integer_data(int64_t val) + : data_base(json_type_tag::integer_t),val_(val) + { + } + + integer_data(const integer_data& val) + : data_base(json_type_tag::integer_t),val_(val.val_) + { + } + + int64_t value() const + { + return val_; + } + }; + + class uinteger_data final : public data_base + { + uint64_t val_; + public: + uinteger_data(uint64_t val) + : data_base(json_type_tag::uinteger_t),val_(val) + { + } + + uinteger_data(const uinteger_data& val) + : data_base(json_type_tag::uinteger_t),val_(val.val_) + { + } + + uint64_t value() const + { + return val_; + } + }; + + class double_data final : public data_base + { + chars_format format_; + uint8_t precision_; + uint8_t decimal_places_; + double val_; + public: + double_data(double val) + : data_base(json_type_tag::double_t), + precision_(0), + decimal_places_(0), + val_(val) + { + } + double_data(double val, const number_format& fmt) + : data_base(json_type_tag::double_t), + format_(fmt.floating_point_format()), + precision_(fmt.precision()), + decimal_places_(fmt.decimal_places()), + val_(val) + { + } + + double_data(const double_data& val) + : data_base(json_type_tag::double_t), + precision_(val.precision_), + decimal_places_(val.decimal_places_), + val_(val.val_) + { + } + + double value() const + { + return val_; + } + + uint8_t precision() const + { + return precision_; + } + + uint8_t decimal_places() const + { + return precision_; + } + }; + + class small_string_data final : public data_base + { + static const size_t capacity = 14/sizeof(char_type); + uint8_t length_; + char_type data_[capacity]; + public: + static const size_t max_length = (14 / sizeof(char_type)) - 1; + + small_string_data(const char_type* p, uint8_t length) + : data_base(json_type_tag::small_string_t), length_(length) + { + JSONCONS_ASSERT(length <= max_length); + std::memcpy(data_,p,length*sizeof(char_type)); + data_[length] = 0; + } + + small_string_data(const small_string_data& val) + : data_base(json_type_tag::small_string_t), length_(val.length_) + { + std::memcpy(data_,val.data_,val.length_*sizeof(char_type)); + data_[length_] = 0; + } + + uint8_t length() const + { + return length_; + } + + const char_type* data() const + { + return data_; + } + + const char_type* c_str() const + { + return data_; + } + }; + + // string_data + class string_data final : public data_base + { + typedef typename detail::heap_only_string_factory<char_type, Allocator>::string_pointer pointer; + + pointer ptr_; + public: + string_data(const string_data& val) + : data_base(json_type_tag::string_t) + { + ptr_ = detail::heap_only_string_factory<char_type,Allocator>::create(val.data(),val.length(),val.get_allocator()); + } + + string_data(string_data&& val) + : data_base(json_type_tag::string_t), ptr_(nullptr) + { + std::swap(val.ptr_,ptr_); + } + + string_data(const string_data& val, const Allocator& a) + : data_base(json_type_tag::string_t) + { + ptr_ = detail::heap_only_string_factory<char_type,Allocator>::create(val.data(),val.length(),a); + } + + string_data(const char_type* data, size_t length, const Allocator& a) + : data_base(json_type_tag::string_t) + { + ptr_ = detail::heap_only_string_factory<char_type,Allocator>::create(data,length,a); + } + + ~string_data() + { + if (ptr_ != nullptr) + { + detail::heap_only_string_factory<char_type,Allocator>::destroy(ptr_); + } + } + + void swap(string_data& val) + { + std::swap(val.ptr_,ptr_); + } + + const char_type* data() const + { + return ptr_->data(); + } + + const char_type* c_str() const + { + return ptr_->c_str(); + } + + size_t length() const + { + return ptr_->length(); + } + + allocator_type get_allocator() const + { + return ptr_->get_allocator(); + } + }; + + // byte_string_data + class byte_string_data final : public data_base + { + typedef typename std::allocator_traits<Allocator>:: template rebind_alloc<byte_string_storage_type> string_holder_allocator_type; + typedef typename std::allocator_traits<string_holder_allocator_type>::pointer pointer; + + pointer ptr_; + + template <typename... Args> + void create(string_holder_allocator_type allocator, Args&& ... args) + { + typename std::allocator_traits<Allocator>:: template rebind_alloc<byte_string_storage_type> alloc(allocator); + ptr_ = alloc.allocate(1); + try + { + std::allocator_traits<string_holder_allocator_type>:: template rebind_traits<byte_string_storage_type>::construct(alloc, detail::to_plain_pointer(ptr_), std::forward<Args>(args)...); + } + catch (...) + { + alloc.deallocate(ptr_,1); + throw; + } + } + public: + byte_string_data(const byte_string_data& val) + : data_base(json_type_tag::byte_string_t) + { + create(val.ptr_->get_allocator(), *(val.ptr_)); + } + + byte_string_data(byte_string_data&& val) + : data_base(json_type_tag::byte_string_t), ptr_(nullptr) + { + std::swap(val.ptr_,ptr_); + } + + byte_string_data(const byte_string_data& val, const Allocator& a) + : data_base(json_type_tag::byte_string_t) + { + create(string_holder_allocator_type(a), *(val.ptr_), a); + } + + byte_string_data(const uint8_t* data, size_t length, const Allocator& a) + : data_base(json_type_tag::byte_string_t) + { + create(string_holder_allocator_type(a), data, data+length, a); + } + + ~byte_string_data() + { + if (ptr_ != nullptr) + { + typename std::allocator_traits<string_holder_allocator_type>:: template rebind_alloc<byte_string_storage_type> alloc(ptr_->get_allocator()); + std::allocator_traits<string_holder_allocator_type>:: template rebind_traits<byte_string_storage_type>::destroy(alloc, detail::to_plain_pointer(ptr_)); + alloc.deallocate(ptr_,1); + } + } + + void swap(byte_string_data& val) + { + std::swap(val.ptr_,ptr_); + } + + const uint8_t* data() const + { + return ptr_->data(); + } + + size_t length() const + { + return ptr_->size(); + } + + allocator_type get_allocator() const + { + return ptr_->get_allocator(); + } + }; + + // array_data + class array_data final : public data_base + { + typedef typename std::allocator_traits<array_allocator>::pointer pointer; + pointer ptr_; + + template <typename... Args> + void create(array_allocator allocator, Args&& ... args) + { + typename std::allocator_traits<Allocator>:: template rebind_alloc<array> alloc(allocator); + ptr_ = alloc.allocate(1); + try + { + std::allocator_traits<array_allocator>:: template rebind_traits<array>::construct(alloc, detail::to_plain_pointer(ptr_), std::forward<Args>(args)...); + } + catch (...) + { + alloc.deallocate(ptr_,1); + throw; + } + } + public: + array_data(const array& val) + : data_base(json_type_tag::array_t) + { + create(val.get_allocator(), val); + } + + array_data(const array& val, const Allocator& a) + : data_base(json_type_tag::array_t) + { + create(array_allocator(a), val, a); + } + + array_data(const array_data& val) + : data_base(json_type_tag::array_t) + { + create(val.ptr_->get_allocator(), *(val.ptr_)); + } + + array_data(array_data&& val) + : data_base(json_type_tag::array_t), ptr_(nullptr) + { + std::swap(val.ptr_, ptr_); + } + + array_data(const array_data& val, const Allocator& a) + : data_base(json_type_tag::array_t) + { + create(array_allocator(a), *(val.ptr_), a); + } + ~array_data() + { + if (ptr_ != nullptr) + { + typename std::allocator_traits<array_allocator>:: template rebind_alloc<array> alloc(ptr_->get_allocator()); + std::allocator_traits<array_allocator>:: template rebind_traits<array>::destroy(alloc, detail::to_plain_pointer(ptr_)); + alloc.deallocate(ptr_,1); + } + } + + allocator_type get_allocator() const + { + return ptr_->get_allocator(); + } + + void swap(array_data& val) + { + std::swap(val.ptr_,ptr_); + } + + array& value() + { + return *ptr_; + } + + const array& value() const + { + return *ptr_; + } + }; + + // object_data + class object_data final : public data_base + { + typedef typename std::allocator_traits<object_allocator>::pointer pointer; + pointer ptr_; + + template <typename... Args> + void create(Allocator allocator, Args&& ... args) + { + typename std::allocator_traits<object_allocator>:: template rebind_alloc<object> alloc(allocator); + ptr_ = alloc.allocate(1); + try + { + std::allocator_traits<object_allocator>:: template rebind_traits<object>::construct(alloc, detail::to_plain_pointer(ptr_), std::forward<Args>(args)...); + } + catch (...) + { + alloc.deallocate(ptr_,1); + throw; + } + } + public: + explicit object_data(const Allocator& a) + : data_base(json_type_tag::object_t) + { + create(a,a); + } + + explicit object_data(const object& val) + : data_base(json_type_tag::object_t) + { + create(val.get_allocator(), val); + } + + explicit object_data(const object& val, const Allocator& a) + : data_base(json_type_tag::object_t) + { + create(object_allocator(a), val, a); + } + + explicit object_data(const object_data& val) + : data_base(json_type_tag::object_t) + { + create(val.ptr_->get_allocator(), *(val.ptr_)); + } + + explicit object_data(object_data&& val) + : data_base(json_type_tag::object_t), ptr_(nullptr) + { + std::swap(val.ptr_,ptr_); + } + + explicit object_data(const object_data& val, const Allocator& a) + : data_base(json_type_tag::object_t) + { + create(object_allocator(a), *(val.ptr_), a); + } + + ~object_data() + { + if (ptr_ != nullptr) + { + typename std::allocator_traits<Allocator>:: template rebind_alloc<object> alloc(ptr_->get_allocator()); + std::allocator_traits<Allocator>:: template rebind_traits<object>::destroy(alloc, detail::to_plain_pointer(ptr_)); + alloc.deallocate(ptr_,1); + } + } + + void swap(object_data& val) + { + std::swap(val.ptr_,ptr_); + } + + object& value() + { + return *ptr_; + } + + const object& value() const + { + return *ptr_; + } + + allocator_type get_allocator() const + { + return ptr_->get_allocator(); + } + }; + + private: + static const size_t data_size = static_max<sizeof(uinteger_data),sizeof(double_data),sizeof(small_string_data), sizeof(string_data), sizeof(array_data), sizeof(object_data)>::value; + static const size_t data_align = static_max<JSONCONS_ALIGNOF(uinteger_data),JSONCONS_ALIGNOF(double_data),JSONCONS_ALIGNOF(small_string_data),JSONCONS_ALIGNOF(string_data),JSONCONS_ALIGNOF(array_data),JSONCONS_ALIGNOF(object_data)>::value; + + typedef typename std::aligned_storage<data_size,data_align>::type data_t; + + data_t data_; + public: + variant() + { + new(reinterpret_cast<void*>(&data_))empty_object_data(); + } + + variant(const Allocator& a) + { + new(reinterpret_cast<void*>(&data_))object_data(a); + } + + variant(const variant& val) + { + Init_(val); + } + + variant(const variant& val, const Allocator& allocator) + { + Init_(val,allocator); + } + + variant(variant&& val) JSONCONS_NOEXCEPT + { + Init_rv_(std::forward<variant>(val)); + } + + variant(variant&& val, const Allocator& allocator) JSONCONS_NOEXCEPT + { + Init_rv_(std::forward<variant>(val), allocator, + typename std::allocator_traits<Allocator>::propagate_on_container_move_assignment()); + } + + explicit variant(null_type) + { + new(reinterpret_cast<void*>(&data_))null_data(); + } + explicit variant(bool val) + { + new(reinterpret_cast<void*>(&data_))bool_data(val); + } + explicit variant(int64_t val) + { + new(reinterpret_cast<void*>(&data_))integer_data(val); + } + explicit variant(uint64_t val, const Allocator&) + { + new(reinterpret_cast<void*>(&data_))uinteger_data(val); + } + explicit variant(uint64_t val) + { + new(reinterpret_cast<void*>(&data_))uinteger_data(val); + } + variant(double val) + { + new(reinterpret_cast<void*>(&data_))double_data(val); + } + variant(double val, const number_format& fmt) + { + new(reinterpret_cast<void*>(&data_))double_data(val, fmt); + } + variant(const char_type* s, size_t length) + { + if (length <= small_string_data::max_length) + { + new(reinterpret_cast<void*>(&data_))small_string_data(s, static_cast<uint8_t>(length)); + } + else + { + new(reinterpret_cast<void*>(&data_))string_data(s, length, char_allocator_type()); + } + } + variant(const uint8_t* s, size_t length) + { + new(reinterpret_cast<void*>(&data_))byte_string_data(s, length, byte_allocator_type()); + } + + variant(const uint8_t* s, size_t length, const Allocator& alloc) + { + new(reinterpret_cast<void*>(&data_))byte_string_data(s, length, alloc); + } + + variant(const char_type* s) + { + size_t length = char_traits_type::length(s); + if (length <= small_string_data::max_length) + { + new(reinterpret_cast<void*>(&data_))small_string_data(s, static_cast<uint8_t>(length)); + } + else + { + new(reinterpret_cast<void*>(&data_))string_data(s, length, char_allocator_type()); + } + } + + variant(const char_type* s, const Allocator& alloc) + { + size_t length = char_traits_type::length(s); + if (length <= small_string_data::max_length) + { + new(reinterpret_cast<void*>(&data_))small_string_data(s, static_cast<uint8_t>(length)); + } + else + { + new(reinterpret_cast<void*>(&data_))string_data(s, length, alloc); + } + } + + variant(const char_type* s, size_t length, const Allocator& alloc) + { + if (length <= small_string_data::max_length) + { + new(reinterpret_cast<void*>(&data_))small_string_data(s, static_cast<uint8_t>(length)); + } + else + { + new(reinterpret_cast<void*>(&data_))string_data(s, length, alloc); + } + } + variant(const object& val) + { + new(reinterpret_cast<void*>(&data_))object_data(val); + } + variant(const object& val, const Allocator& alloc) + { + new(reinterpret_cast<void*>(&data_))object_data(val, alloc); + } + variant(const array& val) + { + new(reinterpret_cast<void*>(&data_))array_data(val); + } + variant(const array& val, const Allocator& alloc) + { + new(reinterpret_cast<void*>(&data_))array_data(val,alloc); + } + + ~variant() + { + Destroy_(); + } + + void Destroy_() + { + switch (type_id()) + { + case json_type_tag::string_t: + reinterpret_cast<string_data*>(&data_)->~string_data(); + break; + case json_type_tag::byte_string_t: + reinterpret_cast<byte_string_data*>(&data_)->~byte_string_data(); + break; + case json_type_tag::object_t: + reinterpret_cast<object_data*>(&data_)->~object_data(); + break; + case json_type_tag::array_t: + reinterpret_cast<array_data*>(&data_)->~array_data(); + break; + default: + break; + } + } + + variant& operator=(const variant& val) + { + if (this !=&val) + { + Destroy_(); + switch (val.type_id()) + { + case json_type_tag::null_t: + new(reinterpret_cast<void*>(&data_))null_data(); + break; + case json_type_tag::empty_object_t: + new(reinterpret_cast<void*>(&data_))empty_object_data(); + break; + case json_type_tag::bool_t: + new(reinterpret_cast<void*>(&data_))bool_data(*(val.bool_data_cast())); + break; + case json_type_tag::integer_t: + new(reinterpret_cast<void*>(&data_))integer_data(*(val.integer_data_cast())); + break; + case json_type_tag::uinteger_t: + new(reinterpret_cast<void*>(&data_))uinteger_data(*(val.uinteger_data_cast())); + break; + case json_type_tag::double_t: + new(reinterpret_cast<void*>(&data_))double_data(*(val.double_data_cast())); + break; + case json_type_tag::small_string_t: + new(reinterpret_cast<void*>(&data_))small_string_data(*(val.small_string_data_cast())); + break; + case json_type_tag::string_t: + new(reinterpret_cast<void*>(&data_))string_data(*(val.string_data_cast())); + break; + case json_type_tag::byte_string_t: + new(reinterpret_cast<void*>(&data_))byte_string_data(*(val.byte_string_data_cast())); + break; + case json_type_tag::array_t: + new(reinterpret_cast<void*>(&data_))array_data(*(val.array_data_cast())); + break; + case json_type_tag::object_t: + new(reinterpret_cast<void*>(&data_))object_data(*(val.object_data_cast())); + break; + default: + JSONCONS_UNREACHABLE(); + break; + } + } + return *this; + } + + variant& operator=(variant&& val) JSONCONS_NOEXCEPT + { + if (this !=&val) + { + swap(val); + } + return *this; + } + + json_type_tag type_id() const + { + return reinterpret_cast<const data_base*>(&data_)->type_id_; + } + + const null_data* null_data_cast() const + { + return reinterpret_cast<const null_data*>(&data_); + } + + const empty_object_data* empty_object_data_cast() const + { + return reinterpret_cast<const empty_object_data*>(&data_); + } + + const bool_data* bool_data_cast() const + { + return reinterpret_cast<const bool_data*>(&data_); + } + + const integer_data* integer_data_cast() const + { + return reinterpret_cast<const integer_data*>(&data_); + } + + const uinteger_data* uinteger_data_cast() const + { + return reinterpret_cast<const uinteger_data*>(&data_); + } + + const double_data* double_data_cast() const + { + return reinterpret_cast<const double_data*>(&data_); + } + + const small_string_data* small_string_data_cast() const + { + return reinterpret_cast<const small_string_data*>(&data_); + } + + string_data* string_data_cast() + { + return reinterpret_cast<string_data*>(&data_); + } + + const string_data* string_data_cast() const + { + return reinterpret_cast<const string_data*>(&data_); + } + + byte_string_data* byte_string_data_cast() + { + return reinterpret_cast<byte_string_data*>(&data_); + } + + const byte_string_data* byte_string_data_cast() const + { + return reinterpret_cast<const byte_string_data*>(&data_); + } + + object_data* object_data_cast() + { + return reinterpret_cast<object_data*>(&data_); + } + + const object_data* object_data_cast() const + { + return reinterpret_cast<const object_data*>(&data_); + } + + array_data* array_data_cast() + { + return reinterpret_cast<array_data*>(&data_); + } + + const array_data* array_data_cast() const + { + return reinterpret_cast<const array_data*>(&data_); + } + + string_view_type as_string_view() const + { + switch (type_id()) + { + case json_type_tag::small_string_t: + return string_view_type(small_string_data_cast()->data(),small_string_data_cast()->length()); + case json_type_tag::string_t: + return string_view_type(string_data_cast()->data(),string_data_cast()->length()); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not a string")); + } + } + + byte_string_view as_byte_string_view() const + { + switch (type_id()) + { + case json_type_tag::byte_string_t: + return byte_string_view(byte_string_data_cast()->data(),byte_string_data_cast()->length()); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not a byte string")); + } + } + + bool operator==(const variant& rhs) const + { + if (this ==&rhs) + { + return true; + } + switch (type_id()) + { + case json_type_tag::null_t: + switch (rhs.type_id()) + { + case json_type_tag::null_t: + return true; + default: + return false; + } + break; + case json_type_tag::empty_object_t: + switch (rhs.type_id()) + { + case json_type_tag::empty_object_t: + return true; + case json_type_tag::object_t: + return rhs.object_data_cast()->value().size() == 0; + default: + return false; + } + break; + case json_type_tag::bool_t: + switch (rhs.type_id()) + { + case json_type_tag::bool_t: + return bool_data_cast()->value() == rhs.bool_data_cast()->value(); + default: + return false; + } + break; + case json_type_tag::integer_t: + switch (rhs.type_id()) + { + case json_type_tag::integer_t: + return integer_data_cast()->value() == rhs.integer_data_cast()->value(); + case json_type_tag::uinteger_t: + return integer_data_cast()->value() >= 0 ? static_cast<uint64_t>(integer_data_cast()->value()) == rhs.uinteger_data_cast()->value() : false; + case json_type_tag::double_t: + return static_cast<double>(integer_data_cast()->value()) == rhs.double_data_cast()->value(); + default: + return false; + } + break; + case json_type_tag::uinteger_t: + switch (rhs.type_id()) + { + case json_type_tag::integer_t: + return rhs.integer_data_cast()->value() >= 0 ? uinteger_data_cast()->value() == static_cast<uint64_t>(rhs.integer_data_cast()->value()) : false; + case json_type_tag::uinteger_t: + return uinteger_data_cast()->value() == rhs.uinteger_data_cast()->value(); + case json_type_tag::double_t: + return static_cast<double>(uinteger_data_cast()->value()) == rhs.double_data_cast()->value(); + default: + return false; + } + break; + case json_type_tag::double_t: + switch (rhs.type_id()) + { + case json_type_tag::integer_t: + return double_data_cast()->value() == static_cast<double>(rhs.integer_data_cast()->value()); + case json_type_tag::uinteger_t: + return double_data_cast()->value() == static_cast<double>(rhs.uinteger_data_cast()->value()); + case json_type_tag::double_t: + return double_data_cast()->value() == rhs.double_data_cast()->value(); + default: + return false; + } + break; + case json_type_tag::small_string_t: + switch (rhs.type_id()) + { + case json_type_tag::small_string_t: + return as_string_view() == rhs.as_string_view(); + case json_type_tag::string_t: + return as_string_view() == rhs.as_string_view(); + default: + return false; + } + break; + case json_type_tag::byte_string_t: + switch (rhs.type_id()) + { + case json_type_tag::byte_string_t: + { + return as_byte_string_view() == rhs.as_byte_string_view(); + } + default: + return false; + } + break; + case json_type_tag::string_t: + switch (rhs.type_id()) + { + case json_type_tag::small_string_t: + return as_string_view() == rhs.as_string_view(); + case json_type_tag::string_t: + return as_string_view() == rhs.as_string_view(); + default: + return false; + } + break; + case json_type_tag::array_t: + switch (rhs.type_id()) + { + case json_type_tag::array_t: + return array_data_cast()->value() == rhs.array_data_cast()->value(); + default: + return false; + } + break; + case json_type_tag::object_t: + switch (rhs.type_id()) + { + case json_type_tag::empty_object_t: + return object_data_cast()->value().size() == 0; + case json_type_tag::object_t: + return object_data_cast()->value() == rhs.object_data_cast()->value(); + default: + return false; + } + break; + default: + JSONCONS_UNREACHABLE(); + break; + } + } + + bool operator!=(const variant& rhs) const + { + return !(*this == rhs); + } + + template <class Alloc = allocator_type> + typename std::enable_if<std::is_pod<typename std::allocator_traits<Alloc>::pointer>::value,void>::type + swap(variant& other) JSONCONS_NOEXCEPT + { + if (this ==&other) + { + return; + } + + std::swap(data_,other.data_); + } + + template <class Alloc = allocator_type> + typename std::enable_if<!std::is_pod<typename std::allocator_traits<Alloc>::pointer>::value, void>::type + swap(variant& other) JSONCONS_NOEXCEPT + { + if (this ==&other) + { + return; + } + switch (type_id()) + { + case json_type_tag::null_t: + { + switch (other.type_id()) + { + case json_type_tag::string_t: + { + string_data temp(std::move(*other.string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))null_data(); + new(reinterpret_cast<void*>(&data_))string_data(std::move(temp)); + } + break; + case json_type_tag::byte_string_t: + { + byte_string_data temp(std::move(*other.byte_string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))null_data(); + new(reinterpret_cast<void*>(&data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::array_t: + { + array_data temp(std::move(*other.array_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))null_data(); + new(reinterpret_cast<void*>(&data_))array_data(std::move(temp)); + } + break; + case json_type_tag::object_t: + { + object_data temp(std::move(*other.object_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))null_data(); + new(reinterpret_cast<void*>(&data_))object_data(std::move(temp)); + } + break; + default: + std::swap(data_,other.data_); + break; + } + } + break; + case json_type_tag::empty_object_t: + { + switch (other.type_id()) + { + case json_type_tag::string_t: + { + string_data temp(std::move(*other.string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))empty_object_data(); + new(reinterpret_cast<void*>(&data_))string_data(std::move(temp)); + } + break; + case json_type_tag::byte_string_t: + { + byte_string_data temp(std::move(*other.byte_string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))empty_object_data(); + new(reinterpret_cast<void*>(&data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::array_t: + { + array_data temp(std::move(*other.array_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))empty_object_data(); + new(reinterpret_cast<void*>(&data_))array_data(std::move(temp)); + } + break; + case json_type_tag::object_t: + { + object_data temp(std::move(*other.object_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))empty_object_data(); + new(reinterpret_cast<void*>(&data_))object_data(std::move(temp)); + } + break; + default: + std::swap(data_,other.data_); + break; + } + } + break; + case json_type_tag::bool_t: + { + switch (other.type_id()) + { + case json_type_tag::string_t: + { + string_data temp(std::move(*other.string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))bool_data(*bool_data_cast()); + new(reinterpret_cast<void*>(&data_))string_data(std::move(temp)); + } + break; + case json_type_tag::byte_string_t: + { + byte_string_data temp(std::move(*other.byte_string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))bool_data(*bool_data_cast()); + new(reinterpret_cast<void*>(&data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::array_t: + { + array_data temp(std::move(*other.array_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))bool_data(*bool_data_cast()); + new(reinterpret_cast<void*>(&data_))array_data(std::move(temp)); + } + break; + case json_type_tag::object_t: + { + object_data temp(std::move(*other.object_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))bool_data(*bool_data_cast()); + new(reinterpret_cast<void*>(&data_))object_data(std::move(temp)); + } + break; + default: + std::swap(data_,other.data_); + break; + } + } + break; + case json_type_tag::integer_t: + { + switch (other.type_id()) + { + case json_type_tag::string_t: + { + string_data temp(std::move(*other.string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))integer_data(*integer_data_cast()); + new(reinterpret_cast<void*>(&data_))string_data(std::move(temp)); + } + break; + case json_type_tag::byte_string_t: + { + byte_string_data temp(std::move(*other.byte_string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))integer_data(*integer_data_cast()); + new(reinterpret_cast<void*>(&data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::array_t: + { + array_data temp(std::move(*other.array_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))integer_data(*integer_data_cast()); + new(reinterpret_cast<void*>(&data_))array_data(std::move(temp)); + } + break; + case json_type_tag::object_t: + { + object_data temp(std::move(*other.object_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))integer_data(*integer_data_cast()); + new(reinterpret_cast<void*>(&data_))object_data(std::move(temp)); + } + break; + default: + std::swap(data_,other.data_); + break; + } + } + break; + case json_type_tag::uinteger_t: + { + switch (other.type_id()) + { + case json_type_tag::string_t: + { + string_data temp(std::move(*other.string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))uinteger_data(*uinteger_data_cast()); + new(reinterpret_cast<void*>(&data_))string_data(std::move(temp)); + } + break; + case json_type_tag::byte_string_t: + { + byte_string_data temp(std::move(*other.byte_string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))uinteger_data(*uinteger_data_cast()); + new(reinterpret_cast<void*>(&data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::array_t: + { + array_data temp(std::move(*other.array_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))uinteger_data(*uinteger_data_cast()); + new(reinterpret_cast<void*>(&data_))array_data(std::move(temp)); + } + break; + case json_type_tag::object_t: + { + object_data temp(std::move(*other.object_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))uinteger_data(*uinteger_data_cast()); + new(reinterpret_cast<void*>(&data_))object_data(std::move(temp)); + } + break; + default: + std::swap(data_,other.data_); + break; + } + } + break; + case json_type_tag::double_t: + { + switch (other.type_id()) + { + case json_type_tag::string_t: + { + string_data temp(std::move(*other.string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))double_data(*double_data_cast()); + new(reinterpret_cast<void*>(&data_))string_data(std::move(temp)); + } + break; + case json_type_tag::byte_string_t: + { + byte_string_data temp(std::move(*other.byte_string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))double_data(*double_data_cast()); + new(reinterpret_cast<void*>(&data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::array_t: + { + array_data temp(std::move(*other.array_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))double_data(*double_data_cast()); + new(reinterpret_cast<void*>(&data_))array_data(std::move(temp)); + } + break; + case json_type_tag::object_t: + { + object_data temp(std::move(*other.object_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))double_data(*double_data_cast()); + new(reinterpret_cast<void*>(&data_))object_data(std::move(temp)); + } + break; + default: + std::swap(data_,other.data_); + break; + } + } + break; + case json_type_tag::small_string_t: + { + switch (other.type_id()) + { + case json_type_tag::string_t: + { + string_data temp(std::move(*other.string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))small_string_data(*small_string_data_cast()); + new(reinterpret_cast<void*>(&data_))string_data(std::move(temp)); + } + break; + case json_type_tag::byte_string_t: + { + byte_string_data temp(std::move(*other.byte_string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))small_string_data(*small_string_data_cast()); + new(reinterpret_cast<void*>(&data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::array_t: + { + array_data temp(std::move(*other.array_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))small_string_data(*small_string_data_cast()); + new(reinterpret_cast<void*>(&data_))array_data(std::move(temp)); + } + break; + case json_type_tag::object_t: + { + object_data temp(std::move(*other.object_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))small_string_data(*small_string_data_cast()); + new(reinterpret_cast<void*>(&data_))object_data(std::move(temp)); + } + break; + default: + std::swap(data_,other.data_); + break; + } + } + break; + case json_type_tag::string_t: + { + switch (other.type_id()) + { + case json_type_tag::null_t: + { + string_data temp(std::move(*string_data_cast())); + new(reinterpret_cast<void*>(&data_))null_data(); + new(reinterpret_cast<void*>(&other.data_))string_data(std::move(temp)); + } + break; + case json_type_tag::empty_object_t: + { + string_data temp(std::move(*string_data_cast())); + new(reinterpret_cast<void*>(&data_))empty_object_data(); + new(reinterpret_cast<void*>(&other.data_))string_data(std::move(temp)); + } + break; + case json_type_tag::bool_t: + { + string_data temp(std::move(*string_data_cast())); + new(reinterpret_cast<void*>(&data_))bool_data(*(other.bool_data_cast())); + new(reinterpret_cast<void*>(&other.data_))string_data(std::move(temp)); + } + break; + case json_type_tag::integer_t: + { + string_data temp(std::move(*string_data_cast())); + new(reinterpret_cast<void*>(&data_))integer_data(*(other.integer_data_cast())); + new(reinterpret_cast<void*>(&other.data_))string_data(std::move(temp)); + } + break; + case json_type_tag::uinteger_t: + { + string_data temp(std::move(*string_data_cast())); + new(reinterpret_cast<void*>(&data_))uinteger_data(*(other.uinteger_data_cast())); + new(reinterpret_cast<void*>(&other.data_))string_data(std::move(temp)); + } + break; + case json_type_tag::double_t: + { + string_data temp(std::move(*string_data_cast())); + new(reinterpret_cast<void*>(&data_))double_data(*(other.double_data_cast())); + new(reinterpret_cast<void*>(&other.data_))string_data(std::move(temp)); + } + break; + case json_type_tag::small_string_t: + { + string_data temp(std::move(*string_data_cast())); + new(reinterpret_cast<void*>(&data_))small_string_data(*(other.small_string_data_cast())); + new(reinterpret_cast<void*>(&other.data_))string_data(std::move(temp)); + } + break; + case json_type_tag::string_t: + { + string_data_cast()->swap(*other.string_data_cast()); + } + break; + case json_type_tag::byte_string_t: + { + string_data temp(std::move(*string_data_cast())); + new(reinterpret_cast<void*>(&data_))byte_string_data(std::move(*other.byte_string_data_cast())); + new(reinterpret_cast<void*>(&other.data_))string_data(std::move(temp)); + } + break; + case json_type_tag::array_t: + { + string_data temp(std::move(*string_data_cast())); + new(reinterpret_cast<void*>(&data_))array_data(std::move(*other.array_data_cast())); + new(reinterpret_cast<void*>(&other.data_))string_data(std::move(temp)); + } + break; + case json_type_tag::object_t: + { + string_data temp(std::move(*string_data_cast())); + new(reinterpret_cast<void*>(&data_))object_data(std::move(*other.object_data_cast())); + new(reinterpret_cast<void*>(&other.data_))string_data(std::move(temp)); + } + break; + default: + JSONCONS_UNREACHABLE(); + break; + } + } + break; + case json_type_tag::byte_string_t: + { + switch (other.type_id()) + { + case json_type_tag::null_t: + { + byte_string_data temp(std::move(*byte_string_data_cast())); + new(reinterpret_cast<void*>(&data_))null_data(); + new(reinterpret_cast<void*>(&other.data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::empty_object_t: + { + byte_string_data temp(std::move(*byte_string_data_cast())); + new(reinterpret_cast<void*>(&data_))empty_object_data(); + new(reinterpret_cast<void*>(&other.data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::bool_t: + { + byte_string_data temp(std::move(*byte_string_data_cast())); + new(reinterpret_cast<void*>(&data_))bool_data(*(other.bool_data_cast())); + new(reinterpret_cast<void*>(&other.data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::integer_t: + { + byte_string_data temp(std::move(*byte_string_data_cast())); + new(reinterpret_cast<void*>(&data_))integer_data(*(other.integer_data_cast())); + new(reinterpret_cast<void*>(&other.data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::uinteger_t: + { + byte_string_data temp(std::move(*byte_string_data_cast())); + new(reinterpret_cast<void*>(&data_))uinteger_data(*(other.uinteger_data_cast())); + new(reinterpret_cast<void*>(&other.data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::double_t: + { + byte_string_data temp(std::move(*byte_string_data_cast())); + new(reinterpret_cast<void*>(&data_))double_data(*(other.double_data_cast())); + new(reinterpret_cast<void*>(&other.data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::small_string_t: + { + byte_string_data temp(std::move(*byte_string_data_cast())); + new(reinterpret_cast<void*>(&data_))small_string_data(*(other.small_string_data_cast())); + new(reinterpret_cast<void*>(&other.data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::string_t: + { + byte_string_data temp(std::move(*byte_string_data_cast())); + new(reinterpret_cast<void*>(&data_))string_data(*(other.string_data_cast())); + new(reinterpret_cast<void*>(&other.data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::byte_string_t: + { + byte_string_data_cast()->swap(*other.byte_string_data_cast()); + } + break; + case json_type_tag::array_t: + { + byte_string_data temp(std::move(*byte_string_data_cast())); + new(reinterpret_cast<void*>(&data_))array_data(std::move(*other.array_data_cast())); + new(reinterpret_cast<void*>(&other.data_))byte_string_data(std::move(temp)); + } + break; + case json_type_tag::object_t: + { + byte_string_data temp(std::move(*byte_string_data_cast())); + new(reinterpret_cast<void*>(&data_))object_data(std::move(*other.object_data_cast())); + new(reinterpret_cast<void*>(&other.data_))byte_string_data(std::move(temp)); + } + break; + default: + JSONCONS_UNREACHABLE(); + break; + } + } + break; + case json_type_tag::array_t: + { + switch (other.type_id()) + { + case json_type_tag::null_t: + { + array_data temp(std::move(*array_data_cast())); + new(reinterpret_cast<void*>(&data_))null_data(); + new(reinterpret_cast<void*>(&(other.data_)))array_data(std::move(temp)); + } + break; + case json_type_tag::empty_object_t: + { + array_data temp(std::move(*array_data_cast())); + new(reinterpret_cast<void*>(&data_))empty_object_data(); + new(reinterpret_cast<void*>(&(other.data_)))array_data(std::move(temp)); + } + break; + case json_type_tag::bool_t: + { + array_data temp(std::move(*array_data_cast())); + new(reinterpret_cast<void*>(&data_))bool_data(*(other.bool_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))array_data(std::move(temp)); + } + break; + case json_type_tag::integer_t: + { + array_data temp(std::move(*array_data_cast())); + new(reinterpret_cast<void*>(&data_))integer_data(*(other.integer_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))array_data(std::move(temp)); + } + break; + case json_type_tag::uinteger_t: + { + array_data temp(std::move(*array_data_cast())); + new(reinterpret_cast<void*>(&data_))uinteger_data(*(other.uinteger_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))array_data(std::move(temp)); + } + break; + case json_type_tag::double_t: + { + array_data temp(std::move(*array_data_cast())); + new(reinterpret_cast<void*>(&data_))double_data(*(other.double_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))array_data(std::move(temp)); + } + break; + case json_type_tag::small_string_t: + { + array_data temp(std::move(*array_data_cast())); + new(reinterpret_cast<void*>(&data_))small_string_data(*(other.small_string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))array_data(std::move(temp)); + } + break; + case json_type_tag::string_t: + { + array_data temp(std::move(*array_data_cast())); + new(reinterpret_cast<void*>(&data_))string_data(std::move(*other.string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))array_data(std::move(temp)); + } + break; + case json_type_tag::byte_string_t: + { + array_data temp(std::move(*array_data_cast())); + new(reinterpret_cast<void*>(&data_))byte_string_data(std::move(*other.byte_string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))array_data(std::move(temp)); + } + break; + case json_type_tag::array_t: + { + array_data_cast()->swap(*other.array_data_cast()); + } + break; + case json_type_tag::object_t: + { + array_data temp(std::move(*array_data_cast())); + new(reinterpret_cast<void*>(&data_))object_data(std::move(*other.object_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))array_data(std::move(temp)); + } + break; + default: + JSONCONS_UNREACHABLE(); + break; + } + } + break; + case json_type_tag::object_t: + { + switch (other.type_id()) + { + case json_type_tag::null_t: + { + object_data temp(std::move(*object_data_cast())); + new(reinterpret_cast<void*>(&data_))null_data(); + new(reinterpret_cast<void*>(&(other.data_)))object_data(std::move(temp)); + } + break; + case json_type_tag::empty_object_t: + { + object_data temp(std::move(*object_data_cast())); + new(reinterpret_cast<void*>(&data_))empty_object_data(); + new(reinterpret_cast<void*>(&(other.data_)))object_data(std::move(temp)); + } + break; + case json_type_tag::bool_t: + { + object_data temp(std::move(*object_data_cast())); + new(reinterpret_cast<void*>(&data_))bool_data(*(other.bool_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))object_data(std::move(temp)); + } + break; + case json_type_tag::integer_t: + { + object_data temp(std::move(*object_data_cast())); + new(reinterpret_cast<void*>(&data_))integer_data(*(other.integer_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))object_data(std::move(temp)); + } + break; + case json_type_tag::uinteger_t: + { + object_data temp(std::move(*object_data_cast())); + new(reinterpret_cast<void*>(&data_))uinteger_data(*(other.uinteger_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))object_data(std::move(temp)); + } + break; + case json_type_tag::double_t: + { + object_data temp(std::move(*object_data_cast())); + new(reinterpret_cast<void*>(&data_))double_data(*(other.double_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))object_data(std::move(temp)); + } + break; + case json_type_tag::small_string_t: + { + object_data temp(std::move(*object_data_cast())); + new(reinterpret_cast<void*>(&data_))small_string_data(*(other.small_string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))object_data(std::move(temp)); + } + break; + case json_type_tag::string_t: + { + object_data temp(std::move(*object_data_cast())); + new(reinterpret_cast<void*>(&data_))string_data(std::move(*other.string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))object_data(std::move(temp)); + } + break; + case json_type_tag::byte_string_t: + { + object_data temp(std::move(*object_data_cast())); + new(reinterpret_cast<void*>(&data_))byte_string_data(std::move(*other.byte_string_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))object_data(std::move(temp)); + } + break; + case json_type_tag::array_t: + { + object_data temp(std::move(*object_data_cast())); + new(reinterpret_cast<void*>(&data_))array_data(std::move(*other.array_data_cast())); + new(reinterpret_cast<void*>(&(other.data_)))object_data(std::move(temp)); + } + break; + case json_type_tag::object_t: + { + object_data_cast()->swap(*other.object_data_cast()); + } + break; + default: + JSONCONS_UNREACHABLE(); + break; + } + } + break; + default: + JSONCONS_UNREACHABLE(); + break; + } + } + private: + + void Init_(const variant& val) + { + switch (val.type_id()) + { + case json_type_tag::null_t: + new(reinterpret_cast<void*>(&data_))null_data(); + break; + case json_type_tag::empty_object_t: + new(reinterpret_cast<void*>(&data_))empty_object_data(); + break; + case json_type_tag::bool_t: + new(reinterpret_cast<void*>(&data_))bool_data(*(val.bool_data_cast())); + break; + case json_type_tag::integer_t: + new(reinterpret_cast<void*>(&data_))integer_data(*(val.integer_data_cast())); + break; + case json_type_tag::uinteger_t: + new(reinterpret_cast<void*>(&data_))uinteger_data(*(val.uinteger_data_cast())); + break; + case json_type_tag::double_t: + new(reinterpret_cast<void*>(&data_))double_data(*(val.double_data_cast())); + break; + case json_type_tag::small_string_t: + new(reinterpret_cast<void*>(&data_))small_string_data(*(val.small_string_data_cast())); + break; + case json_type_tag::string_t: + new(reinterpret_cast<void*>(&data_))string_data(*(val.string_data_cast())); + break; + case json_type_tag::byte_string_t: + new(reinterpret_cast<void*>(&data_))byte_string_data(*(val.byte_string_data_cast())); + break; + case json_type_tag::object_t: + new(reinterpret_cast<void*>(&data_))object_data(*(val.object_data_cast())); + break; + case json_type_tag::array_t: + new(reinterpret_cast<void*>(&data_))array_data(*(val.array_data_cast())); + break; + default: + break; + } + } + + void Init_(const variant& val, const Allocator& a) + { + switch (val.type_id()) + { + case json_type_tag::null_t: + case json_type_tag::empty_object_t: + case json_type_tag::bool_t: + case json_type_tag::integer_t: + case json_type_tag::uinteger_t: + case json_type_tag::double_t: + case json_type_tag::small_string_t: + Init_(val); + break; + case json_type_tag::string_t: + new(reinterpret_cast<void*>(&data_))string_data(*(val.string_data_cast()),a); + break; + case json_type_tag::byte_string_t: + new(reinterpret_cast<void*>(&data_))byte_string_data(*(val.byte_string_data_cast()),a); + break; + case json_type_tag::array_t: + new(reinterpret_cast<void*>(&data_))array_data(*(val.array_data_cast()),a); + break; + case json_type_tag::object_t: + new(reinterpret_cast<void*>(&data_))object_data(*(val.object_data_cast()),a); + break; + default: + break; + } + } + + void Init_rv_(variant&& val) JSONCONS_NOEXCEPT + { + switch (val.type_id()) + { + case json_type_tag::null_t: + case json_type_tag::empty_object_t: + case json_type_tag::double_t: + case json_type_tag::integer_t: + case json_type_tag::uinteger_t: + case json_type_tag::bool_t: + case json_type_tag::small_string_t: + Init_(val); + break; + case json_type_tag::string_t: + { + new(reinterpret_cast<void*>(&data_))string_data(std::move(*val.string_data_cast())); + new(reinterpret_cast<void*>(&val.data_))null_data(); + } + break; + case json_type_tag::byte_string_t: + { + new(reinterpret_cast<void*>(&data_))byte_string_data(std::move(*val.byte_string_data_cast())); + new(reinterpret_cast<void*>(&val.data_))null_data(); + } + break; + case json_type_tag::array_t: + { + new(reinterpret_cast<void*>(&data_))array_data(std::move(*val.array_data_cast())); + new(reinterpret_cast<void*>(&val.data_))null_data(); + } + break; + case json_type_tag::object_t: + { + new(reinterpret_cast<void*>(&data_))object_data(std::move(*val.object_data_cast())); + new(reinterpret_cast<void*>(&val.data_))null_data(); + } + break; + default: + JSONCONS_UNREACHABLE(); + break; + } + } + + void Init_rv_(variant&& val, const Allocator& a, std::true_type) JSONCONS_NOEXCEPT + { + Init_rv_(std::forward<variant>(val)); + } + + void Init_rv_(variant&& val, const Allocator& a, std::false_type) JSONCONS_NOEXCEPT + { + switch (val.type_id()) + { + case json_type_tag::null_t: + case json_type_tag::empty_object_t: + case json_type_tag::double_t: + case json_type_tag::integer_t: + case json_type_tag::uinteger_t: + case json_type_tag::bool_t: + case json_type_tag::small_string_t: + Init_(std::forward<variant>(val)); + break; + case json_type_tag::string_t: + { + if (a == val.string_data_cast()->get_allocator()) + { + Init_rv_(std::forward<variant>(val), a, std::true_type()); + } + else + { + Init_(val,a); + } + } + break; + case json_type_tag::byte_string_t: + { + if (a == val.byte_string_data_cast()->get_allocator()) + { + Init_rv_(std::forward<variant>(val), a, std::true_type()); + } + else + { + Init_(val,a); + } + } + break; + case json_type_tag::object_t: + { + if (a == val.object_data_cast()->get_allocator()) + { + Init_rv_(std::forward<variant>(val), a, std::true_type()); + } + else + { + Init_(val,a); + } + } + break; + case json_type_tag::array_t: + { + if (a == val.array_data_cast()->get_allocator()) + { + Init_rv_(std::forward<variant>(val), a, std::true_type()); + } + else + { + Init_(val,a); + } + } + break; + default: + break; + } + } + }; + + template <class ParentT> + class json_proxy + { + private: + typedef json_proxy<ParentT> proxy_type; + + ParentT& parent_; + key_storage_type key_; + + json_proxy() = delete; + json_proxy& operator = (const json_proxy& other) = delete; + + json_proxy(ParentT& parent, key_storage_type&& name) + : parent_(parent), key_(std::forward<key_storage_type>(name)) + { + } + + basic_json& evaluate() + { + return parent_.evaluate(string_view_type(key_.data(),key_.size())); + } + + const basic_json& evaluate() const + { + return parent_.evaluate(string_view_type(key_.data(),key_.size())); + } + + basic_json& evaluate_with_default() + { + basic_json& val = parent_.evaluate_with_default(); + auto it = val.find(string_view_type(key_.data(),key_.size())); + if (it == val.object_range().end()) + { + it = val.set_(val.object_range().begin(),std::move(key_),object(val.object_value().get_allocator())); + } + return it->value(); + } + + basic_json& evaluate(size_t index) + { + return evaluate().at(index); + } + + const basic_json& evaluate(size_t index) const + { + return evaluate().at(index); + } + + basic_json& evaluate(const string_view_type& index) + { + return evaluate().at(index); + } + + const basic_json& evaluate(const string_view_type& index) const + { + return evaluate().at(index); + } + public: + + friend class basic_json<CharT,ImplementationPolicy,Allocator>; + + range<object_iterator> object_range() + { + return evaluate().object_range(); + } + + range<const_object_iterator> object_range() const + { + return evaluate().object_range(); + } + + range<array_iterator> array_range() + { + return evaluate().array_range(); + } + + range<const_array_iterator> array_range() const + { + return evaluate().array_range(); + } + + size_t size() const JSONCONS_NOEXCEPT + { + return evaluate().size(); + } + + json_type_tag type_id() const + { + return evaluate().type_id(); + } + + size_t count(const string_view_type& name) const + { + return evaluate().count(name); + } + + bool has_key(const string_view_type& name) const + { + return evaluate().has_key(name); + } + + bool is_null() const JSONCONS_NOEXCEPT + { + return evaluate().is_null(); + } + + bool empty() const + { + return evaluate().empty(); + } + + size_t capacity() const + { + return evaluate().capacity(); + } + + void reserve(size_t n) + { + evaluate().reserve(n); + } + + void resize(size_t n) + { + evaluate().resize(n); + } + + template <class T> + void resize(size_t n, T val) + { + evaluate().resize(n,val); + } + + template<class T, class... Args> + bool is(Args&&... args) const + { + return evaluate().template is<T>(std::forward<Args>(args)...); + } + + bool is_string() const JSONCONS_NOEXCEPT + { + return evaluate().is_string(); + } + + bool is_byte_string() const JSONCONS_NOEXCEPT + { + return evaluate().is_byte_string(); + } + + bool is_number() const JSONCONS_NOEXCEPT + { + return evaluate().is_number(); + } + bool is_bool() const JSONCONS_NOEXCEPT + { + return evaluate().is_bool(); + } + + bool is_object() const JSONCONS_NOEXCEPT + { + return evaluate().is_object(); + } + + bool is_array() const JSONCONS_NOEXCEPT + { + return evaluate().is_array(); + } + bool is_integer() const JSONCONS_NOEXCEPT + { + return evaluate().is_integer(); + } + + bool is_uinteger() const JSONCONS_NOEXCEPT + { + return evaluate().is_uinteger(); + } + + bool is_double() const JSONCONS_NOEXCEPT + { + return evaluate().is_double(); + } + + string_view_type as_string_view() const + { + return evaluate().as_string_view(); + } + + byte_string_view as_byte_string_view() const + { + return evaluate().as_byte_string_view(); + } + + string_type as_string() const + { + return evaluate().as_string(); + } + + template <class SAllocator> + string_type as_string(const SAllocator& allocator) const + { + return evaluate().as_string(allocator); + } + + string_type as_string(const basic_serialization_options<char_type>& options) const + { + return evaluate().as_string(options); + } + + template <class SAllocator> + string_type as_string(const basic_serialization_options<char_type>& options, + const SAllocator& allocator) const + { + return evaluate().as_string(options,allocator); + } + + template<class T, class... Args> + T as(Args&&... args) const + { + return evaluate().template as<T>(std::forward<Args>(args)...); + } + + template<class T> + typename std::enable_if<std::is_same<string_type,T>::value,T>::type + as(const char_allocator_type& allocator) const + { + return evaluate().template as<T>(allocator); + } + bool as_bool() const + { + return evaluate().as_bool(); + } + + double as_double() const + { + return evaluate().as_double(); + } + + int64_t as_integer() const + { + return evaluate().as_integer(); + } + + unsigned long long as_ulonglong() const + { + return evaluate().as_ulonglong(); + } + + uint64_t as_uinteger() const + { + return evaluate().as_uinteger(); + } + + template <class T> + json_proxy& operator=(T&& val) + { + parent_.evaluate_with_default().set_(std::move(key_), std::forward<T>(val)); + return *this; + } + + bool operator==(const basic_json& val) const + { + return evaluate() == val; + } + + bool operator!=(const basic_json& val) const + { + return evaluate() != val; + } + + basic_json& operator[](size_t i) + { + return evaluate_with_default().at(i); + } + + const basic_json& operator[](size_t i) const + { + return evaluate().at(i); + } + + json_proxy<proxy_type> operator[](const string_view_type& name) + { + return json_proxy<proxy_type>(*this,key_storage_type(name.begin(),name.end(),key_.get_allocator())); + } + + const basic_json& operator[](const string_view_type& name) const + { + return at(name); + } + + basic_json& at(const string_view_type& name) + { + return evaluate().at(name); + } + + const basic_json& at(const string_view_type& name) const + { + return evaluate().at(name); + } + + const basic_json& at(size_t index) + { + return evaluate().at(index); + } + + const basic_json& at(size_t index) const + { + return evaluate().at(index); + } + + object_iterator find(const string_view_type& name) + { + return evaluate().find(name); + } + + const_object_iterator find(const string_view_type& name) const + { + return evaluate().find(name); + } + + template <class T> + basic_json get(const string_view_type& name, T&& default_val) const + { + return evaluate().get(name,std::forward<T>(default_val)); + } + + template <class T> + T get_with_default(const string_view_type& name, const T& default_val) const + { + return evaluate().get_with_default(name,default_val); + } + + const CharT* get_with_default(const string_view_type& name, const CharT* default_val) const + { + return evaluate().get_with_default(name,default_val); + } + + void shrink_to_fit() + { + evaluate_with_default().shrink_to_fit(); + } + + void clear() + { + evaluate().clear(); + } + // Remove all elements from an array or object + + void erase(const_object_iterator pos) + { + evaluate().erase(pos); + } + // Remove a range of elements from an object + + void erase(const_object_iterator first, const_object_iterator last) + { + evaluate().erase(first, last); + } + // Remove a range of elements from an object + + void erase(const string_view_type& name) + { + evaluate().erase(name); + } + + void erase(const_array_iterator pos) + { + evaluate().erase(pos); + } + // Removes the element at pos + + void erase(const_array_iterator first, const_array_iterator last) + { + evaluate().erase(first, last); + } + // Remove a range of elements from an array + + // merge + + void merge(const basic_json& source) + { + return evaluate().merge(source); + } + + void merge(basic_json&& source) + { + return evaluate().merge(std::forward<basic_json>(source)); + } + + void merge(object_iterator hint, const basic_json& source) + { + return evaluate().merge(hint, source); + } + + void merge(object_iterator hint, basic_json&& source) + { + return evaluate().merge(hint, std::forward<basic_json>(source)); + } + + // merge_or_update + + void merge_or_update(const basic_json& source) + { + return evaluate().merge_or_update(source); + } + + void merge_or_update(basic_json&& source) + { + return evaluate().merge_or_update(std::forward<basic_json>(source)); + } + + void merge_or_update(object_iterator hint, const basic_json& source) + { + return evaluate().merge_or_update(hint, source); + } + + void merge_or_update(object_iterator hint, basic_json&& source) + { + return evaluate().merge_or_update(hint, std::forward<basic_json>(source)); + } + + // set + + template <class T> + std::pair<object_iterator,bool> set(const string_view_type& name, T&& val) + { + return evaluate().set(name,std::forward<T>(val)); + } + + template <class T> + std::pair<object_iterator,bool> insert_or_assign(const string_view_type& name, T&& val) + { + return evaluate().insert_or_assign(name,std::forward<T>(val)); + } + + template <class T> + void set_(key_storage_type&& name, T&& val) + { + evaluate().set_(std::forward<key_storage_type>(name),std::forward<T>(val)); + } + + // emplace + + template <class ... Args> + std::pair<object_iterator,bool> try_emplace(const string_view_type& name, Args&&... args) + { + return evaluate().try_emplace(name,std::forward<Args>(args)...); + } + + template <class T> + object_iterator set(object_iterator hint, const string_view_type& name, T&& val) + { + return evaluate().set(hint, name, std::forward<T>(val)); + } + + template <class T> + object_iterator insert_or_assign(object_iterator hint, const string_view_type& name, T&& val) + { + return evaluate().insert_or_assign(hint, name, std::forward<T>(val)); + } + + template <class ... Args> + object_iterator try_emplace(object_iterator hint, const string_view_type& name, Args&&... args) + { + return evaluate().try_emplace(hint, name, std::forward<Args>(args)...); + } + + template <class T> + object_iterator set_(object_iterator hint, key_storage_type&& name, T&& val) + { + return evaluate().set_(hint, std::forward<key_storage_type>(name), std::forward<T>(val)); + } + + template <class... Args> + array_iterator emplace(const_array_iterator pos, Args&&... args) + { + evaluate_with_default().emplace(pos, std::forward<Args>(args)...); + } + + template <class... Args> + basic_json& emplace_back(Args&&... args) + { + return evaluate_with_default().emplace_back(std::forward<Args>(args)...); + } + + template <class T> + void add(T&& val) + { + evaluate_with_default().add(std::forward<T>(val)); + } + + template <class T> + void push_back(T&& val) + { + evaluate_with_default().push_back(std::forward<T>(val)); + } + + template <class T> + array_iterator add(const_array_iterator pos, T&& val) + { + return evaluate_with_default().add(pos, std::forward<T>(val)); + } + + template <class T> + array_iterator insert(const_array_iterator pos, T&& val) + { + return evaluate_with_default().insert(pos, std::forward<T>(val)); + } + + template <class InputIt> + array_iterator insert(const_array_iterator pos, InputIt first, InputIt last) + { + return evaluate_with_default().insert(pos, first, last); + } + + template <class SAllocator> + void dump(std::basic_string<char_type,char_traits_type,SAllocator>& s) const + { + evaluate().dump(s); + } + + template <class SAllocator> + void dump(std::basic_string<char_type,char_traits_type,SAllocator>& s, + const basic_serialization_options<char_type>& options) const + { + evaluate().dump(s,options); + } + void dump(basic_json_output_handler<char_type>& handler) const + { + evaluate().dump(handler); + } + + void dump(std::basic_ostream<char_type>& os) const + { + evaluate().dump(os); + } + + void dump(std::basic_ostream<char_type>& os, bool pprint) const + { + evaluate().dump(os, pprint); + } + + void dump(std::basic_ostream<char_type>& os, const basic_serialization_options<char_type>& options) const + { + evaluate().dump(os,options); + } + + void dump(std::basic_ostream<char_type>& os, const basic_serialization_options<char_type>& options, bool pprint) const + { + evaluate().dump(os,options,pprint); + } +#if !defined(JSONCONS_NO_DEPRECATED) + + string_type to_string(const char_allocator_type& allocator = char_allocator_type()) const JSONCONS_NOEXCEPT + { + return evaluate().to_string(allocator); + } + void write(basic_json_output_handler<char_type>& handler) const + { + evaluate().write(handler); + } + + void write(std::basic_ostream<char_type>& os) const + { + evaluate().write(os); + } + + void write(std::basic_ostream<char_type>& os, const basic_serialization_options<char_type>& options) const + { + evaluate().write(os,options); + } + + void write(std::basic_ostream<char_type>& os, const basic_serialization_options<char_type>& options, bool pprint) const + { + evaluate().write(os,options,pprint); + } + + string_type to_string(const basic_serialization_options<char_type>& options, char_allocator_type& allocator = char_allocator_type()) const + { + return evaluate().to_string(options,allocator); + } + + range<object_iterator> members() + { + return evaluate().members(); + } + + range<const_object_iterator> members() const + { + return evaluate().members(); + } + + range<array_iterator> elements() + { + return evaluate().elements(); + } + + range<const_array_iterator> elements() const + { + return evaluate().elements(); + } + void to_stream(basic_json_output_handler<char_type>& handler) const + { + evaluate().to_stream(handler); + } + + void to_stream(std::basic_ostream<char_type>& os) const + { + evaluate().to_stream(os); + } + + void to_stream(std::basic_ostream<char_type>& os, const basic_serialization_options<char_type>& options) const + { + evaluate().to_stream(os,options); + } + + void to_stream(std::basic_ostream<char_type>& os, const basic_serialization_options<char_type>& options, bool pprint) const + { + evaluate().to_stream(os,options,pprint); + } +#endif + void swap(basic_json& val) + { + evaluate_with_default().swap(val); + } + + friend std::basic_ostream<char_type>& operator<<(std::basic_ostream<char_type>& os, const json_proxy& o) + { + o.dump(os); + return os; + } + +#if !defined(JSONCONS_NO_DEPRECATED) + + void resize_array(size_t n) + { + evaluate().resize_array(n); + } + + template <class T> + void resize_array(size_t n, T val) + { + evaluate().resize_array(n,val); + } + + object_iterator begin_members() + { + return evaluate().begin_members(); + } + + const_object_iterator begin_members() const + { + return evaluate().begin_members(); + } + + object_iterator end_members() + { + return evaluate().end_members(); + } + + const_object_iterator end_members() const + { + return evaluate().end_members(); + } + + array_iterator begin_elements() + { + return evaluate().begin_elements(); + } + + const_array_iterator begin_elements() const + { + return evaluate().begin_elements(); + } + + array_iterator end_elements() + { + return evaluate().end_elements(); + } + + const_array_iterator end_elements() const + { + return evaluate().end_elements(); + } + + const basic_json& get(const string_view_type& name) const + { + return evaluate().get(name); + } + + bool is_ulonglong() const JSONCONS_NOEXCEPT + { + return evaluate().is_ulonglong(); + } + + bool is_longlong() const JSONCONS_NOEXCEPT + { + return evaluate().is_longlong(); + } + + int as_int() const + { + return evaluate().as_int(); + } + + unsigned int as_uint() const + { + return evaluate().as_uint(); + } + + long as_long() const + { + return evaluate().as_long(); + } + + unsigned long as_ulong() const + { + return evaluate().as_ulong(); + } + + long long as_longlong() const + { + return evaluate().as_longlong(); + } + + void add(size_t index, const basic_json& value) + { + evaluate_with_default().add(index, value); + } + + void add(size_t index, basic_json&& value) + { + evaluate_with_default().add(index, std::forward<basic_json>(value)); + } + + bool has_member(const key_storage_type& name) const + { + return evaluate().has_member(name); + } + + // Remove a range of elements from an array + void remove_range(size_t from_index, size_t to_index) + { + evaluate().remove_range(from_index, to_index); + } + // Remove a range of elements from an array + void remove(const string_view_type& name) + { + evaluate().remove(name); + } + void remove_member(const string_view_type& name) + { + evaluate().remove(name); + } + bool is_empty() const JSONCONS_NOEXCEPT + { + return empty(); + } + bool is_numeric() const JSONCONS_NOEXCEPT + { + return is_number(); + } +#endif + }; + + static basic_json parse(std::basic_istream<char_type>& is); + static basic_json parse(std::basic_istream<char_type>& is, parse_error_handler& err_handler); + + static basic_json parse(const string_view_type& s) + { + parse_error_handler_type err_handler; + return parse(s,err_handler); + } + + static basic_json parse(const char_type* s, size_t length) + { + parse_error_handler_type err_handler; + return parse(s,length,err_handler); + } + + static basic_json parse(const char_type* s, size_t length, parse_error_handler& err_handler) + { + return parse(string_view_type(s,length),err_handler); + } + + static basic_json parse(const string_view_type& s, parse_error_handler& err_handler) + { + json_decoder<basic_json> decoder; + basic_json_parser<char_type> parser(decoder,err_handler); + + auto result = unicons::skip_bom(s.begin(), s.end()); + if (result.ec != unicons::encoding_errc()) + { + throw parse_error(result.ec,1,1); + } + size_t offset = result.it - s.begin(); + parser.set_source(s.data()+offset,s.size()-offset); + parser.parse_some(); + parser.end_parse(); + parser.check_done(); + if (!decoder.is_valid()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Failed to parse json string")); + } + return decoder.get_result(); + } + + static basic_json make_array() + { + return basic_json(variant(array())); + } + + static basic_json make_array(const array& a) + { + return basic_json(variant(a)); + } + + static basic_json make_array(const array& a, allocator_type allocator) + { + return basic_json(variant(a,allocator)); + } + + static basic_json make_array(std::initializer_list<basic_json> init, const Allocator& allocator = Allocator()) + { + return array(std::move(init),allocator); + } + + static basic_json make_array(size_t n, const Allocator& allocator = Allocator()) + { + return array(n,allocator); + } + + template <class T> + static basic_json make_array(size_t n, const T& val, const Allocator& allocator = Allocator()) + { + return basic_json::array(n, val,allocator); + } + + template <size_t dim> + static typename std::enable_if<dim==1,basic_json>::type make_array(size_t n) + { + return array(n); + } + + template <size_t dim, class T> + static typename std::enable_if<dim==1,basic_json>::type make_array(size_t n, const T& val, const Allocator& allocator = Allocator()) + { + return array(n,val,allocator); + } + + template <size_t dim, typename... Args> + static typename std::enable_if<(dim>1),basic_json>::type make_array(size_t n, Args... args) + { + const size_t dim1 = dim - 1; + + basic_json val = make_array<dim1>(args...); + val.resize(n); + for (size_t i = 0; i < n; ++i) + { + val[i] = make_array<dim1>(args...); + } + return val; + } + + static const basic_json& null() + { + static basic_json a_null = basic_json(variant(null_type())); + return a_null; + } + + variant var_; + + basic_json() + : var_() + { + } + + explicit basic_json(const Allocator& allocator) + : var_(allocator) + { + } + + basic_json(const basic_json& val) + : var_(val.var_) + { + } + + basic_json(const basic_json& val, const Allocator& allocator) + : var_(val.var_,allocator) + { + } + + basic_json(basic_json&& other) JSONCONS_NOEXCEPT + : var_(std::move(other.var_)) + { + } + + basic_json(basic_json&& other, const Allocator& allocator) JSONCONS_NOEXCEPT + : var_(std::move(other.var_) /*,allocator*/ ) + { + } + + basic_json(const variant& val) + : var_(val) + { + } + + basic_json(variant&& other) + : var_(std::forward<variant>(other)) + { + } + + basic_json(const array& val) + : var_(val) + { + } + + basic_json(array&& other) + : var_(std::forward<array>(other)) + { + } + + basic_json(const object& other) + : var_(other) + { + } + + basic_json(object&& other) + : var_(std::forward<object>(other)) + { + } + + template <class ParentT> + basic_json(const json_proxy<ParentT>& proxy) + : var_(proxy.evaluate().var_) + { + } + + template <class ParentT> + basic_json(const json_proxy<ParentT>& proxy, const Allocator& allocator) + : var_(proxy.evaluate().var_,allocator) + { + } + + template <class T> + basic_json(const T& val) + : var_(json_type_traits<basic_json,T>::to_json(val).var_) + { + } + + template <class T> + basic_json(const T& val, const Allocator& allocator) + : var_(json_type_traits<basic_json,T>::to_json(val,allocator).var_) + { + } + + basic_json(const char_type* s) + : var_(s) + { + } + + basic_json(const char_type* s, const Allocator& allocator) + : var_(s,allocator) + { + } + + basic_json(double val, uint8_t precision) + : var_(val, number_format(precision, 0)) + { + } + + basic_json(double val, const number_format& fmt) + : var_(val, fmt) + { + } + + basic_json(const char_type *s, size_t length) + : var_(s, length) + { + } + + basic_json(const char_type *s, size_t length, const Allocator& allocator) + : var_(s, length, allocator) + { + } + + basic_json(const uint8_t* s, size_t length) + : var_(s, length) + { + } + + explicit basic_json(const byte_string_view& s) + : var_(s.data(), s.length()) + { + } + + basic_json(const uint8_t* s, size_t length, const Allocator& allocator) + : var_(s, length, allocator) + { + } +#if !defined(JSONCONS_NO_DEPRECATED) + template<class InputIterator> + basic_json(InputIterator first, InputIterator last, const Allocator& allocator = Allocator()) + : var_(first,last,allocator) + { + } +#endif + + ~basic_json() + { + } + + basic_json& operator=(const basic_json& rhs) + { + if (this != &rhs) + { + var_ = rhs.var_; + } + return *this; + } + + basic_json& operator=(basic_json&& rhs) JSONCONS_NOEXCEPT + { + if (this !=&rhs) + { + var_ = std::move(rhs.var_); + } + return *this; + } + + template <class T> + basic_json& operator=(const T& val) + { + var_ = json_type_traits<basic_json,T>::to_json(val).var_; + return *this; + } + + basic_json& operator=(const char_type* s) + { + var_ = variant(s); + return *this; + } + + bool operator!=(const basic_json& rhs) const + { + return !(*this == rhs); + } + + bool operator==(const basic_json& rhs) const + { + return var_ == rhs.var_; + } + + size_t size() const JSONCONS_NOEXCEPT + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + return 0; + case json_type_tag::object_t: + return object_value().size(); + case json_type_tag::array_t: + return array_value().size(); + default: + return 0; + } + } + + basic_json& operator[](size_t i) + { + return at(i); + } + + const basic_json& operator[](size_t i) const + { + return at(i); + } + + json_proxy<basic_json> operator[](const string_view_type& name) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + return json_proxy<basic_json>(*this, key_storage_type(name.begin(),name.end(),char_allocator_type(object_value().get_allocator()))); + break; + default: + JSONCONS_THROW(not_an_object(name.data(),name.length())); + break; + } + } + + const basic_json& operator[](const string_view_type& name) const + { + return at(name); + } + + template <class SAllocator> + void dump(std::basic_string<char_type,char_traits_type,SAllocator>& s) const + { + basic_json_serializer<char_type,detail::string_writer<char_type>> serializer(s); + dump(serializer); + } + + template <class SAllocator> + void dump(std::basic_string<char_type,char_traits_type,SAllocator>& s, + const basic_serialization_options<char_type>& options) const + { + basic_json_serializer<char_type,detail::string_writer<char_type>> serializer(s, options); + dump(serializer); + } + +#if !defined(JSONCONS_NO_DEPRECATED) + void dump_body(basic_json_output_handler<char_type>& handler) const + { + dump_fragment(handler); + } +#endif + void dump_fragment(basic_json_output_handler<char_type>& handler) const + { + switch (var_.type_id()) + { + case json_type_tag::small_string_t: + case json_type_tag::string_t: + handler.string_value(as_string_view()); + break; + case json_type_tag::byte_string_t: + handler.byte_string_value(var_.byte_string_data_cast()->data(), var_.byte_string_data_cast()->length()); + break; + case json_type_tag::double_t: + handler.double_value(var_.double_data_cast()->value(), number_format(var_.double_data_cast()->precision(), var_.double_data_cast()->decimal_places())); + break; + case json_type_tag::integer_t: + handler.integer_value(var_.integer_data_cast()->value()); + break; + case json_type_tag::uinteger_t: + handler.uinteger_value(var_.uinteger_data_cast()->value()); + break; + case json_type_tag::bool_t: + handler.bool_value(var_.bool_data_cast()->value()); + break; + case json_type_tag::null_t: + handler.null_value(); + break; + case json_type_tag::empty_object_t: + handler.begin_object(0); + handler.end_object(); + break; + case json_type_tag::object_t: + { + handler.begin_object(size()); + const object& o = object_value(); + for (const_object_iterator it = o.begin(); it != o.end(); ++it) + { + handler.name(string_view_type((it->key()).data(),it->key().length())); + it->value().dump_fragment(handler); + } + handler.end_object(); + } + break; + case json_type_tag::array_t: + { + handler.begin_array(size()); + const array& o = array_value(); + for (const_array_iterator it = o.begin(); it != o.end(); ++it) + { + it->dump_fragment(handler); + } + handler.end_array(); + } + break; + default: + break; + } + } + void dump(basic_json_output_handler<char_type>& handler) const + { + handler.begin_json(); + dump_fragment(handler); + handler.end_json(); + } + + void dump(std::basic_ostream<char_type>& os) const + { + basic_json_serializer<char_type> serializer(os); + dump(serializer); + } + + void dump(std::basic_ostream<char_type>& os, bool pprint) const + { + basic_json_serializer<char_type> serializer(os, pprint); + dump(serializer); + } + + void dump(std::basic_ostream<char_type>& os, const basic_serialization_options<char_type>& options) const + { + basic_json_serializer<char_type> serializer(os, options); + dump(serializer); + } + + void dump(std::basic_ostream<char_type>& os, const basic_serialization_options<char_type>& options, bool pprint) const + { + basic_json_serializer<char_type> serializer(os, options, pprint); + dump(serializer); + } + + string_type to_string(const char_allocator_type& allocator=char_allocator_type()) const JSONCONS_NOEXCEPT + { + string_type s(allocator); + basic_json_serializer<char_type,detail::string_writer<char_type>> serializer(s); + dump_fragment(serializer); + return s; + } + + string_type to_string(const basic_serialization_options<char_type>& options, + const char_allocator_type& allocator=char_allocator_type()) const + { + string_type s(allocator); + basic_json_serializer<char_type,detail::string_writer<char_type>> serializer(s,options); + dump_fragment(serializer); + return s; + } + +#if !defined(JSONCONS_NO_DEPRECATED) + + void write_body(basic_json_output_handler<char_type>& handler) const + { + dump(handler); + } + void write(basic_json_output_handler<char_type>& handler) const + { + dump(handler); + } + + void write(std::basic_ostream<char_type>& os) const + { + dump(os); + } + + void write(std::basic_ostream<char_type>& os, const basic_serialization_options<char_type>& options) const + { + dump(os,options); + } + + void write(std::basic_ostream<char_type>& os, const basic_serialization_options<char_type>& options, bool pprint) const + { + dump(os,options,pprint); + } + + void to_stream(basic_json_output_handler<char_type>& handler) const + { + handler.begin_json(); + dump_fragment(handler); + handler.end_json(); + } + + void to_stream(std::basic_ostream<char_type>& os) const + { + basic_json_serializer<char_type> serializer(os); + to_stream(serializer); + } + + void to_stream(std::basic_ostream<char_type>& os, const basic_serialization_options<char_type>& options) const + { + basic_json_serializer<char_type> serializer(os, options); + to_stream(serializer); + } + + void to_stream(std::basic_ostream<char_type>& os, const basic_serialization_options<char_type>& options, bool pprint) const + { + basic_json_serializer<char_type> serializer(os, options, pprint); + to_stream(serializer); + } +#endif + bool is_null() const JSONCONS_NOEXCEPT + { + return var_.type_id() == json_type_tag::null_t; + } + + bool has_key(const string_view_type& name) const + { + switch (var_.type_id()) + { + case json_type_tag::object_t: + { + const_object_iterator it = object_value().find(name); + return it != object_range().end(); + } + break; + default: + return false; + } + } + + size_t count(const string_view_type& name) const + { + switch (var_.type_id()) + { + case json_type_tag::object_t: + { + auto it = object_value().find(name); + if (it == object_range().end()) + { + return 0; + } + size_t count = 0; + while (it != object_range().end()&& it->key() == name) + { + ++count; + ++it; + } + return count; + } + break; + default: + return 0; + } + } + + template<class T, class... Args> + bool is(Args&&... args) const + { + return json_type_traits<basic_json,T>::is(*this,std::forward<Args>(args)...); + } + + bool is_string() const JSONCONS_NOEXCEPT + { + return (var_.type_id() == json_type_tag::string_t) || (var_.type_id() == json_type_tag::small_string_t); + } + + bool is_byte_string() const JSONCONS_NOEXCEPT + { + return (var_.type_id() == json_type_tag::byte_string_t); + } + + bool is_bool() const JSONCONS_NOEXCEPT + { + return var_.type_id() == json_type_tag::bool_t; + } + + bool is_object() const JSONCONS_NOEXCEPT + { + return var_.type_id() == json_type_tag::object_t || var_.type_id() == json_type_tag::empty_object_t; + } + + bool is_array() const JSONCONS_NOEXCEPT + { + return var_.type_id() == json_type_tag::array_t; + } + + bool is_integer() const JSONCONS_NOEXCEPT + { + return var_.type_id() == json_type_tag::integer_t || (var_.type_id() == json_type_tag::uinteger_t&& (as_uinteger() <= static_cast<uint64_t>((std::numeric_limits<int64_t>::max)()))); + } + + bool is_uinteger() const JSONCONS_NOEXCEPT + { + return var_.type_id() == json_type_tag::uinteger_t || (var_.type_id() == json_type_tag::integer_t&& as_integer() >= 0); + } + + bool is_double() const JSONCONS_NOEXCEPT + { + return var_.type_id() == json_type_tag::double_t; + } + + bool is_number() const JSONCONS_NOEXCEPT + { + return var_.type_id() == json_type_tag::integer_t || var_.type_id() == json_type_tag::uinteger_t || var_.type_id() == json_type_tag::double_t; + } + + bool empty() const JSONCONS_NOEXCEPT + { + switch (var_.type_id()) + { + case json_type_tag::small_string_t: + return var_.small_string_data_cast()->length() == 0; + case json_type_tag::string_t: + return var_.string_data_cast()->length() == 0; + case json_type_tag::array_t: + return array_value().size() == 0; + case json_type_tag::empty_object_t: + return true; + case json_type_tag::object_t: + return object_value().size() == 0; + default: + return false; + } + } + + size_t capacity() const + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + return array_value().capacity(); + case json_type_tag::object_t: + return object_value().capacity(); + default: + return 0; + } + } + + template<class U=Allocator> + typename std::enable_if<is_stateless<U>::value,void>::type + create_object_implicitly() + { + var_ = variant(Allocator()); + } + + template<class U=Allocator> + typename std::enable_if<!is_stateless<U>::value,void>::type + create_object_implicitly() const + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Cannot create object implicitly - allocator is not default constructible.")); + } + + void reserve(size_t n) + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + array_value().reserve(n); + break; + case json_type_tag::empty_object_t: + { + create_object_implicitly(); + object_value().reserve(n); + } + break; + case json_type_tag::object_t: + { + object_value().reserve(n); + } + break; + default: + break; + } + } + + void resize(size_t n) + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + array_value().resize(n); + break; + default: + break; + } + } + + template <class T> + void resize(size_t n, T val) + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + array_value().resize(n, val); + break; + default: + break; + } + } + + template<class T, class... Args> + T as(Args&&... args) const + { + return json_type_traits<basic_json,T>::as(*this,std::forward<Args>(args)...); + } + + template<class T> + typename std::enable_if<std::is_same<string_type,T>::value,T>::type + as(const char_allocator_type& allocator) const + { + return json_type_traits<basic_json,T>::as(*this,allocator); + } + + bool as_bool() const + { + switch (var_.type_id()) + { + case json_type_tag::small_string_t: + case json_type_tag::string_t: + try + { + basic_json j = basic_json::parse(as_string_view().data(),as_string_view().length()); + return j.as_bool(); + } + catch (...) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not a bool")); + } + break; + case json_type_tag::bool_t: + return var_.bool_data_cast()->value(); + case json_type_tag::double_t: + return var_.double_data_cast()->value() != 0.0; + case json_type_tag::integer_t: + return var_.integer_data_cast()->value() != 0; + case json_type_tag::uinteger_t: + return var_.uinteger_data_cast()->value() != 0; + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not a bool")); + } + } + + int64_t as_integer() const + { + switch (var_.type_id()) + { + case json_type_tag::small_string_t: + case json_type_tag::string_t: + try + { + basic_json j = basic_json::parse(as_string_view().data(),as_string_view().length()); + return j.as<int64_t>(); + } + catch (...) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an integer")); + } + break; + case json_type_tag::double_t: + return static_cast<int64_t>(var_.double_data_cast()->value()); + case json_type_tag::integer_t: + return static_cast<int64_t>(var_.integer_data_cast()->value()); + case json_type_tag::uinteger_t: + return static_cast<int64_t>(var_.uinteger_data_cast()->value()); + case json_type_tag::bool_t: + return var_.bool_data_cast()->value() ? 1 : 0; + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an integer")); + } + } + + uint64_t as_uinteger() const + { + switch (var_.type_id()) + { + case json_type_tag::small_string_t: + case json_type_tag::string_t: + try + { + basic_json j = basic_json::parse(as_string_view().data(),as_string_view().length()); + return j.as<uint64_t>(); + } + catch (...) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an unsigned integer")); + } + break; + case json_type_tag::double_t: + return static_cast<uint64_t>(var_.double_data_cast()->value()); + case json_type_tag::integer_t: + return static_cast<uint64_t>(var_.integer_data_cast()->value()); + case json_type_tag::uinteger_t: + return static_cast<uint64_t>(var_.uinteger_data_cast()->value()); + case json_type_tag::bool_t: + return var_.bool_data_cast()->value() ? 1 : 0; + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an unsigned integer")); + } + } + + size_t precision() const + { + switch (var_.type_id()) + { + case json_type_tag::double_t: + return var_.double_data_cast()->precision(); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not a double")); + } + } + + size_t decimal_places() const + { + switch (var_.type_id()) + { + case json_type_tag::double_t: + return var_.double_data_cast()->decimal_places(); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not a double")); + } + } + + double as_double() const + { + switch (var_.type_id()) + { + case json_type_tag::small_string_t: + case json_type_tag::string_t: + try + { + basic_json j = basic_json::parse(as_string_view().data(),as_string_view().length()); + return j.as<double>(); + } + catch (...) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not a double")); + } + break; + case json_type_tag::double_t: + return var_.double_data_cast()->value(); + case json_type_tag::integer_t: + return static_cast<double>(var_.integer_data_cast()->value()); + case json_type_tag::uinteger_t: + return static_cast<double>(var_.uinteger_data_cast()->value()); + //case json_type_tag::null_t: + // return std::numeric_limits<double>::quiet_NaN(); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not a double")); + } + } + + string_view_type as_string_view() const + { + return var_.as_string_view(); + } + + byte_string_view as_byte_string_view() const + { + return var_.as_byte_string_view(); + } + + string_type as_string() const + { + switch (var_.type_id()) + { + case json_type_tag::small_string_t: + case json_type_tag::string_t: + return string_type(as_string_view().data(),as_string_view().length()); + default: + return to_string(); + } + } + + template <class SAllocator> + string_type as_string(const SAllocator& allocator) const + { + switch (var_.type_id()) + { + case json_type_tag::small_string_t: + case json_type_tag::string_t: + return string_type(as_string_view().data(),as_string_view().length(),allocator); + default: + return to_string(allocator); + } + } + + string_type as_string(const basic_serialization_options<char_type>& options) const + { + switch (var_.type_id()) + { + case json_type_tag::small_string_t: + case json_type_tag::string_t: + return string_type(as_string_view().data(),as_string_view().length()); + default: + return to_string(options); + } + } + + template <class SAllocator> + string_type as_string(const basic_serialization_options<char_type>& options, + const SAllocator& allocator) const + { + switch (var_.type_id()) + { + case json_type_tag::small_string_t: + case json_type_tag::string_t: + return string_type(as_string_view().data(),as_string_view().length(),allocator); + default: + return to_string(options,allocator); + } + } + + const char_type* as_cstring() const + { + switch (var_.type_id()) + { + case json_type_tag::small_string_t: + return var_.small_string_data_cast()->c_str(); + case json_type_tag::string_t: + return var_.string_data_cast()->c_str(); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not a cstring")); + } + } + +#if !defined(JSONCONS_NO_DEPRECATED) + + size_t double_precision() const + { + switch (var_.type_id()) + { + case json_type_tag::double_t: + return var_.double_data_cast()->precision(); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not a double")); + } + } +#endif + + basic_json& at(const string_view_type& name) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + JSONCONS_THROW(key_not_found(name.data(),name.length())); + case json_type_tag::object_t: + { + auto it = object_value().find(name); + if (it == object_range().end()) + { + JSONCONS_THROW(key_not_found(name.data(),name.length())); + } + return it->value(); + } + break; + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + basic_json& evaluate() + { + return *this; + } + + basic_json& evaluate_with_default() + { + return *this; + } + + const basic_json& evaluate() const + { + return *this; + } + basic_json& evaluate(const string_view_type& name) + { + return at(name); + } + + const basic_json& evaluate(const string_view_type& name) const + { + return at(name); + } + + const basic_json& at(const string_view_type& name) const + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + JSONCONS_THROW(key_not_found(name.data(),name.length())); + case json_type_tag::object_t: + { + auto it = object_value().find(name); + if (it == object_range().end()) + { + JSONCONS_THROW(key_not_found(name.data(),name.length())); + } + return it->value(); + } + break; + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + basic_json& at(size_t i) + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + if (i >= array_value().size()) + { + JSONCONS_THROW(json_exception_impl<std::out_of_range>("Invalid array subscript")); + } + return array_value().operator[](i); + case json_type_tag::object_t: + return object_value().at(i); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Index on non-array value not supported")); + } + } + + const basic_json& at(size_t i) const + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + if (i >= array_value().size()) + { + JSONCONS_THROW(json_exception_impl<std::out_of_range>("Invalid array subscript")); + } + return array_value().operator[](i); + case json_type_tag::object_t: + return object_value().at(i); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Index on non-array value not supported")); + } + } + + object_iterator find(const string_view_type& name) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + return object_range().end(); + case json_type_tag::object_t: + return object_value().find(name); + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + const_object_iterator find(const string_view_type& name) const + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + return object_range().end(); + case json_type_tag::object_t: + return object_value().find(name); + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + template<class T> + basic_json get(const string_view_type& name, T&& default_val) const + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + { + return basic_json(std::forward<T>(default_val)); + } + case json_type_tag::object_t: + { + const_object_iterator it = object_value().find(name); + if (it != object_range().end()) + { + return it->value(); + } + else + { + return basic_json(std::forward<T>(default_val)); + } + } + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + template<class T> + T get_with_default(const string_view_type& name, const T& default_val) const + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + { + return default_val; + } + case json_type_tag::object_t: + { + const_object_iterator it = object_value().find(name); + if (it != object_range().end()) + { + return it->value().template as<T>(); + } + else + { + return default_val; + } + } + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + const CharT* get_with_default(const string_view_type& name, const CharT* default_val) const + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + { + return default_val; + } + case json_type_tag::object_t: + { + const_object_iterator it = object_value().find(name); + if (it != object_range().end()) + { + return it->value().as_cstring(); + } + else + { + return default_val; + } + } + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + // Modifiers + + void shrink_to_fit() + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + array_value().shrink_to_fit(); + break; + case json_type_tag::object_t: + object_value().shrink_to_fit(); + break; + default: + break; + } + } + + void clear() + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + array_value().clear(); + break; + case json_type_tag::object_t: + object_value().clear(); + break; + default: + break; + } + } + + void erase(const_object_iterator pos) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + break; + case json_type_tag::object_t: + object_value().erase(pos); + break; + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an object")); + break; + } + } + + void erase(const_object_iterator first, const_object_iterator last) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + break; + case json_type_tag::object_t: + object_value().erase(first, last); + break; + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an object")); + break; + } + } + + void erase(const_array_iterator pos) + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + array_value().erase(pos); + break; + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an array")); + break; + } + } + + void erase(const_array_iterator first, const_array_iterator last) + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + array_value().erase(first, last); + break; + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an array")); + break; + } + } + + // Removes all elements from an array value whose index is between from_index, inclusive, and to_index, exclusive. + + void erase(const string_view_type& name) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + break; + case json_type_tag::object_t: + object_value().erase(name); + break; + default: + JSONCONS_THROW(not_an_object(name.data(),name.length())); + break; + } + } + + template <class T> + std::pair<object_iterator,bool> set(const string_view_type& name, T&& val) + { + return insert_or_assign(name, std::forward<T>(val)); + } + + template <class T> + std::pair<object_iterator,bool> insert_or_assign(const string_view_type& name, T&& val) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + return object_value().insert_or_assign(name, std::forward<T>(val)); + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + template <class ... Args> + std::pair<object_iterator,bool> try_emplace(const string_view_type& name, Args&&... args) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + return object_value().try_emplace(name, std::forward<Args>(args)...); + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + template <class T> + void set_(key_storage_type&& name, T&& val) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + object_value().set_(std::forward<key_storage_type>(name), std::forward<T>(val)); + break; + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + // merge + + void merge(const basic_json& source) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + return object_value().merge(source.object_value()); + default: + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempting to merge a value that is not an object")); + } + } + } + + void merge(basic_json&& source) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + return object_value().merge(std::move(source.object_value())); + default: + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempting to merge a value that is not an object")); + } + } + } + + void merge(object_iterator hint, const basic_json& source) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + return object_value().merge(hint, source.object_value()); + default: + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempting to merge a value that is not an object")); + } + } + } + + void merge(object_iterator hint, basic_json&& source) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + return object_value().merge(hint, std::move(source.object_value())); + default: + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempting to merge a value that is not an object")); + } + } + } + + // merge_or_update + + void merge_or_update(const basic_json& source) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + return object_value().merge_or_update(source.object_value()); + default: + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempting to merge or update a value that is not an object")); + } + } + } + + void merge_or_update(basic_json&& source) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + return object_value().merge_or_update(std::move(source.object_value())); + default: + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempting to merge or update a value that is not an object")); + } + } + } + + void merge_or_update(object_iterator hint, const basic_json& source) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + return object_value().merge_or_update(hint, source.object_value()); + default: + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempting to merge or update a value that is not an object")); + } + } + } + + void merge_or_update(object_iterator hint, basic_json&& source) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + return object_value().merge_or_update(hint, std::move(source.object_value())); + default: + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempting to merge or update a value that is not an object")); + } + } + } + + // set + + template <class T> + object_iterator set(object_iterator hint, const string_view_type& name, T&& val) + { + return insert_or_assign(hint, name, std::forward<T>(val)); + } + + template <class T> + object_iterator insert_or_assign(object_iterator hint, const string_view_type& name, T&& val) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + return object_value().insert_or_assign(hint, name, std::forward<T>(val)); + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + template <class ... Args> + object_iterator try_emplace(object_iterator hint, const string_view_type& name, Args&&... args) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + return object_value().try_emplace(hint, name, std::forward<Args>(args)...); + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + template <class T> + object_iterator set_(object_iterator hint, key_storage_type&& name, T&& val) + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + return object_value().set_(hint, std::forward<key_storage_type>(name), std::forward<T>(val)); + break; + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + template <class T> + void add(T&& val) + { + push_back(std::forward<T>(val)); + } + + template <class T> + void push_back(T&& val) + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + array_value().push_back(std::forward<T>(val)); + break; + default: + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempting to insert into a value that is not an array")); + } + } + } + + template <class T> + array_iterator add(const_array_iterator pos, T&& val) + { + return insert(pos, std::forward<T>(val)); + } + + template <class T> + array_iterator insert(const_array_iterator pos, T&& val) + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + return array_value().insert(pos, std::forward<T>(val)); + break; + default: + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempting to insert into a value that is not an array")); + } + } + } + + template <class InputIt> + array_iterator insert(const_array_iterator pos, InputIt first, InputIt last) + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + return array_value().insert(pos, first, last); + break; + default: + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempting to insert into a value that is not an array")); + } + } + } + + template <class... Args> + array_iterator emplace(const_array_iterator pos, Args&&... args) + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + return array_value().emplace(pos, std::forward<Args>(args)...); + break; + default: + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempting to insert into a value that is not an array")); + } + } + } + + template <class... Args> + basic_json& emplace_back(Args&&... args) + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + return array_value().emplace_back(std::forward<Args>(args)...); + default: + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempting to insert into a value that is not an array")); + } + } + } + + json_type_tag type_id() const + { + return var_.type_id(); + } + + void swap(basic_json& b) + { + var_.swap(b.var_); + } + + friend void swap(basic_json& a, basic_json& b) + { + a.swap(b); + } + + static basic_json make_string(const string_view_type& s) + { + return basic_json(variant(s.data(),s.length())); + } + + static basic_json make_string(const char_type* rhs, size_t length) + { + return basic_json(variant(rhs,length)); + } + + static basic_json make_string(const string_view_type& s, allocator_type allocator) + { + return basic_json(variant(s.data(),s.length(),allocator)); + } + + static basic_json from_integer(int64_t val) + { + return basic_json(variant(val)); + } + + static basic_json from_integer(int64_t val, allocator_type) + { + return basic_json(variant(val)); + } + + static basic_json from_uinteger(uint64_t val) + { + return basic_json(variant(val)); + } + + static basic_json from_uinteger(uint64_t val, allocator_type) + { + return basic_json(variant(val)); + } + + static basic_json from_floating_point(double val) + { + return basic_json(variant(val)); + } + + static basic_json from_floating_point(double val, allocator_type) + { + return basic_json(variant(val)); + } + + static basic_json from_bool(bool val) + { + return basic_json(variant(val)); + } + + static basic_json make_object(const object& o) + { + return basic_json(variant(o)); + } + + static basic_json make_object(const object& o, allocator_type allocator) + { + return basic_json(variant(o,allocator)); + } + +#if !defined(JSONCONS_NO_DEPRECATED) + + static basic_json parse_file(const std::basic_string<char_type,char_traits_type>& filename) + { + parse_error_handler_type err_handler; + return parse_file(filename,err_handler); + } + + static basic_json parse_file(const std::basic_string<char_type,char_traits_type>& filename, + parse_error_handler& err_handler) + { + std::basic_ifstream<CharT> is(filename); + return parse(is,err_handler); + } + + static basic_json parse_stream(std::basic_istream<char_type>& is) + { + return parse(is); + } + static basic_json parse_stream(std::basic_istream<char_type>& is, parse_error_handler& err_handler) + { + return parse(is,err_handler); + } + + static basic_json parse_string(const string_type& s) + { + return parse(s); + } + + static basic_json parse_string(const string_type& s, parse_error_handler& err_handler) + { + return parse(s,err_handler); + } + + void resize_array(size_t n) + { + resize(n); + } + + template <class T> + void resize_array(size_t n, T val) + { + resize(n,val); + } + + object_iterator begin_members() + { + return object_range().begin(); + } + + const_object_iterator begin_members() const + { + return object_range().begin(); + } + + object_iterator end_members() + { + return object_range().end(); + } + + const_object_iterator end_members() const + { + return object_range().end(); + } + + array_iterator begin_elements() + { + return array_range().begin(); + } + + const_array_iterator begin_elements() const + { + return array_range().begin(); + } + + array_iterator end_elements() + { + return array_range().end(); + } + + const_array_iterator end_elements() const + { + return array_range().end(); + } + + const basic_json& get(const string_view_type& name) const + { + static const basic_json a_null = null_type(); + + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + return a_null; + case json_type_tag::object_t: + { + const_object_iterator it = object_value().find(name); + return it != object_range().end() ? it->value() : a_null; + } + default: + { + JSONCONS_THROW(not_an_object(name.data(),name.length())); + } + } + } + + bool is_longlong() const JSONCONS_NOEXCEPT + { + return var_.type_id() == json_type_tag::integer_t; + } + + bool is_ulonglong() const JSONCONS_NOEXCEPT + { + return var_.type_id() == json_type_tag::uinteger_t; + } + + long long as_longlong() const + { + return as_integer(); + } + + unsigned long long as_ulonglong() const + { + return as_uinteger(); + } + + int as_int() const + { + switch (var_.type_id()) + { + case json_type_tag::double_t: + return static_cast<int>(var_.double_data_cast()->value()); + case json_type_tag::integer_t: + return static_cast<int>(var_.integer_data_cast()->value()); + case json_type_tag::uinteger_t: + return static_cast<int>(var_.uinteger_data_cast()->value()); + case json_type_tag::bool_t: + return var_.bool_data_cast()->value() ? 1 : 0; + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an int")); + } + } + + unsigned int as_uint() const + { + switch (var_.type_id()) + { + case json_type_tag::double_t: + return static_cast<unsigned int>(var_.double_data_cast()->value()); + case json_type_tag::integer_t: + return static_cast<unsigned int>(var_.integer_data_cast()->value()); + case json_type_tag::uinteger_t: + return static_cast<unsigned int>(var_.uinteger_data_cast()->value()); + case json_type_tag::bool_t: + return var_.bool_data_cast()->value() ? 1 : 0; + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an unsigned int")); + } + } + + long as_long() const + { + switch (var_.type_id()) + { + case json_type_tag::double_t: + return static_cast<long>(var_.double_data_cast()->value()); + case json_type_tag::integer_t: + return static_cast<long>(var_.integer_data_cast()->value()); + case json_type_tag::uinteger_t: + return static_cast<long>(var_.uinteger_data_cast()->value()); + case json_type_tag::bool_t: + return var_.bool_data_cast()->value() ? 1 : 0; + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not a long")); + } + } + + unsigned long as_ulong() const + { + switch (var_.type_id()) + { + case json_type_tag::double_t: + return static_cast<unsigned long>(var_.double_data_cast()->value()); + case json_type_tag::integer_t: + return static_cast<unsigned long>(var_.integer_data_cast()->value()); + case json_type_tag::uinteger_t: + return static_cast<unsigned long>(var_.uinteger_data_cast()->value()); + case json_type_tag::bool_t: + return var_.bool_data_cast()->value() ? 1 : 0; + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an unsigned long")); + } + } + + bool has_member(const key_storage_type& name) const + { + switch (var_.type_id()) + { + case json_type_tag::object_t: + { + const_object_iterator it = object_value().find(name); + return it != object_range().end(); + } + break; + default: + return false; + } + } + + void remove_range(size_t from_index, size_t to_index) + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + array_value().remove_range(from_index, to_index); + break; + default: + break; + } + } + // Removes all elements from an array value whose index is between from_index, inclusive, and to_index, exclusive. + + void remove(const string_view_type& name) + { + erase(name); + } + void remove_member(const string_view_type& name) + { + erase(name); + } + // Removes a member from an object value + + bool is_empty() const JSONCONS_NOEXCEPT + { + return empty(); + } + bool is_numeric() const JSONCONS_NOEXCEPT + { + return is_number(); + } + + template<int size> + static typename std::enable_if<size==1,basic_json>::type make_multi_array() + { + return make_array(); + } + template<size_t size> + static typename std::enable_if<size==1,basic_json>::type make_multi_array(size_t n) + { + return make_array(n); + } + template<size_t size,typename T> + static typename std::enable_if<size==1,basic_json>::type make_multi_array(size_t n, T val) + { + return make_array(n,val); + } + template<size_t size> + static typename std::enable_if<size==2,basic_json>::type make_multi_array(size_t m, size_t n) + { + return make_array<2>(m, n); + } + template<size_t size,typename T> + static typename std::enable_if<size==2,basic_json>::type make_multi_array(size_t m, size_t n, T val) + { + return make_array<2>(m, n, val); + } + template<size_t size> + static typename std::enable_if<size==3,basic_json>::type make_multi_array(size_t m, size_t n, size_t k) + { + return make_array<3>(m, n, k); + } + template<size_t size,typename T> + static typename std::enable_if<size==3,basic_json>::type make_multi_array(size_t m, size_t n, size_t k, T val) + { + return make_array<3>(m, n, k, val); + } + range<object_iterator> members() + { + return object_range(); + } + + range<const_object_iterator> members() const + { + return object_range(); + } + + range<array_iterator> elements() + { + return array_range(); + } + + range<const_array_iterator> elements() const + { + return array_range(); + } +#endif + + range<object_iterator> object_range() + { + static basic_json empty_object = object(); + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + return range<object_iterator>(empty_object.object_range().begin(), empty_object.object_range().end()); + case json_type_tag::object_t: + return range<object_iterator>(object_value().begin(),object_value().end()); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an object")); + } + } + + range<const_object_iterator> object_range() const + { + static const basic_json empty_object = object(); + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + return range<const_object_iterator>(empty_object.object_range().begin(), empty_object.object_range().end()); + case json_type_tag::object_t: + return range<const_object_iterator>(object_value().begin(),object_value().end()); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an object")); + } + } + + range<array_iterator> array_range() + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + return range<array_iterator>(array_value().begin(),array_value().end()); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an array")); + } + } + + range<const_array_iterator> array_range() const + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + return range<const_array_iterator>(array_value().begin(),array_value().end()); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an array")); + } + } + + array& array_value() + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + return var_.array_data_cast()->value(); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Bad array cast")); + break; + } + } + + const array& array_value() const + { + switch (var_.type_id()) + { + case json_type_tag::array_t: + return var_.array_data_cast()->value(); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Bad array cast")); + break; + } + } + + object& object_value() + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + create_object_implicitly(); + // FALLTHRU + case json_type_tag::object_t: + return var_.object_data_cast()->value(); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Bad object cast")); + break; + } + } + + const object& object_value() const + { + switch (var_.type_id()) + { + case json_type_tag::empty_object_t: + const_cast<basic_json*>(this)->create_object_implicitly(); // HERE + // FALLTHRU + case json_type_tag::object_t: + return var_.object_data_cast()->value(); + default: + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Bad object cast")); + break; + } + } + +private: + + friend std::basic_ostream<char_type>& operator<<(std::basic_ostream<char_type>& os, const basic_json& o) + { + o.dump(os); + return os; + } + + friend std::basic_istream<char_type>& operator<<(std::basic_istream<char_type>& is, basic_json& o) + { + json_decoder<basic_json> handler; + basic_json_reader<char_type> reader(is, handler); + reader.read_next(); + reader.check_done(); + if (!handler.is_valid()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Failed to parse json stream")); + } + o = handler.get_result(); + return is; + } +}; + +template <class Json> +void swap(typename Json::key_value_pair_type& a, typename Json::key_value_pair_type& b) +{ + a.swap(b); +} + +template<class CharT,class ImplementationPolicy,class Allocator> +basic_json<CharT,ImplementationPolicy,Allocator> basic_json<CharT,ImplementationPolicy,Allocator>::parse(std::basic_istream<char_type>& is) +{ + parse_error_handler_type err_handler; + return parse(is,err_handler); +} + +template<class CharT,class ImplementationPolicy,class Allocator> +basic_json<CharT,ImplementationPolicy,Allocator> basic_json<CharT,ImplementationPolicy,Allocator>::parse(std::basic_istream<char_type>& is, + parse_error_handler& err_handler) +{ + json_decoder<basic_json<CharT,ImplementationPolicy,Allocator>> handler; + basic_json_reader<char_type> reader(is, handler, err_handler); + reader.read_next(); + reader.check_done(); + if (!handler.is_valid()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Failed to parse json stream")); + } + return handler.get_result(); +} + +template <class Json> +std::basic_istream<typename Json::char_type>& operator>>(std::basic_istream<typename Json::char_type>& is, Json& o) +{ + json_decoder<Json> handler; + basic_json_reader<typename Json::char_type> reader(is, handler); + reader.read_next(); + reader.check_done(); + if (!handler.is_valid()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Failed to parse json stream")); + } + o = handler.get_result(); + return is; +} + +template<class Json> +class json_printable +{ +public: + typedef typename Json::char_type char_type; + + json_printable(const Json& o, + bool is_pretty_print) + : o_(&o), is_pretty_print_(is_pretty_print) + { + } + + json_printable(const Json& o, + bool is_pretty_print, + const basic_serialization_options<char_type>& options) + : o_(&o), is_pretty_print_(is_pretty_print), options_(options) + { + ; + } + + void dump(std::basic_ostream<char_type>& os) const + { + o_->dump(os, options_, is_pretty_print_); + } + + friend std::basic_ostream<char_type>& operator<<(std::basic_ostream<char_type>& os, const json_printable<Json>& o) + { + o.dump(os); + return os; + } + + const Json *o_; + bool is_pretty_print_; + basic_serialization_options<char_type> options_; +private: + json_printable(); +}; + +template<class Json> +json_printable<Json> print(const Json& val) +{ + return json_printable<Json>(val,false); +} + +template<class Json> +json_printable<Json> print(const Json& val, + const basic_serialization_options<typename Json::char_type>& options) +{ + return json_printable<Json>(val, false, options); +} + +template<class Json> +json_printable<Json> pretty_print(const Json& val) +{ + return json_printable<Json>(val,true); +} + +template<class Json> +json_printable<Json> pretty_print(const Json& val, + const basic_serialization_options<typename Json::char_type>& options) +{ + return json_printable<Json>(val, true, options); +} + +typedef basic_json<char,sorted_policy,std::allocator<char>> json; +typedef basic_json<wchar_t,sorted_policy,std::allocator<wchar_t>> wjson; +typedef basic_json<char, preserve_order_policy, std::allocator<char>> ojson; +typedef basic_json<wchar_t, preserve_order_policy, std::allocator<wchar_t>> wojson; + +#if !defined(JSONCONS_NO_DEPRECATED) +typedef basic_json<wchar_t, preserve_order_policy, std::allocator<wchar_t>> owjson; +typedef json_decoder<json> json_deserializer; +typedef json_decoder<wjson> wjson_deserializer; +typedef json_decoder<ojson> ojson_deserializer; +typedef json_decoder<wojson> wojson_deserializer; +#endif + +#if defined(JSONCONS_HAS_USER_DEFINED_LITERALS) +namespace literals { + +inline +jsoncons::json operator "" _json(const char* s, std::size_t n) +{ + return jsoncons::json::parse(s, n); +} + +inline +jsoncons::wjson operator "" _json(const wchar_t* s, std::size_t n) +{ + return jsoncons::wjson::parse(s, n); +} + +inline +jsoncons::ojson operator "" _ojson(const char* s, std::size_t n) +{ + return jsoncons::ojson::parse(s, n); +} + +inline +jsoncons::wojson operator "" _ojson(const wchar_t* s, std::size_t n) +{ + return jsoncons::wojson::parse(s, n); +} + +} +#endif + +} + + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/json_decoder.hpp b/vendor/jsoncons-0.104.0/jsoncons/json_decoder.hpp new file mode 100644 index 00000000..9ca5bd4c --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/json_decoder.hpp @@ -0,0 +1,310 @@ +// Copyright 2013-2016 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_DECODER_HPP +#define JSONCONS_JSON_DECODER_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <memory> +#include <jsoncons/json_exception.hpp> +#include <jsoncons/json_input_handler.hpp> + +namespace jsoncons { + +template <class Json,class Allocator=std::allocator<typename Json::char_type>> +class json_decoder final : public basic_json_input_handler<typename Json::char_type> +{ +public: + typedef typename Json::char_type char_type; + using typename basic_json_input_handler<char_type>::string_view_type; + + typedef typename Json::key_value_pair_type key_value_pair_type; + typedef typename Json::key_storage_type key_storage_type; + typedef typename Json::string_type string_type; + typedef typename Json::array array; + typedef typename Json::object object; + typedef typename Json::allocator_type json_allocator_type; + typedef typename string_type::allocator_type json_string_allocator; + typedef typename array::allocator_type json_array_allocator; + typedef typename object::allocator_type json_object_allocator; + + json_string_allocator string_allocator_; + json_object_allocator object_allocator_; + json_array_allocator array_allocator_; + + Json result_; + + struct stack_item + { + stack_item(key_storage_type&& name) + : name_(std::forward<key_storage_type>(name)) + { + } + stack_item(Json&& value) + : value_(std::forward<Json>(value)) + { + } + + stack_item() = default; + stack_item(const stack_item&) = default; + stack_item(stack_item&&) = default; + stack_item& operator=(const stack_item&) = default; + stack_item& operator=(stack_item&&) = default; + + key_storage_type name_; + Json value_; + }; + + struct structure_offset + { + size_t offset_; + bool is_object_; + }; + + typedef Allocator allocator_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<stack_item> stack_item_allocator_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<structure_offset> size_t_allocator_type; + + + std::vector<stack_item,stack_item_allocator_type> stack_; + std::vector<structure_offset,size_t_allocator_type> stack_offsets_; + bool is_valid_; + +public: + json_decoder(const json_allocator_type& jallocator = json_allocator_type()) + : string_allocator_(jallocator), + object_allocator_(jallocator), + array_allocator_(jallocator), + is_valid_(false) + + { + stack_offsets_.reserve(100); + stack_.reserve(1000); + } + + bool is_valid() const + { + return is_valid_; + } + + Json get_result() + { + is_valid_ = false; + return std::move(result_); + } + +#if !defined(JSONCONS_NO_DEPRECATED) + Json& root() + { + return result_; + } +#endif + +private: + + void push_object() + { + if (stack_offsets_.back().is_object_) + { + stack_.back().value_ = Json(object(object_allocator_)); + } + else + { + stack_.push_back(Json(object(object_allocator_))); + } + stack_offsets_.push_back({stack_.size()-1,true}); + } + + void pop_object() + { + stack_.erase(stack_.begin()+stack_offsets_.back().offset_+1, stack_.end()); + stack_offsets_.pop_back(); + } + + void push_array() + { + if (stack_offsets_.back().is_object_) + { + stack_.back().value_ = Json(array(array_allocator_)); + } + else + { + stack_.push_back(Json(array(array_allocator_))); + } + stack_offsets_.push_back({stack_.size()-1,false}); + } + + void pop_array() + { + stack_.erase(stack_.begin()+stack_offsets_.back().offset_+1, stack_.end()); + stack_offsets_.pop_back(); + } + + void do_begin_json() override + { + stack_offsets_.clear(); + stack_.clear(); + stack_offsets_.push_back({0,false}); + is_valid_ = false; + } + + void do_end_json() override + { + if (stack_.size() == 1) + { + result_.swap(stack_.front().value_); + stack_.pop_back(); + is_valid_ = true; + } + } + + void do_begin_object(const parsing_context&) override + { + push_object(); + } + + void do_end_object(const parsing_context&) override + { + end_structure(); + pop_object(); + } + + void do_begin_array(const parsing_context&) override + { + push_array(); + } + + void do_end_array(const parsing_context&) override + { + end_structure(); + pop_array(); + } + + void end_structure() + { + JSONCONS_ASSERT(stack_offsets_.size() > 0); + const size_t structure_index = stack_offsets_.back().offset_; + JSONCONS_ASSERT(stack_.size() > structure_index); + const size_t count = stack_.size() - (structure_index + 1); + + auto first = stack_.begin() + (structure_index+1); + auto last = first + count; + if (stack_offsets_.back().is_object_) + { + stack_[structure_index].value_.object_value().insert( + std::make_move_iterator(first), + std::make_move_iterator(last), + [](stack_item&& val){return key_value_pair_type(std::move(val.name_),std::move(val.value_));}); + } + else + { + auto& j = stack_[structure_index].value_; + j.reserve(count); + while (first != last) + { + j.push_back(std::move(first->value_)); + ++first; + } + } + } + + void do_name(const string_view_type& name, const parsing_context&) override + { + stack_.push_back(key_storage_type(name.begin(),name.end(),string_allocator_)); + } + + void do_string_value(const string_view_type& val, const parsing_context&) override + { + if (stack_offsets_.back().is_object_) + { + stack_.back().value_ = Json(val.data(),val.length(),string_allocator_); + } + else + { + stack_.push_back(Json(val.data(),val.length(),string_allocator_)); + } + } + + void do_byte_string_value(const uint8_t* data, size_t length, const parsing_context&) override + { + if (stack_offsets_.back().is_object_) + { + stack_.back().value_ = Json(data,length,string_allocator_); + } + else + { + stack_.push_back(Json(data,length,string_allocator_)); + } + } + + void do_integer_value(int64_t value, const parsing_context&) override + { + if (stack_offsets_.back().is_object_) + { + stack_.back().value_ = value; + } + else + { + stack_.push_back(Json(value)); + } + } + + void do_uinteger_value(uint64_t value, const parsing_context&) override + { + if (stack_offsets_.back().is_object_) + { + stack_.back().value_ = value; + } + else + { + stack_.push_back(Json(value)); + } + } + + void do_double_value(double value, const number_format& fmt, const parsing_context&) override + { + if (stack_offsets_.back().is_object_) + { + stack_.back().value_ = Json(value,fmt); + } + else + { + stack_.push_back(Json(value,fmt)); + } + } + + void do_bool_value(bool value, const parsing_context&) override + { + if (stack_offsets_.back().is_object_) + { + stack_.back().value_ = value; + } + else + { + stack_.push_back(Json(value)); + } + } + + void do_null_value(const parsing_context&) override + { + if (stack_offsets_.back().is_object_) + { + stack_.back().value_ = Json::null(); + } + else + { + stack_.push_back(Json(Json::null())); + } + } +}; + +} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/json_deserializer.hpp b/vendor/jsoncons-0.104.0/jsoncons/json_deserializer.hpp new file mode 100644 index 00000000..05b44a40 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/json_deserializer.hpp @@ -0,0 +1,12 @@ +// Copyright 2013-2016 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_DESERIALIZER_HPP +#define JSONCONS_JSON_DESERIALIZER_HPP + +#include <jsoncons/json_decoder.hpp> + +#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons/json_error_category.hpp b/vendor/jsoncons-0.104.0/jsoncons/json_error_category.hpp index 90d12d56..c09b847a 100644 --- a/vendor/jsoncons-0.99.2/jsoncons/json_error_category.hpp +++ b/vendor/jsoncons-0.104.0/jsoncons/json_error_category.hpp @@ -4,39 +4,47 @@ // See https://github.com/danielaparker/jsoncons for latest version -#ifndef JSONCONS_JSON_TEXT_ERROR_CATEGORY_HPP -#define JSONCONS_JSON_TEXT_ERROR_CATEGORY_HPP +#ifndef JSONCONS_JSON_ERROR_CATEGORY_HPP +#define JSONCONS_JSON_ERROR_CATEGORY_HPP -#include "jsoncons/jsoncons.hpp" #include <system_error> +#include <jsoncons/jsoncons_config.hpp> namespace jsoncons { -namespace json_parser_errc -{ - const int unexpected_eof = 1; - const int invalid_json_text = 2; - const int extra_character = 3; - const int max_depth_exceeded = 4; - const int single_quote = 5; - const int illegal_character_in_string = 6; - const int extra_comma = 7; - const int expected_name = 8; - const int expected_value = 9; - const int invalid_value = 10; - const int expected_colon = 11; - const int illegal_control_character = 12; - const int illegal_escaped_character = 13; - const int expected_codepoint_surrogate_pair = 14; - const int invalid_hex_escape_sequence = 15; - const int invalid_unicode_escape_sequence = 16; - const int leading_zero = 17; - const int invalid_number = 18; - const int expected_comma_or_right_brace = 19; - const int expected_comma_or_right_bracket = 20; - const int unexpected_right_bracket = 21; - const int unexpected_right_brace = 22; -} + enum class json_parser_errc + { + ok = 0, + unexpected_eof = 1, + source_error, + invalid_json_text, + extra_character, + max_depth_exceeded, + single_quote, + illegal_character_in_string, + extra_comma, + expected_name, + expected_value, + invalid_value, + expected_colon, + illegal_control_character, + illegal_escaped_character, + expected_codepoint_surrogate_pair, + invalid_hex_escape_sequence, + invalid_unicode_escape_sequence, + leading_zero, + invalid_number, + expected_comma_or_right_brace, + expected_comma_or_right_bracket, + unexpected_right_bracket, + unexpected_right_brace, + illegal_comment, + expected_continuation_byte, + over_long_utf8_sequence, + illegal_codepoint, + illegal_surrogate_value, + unpaired_high_surrogate + }; class json_error_category_impl : public std::error_category @@ -44,14 +52,16 @@ class json_error_category_impl public: virtual const char* name() const JSONCONS_NOEXCEPT { - return "json"; + return "jsoncons"; } virtual std::string message(int ev) const { - switch (ev) + switch (static_cast<json_parser_errc>(ev)) { case json_parser_errc::unexpected_eof: return "Unexpected end of file"; + case json_parser_errc::source_error: + return "Source error"; case json_parser_errc::invalid_json_text: return "Invalid JSON text"; case json_parser_errc::extra_character: @@ -94,7 +104,19 @@ public: return "Unexpected right brace '}'"; case json_parser_errc::unexpected_right_bracket: return "Unexpected right bracket ']'"; - default: + case json_parser_errc::illegal_comment: + return "Illegal comment"; + case json_parser_errc::expected_continuation_byte: + return "Expected continuation byte"; + case json_parser_errc::over_long_utf8_sequence: + return "Over long UTF-8 sequence"; + case json_parser_errc::illegal_codepoint: + return "Illegal codepoint (>= 0xd800 && <= 0xdfff)"; + case json_parser_errc::illegal_surrogate_value: + return "UTF-16 surrogate values are illegal in UTF-32"; + case json_parser_errc::unpaired_high_surrogate: + return "Expected low surrogate following the high surrogate"; + default: return "Unknown JSON parser error"; } } @@ -107,5 +129,20 @@ const std::error_category& json_error_category() return instance; } +inline +std::error_code make_error_code(json_parser_errc result) +{ + return std::error_code(static_cast<int>(result),json_error_category()); } + + +} + +namespace std { + template<> + struct is_error_code_enum<jsoncons::json_parser_errc> : public true_type + { + }; +} + #endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/json_exception.hpp b/vendor/jsoncons-0.104.0/jsoncons/json_exception.hpp new file mode 100644 index 00000000..668fa3c5 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/json_exception.hpp @@ -0,0 +1,107 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSON_EXCEPTION_HPP +#define JSON_EXCEPTION_HPP + +#include <locale> +#include <string> +#include <vector> +#include <cstdlib> +#include <cwchar> +#include <cstdint> +#include <iostream> +#include <vector> +#include <iterator> +#include <jsoncons/detail/unicode_traits.hpp> +#include <jsoncons/jsoncons_config.hpp> + +namespace jsoncons { + +// json_exception + +class json_exception +{ +public: + virtual const char* what() const JSONCONS_NOEXCEPT = 0; +}; + +template <class Base> +class json_exception_impl : public Base, public virtual json_exception +{ +public: + json_exception_impl(const std::string& s) JSONCONS_NOEXCEPT + : Base(""), message_(s) + { + } + ~json_exception_impl() JSONCONS_NOEXCEPT + { + } + const char* what() const JSONCONS_NOEXCEPT override + { + return message_.c_str(); + } +private: + std::string message_; +}; + +class key_not_found : public std::out_of_range, public virtual json_exception +{ +public: + template <class CharT> + explicit key_not_found(const CharT* key, size_t length) JSONCONS_NOEXCEPT + : std::out_of_range("") + { + buffer_.append("Key '"); + unicons::convert(key, key+length, std::back_inserter(buffer_), + unicons::conv_flags::strict); + buffer_.append("' not found"); + } + ~key_not_found() JSONCONS_NOEXCEPT + { + } + const char* what() const JSONCONS_NOEXCEPT override + { + return buffer_.c_str(); + } +private: + std::string buffer_; +}; + +class not_an_object : public std::runtime_error, public virtual json_exception +{ +public: + template <class CharT> + explicit not_an_object(const CharT* key, size_t length) JSONCONS_NOEXCEPT + : std::runtime_error("") + { + buffer_.append("Attempting to access or modify '"); + unicons::convert(key, key+length, std::back_inserter(buffer_), + unicons::conv_flags::strict); + buffer_.append("' on a value that is not an object"); + } + ~not_an_object() JSONCONS_NOEXCEPT + { + } + const char* what() const JSONCONS_NOEXCEPT override + { + return buffer_.c_str(); + } +private: + std::string buffer_; +}; + +#define JSONCONS_STR2(x) #x +#define JSONCONS_STR(x) JSONCONS_STR2(x) + +#define JSONCONS_ASSERT(x) if (!(x)) { \ + throw jsoncons::json_exception_impl<std::runtime_error>("assertion '" #x "' failed at " __FILE__ ":" \ + JSONCONS_STR(__LINE__)); } + +#define JSONCONS_THROW(x) throw (x) + +} +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/json_filter.hpp b/vendor/jsoncons-0.104.0/jsoncons/json_filter.hpp new file mode 100644 index 00000000..30b69e18 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/json_filter.hpp @@ -0,0 +1,465 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_FILTER_HPP +#define JSONCONS_JSON_FILTER_HPP + +#include <string> + +#include <jsoncons/json_input_handler.hpp> +#include <jsoncons/json_output_handler.hpp> +#include <jsoncons/parse_error_handler.hpp> + +namespace jsoncons { + +template <class CharT> +class basic_json_output_input_adapter : public basic_json_input_handler<CharT> +{ +public: + using typename basic_json_input_handler<CharT>::string_view_type; +private: + + basic_null_json_output_handler<CharT> null_output_handler_; + basic_json_output_handler<CharT>& output_handler_; + + // noncopyable and nonmoveable + basic_json_output_input_adapter<CharT>(const basic_json_output_input_adapter<CharT>&) = delete; + basic_json_output_input_adapter<CharT>& operator=(const basic_json_output_input_adapter<CharT>&) = delete; + +public: + basic_json_output_input_adapter() + : output_handler_(null_output_handler_) + { + } + + basic_json_output_input_adapter(basic_json_output_handler<CharT>& handler) + : output_handler_(handler) + { + } + +private: + + void do_begin_json() override + { + output_handler_.begin_json(); + } + + void do_end_json() override + { + output_handler_.end_json(); + } + + void do_begin_object(const parsing_context&) override + { + output_handler_.begin_object(); + } + + void do_begin_object(size_t length, const parsing_context&) override + { + output_handler_.begin_object(length); + } + + void do_end_object(const parsing_context&) override + { + output_handler_.end_object(); + } + + void do_begin_array(const parsing_context&) override + { + output_handler_.begin_array(); + } + + void do_begin_array(size_t length, const parsing_context&) override + { + output_handler_.begin_array(length); + } + + void do_end_array(const parsing_context&) override + { + output_handler_.end_array(); + } + + void do_name(const string_view_type& name, + const parsing_context&) override + { + output_handler_.name(name); + } + + void do_string_value(const string_view_type& value, + const parsing_context&) override + { + output_handler_.string_value(value); + } + + void do_byte_string_value(const uint8_t* data, size_t length, + const parsing_context&) override + { + output_handler_.byte_string_value(data, length); + } + + void do_integer_value(int64_t value, const parsing_context&) override + { + output_handler_.integer_value(value); + } + + void do_uinteger_value(uint64_t value, + const parsing_context&) override + { + output_handler_.uinteger_value(value); + } + + void do_double_value(double value, const number_format& fmt, const parsing_context&) override + { + output_handler_.double_value(value, fmt); + } + + void do_bool_value(bool value, const parsing_context&) override + { + output_handler_.bool_value(value); + } + + void do_null_value(const parsing_context&) override + { + output_handler_.null_value(); + } +}; + +template <class CharT> +class basic_json_input_output_adapter : public basic_json_output_handler<CharT> +{ +public: + using typename basic_json_output_handler<CharT>::string_view_type ; +private: + class null_parsing_context : public parsing_context + { + size_t do_line_number() const override { return 0; } + + size_t do_column_number() const override { return 0; } + }; + const null_parsing_context default_context_ = null_parsing_context(); + + basic_null_json_input_handler<CharT> null_input_handler_; + basic_json_output_input_adapter<CharT> default_input_output_adapter_; + basic_json_input_handler<CharT>& input_handler_; + const basic_json_output_input_adapter<CharT>& input_output_adapter_; + + // noncopyable and nonmoveable + basic_json_input_output_adapter<CharT>(const basic_json_input_output_adapter<CharT>&) = delete; + basic_json_input_output_adapter<CharT>& operator=(const basic_json_input_output_adapter<CharT>&) = delete; + +public: + basic_json_input_output_adapter() + : input_handler_(null_input_handler_), + input_output_adapter_(default_input_output_adapter_) + { + } + basic_json_input_output_adapter(basic_json_input_handler<CharT>& input_handler) + : input_handler_(input_handler), + input_output_adapter_(default_input_output_adapter_) + { + } + basic_json_input_output_adapter(basic_json_input_handler<CharT>& input_handler, + const basic_json_output_input_adapter<CharT>& input_output_adapter) + : input_handler_(input_handler), + input_output_adapter_(input_output_adapter) + { + } + +private: + + void do_begin_json() override + { + input_handler_.begin_json(); + } + + void do_end_json() override + { + input_handler_.end_json(); + } + + void do_begin_object() override + { + input_handler_.begin_object(default_context_); + } + + void do_begin_object(size_t length) override + { + input_handler_.begin_object(length, default_context_); + } + + void do_end_object() override + { + input_handler_.end_object(default_context_); + } + + void do_begin_array() override + { + input_handler_.begin_array(default_context_); + } + + void do_begin_array(size_t length) override + { + input_handler_.begin_array(length, default_context_); + } + + void do_end_array() override + { + input_handler_.end_array(default_context_); + } + + void do_name(const string_view_type& name) override + { + input_handler_.name(name, default_context_); + } + + void do_string_value(const string_view_type& value) override + { + input_handler_.string_value(value, default_context_); + } + + void do_byte_string_value(const uint8_t* data, size_t length) override + { + input_handler_.byte_string_value(data, length, default_context_); + } + + void do_integer_value(int64_t value) override + { + input_handler_.integer_value(value, default_context_); + } + + void do_uinteger_value(uint64_t value) override + { + input_handler_.uinteger_value(value, default_context_); + } + + void do_double_value(double value, const number_format& fmt) override + { + input_handler_.double_value(value, fmt, default_context_); + } + + void do_bool_value(bool value) override + { + input_handler_.bool_value(value, default_context_); + } + + void do_null_value() override + { + input_handler_.null_value(default_context_); + } +}; + +template <class CharT> +class basic_json_filter : public basic_json_input_handler<CharT> +{ +public: + using typename basic_json_input_handler<CharT>::string_view_type ; +private: + basic_json_output_input_adapter<CharT> input_output_adapter_; + basic_json_input_output_adapter<CharT> output_input_adapter_; + basic_json_output_handler<CharT>& output_handler_; + basic_json_input_handler<CharT>& downstream_handler_; + + // noncopyable and nonmoveable + basic_json_filter<CharT>(const basic_json_filter<CharT>&) = delete; + basic_json_filter<CharT>& operator=(const basic_json_filter<CharT>&) = delete; +public: + basic_json_filter(basic_json_output_handler<CharT>& handler) + : input_output_adapter_(handler), + output_input_adapter_(*this), + output_handler_(output_input_adapter_), + downstream_handler_(input_output_adapter_) + { + } + + basic_json_filter(basic_json_input_handler<CharT>& handler) + : output_input_adapter_(*this), + output_handler_(output_input_adapter_), + downstream_handler_(handler) + { + } + + operator basic_json_output_handler<CharT>&() + { + return output_handler_; + } + +#if !defined(JSONCONS_NO_DEPRECATED) + basic_json_input_handler<CharT>& input_handler() + { + return downstream_handler_; + } +#endif + + basic_json_input_handler<CharT>& downstream_handler() + { + return downstream_handler_; + } + +private: + void do_begin_json() override + { + downstream_handler_.begin_json(); + } + + void do_end_json() override + { + downstream_handler_.end_json(); + } + + void do_begin_object(const parsing_context& context) override + { + downstream_handler_.begin_object(context); + } + + void do_begin_object(size_t length, const parsing_context& context) override + { + downstream_handler_.begin_object(length, context); + } + + void do_end_object(const parsing_context& context) override + { + downstream_handler_.end_object(context); + } + + void do_begin_array(const parsing_context& context) override + { + downstream_handler_.begin_array(context); + } + + void do_begin_array(size_t length, const parsing_context& context) override + { + downstream_handler_.begin_array(length, context); + } + + void do_end_array(const parsing_context& context) override + { + downstream_handler_.end_array(context); + } + + void do_name(const string_view_type& name, + const parsing_context& context) override + { + downstream_handler_.name(name,context); + } + + void do_string_value(const string_view_type& value, + const parsing_context& context) override + { + downstream_handler_.string_value(value,context); + } + + void do_byte_string_value(const uint8_t* data, size_t length, + const parsing_context& context) override + { + downstream_handler_.byte_string_value(data, length, context); + } + + void do_double_value(double value, const number_format& fmt, + const parsing_context& context) override + { + downstream_handler_.double_value(value, fmt, context); + } + + void do_integer_value(int64_t value, + const parsing_context& context) override + { + downstream_handler_.integer_value(value,context); + } + + void do_uinteger_value(uint64_t value, + const parsing_context& context) override + { + downstream_handler_.uinteger_value(value,context); + } + + void do_bool_value(bool value, + const parsing_context& context) override + { + downstream_handler_.bool_value(value,context); + } + + void do_null_value(const parsing_context& context) override + { + downstream_handler_.null_value(context); + } + +}; + +// Filters out begin_json and end_json events +template <class CharT> +class basic_json_fragment_filter : public basic_json_filter<CharT> +{ +public: + using typename basic_json_filter<CharT>::string_view_type; + + basic_json_fragment_filter(basic_json_input_handler<CharT>& handler) + : basic_json_filter<CharT>(handler) + { + } +private: + void do_begin_json() override + { + } + + void do_end_json() override + { + } +}; + +template <class CharT> +class basic_rename_object_member_filter : public basic_json_filter<CharT> +{ +public: + using typename basic_json_filter<CharT>::string_view_type; + +private: + std::basic_string<CharT> name_; + std::basic_string<CharT> new_name_; +public: + basic_rename_object_member_filter(const std::basic_string<CharT>& name, + const std::basic_string<CharT>& new_name, + basic_json_output_handler<CharT>& handler) + : basic_json_filter<CharT>(handler), + name_(name), new_name_(new_name) + { + } + + basic_rename_object_member_filter(const std::basic_string<CharT>& name, + const std::basic_string<CharT>& new_name, + basic_json_input_handler<CharT>& handler) + : basic_json_filter<CharT>(handler), + name_(name), new_name_(new_name) + { + } + +private: + void do_name(const string_view_type& name, + const parsing_context& context) override + { + if (name == name_) + { + this->downstream_handler().name(new_name_,context); + } + else + { + this->downstream_handler().name(name,context); + } + } +}; + +typedef basic_json_filter<char> json_filter; +typedef basic_json_filter<wchar_t> wjson_filter; +typedef basic_rename_object_member_filter<char> rename_object_member_filter; +typedef basic_rename_object_member_filter<wchar_t> wrename_object_member_filter; + +#if !defined(JSONCONS_NO_DEPRECATED) +typedef basic_rename_object_member_filter<char> rename_name_filter; +typedef basic_rename_object_member_filter<wchar_t> wrename_name_filter; +#endif + +} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/json_input_handler.hpp b/vendor/jsoncons-0.104.0/jsoncons/json_input_handler.hpp new file mode 100644 index 00000000..ed014287 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/json_input_handler.hpp @@ -0,0 +1,308 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_INPUT_HANDLER_HPP +#define JSONCONS_JSON_INPUT_HANDLER_HPP + +#include <string> +#include <jsoncons/json_exception.hpp> +#include <jsoncons/jsoncons_utilities.hpp> +#if !defined(JSONCONS_NO_DEPRECATED) +#include <jsoncons/json_type_traits.hpp> // for null_type +#endif + +namespace jsoncons { + +class parsing_context; + +template <class CharT> +class basic_json_input_handler +{ +public: + typedef CharT char_type; + typedef std::char_traits<char_type> char_traits_type; + + typedef basic_string_view_ext<char_type,char_traits_type> string_view_type; + + virtual ~basic_json_input_handler() {} + + void begin_json() + { + do_begin_json(); + } + + void end_json() + { + do_end_json(); + } + + void begin_object(const parsing_context& context) + { + do_begin_object(context); + } + + void begin_object(size_t length, const parsing_context& context) + { + do_begin_object(length, context); + } + + void end_object(const parsing_context& context) + { + do_end_object(context); + } + + void begin_array(const parsing_context& context) + { + do_begin_array(context); + } + + void begin_array(size_t length, const parsing_context& context) + { + do_begin_array(length, context); + } + + void end_array(const parsing_context& context) + { + do_end_array(context); + } + + void name(const string_view_type& name, const parsing_context& context) + { + do_name(name, context); + } + +// new + + void string_value(const string_view_type& value, const parsing_context& context) + { + do_string_value(value, context); + } + + void byte_string_value(const uint8_t* data, size_t length, const parsing_context& context) + { + do_byte_string_value(data, length, context); + } + + void integer_value(int64_t value, const parsing_context& context) + { + do_integer_value(value,context); + } + + void uinteger_value(uint64_t value, const parsing_context& context) + { + do_uinteger_value(value,context); + } + + void double_value(double value, const parsing_context& context) + { + do_double_value(value, number_format(), context); + } + + void double_value(double value, uint8_t precision, const parsing_context& context) + { + do_double_value(value, number_format(precision, 0), context); + } + + void double_value(double value, const number_format& fmt, const parsing_context& context) + { + do_double_value(value, fmt, context); + } + + void bool_value(bool value, const parsing_context& context) + { + do_bool_value(value,context); + } + + void null_value(const parsing_context& context) + { + do_null_value(context); + } + +#if !defined(JSONCONS_NO_DEPRECATED) + + void name(const CharT* p, size_t length, const parsing_context& context) + { + do_name(string_view_type(p, length), context); + } + + void value(const std::basic_string<CharT>& value, const parsing_context& context) + { + do_string_value(value, context); + } + + void value(const CharT* p, size_t length, const parsing_context& context) + { + do_string_value(string_view_type(p, length), context); + } + + void value(const CharT* p, const parsing_context& context) + { + do_string_value(string_view_type(p), context); + } + + void value(int value, const parsing_context& context) + { + do_integer_value(value,context); + } + + void value(long value, const parsing_context& context) + { + do_integer_value(value,context); + } + + void value(long long value, const parsing_context& context) + { + do_integer_value(value,context); + } + + void value(unsigned int value, const parsing_context& context) + { + do_uinteger_value(value,context); + } + + void value(unsigned long value, const parsing_context& context) + { + do_uinteger_value(value,context); + } + + void value(unsigned long long value, const parsing_context& context) + { + do_uinteger_value(value,context); + } + + void value(float value, uint8_t precision, const parsing_context& context) + { + do_double_value(value, number_format(precision, 0), context); + } + + void value(double value, uint8_t precision, const parsing_context& context) + { + do_double_value(value, number_format(precision, 0), context); + } + + void value(bool value, const parsing_context& context) + { + do_bool_value(value,context); + } + + void value(null_type, const parsing_context& context) + { + do_null_value(context); + } +#endif + +private: + virtual void do_begin_json() = 0; + + virtual void do_end_json() = 0; + + virtual void do_begin_object(const parsing_context& context) = 0; + + virtual void do_begin_object(size_t length, const parsing_context& context) + { + do_begin_object(context); + } + + virtual void do_end_object(const parsing_context& context) = 0; + + virtual void do_begin_array(const parsing_context& context) = 0; + + virtual void do_begin_array(size_t length, const parsing_context& context) + { + do_begin_array(context); + } + + virtual void do_end_array(const parsing_context& context) = 0; + + virtual void do_name(const string_view_type& name, const parsing_context& context) = 0; + + virtual void do_null_value(const parsing_context& context) = 0; + + virtual void do_string_value(const string_view_type& value, const parsing_context& context) = 0; + + virtual void do_byte_string_value(const uint8_t* data, size_t length, const parsing_context& context) = 0; + + virtual void do_double_value(double value, const number_format& fmt, const parsing_context& context) = 0; + + virtual void do_integer_value(int64_t value, const parsing_context& context) = 0; + + virtual void do_uinteger_value(uint64_t value, const parsing_context& context) = 0; + + virtual void do_bool_value(bool value, const parsing_context& context) = 0; +}; + +template <class CharT> +class basic_null_json_input_handler final : public basic_json_input_handler<CharT> +{ +public: + using typename basic_json_input_handler<CharT>::string_view_type ; +private: + void do_begin_json() override + { + } + + void do_end_json() override + { + } + + void do_begin_object(const parsing_context&) override + { + } + + void do_end_object(const parsing_context&) override + { + } + + void do_begin_array(const parsing_context&) override + { + } + + void do_end_array(const parsing_context&) override + { + } + + void do_name(const string_view_type&, const parsing_context&) override + { + } + + void do_null_value(const parsing_context&) override + { + } + + void do_string_value(const string_view_type&, const parsing_context&) override + { + } + + void do_byte_string_value(const uint8_t* data, size_t length, const parsing_context&) override + { + } + + void do_double_value(double, const number_format& fmt, const parsing_context&) override + { + } + + void do_integer_value(int64_t, const parsing_context&) override + { + } + + void do_uinteger_value(uint64_t, const parsing_context&) override + { + } + + void do_bool_value(bool, const parsing_context&) override + { + } +}; + +typedef basic_json_input_handler<char> json_input_handler; +typedef basic_json_input_handler<wchar_t> wjson_input_handler; + +typedef basic_null_json_input_handler<char> null_json_input_handler; +typedef basic_null_json_input_handler<wchar_t> wnull_json_input_handler; + +} + +#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons/json_output_handler.hpp b/vendor/jsoncons-0.104.0/jsoncons/json_output_handler.hpp index d0f3de8f..b16f098e 100644 --- a/vendor/jsoncons-0.99.2/jsoncons/json_output_handler.hpp +++ b/vendor/jsoncons-0.104.0/jsoncons/json_output_handler.hpp @@ -8,50 +8,23 @@ #define JSONCONS_JSON_OUTPUT_HANDLER_HPP #include <string> -#include "jsoncons/jsoncons.hpp" +#include <jsoncons/json_exception.hpp> +#include <jsoncons/jsoncons_utilities.hpp> +#if !defined(JSONCONS_NO_DEPRECATED) +#include <jsoncons/json_type_traits.hpp> // for null_type +#endif namespace jsoncons { -template<typename CharT> -void print_integer(int64_t value, buffered_ostream<CharT>& os) -{ - CharT buf[255]; - uint64_t u = (value < 0) ? static_cast<uint64_t>(-value) : static_cast<uint64_t>(value); - CharT* p = buf; - do - { - *p++ = static_cast<CharT>(48 + u%10); - } - while (u /= 10); - if (value < 0) - { - os.put('-'); - } - while (--p >= buf) - { - os.put(*p); - } -} - -template<typename CharT> -void print_uinteger(uint64_t value, buffered_ostream<CharT>& os) -{ - CharT buf[255]; - CharT* p = buf; - do - { - *p++ = static_cast<CharT>(48 + value % 10); - } while (value /= 10); - while (--p >= buf) - { - os.put(*p); - } -} - -template <typename CharT> +template <class CharT> class basic_json_output_handler { public: + typedef CharT char_type; + typedef std::char_traits<char_type> char_traits_type; + + typedef basic_string_view_ext<char_type,char_traits_type> string_view_type; + virtual ~basic_json_output_handler() {} // Overloaded methods @@ -71,6 +44,11 @@ public: do_begin_object(); } + void begin_object(size_t length) + { + do_begin_object(length); + } + void end_object() { do_end_object(); @@ -81,34 +59,86 @@ public: do_begin_array(); } + void begin_array(size_t length) + { + do_begin_array(length); + } + void end_array() { do_end_array(); } - void name(const std::basic_string<CharT>& name) + void name(const string_view_type& name) + { + do_name(name); + } + + void string_value(const string_view_type& value) + { + do_string_value(value); + } + + void byte_string_value(const uint8_t* data, size_t length) { - do_name(name.data(), name.length()); + do_byte_string_value(data, length); } + void integer_value(int64_t value) + { + do_integer_value(value); + } + + void uinteger_value(uint64_t value) + { + do_uinteger_value(value); + } + + void double_value(double value) + { + do_double_value(value, number_format()); + } + + void double_value(double value, uint8_t precision) + { + do_double_value(value, number_format(precision, 0)); + } + + void double_value(double value, const number_format& fmt) + { + do_double_value(value, fmt); + } + + void bool_value(bool value) + { + do_bool_value(value); + } + + void null_value() + { + do_null_value(); + } + +#if !defined(JSONCONS_NO_DEPRECATED) + void name(const CharT* p, size_t length) { - do_name(p, length); + do_name(string_view_type(p, length)); } - void value(const std::basic_string<CharT>& value) + void value(const string_view_type& value) { - do_string_value(value.data(), value.length()); + do_string_value(value); } void value(const CharT* p, size_t length) { - do_string_value(p, length); + do_string_value(string_view_type(p, length)); } void value(const CharT* p) { - do_string_value(p, std::char_traits<CharT>::length(p)); + do_string_value(string_view_type(p)); } void value(int value) @@ -141,9 +171,9 @@ public: do_uinteger_value(value); } - void value(double value, uint8_t precision = 0) + void value(double value, uint8_t precision = 0, uint8_t decimal_places = 0) { - do_double_value(value, precision); + do_double_value(value, precision, decimal_places); } void value(bool value) @@ -155,6 +185,7 @@ public: { do_null_value(); } +#endif private: @@ -162,21 +193,33 @@ private: virtual void do_end_json() = 0; - virtual void do_name(const CharT* name, size_t length) = 0; + virtual void do_name(const string_view_type& name) = 0; virtual void do_begin_object() = 0; + virtual void do_begin_object(size_t length) + { + do_begin_object(); + } + virtual void do_end_object() = 0; virtual void do_begin_array() = 0; + virtual void do_begin_array(size_t length) + { + do_begin_array(); + } + virtual void do_end_array() = 0; virtual void do_null_value() = 0; - virtual void do_string_value(const CharT* value, size_t length) = 0; + virtual void do_string_value(const string_view_type& value) = 0; + + virtual void do_byte_string_value(const uint8_t* data, size_t length) = 0; - virtual void do_double_value(double value, uint8_t precision) = 0; + virtual void do_double_value(double value, const number_format& fmt) = 0; virtual void do_integer_value(int64_t value) = 0; @@ -185,9 +228,11 @@ private: virtual void do_bool_value(bool value) = 0; }; -template <typename CharT> -class null_json_output_handler_impl : public basic_json_output_handler<CharT> +template <class CharT> +class basic_null_json_output_handler : public basic_json_output_handler<CharT> { +public: + using typename basic_json_output_handler<CharT>::string_view_type ; private: void do_begin_json() override @@ -198,10 +243,8 @@ private: { } - void do_name(const CharT* name, size_t length) override + void do_name(const string_view_type&) override { - (void)name; - (void)length; } void do_begin_object() override @@ -224,13 +267,15 @@ private: { } - void do_string_value(const CharT* p, size_t length) override + void do_string_value(const string_view_type&) override { - (void)p; - (void)length; } - void do_double_value(double, uint8_t) override + void do_byte_string_value(const uint8_t* data, size_t length) override + { + } + + void do_double_value(double, const number_format&) override { } @@ -248,13 +293,6 @@ private: }; -template<typename CharT> -basic_json_output_handler<CharT>& null_json_output_handler() -{ - static null_json_output_handler_impl<CharT> instance; - return instance; -} - typedef basic_json_output_handler<char> json_output_handler; typedef basic_json_output_handler<wchar_t> wjson_output_handler; diff --git a/vendor/jsoncons-0.104.0/jsoncons/json_parser.hpp b/vendor/jsoncons-0.104.0/jsoncons/json_parser.hpp new file mode 100644 index 00000000..13bd9500 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/json_parser.hpp @@ -0,0 +1,2830 @@ +// Copyright 2015 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_PARSER_HPP +#define JSONCONS_JSON_PARSER_HPP + +#include <memory> +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <stdexcept> +#include <system_error> +#include <jsoncons/json_exception.hpp> +#include <jsoncons/json_input_handler.hpp> +#include <jsoncons/parse_error_handler.hpp> +#include <jsoncons/json_error_category.hpp> +#include <jsoncons/detail/number_parsers.hpp> + +#define JSONCONS_ILLEGAL_CONTROL_CHARACTER \ + case 0x00:case 0x01:case 0x02:case 0x03:case 0x04:case 0x05:case 0x06:case 0x07:case 0x08:case 0x0b: \ + case 0x0c:case 0x0e:case 0x0f:case 0x10:case 0x11:case 0x12:case 0x13:case 0x14:case 0x15:case 0x16: \ + case 0x17:case 0x18:case 0x19:case 0x1a:case 0x1b:case 0x1c:case 0x1d:case 0x1e:case 0x1f + +namespace jsoncons { + +enum class parse_state : uint8_t +{ + root, + start, + slash, + slash_slash, + slash_star, + slash_star_star, + expect_comma_or_end, + object, + expect_member_name_or_end, + expect_member_name, + expect_colon, + expect_value_or_end, + expect_value, + array, + string_u1, + member_name, + escape, + escape_u1, + escape_u2, + escape_u3, + escape_u4, + escape_expect_surrogate_pair1, + escape_expect_surrogate_pair2, + escape_u6, + escape_u7, + escape_u8, + escape_u9, + minus, + zero, + integer, + fraction1, + fraction2, + exp1, + exp2, + exp3, + n, + nu, + nul, + t, + tr, + tru, + f, + fa, + fal, + fals, + cr, + lf, + done +}; + +template <class CharT, class Allocator = std::allocator<char>> +class basic_json_parser : private parsing_context +{ + static const size_t initial_string_buffer_capacity_ = 1024; + static const size_t initial_number_buffer_capacity_ = 64; + static const int default_initial_stack_capacity_ = 100; + typedef typename basic_json_input_handler<CharT>::string_view_type string_view_type; + + basic_null_json_input_handler<CharT> default_input_handler_; + default_parse_error_handler default_err_handler_; + + basic_json_input_handler<CharT>& handler_; + parse_error_handler& err_handler_; + uint32_t cp_; + uint32_t cp2_; + + typedef Allocator allocator_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<CharT> char_allocator_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<char> numeral_allocator_type; + + std::basic_string<CharT,std::char_traits<CharT>,char_allocator_type> string_buffer_; + std::basic_string<char,std::char_traits<char>,numeral_allocator_type> number_buffer_; + + bool is_negative_; + uint8_t precision_; + uint8_t decimal_places_; + + size_t line_; + size_t column_; + int nesting_depth_; + int initial_stack_capacity_; + + int max_depth_; + detail::string_to_double to_double_; + const CharT* begin_input_; + const CharT* input_end_; + const CharT* input_ptr_; + + parse_state state_; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<parse_state> parse_state_allocator_type; + std::vector<parse_state,parse_state_allocator_type> state_stack_; + + // Noncopyable and nonmoveable + basic_json_parser(const basic_json_parser&) = delete; + basic_json_parser& operator=(const basic_json_parser&) = delete; + +public: + + basic_json_parser() + : handler_(default_input_handler_), + err_handler_(default_err_handler_), + cp_(0), + cp2_(0), + is_negative_(false), + precision_(0), + decimal_places_(0), + line_(1), + column_(1), + nesting_depth_(0), + initial_stack_capacity_(default_initial_stack_capacity_), + begin_input_(nullptr), + input_end_(nullptr), + input_ptr_(nullptr), + state_(parse_state::start) + { + string_buffer_.reserve(initial_string_buffer_capacity_); + number_buffer_.reserve(initial_number_buffer_capacity_); + max_depth_ = (std::numeric_limits<int>::max)(); + + state_stack_.reserve(initial_stack_capacity_); + push_state(parse_state::root); + } + + basic_json_parser(parse_error_handler& err_handler) + : handler_(default_input_handler_), + err_handler_(err_handler), + cp_(0), + cp2_(0), + is_negative_(false), + precision_(0), + decimal_places_(0), + line_(1), + column_(1), + nesting_depth_(0), + initial_stack_capacity_(default_initial_stack_capacity_), + begin_input_(nullptr), + input_end_(nullptr), + input_ptr_(nullptr), + state_(parse_state::start) + { + string_buffer_.reserve(initial_string_buffer_capacity_); + number_buffer_.reserve(initial_number_buffer_capacity_); + max_depth_ = (std::numeric_limits<int>::max)(); + + state_stack_.reserve(initial_stack_capacity_); + push_state(parse_state::root); + } + + basic_json_parser(basic_json_input_handler<CharT>& handler) + : handler_(handler), + err_handler_(default_err_handler_), + cp_(0), + cp2_(0), + is_negative_(false), + precision_(0), + decimal_places_(0), + line_(1), + column_(1), + nesting_depth_(0), + initial_stack_capacity_(default_initial_stack_capacity_), + begin_input_(nullptr), + input_end_(nullptr), + input_ptr_(nullptr), + state_(parse_state::start) + { + string_buffer_.reserve(initial_string_buffer_capacity_); + number_buffer_.reserve(initial_number_buffer_capacity_); + max_depth_ = (std::numeric_limits<int>::max)(); + + state_stack_.reserve(initial_stack_capacity_); + push_state(parse_state::root); + } + + basic_json_parser(basic_json_input_handler<CharT>& handler, + parse_error_handler& err_handler) + : handler_(handler), + err_handler_(err_handler), + cp_(0), + cp2_(0), + is_negative_(false), + precision_(0), + decimal_places_(0), + line_(1), + column_(1), + nesting_depth_(0), + initial_stack_capacity_(default_initial_stack_capacity_), + begin_input_(nullptr), + input_end_(nullptr), + input_ptr_(nullptr), + state_(parse_state::start) + { + string_buffer_.reserve(initial_string_buffer_capacity_); + number_buffer_.reserve(initial_number_buffer_capacity_); + max_depth_ = (std::numeric_limits<int>::max)(); + + state_stack_.reserve(initial_stack_capacity_); + push_state(parse_state::root); + } + + size_t line_number() const + { + return line_; + } + + size_t column_number() const + { + return column_; + } + + void set_column_number(size_t column) + { + column_ = column; + } + + bool source_exhausted() const + { + return input_ptr_ == input_end_; + } + + const parsing_context& parsing_context() const + { + return *this; + } + + ~basic_json_parser() + { + } + + size_t max_nesting_depth() const + { + return static_cast<size_t>(max_depth_); + } + + void max_nesting_depth(size_t max_nesting_depth) + { + max_depth_ = static_cast<int>((std::min)(max_nesting_depth,static_cast<size_t>((std::numeric_limits<int>::max)()))); + } + + parse_state parent() const + { + JSONCONS_ASSERT(state_stack_.size() >= 1); + return state_stack_.back(); + } + + bool done() const + { + return state_ == parse_state::done; + } + + void skip_whitespace() + { + const CharT* local_input_end = input_end_; + for (;;) + { + if (JSONCONS_UNLIKELY(input_ptr_ == local_input_end)) + { + return; + } + else if (*input_ptr_ == ' ' || *input_ptr_ == '\t') + { + ++input_ptr_; + ++column_; + } + else + { + return; + } + } + } + + void do_begin_object(std::error_code& ec) + { + if (++nesting_depth_ >= max_depth_) + { + if (err_handler_.error(json_parser_errc::max_depth_exceeded, *this)) + { + ec = json_parser_errc::max_depth_exceeded; + return; + } + } + push_state(parse_state::object); + state_ = parse_state::expect_member_name_or_end; + handler_.begin_object(*this); + } + + void do_end_object(std::error_code& ec) + { + --nesting_depth_; + state_ = pop_state(); + if (state_ == parse_state::object) + { + handler_.end_object(*this); + } + else if (state_ == parse_state::array) + { + err_handler_.fatal_error(json_parser_errc::expected_comma_or_right_bracket, *this); + ec = json_parser_errc::expected_comma_or_right_bracket; + return; + } + else + { + err_handler_.fatal_error(json_parser_errc::unexpected_right_brace, *this); + ec = json_parser_errc::unexpected_right_brace; + return; + } + + if (parent() == parse_state::root) + { + state_ = parse_state::done; + handler_.end_json(); + } + else + { + state_ = parse_state::expect_comma_or_end; + } + } + + void do_begin_array(std::error_code& ec) + { + if (++nesting_depth_ >= max_depth_) + { + if (err_handler_.error(json_parser_errc::max_depth_exceeded, *this)) + { + ec = json_parser_errc::max_depth_exceeded; + return; + } + + } + push_state(parse_state::array); + state_ = parse_state::expect_value_or_end; + handler_.begin_array(*this); + } + + void do_end_array(std::error_code& ec) + { + --nesting_depth_; + state_ = pop_state(); + if (state_ == parse_state::array) + { + handler_.end_array(*this); + } + else if (state_ == parse_state::object) + { + err_handler_.fatal_error(json_parser_errc::expected_comma_or_right_brace, *this); + ec = json_parser_errc::expected_comma_or_right_brace; + return; + } + else + { + err_handler_.fatal_error(json_parser_errc::unexpected_right_bracket, *this); + ec = json_parser_errc::unexpected_right_bracket; + return; + } + if (parent() == parse_state::root) + { + state_ = parse_state::done; + handler_.end_json(); + } + else + { + state_ = parse_state::expect_comma_or_end; + } + } + + void reset() + { + state_stack_.clear(); + state_stack_.reserve(initial_stack_capacity_); + push_state(parse_state::root); + state_ = parse_state::start; + line_ = 1; + column_ = 1; + nesting_depth_ = 0; + } + + void check_done() + { + std::error_code ec; + check_done(ec); + if (ec) + { + throw parse_error(ec,line_,column_); + } + } + + void check_done(std::error_code& ec) + { + if (state_ != parse_state::done) + { + if (err_handler_.error(json_parser_errc::unexpected_eof, *this)) + { + ec = json_parser_errc::unexpected_eof; + return; + } + } + for (; input_ptr_ != input_end_; ++input_ptr_) + { + CharT curr_char_ = *input_ptr_; + switch (curr_char_) + { + case '\n': + case '\r': + case '\t': + case ' ': + break; + default: + if (err_handler_.error(json_parser_errc::extra_character, *this)) + { + ec = json_parser_errc::extra_character; + return; + } + break; + } + } + } + + void parse_some(std::error_code& ec) + { + const CharT* local_input_end = input_end_; + + while ((input_ptr_ < local_input_end) && (state_ != parse_state::done)) + { + switch (state_) + { + case parse_state::cr: + ++line_; + column_ = 1; + switch (*input_ptr_) + { + case '\n': + state_ = pop_state(); + ++input_ptr_; + break; + default: + state_ = pop_state(); + break; + } + break; + case parse_state::lf: + ++line_; + column_ = 1; + state_ = pop_state(); + break; + case parse_state::start: + { + handler_.begin_json(); + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + if (err_handler_.error(json_parser_errc::illegal_control_character, *this)) + { + ec = json_parser_errc::illegal_control_character; + return; + } + break; + case '\r': + push_state(state_); + ++input_ptr_; + ++column_; + state_ = parse_state::cr; + break; + case '\n': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::lf; + break; + case ' ':case '\t': + skip_whitespace(); + break; + case '/': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::slash; + break; + case '{': + do_begin_object(ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + case '[': + do_begin_array(ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + case '\"': + state_ = parse_state::string_u1; + ++input_ptr_; + ++column_; + break; + case '-': + number_buffer_.clear(); + is_negative_ = true; + precision_ = 0; + ++input_ptr_; + ++column_; + state_ = parse_state::minus; + parse_number(ec); + if (ec) {return;} + break; + case '0': + number_buffer_.clear(); + is_negative_ = false; + precision_ = 1; + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + state_ = parse_state::zero; + ++input_ptr_; + ++column_; + parse_number(ec); + if (ec) {return;} + break; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + number_buffer_.clear(); + is_negative_ = false; + precision_ = 1; + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++input_ptr_; + ++column_; + state_ = parse_state::integer; + parse_number(ec); + if (ec) {return;} + break; + case 'n': + parse_null(ec); + if (ec) {return;} + break; + case 't': + parse_true(ec); + if (ec) {return;} + break; + case 'f': + parse_false(ec); + if (ec) {return;} + break; + case '}': + err_handler_.fatal_error(json_parser_errc::unexpected_right_brace, *this); + ec = json_parser_errc::unexpected_right_brace; + return; + case ']': + err_handler_.fatal_error(json_parser_errc::unexpected_right_bracket, *this); + ec = json_parser_errc::unexpected_right_bracket; + return; + default: + err_handler_.fatal_error(json_parser_errc::invalid_json_text, *this); + ec = json_parser_errc::invalid_json_text; + return; + } + } + break; + + case parse_state::expect_comma_or_end: + { + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + if (err_handler_.error(json_parser_errc::illegal_control_character, *this)) + { + ec = json_parser_errc::illegal_control_character; + return; + } + ++input_ptr_; + ++column_; + break; + case '\r': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::cr; + break; + case '\n': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::lf; + break; + case ' ':case '\t': + skip_whitespace(); + break; + case '/': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::slash; + break; + case '}': + do_end_object(ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + case ']': + do_end_array(ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + case ',': + begin_member_or_element(ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + default: + if (parent() == parse_state::array) + { + if (err_handler_.error(json_parser_errc::expected_comma_or_right_bracket, *this)) + { + ec = json_parser_errc::expected_comma_or_right_bracket; + return; + } + } + else if (parent() == parse_state::object) + { + if (err_handler_.error(json_parser_errc::expected_comma_or_right_brace, *this)) + { + ec = json_parser_errc::expected_comma_or_right_brace; + return; + } + } + ++input_ptr_; + ++column_; + break; + } + } + break; + case parse_state::expect_member_name_or_end: + { + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + if (err_handler_.error(json_parser_errc::illegal_control_character, *this)) + { + ec = json_parser_errc::illegal_control_character; + return; + } + ++input_ptr_; + ++column_; + break; + case '\r': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::cr; + break; + case '\n': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::lf; + break; + case ' ':case '\t': + skip_whitespace(); + break; + case '/': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::slash; + break; + case '}': + do_end_object(ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + case '\"': + ++input_ptr_; + ++column_; + push_state(parse_state::member_name); + state_ = parse_state::string_u1; + break; + case '\'': + if (err_handler_.error(json_parser_errc::single_quote, *this)) + { + ec = json_parser_errc::single_quote; + return; + } + ++input_ptr_; + ++column_; + break; + default: + if (err_handler_.error(json_parser_errc::expected_name, *this)) + { + ec = json_parser_errc::expected_name; + return; + } + ++input_ptr_; + ++column_; + break; + } + } + break; + case parse_state::expect_member_name: + { + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + if (err_handler_.error(json_parser_errc::illegal_control_character, *this)) + { + ec = json_parser_errc::illegal_control_character; + return; + } + ++input_ptr_; + ++column_; + break; + case '\r': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::cr; + break; + case '\n': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::lf; + break; + case ' ':case '\t': + skip_whitespace(); + break; + case '/': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::slash; + break; + case '\"': + ++input_ptr_; + ++column_; + push_state(parse_state::member_name); + state_ = parse_state::string_u1; + break; + case '}': + if (err_handler_.error(json_parser_errc::extra_comma, *this)) + { + ec = json_parser_errc::extra_comma; + return; + } + do_end_object(ec); // Recover + if (ec) return; + ++input_ptr_; + ++column_; + break; + case '\'': + if (err_handler_.error(json_parser_errc::single_quote, *this)) + { + ec = json_parser_errc::single_quote; + return; + } + ++input_ptr_; + ++column_; + break; + default: + if (err_handler_.error(json_parser_errc::expected_name, *this)) + { + ec = json_parser_errc::expected_name; + return; + } + ++input_ptr_; + ++column_; + break; + } + } + break; + case parse_state::expect_colon: + { + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + if (err_handler_.error(json_parser_errc::illegal_control_character, *this)) + { + ec = json_parser_errc::illegal_control_character; + return; + } + ++input_ptr_; + ++column_; + break; + case '\r': + push_state(state_); + state_ = parse_state::cr; + ++input_ptr_; + ++column_; + break; + case '\n': + push_state(state_); + state_ = parse_state::lf; + ++input_ptr_; + ++column_; + break; + case ' ':case '\t': + skip_whitespace(); + break; + case '/': + push_state(state_); + state_ = parse_state::slash; + ++input_ptr_; + ++column_; + break; + case ':': + state_ = parse_state::expect_value; + ++input_ptr_; + ++column_; + break; + default: + if (err_handler_.error(json_parser_errc::expected_colon, *this)) + { + ec = json_parser_errc::expected_colon; + return; + } + ++input_ptr_; + ++column_; + break; + } + } + break; + + case parse_state::expect_value: + { + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + if (err_handler_.error(json_parser_errc::illegal_control_character, *this)) + { + ec = json_parser_errc::illegal_control_character; + return; + } + ++input_ptr_; + ++column_; + break; + case '\r': + push_state(state_); + ++input_ptr_; + ++column_; + state_ = parse_state::cr; + break; + case '\n': + push_state(state_); + ++input_ptr_; + ++column_; + state_ = parse_state::lf; + break; + case ' ':case '\t': + skip_whitespace(); + break; + case '/': + push_state(state_); + ++input_ptr_; + ++column_; + state_ = parse_state::slash; + break; + case '{': + do_begin_object(ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + case '[': + do_begin_array(ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + case '\"': + ++input_ptr_; + ++column_; + state_ = parse_state::string_u1; + break; + case '-': + number_buffer_.clear(); + is_negative_ = true; + precision_ = 0; + ++input_ptr_; + ++column_; + state_ = parse_state::minus; + parse_number(ec); + if (ec) {return;} + break; + case '0': + number_buffer_.clear(); + is_negative_ = false; + precision_ = 1; + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++input_ptr_; + ++column_; + state_ = parse_state::zero; + parse_number(ec); + if (ec) {return;} + break; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + number_buffer_.clear(); + is_negative_ = false; + precision_ = 1; + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++input_ptr_; + ++column_; + state_ = parse_state::integer; + parse_number(ec); + if (ec) {return;} + break; + case 'n': + parse_null(ec); + if (ec) {return;} + break; + case 't': + parse_true(ec); + if (ec) {return;} + break; + case 'f': + parse_false(ec); + if (ec) {return;} + break; + case ']': + if (parent() == parse_state::array) + { + if (err_handler_.error(json_parser_errc::extra_comma, *this)) + { + ec = json_parser_errc::extra_comma; + return; + } + do_end_array(ec); // Recover + if (ec) return; + } + else + { + if (err_handler_.error(json_parser_errc::expected_value, *this)) + { + ec = json_parser_errc::expected_value; + return; + } + } + ++input_ptr_; + ++column_; + break; + case '\'': + if (err_handler_.error(json_parser_errc::single_quote, *this)) + { + ec = json_parser_errc::single_quote; + return; + } + ++input_ptr_; + ++column_; + break; + default: + if (err_handler_.error(json_parser_errc::expected_value, *this)) + { + ec = json_parser_errc::expected_value; + return; + } + ++input_ptr_; + ++column_; + break; + } + } + break; + case parse_state::expect_value_or_end: + { + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + if (err_handler_.error(json_parser_errc::illegal_control_character, *this)) + { + ec = json_parser_errc::illegal_control_character; + return; + } + ++input_ptr_; + ++column_; + break; + case '\r': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::cr; + break; + case '\n': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::lf; + break; + case ' ':case '\t': + skip_whitespace(); + break; + case '/': + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::slash; + break; + case '{': + do_begin_object(ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + case '[': + do_begin_array(ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + case ']': + do_end_array(ec); + if (ec) return; + ++input_ptr_; + ++column_; + break; + case '\"': + ++input_ptr_; + ++column_; + state_ = parse_state::string_u1; + break; + case '-': + number_buffer_.clear(); + is_negative_ = true; + precision_ = 0; + ++input_ptr_; + ++column_; + state_ = parse_state::minus; + parse_number(ec); + if (ec) {return;} + break; + case '0': + number_buffer_.clear(); + is_negative_ = false; + precision_ = 1; + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++input_ptr_; + ++column_; + state_ = parse_state::zero; + parse_number(ec); + if (ec) {return;} + break; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + number_buffer_.clear(); + is_negative_ = false; + precision_ = 1; + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++input_ptr_; + ++column_; + state_ = parse_state::integer; + parse_number(ec); + if (ec) {return;} + break; + case 'n': + parse_null(ec); + if (ec) {return;} + break; + case 't': + parse_true(ec); + if (ec) {return;} + break; + case 'f': + parse_false(ec); + if (ec) {return;} + break; + case '\'': + if (err_handler_.error(json_parser_errc::single_quote, *this)) + { + ec = json_parser_errc::single_quote; + return; + } + ++input_ptr_; + ++column_; + break; + default: + if (err_handler_.error(json_parser_errc::expected_value, *this)) + { + ec = json_parser_errc::expected_value; + return; + } + ++input_ptr_; + ++column_; + break; + } + } + break; + case parse_state::string_u1: + case parse_state::escape: + case parse_state::escape_u1: + case parse_state::escape_u2: + case parse_state::escape_u3: + case parse_state::escape_u4: + case parse_state::escape_expect_surrogate_pair1: + case parse_state::escape_expect_surrogate_pair2: + case parse_state::escape_u6: + case parse_state::escape_u7: + case parse_state::escape_u8: + case parse_state::escape_u9: + parse_string(ec); + if (ec) return; + break; + case parse_state::minus: + case parse_state::zero: + case parse_state::integer: + case parse_state::fraction1: + case parse_state::fraction2: + case parse_state::exp1: + case parse_state::exp2: + case parse_state::exp3: + parse_number(ec); + if (ec) return; + break; + case parse_state::t: + switch (*input_ptr_) + { + case 'r': + ++input_ptr_; + ++column_; + state_ = parse_state::tr; + break; + default: + err_handler_.error(json_parser_errc::invalid_value, *this); + ec = json_parser_errc::invalid_value; + return; + } + break; + case parse_state::tr: + switch (*input_ptr_) + { + case 'u': + state_ = parse_state::tru; + break; + default: + err_handler_.error(json_parser_errc::invalid_value, *this); + ec = json_parser_errc::invalid_value; + return; + } + ++input_ptr_; + ++column_; + break; + case parse_state::tru: + switch (*input_ptr_) + { + case 'e': + handler_.bool_value(true,*this); + if (parent() == parse_state::root) + { + state_ = parse_state::done; + handler_.end_json(); + } + else + { + state_ = parse_state::expect_comma_or_end; + } + break; + default: + err_handler_.error(json_parser_errc::invalid_value, *this); + ec = json_parser_errc::invalid_value; + return; + } + ++input_ptr_; + ++column_; + break; + case parse_state::f: + switch (*input_ptr_) + { + case 'a': + ++input_ptr_; + ++column_; + state_ = parse_state::fa; + break; + default: + err_handler_.error(json_parser_errc::invalid_value, *this); + ec = json_parser_errc::invalid_value; + return; + } + break; + case parse_state::fa: + switch (*input_ptr_) + { + case 'l': + state_ = parse_state::fal; + break; + default: + err_handler_.error(json_parser_errc::invalid_value, *this); + ec = json_parser_errc::invalid_value; + return; + } + ++input_ptr_; + ++column_; + break; + case parse_state::fal: + switch (*input_ptr_) + { + case 's': + state_ = parse_state::fals; + break; + default: + err_handler_.error(json_parser_errc::invalid_value, *this); + ec = json_parser_errc::invalid_value; + return; + } + ++input_ptr_; + ++column_; + break; + case parse_state::fals: + switch (*input_ptr_) + { + case 'e': + handler_.bool_value(false,*this); + if (parent() == parse_state::root) + { + state_ = parse_state::done; + handler_.end_json(); + } + else + { + state_ = parse_state::expect_comma_or_end; + } + break; + default: + err_handler_.error(json_parser_errc::invalid_value, *this); + ec = json_parser_errc::invalid_value; + return; + } + ++input_ptr_; + ++column_; + break; + case parse_state::n: + switch (*input_ptr_) + { + case 'u': + ++input_ptr_; + ++column_; + state_ = parse_state::nu; + break; + default: + err_handler_.error(json_parser_errc::invalid_value, *this); + ec = json_parser_errc::invalid_value; + return; + } + break; + case parse_state::nu: + switch (*input_ptr_) + { + case 'l': + state_ = parse_state::nul; + break; + default: + err_handler_.error(json_parser_errc::invalid_value, *this); + ec = json_parser_errc::invalid_value; + return; + } + ++input_ptr_; + ++column_; + break; + case parse_state::nul: + switch (*input_ptr_) + { + case 'l': + handler_.null_value(*this); + if (parent() == parse_state::root) + { + state_ = parse_state::done; + handler_.end_json(); + } + else + { + state_ = parse_state::expect_comma_or_end; + } + break; + default: + err_handler_.error(json_parser_errc::invalid_value, *this); + ec = json_parser_errc::invalid_value; + return; + } + ++input_ptr_; + ++column_; + break; + case parse_state::slash: + { + switch (*input_ptr_) + { + case '*': + state_ = parse_state::slash_star; + if (err_handler_.error(json_parser_errc::illegal_comment, *this)) + { + ec = json_parser_errc::illegal_comment; + return; + } + break; + case '/': + state_ = parse_state::slash_slash; + if (err_handler_.error(json_parser_errc::illegal_comment, *this)) + { + ec = json_parser_errc::illegal_comment; + return; + } + break; + default: + if (err_handler_.error(json_parser_errc::invalid_json_text, *this)) + { + ec = json_parser_errc::invalid_json_text; + return; + } + break; + } + } + ++input_ptr_; + ++column_; + break; + case parse_state::slash_star: + { + switch (*input_ptr_) + { + case '\r': + push_state(state_); + state_ = parse_state::cr; + break; + case '\n': + push_state(state_); + state_ = parse_state::lf; + break; + case '*': + state_ = parse_state::slash_star_star; + break; + } + } + ++input_ptr_; + ++column_; + break; + case parse_state::slash_slash: + { + switch (*input_ptr_) + { + case '\r': + state_ = pop_state(); + break; + case '\n': + state_ = pop_state(); + break; + default: + ++input_ptr_; + ++column_; + } + } + break; + case parse_state::slash_star_star: + { + switch (*input_ptr_) + { + case '/': + state_ = pop_state(); + break; + default: + state_ = parse_state::slash_star; + break; + } + } + ++input_ptr_; + ++column_; + break; + default: + JSONCONS_ASSERT(false); + break; + } + } + } + + void parse_true(std::error_code& ec) + { + if (JSONCONS_LIKELY(input_end_ - input_ptr_ >= 4)) + { + if (*(input_ptr_+1) == 'r' && *(input_ptr_+2) == 'u' && *(input_ptr_+3) == 'e') + { + handler_.bool_value(true,*this); + input_ptr_ += 4; + column_ += 4; + if (parent() == parse_state::root) + { + handler_.end_json(); + state_ = parse_state::done; + } + else + { + state_ = parse_state::expect_comma_or_end; + } + } + else + { + err_handler_.error(json_parser_errc::invalid_value, *this); + ec = json_parser_errc::invalid_value; + return; + } + } + else + { + ++input_ptr_; + ++column_; + state_ = parse_state::t; + } + } + + void parse_null(std::error_code& ec) + { + if (JSONCONS_LIKELY(input_end_ - input_ptr_ >= 4)) + { + if (*(input_ptr_+1) == 'u' && *(input_ptr_+2) == 'l' && *(input_ptr_+3) == 'l') + { + handler_.null_value(*this); + input_ptr_ += 4; + column_ += 4; + if (parent() == parse_state::root) + { + handler_.end_json(); + state_ = parse_state::done; + } + else + { + state_ = parse_state::expect_comma_or_end; + } + } + else + { + err_handler_.error(json_parser_errc::invalid_value, *this); + ec = json_parser_errc::invalid_value; + return; + } + } + else + { + ++input_ptr_; + ++column_; + state_ = parse_state::n; + } + } + + void parse_false(std::error_code& ec) + { + if (JSONCONS_LIKELY(input_end_ - input_ptr_ >= 5)) + { + if (*(input_ptr_+1) == 'a' && *(input_ptr_+2) == 'l' && *(input_ptr_+3) == 's' && *(input_ptr_+4) == 'e') + { + handler_.bool_value(false,*this); + input_ptr_ += 5; + column_ += 5; + if (parent() == parse_state::root) + { + handler_.end_json(); + state_ = parse_state::done; + } + else + { + state_ = parse_state::expect_comma_or_end; + } + } + else + { + err_handler_.error(json_parser_errc::invalid_value, *this); + ec = json_parser_errc::invalid_value; + return; + } + } + else + { + ++input_ptr_; + ++column_; + state_ = parse_state::f; + } + } + + void parse_number(std::error_code& ec) + { + const CharT* local_input_end = input_end_; + + switch (state_) + { + case parse_state::minus: + goto minus_sign; + case parse_state::zero: + goto zero; + case parse_state::integer: + goto integer; + case parse_state::fraction1: + goto fraction1; + case parse_state::fraction2: + goto fraction2; + case parse_state::exp1: + goto exp1; + case parse_state::exp2: + goto exp2; + case parse_state::exp3: + goto exp3; + default: + JSONCONS_UNREACHABLE(); + } +minus_sign: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::minus; + return; + } + switch (*input_ptr_) + { + case '0': + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++precision_; + ++input_ptr_; + ++column_; + goto zero; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++precision_; + ++input_ptr_; + ++column_; + goto integer; + default: + err_handler_.error(json_parser_errc::expected_value, *this); + ec = json_parser_errc::expected_value; + return; + } +zero: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::zero; + return; + } + switch (*input_ptr_) + { + case '\r': + end_integer_value(ec); + if (ec) return; + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::cr; + return; + case '\n': + end_integer_value(ec); + if (ec) return; + push_state(state_); + ++input_ptr_; + ++column_; + state_ = parse_state::lf; + return; + case ' ':case '\t': + end_integer_value(ec); + if (ec) return; + skip_whitespace(); + return; + case '/': + end_integer_value(ec); + if (ec) return; + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::slash; + return; + case '}': + end_integer_value(ec); + if (ec) return; + do_end_object(ec); + ++input_ptr_; + ++column_; + if (ec) return; + return; + case ']': + end_integer_value(ec); + if (ec) return; + do_end_array(ec); + ++input_ptr_; + ++column_; + if (ec) return; + return; + case '.': + decimal_places_ = 0; + JSONCONS_ASSERT(precision_ == number_buffer_.length()); + number_buffer_.push_back(to_double_.get_decimal_point()); + ++input_ptr_; + ++column_; + goto fraction1; + case 'e':case 'E': + JSONCONS_ASSERT(precision_ == number_buffer_.length()); + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++input_ptr_; + ++column_; + goto exp1; + case ',': + end_integer_value(ec); + if (ec) return; + begin_member_or_element(ec); + if (ec) return; + ++input_ptr_; + ++column_; + return; + case '0': case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + err_handler_.error(json_parser_errc::leading_zero, *this); + ec = json_parser_errc::leading_zero; + state_ = parse_state::zero; + return; + default: + err_handler_.error(json_parser_errc::invalid_number, *this); + ec = json_parser_errc::invalid_number; + state_ = parse_state::zero; + return; + } +integer: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::integer; + return; + } + switch (*input_ptr_) + { + case '\r': + end_integer_value(ec); + if (ec) return; + push_state(state_); + ++input_ptr_; + ++column_; + state_ = parse_state::cr; + return; + case '\n': + end_integer_value(ec); + if (ec) return; + push_state(state_); + ++input_ptr_; + ++column_; + state_ = parse_state::lf; + return; + case ' ':case '\t': + end_integer_value(ec); + if (ec) return; + skip_whitespace(); + return; + case '/': + end_integer_value(ec); + if (ec) return; + push_state(state_); + ++input_ptr_; + ++column_; + state_ = parse_state::slash; + return; + case '}': + end_integer_value(ec); + if (ec) return; + do_end_object(ec); + if (ec) return; + ++input_ptr_; + ++column_; + return; + case ']': + end_integer_value(ec); + if (ec) return; + do_end_array(ec); + if (ec) return; + ++input_ptr_; + ++column_; + return; + case '0': case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++precision_; + ++input_ptr_; + ++column_; + goto integer; + case '.': + decimal_places_ = 0; + JSONCONS_ASSERT(precision_ == number_buffer_.length()); + number_buffer_.push_back(to_double_.get_decimal_point()); + ++input_ptr_; + ++column_; + goto fraction1; + case 'e':case 'E': + JSONCONS_ASSERT(precision_ == number_buffer_.length()); + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++input_ptr_; + ++column_; + goto exp1; + case ',': + end_integer_value(ec); + if (ec) return; + begin_member_or_element(ec); + if (ec) return; + ++input_ptr_; + ++column_; + return; + default: + err_handler_.error(json_parser_errc::invalid_number, *this); + ec = json_parser_errc::invalid_number; + state_ = parse_state::integer; + return; + } +fraction1: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::fraction1; + return; + } + switch (*input_ptr_) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + ++precision_; + ++decimal_places_; + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++input_ptr_; + ++column_; + goto fraction2; + default: + err_handler_.error(json_parser_errc::invalid_number, *this); + ec = json_parser_errc::invalid_number; + state_ = parse_state::fraction1; + return; + } +fraction2: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::fraction2; + return; + } + switch (*input_ptr_) + { + case '\r': + end_fraction_value(chars_format::fixed,ec); + if (ec) return; + push_state(state_); + ++input_ptr_; + ++column_; + state_ = parse_state::cr; + return; + case '\n': + end_fraction_value(chars_format::fixed,ec); + if (ec) return; + push_state(state_); + ++input_ptr_; + ++column_; + state_ = parse_state::lf; + return; + case ' ':case '\t': + end_fraction_value(chars_format::fixed,ec); + if (ec) return; + skip_whitespace(); + return; + case '/': + end_fraction_value(chars_format::fixed,ec); + if (ec) return; + push_state(state_); + ++input_ptr_; + ++column_; + state_ = parse_state::slash; + return; + case '}': + end_fraction_value(chars_format::fixed,ec); + if (ec) return; + do_end_object(ec); + if (ec) return; + ++input_ptr_; + ++column_; + return; + case ']': + end_fraction_value(chars_format::fixed,ec); + if (ec) return; + do_end_array(ec); + if (ec) return; + ++input_ptr_; + ++column_; + return; + case ',': + end_fraction_value(chars_format::fixed,ec); + if (ec) return; + begin_member_or_element(ec); + if (ec) return; + ++input_ptr_; + ++column_; + return; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + ++precision_; + ++decimal_places_; + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++input_ptr_; + ++column_; + goto fraction2; + case 'e':case 'E': + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++input_ptr_; + ++column_; + goto exp1; + default: + err_handler_.error(json_parser_errc::invalid_number, *this); + ec = json_parser_errc::invalid_number; + state_ = parse_state::fraction2; + return; + } +exp1: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::exp1; + return; + } + switch (*input_ptr_) + { + case '+': + ++input_ptr_; + ++column_; + goto exp2; + case '-': + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++input_ptr_; + ++column_; + goto exp2; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++input_ptr_; + ++column_; + goto exp3; + default: + err_handler_.error(json_parser_errc::expected_value, *this); + ec = json_parser_errc::expected_value; + state_ = parse_state::exp1; + return; + } +exp2: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::exp2; + return; + } + switch (*input_ptr_) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++input_ptr_; + ++column_; + goto exp3; + default: + err_handler_.error(json_parser_errc::expected_value, *this); + ec = json_parser_errc::expected_value; + state_ = parse_state::exp2; + return; + } + +exp3: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::exp3; + return; + } + switch (*input_ptr_) + { + case '\r': + end_fraction_value(chars_format::scientific,ec); + if (ec) return; + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::cr; + return; + case '\n': + end_fraction_value(chars_format::scientific,ec); + if (ec) return; + ++input_ptr_; + ++column_; + push_state(state_); + state_ = parse_state::lf; + return; + case ' ':case '\t': + end_fraction_value(chars_format::scientific,ec); + if (ec) return; + skip_whitespace(); + return; + case '/': + end_fraction_value(chars_format::scientific,ec); + if (ec) return; + push_state(state_); + ++input_ptr_; + ++column_; + state_ = parse_state::slash; + return; + case '}': + end_fraction_value(chars_format::scientific,ec); + if (ec) return; + do_end_object(ec); + if (ec) return; + ++input_ptr_; + ++column_; + return; + case ']': + end_fraction_value(chars_format::scientific,ec); + if (ec) return; + do_end_array(ec); + if (ec) return; + ++input_ptr_; + ++column_; + return; + case ',': + end_fraction_value(chars_format::scientific,ec); + if (ec) return; + begin_member_or_element(ec); + if (ec) return; + ++input_ptr_; + ++column_; + return; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + number_buffer_.push_back(static_cast<char>(*input_ptr_)); + ++input_ptr_; + ++column_; + goto exp3; + default: + err_handler_.error(json_parser_errc::invalid_number, *this); + ec = json_parser_errc::invalid_number; + state_ = parse_state::exp3; + return; + } + + JSONCONS_UNREACHABLE(); + } + + void parse_string(std::error_code& ec) + { + const CharT* local_input_end = input_end_; + const CharT* sb = input_ptr_; + + switch (state_) + { + case parse_state::string_u1: + goto string_u1; + case parse_state::escape: + goto escape; + case parse_state::escape_u1: + goto escape_u1; + case parse_state::escape_u2: + goto escape_u2; + case parse_state::escape_u3: + goto escape_u3; + case parse_state::escape_u4: + goto escape_u4; + case parse_state::escape_expect_surrogate_pair1: + goto escape_expect_surrogate_pair1; + case parse_state::escape_expect_surrogate_pair2: + goto escape_expect_surrogate_pair2; + case parse_state::escape_u6: + goto escape_u6; + case parse_state::escape_u7: + goto escape_u7; + case parse_state::escape_u8: + goto escape_u8; + case parse_state::escape_u9: + goto escape_u9; + default: + JSONCONS_UNREACHABLE(); + } + +string_u1: + while (input_ptr_ < local_input_end) + { + switch (*input_ptr_) + { + JSONCONS_ILLEGAL_CONTROL_CHARACTER: + { + column_ += (input_ptr_ - sb + 1); + if (err_handler_.error(json_parser_errc::illegal_control_character, *this)) + { + ec = json_parser_errc::illegal_control_character; + state_ = parse_state::string_u1; + return; + } + // recovery - skip + auto result = unicons::validate(sb,input_ptr_); + if (result.ec != unicons::conv_errc()) + { + translate_conv_errc(result.ec,ec); + column_ += (result.it - sb); + return; + } + string_buffer_.append(sb,input_ptr_-sb); + ++input_ptr_; + state_ = parse_state::string_u1; + return; + } + case '\r': + { + column_ += (input_ptr_ - sb + 1); + if (err_handler_.error(json_parser_errc::illegal_character_in_string, *this)) + { + ec = json_parser_errc::illegal_character_in_string; + state_ = parse_state::string_u1; + return; + } + // recovery - keep + auto result = unicons::validate(sb,input_ptr_); + if (result.ec != unicons::conv_errc()) + { + translate_conv_errc(result.ec,ec); + column_ += (result.it - sb); + return; + } + string_buffer_.append(sb, input_ptr_ - sb + 1); + ++input_ptr_; + push_state(state_); + state_ = parse_state::cr; + return; + } + case '\n': + { + column_ += (input_ptr_ - sb + 1); + if (err_handler_.error(json_parser_errc::illegal_character_in_string, *this)) + { + ec = json_parser_errc::illegal_character_in_string; + state_ = parse_state::string_u1; + return; + } + // recovery - keep + auto result = unicons::validate(sb,input_ptr_); + if (result.ec != unicons::conv_errc()) + { + translate_conv_errc(result.ec,ec); + column_ += (result.it - sb); + return; + } + string_buffer_.append(sb, input_ptr_ - sb + 1); + ++input_ptr_; + push_state(state_); + state_ = parse_state::lf; + return; + } + case '\t': + { + column_ += (input_ptr_ - sb + 1); + if (err_handler_.error(json_parser_errc::illegal_character_in_string, *this)) + { + ec = json_parser_errc::illegal_character_in_string; + state_ = parse_state::string_u1; + return; + } + // recovery - keep + auto result = unicons::validate(sb,input_ptr_); + if (result.ec != unicons::conv_errc()) + { + translate_conv_errc(result.ec,ec); + column_ += (result.it - sb); + return; + } + string_buffer_.append(sb, input_ptr_ - sb + 1); + ++input_ptr_; + state_ = parse_state::string_u1; + return; + } + case '\\': + { + auto result = unicons::validate(sb,input_ptr_); + if (result.ec != unicons::conv_errc()) + { + translate_conv_errc(result.ec,ec); + column_ += (result.it - sb); + return; + } + string_buffer_.append(sb,input_ptr_-sb); + column_ += (input_ptr_ - sb + 1); + ++input_ptr_; + goto escape; + } + case '\"': + { + auto result = unicons::validate(sb,input_ptr_); + if (result.ec != unicons::conv_errc()) + { + translate_conv_errc(result.ec,ec); + column_ += (result.it - sb); + return; + } + if (string_buffer_.length() == 0) + { + end_string_value(sb,input_ptr_-sb, ec); + if (ec) {return;} + } + else + { + string_buffer_.append(sb,input_ptr_-sb); + end_string_value(string_buffer_.data(),string_buffer_.length(), ec); + string_buffer_.clear(); + if (ec) {return;} + } + column_ += (input_ptr_ - sb + 1); + ++input_ptr_; + return; + } + default: + break; + } + ++input_ptr_; + } + + // Buffer exhausted + { + auto result = unicons::validate(sb,input_ptr_); + if (result.ec != unicons::conv_errc()) + { + translate_conv_errc(result.ec,ec); + column_ += (result.it - sb); + return; + } + string_buffer_.append(sb,input_ptr_-sb); + column_ += (input_ptr_ - sb + 1); + state_ = parse_state::string_u1; + return; + } + +escape: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::escape; + return; + } + switch (*input_ptr_) + { + case '\"': + string_buffer_.push_back('\"'); + sb = ++input_ptr_; + ++column_; + goto string_u1; + case '\\': + string_buffer_.push_back('\\'); + sb = ++input_ptr_; + ++column_; + goto string_u1; + case '/': + string_buffer_.push_back('/'); + sb = ++input_ptr_; + ++column_; + goto string_u1; + case 'b': + string_buffer_.push_back('\b'); + sb = ++input_ptr_; + ++column_; + goto string_u1; + case 'f': + string_buffer_.push_back('\f'); + sb = ++input_ptr_; + ++column_; + goto string_u1; + case 'n': + string_buffer_.push_back('\n'); + sb = ++input_ptr_; + ++column_; + goto string_u1; + case 'r': + string_buffer_.push_back('\r'); + sb = ++input_ptr_; + ++column_; + goto string_u1; + case 't': + string_buffer_.push_back('\t'); + sb = ++input_ptr_; + ++column_; + goto string_u1; + case 'u': + cp_ = 0; + ++input_ptr_; + ++column_; + goto escape_u1; + default: + err_handler_.error(json_parser_errc::illegal_escaped_character, *this); + ec = json_parser_errc::illegal_escaped_character; + state_ = parse_state::escape; + return; + } + +escape_u1: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::escape_u1; + return; + } + { + append_codepoint(*input_ptr_,ec); + if (ec) + { + state_ = parse_state::escape_u1; + return; + } + ++input_ptr_; + ++column_; + goto escape_u2; + } + +escape_u2: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::escape_u2; + return; + } + { + append_codepoint(*input_ptr_, ec); + if (ec) + { + state_ = parse_state::escape_u2; + return; + } + ++input_ptr_; + ++column_; + goto escape_u3; + } + +escape_u3: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::escape_u3; + return; + } + { + append_codepoint(*input_ptr_, ec); + if (ec) + { + state_ = parse_state::escape_u3; + return; + } + ++input_ptr_; + ++column_; + goto escape_u4; + } + +escape_u4: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::escape_u4; + return; + } + { + append_codepoint(*input_ptr_, ec); + if (ec) + { + state_ = parse_state::escape_u4; + return; + } + if (unicons::is_high_surrogate(cp_)) + { + ++input_ptr_; + ++column_; + goto escape_expect_surrogate_pair1; + } + else + { + unicons::convert(&cp_, &cp_ + 1, std::back_inserter(string_buffer_)); + sb = ++input_ptr_; + ++column_; + state_ = parse_state::string_u1; + return; + } + } + +escape_expect_surrogate_pair1: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::escape_expect_surrogate_pair1; + return; + } + { + switch (*input_ptr_) + { + case '\\': + cp2_ = 0; + ++input_ptr_; + ++column_; + goto escape_expect_surrogate_pair2; + default: + err_handler_.error(json_parser_errc::expected_codepoint_surrogate_pair, *this); + ec = json_parser_errc::expected_codepoint_surrogate_pair; + state_ = parse_state::escape_expect_surrogate_pair1; + return; + } + } + +escape_expect_surrogate_pair2: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::escape_expect_surrogate_pair2; + return; + } + { + switch (*input_ptr_) + { + case 'u': + ++input_ptr_; + ++column_; + goto escape_u6; + default: + err_handler_.error(json_parser_errc::expected_codepoint_surrogate_pair, *this); + ec = json_parser_errc::expected_codepoint_surrogate_pair; + state_ = parse_state::escape_expect_surrogate_pair2; + return; + } + } + +escape_u6: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::escape_u6; + return; + } + { + append_second_codepoint(*input_ptr_, ec); + if (ec) + { + state_ = parse_state::escape_u6; + return; + } + } + ++input_ptr_; + ++column_; + goto escape_u7; + +escape_u7: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::escape_u7; + return; + } + { + append_second_codepoint(*input_ptr_, ec); + if (ec) + { + state_ = parse_state::escape_u7; + return; + } + ++input_ptr_; + ++column_; + goto escape_u8; + } + +escape_u8: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::escape_u8; + return; + } + { + append_second_codepoint(*input_ptr_, ec); + if (ec) + { + state_ = parse_state::escape_u8; + return; + } + ++input_ptr_; + ++column_; + goto escape_u9; + } + +escape_u9: + if (JSONCONS_UNLIKELY(input_ptr_ >= local_input_end)) // Buffer exhausted + { + state_ = parse_state::escape_u9; + return; + } + { + append_second_codepoint(*input_ptr_, ec); + if (ec) + { + state_ = parse_state::escape_u9; + return; + } + uint32_t cp = 0x10000 + ((cp_ & 0x3FF) << 10) + (cp2_ & 0x3FF); + unicons::convert(&cp, &cp + 1, std::back_inserter(string_buffer_)); + sb = ++input_ptr_; + ++column_; + goto string_u1; + } + + JSONCONS_UNREACHABLE(); + } + + void translate_conv_errc(unicons::conv_errc result, std::error_code& ec) + { + switch (result) + { + case unicons::conv_errc(): + break; + case unicons::conv_errc::over_long_utf8_sequence: + if (err_handler_.error(json_parser_errc::over_long_utf8_sequence, *this)) + { + ec = json_parser_errc::over_long_utf8_sequence; + return; + } + break; + case unicons::conv_errc::unpaired_high_surrogate: + if (err_handler_.error(json_parser_errc::unpaired_high_surrogate, *this)) + { + ec = json_parser_errc::unpaired_high_surrogate; + return; + } + break; + case unicons::conv_errc::expected_continuation_byte: + if (err_handler_.error(json_parser_errc::expected_continuation_byte, *this)) + { + ec = json_parser_errc::expected_continuation_byte; + return; + } + break; + case unicons::conv_errc::illegal_surrogate_value: + if (err_handler_.error(json_parser_errc::illegal_surrogate_value, *this)) + { + ec = json_parser_errc::illegal_surrogate_value; + return; + } + break; + default: + if (err_handler_.error(json_parser_errc::illegal_codepoint, *this)) + { + ec = json_parser_errc::illegal_codepoint; + return; + } + break; + } + } + + void parse_some() + { + std::error_code ec; + parse_some(ec); + if (ec) + { + throw parse_error(ec,line_,column_); + } + } + + void end_parse() + { + std::error_code ec; + end_parse(ec); + if (ec) + { + throw parse_error(ec,line_,column_); + } + } + + void end_parse(std::error_code& ec) + { + if (parent() == parse_state::root) + { + switch (state_) + { + case parse_state::zero: + case parse_state::integer: + end_integer_value(ec); + if (ec) return; + break; + case parse_state::fraction2: + end_fraction_value(chars_format::fixed,ec); + if (ec) return; + break; + case parse_state::exp3: + end_fraction_value(chars_format::scientific,ec); + if (ec) return; + break; + default: + break; + } + } + if (state_ == parse_state::lf || state_ == parse_state::cr) + { + state_ = pop_state(); + } + if (!(state_ == parse_state::done || state_ == parse_state::start)) + { + if (err_handler_.error(json_parser_errc::unexpected_eof, *this)) + { + ec = json_parser_errc::unexpected_eof; + return; + } + } + } + + parse_state state() const + { + return state_; + } + + void set_source(const CharT* input, size_t length) + { + begin_input_ = input; + input_end_ = input + length; + input_ptr_ = begin_input_; + } +private: + + void end_integer_value(std::error_code& ec) + { + if (is_negative_) + { + end_negative_value(ec); + } + else + { + end_positive_value(ec); + } + } + + void end_negative_value(std::error_code& ec) + { + static const int64_t min_value = (std::numeric_limits<int64_t>::min)(); + static const int64_t min_value_div_10 = min_value / 10; + + const char* s = number_buffer_.data(); + size_t length = number_buffer_.length(); + int64_t n = 0; + bool overflow = false; + const char* end = s + length; + for (; s < end; ++s) + { + int64_t x = *s - '0'; + if (n < min_value_div_10) + { + overflow = true; + break; + } + n = n * 10; + if (n < min_value + x) + { + overflow = true; + break; + } + + n -= x; + } + + if (!overflow) + { + handler_.integer_value(n, *this); + + switch (parent()) + { + case parse_state::array: + case parse_state::object: + state_ = parse_state::expect_comma_or_end; + break; + case parse_state::root: + state_ = parse_state::done; + handler_.end_json(); + break; + default: + if (err_handler_.error(json_parser_errc::invalid_json_text, *this)) + { + ec = json_parser_errc::invalid_json_text; + return; + } + break; + } + } + else + { + end_fraction_value(chars_format::general,ec); + } + } + + void end_positive_value(std::error_code& ec) + { + static const uint64_t max_value = (std::numeric_limits<uint64_t>::max)(); + static const uint64_t max_value_div_10 = max_value / 10; + uint64_t n = 0; + bool overflow = false; + const char* s = number_buffer_.data(); + size_t length = number_buffer_.length(); + + const char* end = s + length; + for (; s < end; ++s) + { + uint64_t x = *s - '0'; + if (n > max_value_div_10) + { + overflow = true; + break; + } + n = n * 10; + if (n > max_value - x) + { + overflow = true; + break; + } + + n += x; + } + + if (!overflow) + { + handler_.uinteger_value(n, *this); + + switch (parent()) + { + case parse_state::array: + case parse_state::object: + state_ = parse_state::expect_comma_or_end; + break; + case parse_state::root: + state_ = parse_state::done; + handler_.end_json(); + break; + default: + if (err_handler_.error(json_parser_errc::invalid_json_text, *this)) + { + ec = json_parser_errc::invalid_json_text; + return; + } + break; + } + } + else + { + end_fraction_value(chars_format::general,ec); + } + } + + void end_fraction_value(chars_format format, std::error_code& ec) + { + try + { + double d = to_double_(number_buffer_.c_str(), number_buffer_.length()); + if (is_negative_) + d = -d; + + if (precision_ > std::numeric_limits<double>::max_digits10) + { + handler_.double_value(d, number_format(format,std::numeric_limits<double>::max_digits10, decimal_places_), *this); + } + else + { + handler_.double_value(d, number_format(format,static_cast<uint8_t>(precision_), decimal_places_), *this); + } + } + catch (...) + { + if (err_handler_.error(json_parser_errc::invalid_number, *this)) + { + ec = json_parser_errc::invalid_number; + return; + } + handler_.null_value(*this); // recovery + } + + switch (parent()) + { + case parse_state::array: + case parse_state::object: + state_ = parse_state::expect_comma_or_end; + break; + case parse_state::root: + state_ = parse_state::done; + handler_.end_json(); + break; + default: + if (err_handler_.error(json_parser_errc::invalid_json_text, *this)) + { + ec = json_parser_errc::invalid_json_text; + return; + } + break; + } + } + + void append_codepoint(int c, std::error_code& ec) + { + switch (c) + { + case '0': case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + case 'a':case 'b':case 'c':case 'd':case 'e':case 'f': + case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': + cp_ = append_to_codepoint(cp_, c, ec); + if (ec) return; + break; + default: + if (err_handler_.error(json_parser_errc::expected_value, *this)) + { + ec = json_parser_errc::expected_value; + return; + } + break; + } + } + + void append_second_codepoint(int c, std::error_code& ec) + { + switch (c) + { + case '0': + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': + case 'a':case 'b':case 'c':case 'd':case 'e':case 'f': + case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': + cp2_ = append_to_codepoint(cp2_, c, ec); + if (ec) return; + break; + default: + if (err_handler_.error(json_parser_errc::expected_value, *this)) + { + ec = json_parser_errc::expected_value; + return; + } + break; + } + } + + void end_string_value(const CharT* s, size_t length, std::error_code& ec) + { + switch (parent()) + { + case parse_state::member_name: + handler_.name(string_view_type(s, length), *this); + state_ = pop_state(); + state_ = parse_state::expect_colon; + break; + case parse_state::object: + case parse_state::array: + handler_.string_value(string_view_type(s, length), *this); + state_ = parse_state::expect_comma_or_end; + break; + case parse_state::root: + handler_.string_value(string_view_type(s, length), *this); + state_ = parse_state::done; + handler_.end_json(); + break; + default: + if (err_handler_.error(json_parser_errc::invalid_json_text, *this)) + { + ec = json_parser_errc::invalid_json_text; + return; + } + break; + } + } + + void begin_member_or_element(std::error_code& ec) + { + switch (parent()) + { + case parse_state::object: + state_ = parse_state::expect_member_name; + break; + case parse_state::array: + state_ = parse_state::expect_value; + break; + case parse_state::root: + break; + default: + if (err_handler_.error(json_parser_errc::invalid_json_text, *this)) + { + ec = json_parser_errc::invalid_json_text; + return; + } + break; + } + } + + void push_state(parse_state state) + { + state_stack_.push_back(state); + } + + parse_state pop_state() + { + JSONCONS_ASSERT(!state_stack_.empty()) + parse_state state = state_stack_.back(); + state_stack_.pop_back(); + return state; + } + + uint32_t append_to_codepoint(uint32_t cp, int c, std::error_code& ec) + { + cp *= 16; + if (c >= '0' && c <= '9') + { + cp += c - '0'; + } + else if (c >= 'a' && c <= 'f') + { + cp += c - 'a' + 10; + } + else if (c >= 'A' && c <= 'F') + { + cp += c - 'A' + 10; + } + else + { + if (err_handler_.error(json_parser_errc::invalid_hex_escape_sequence, *this)) + { + ec = json_parser_errc::invalid_hex_escape_sequence; + return cp; + } + } + return cp; + } + + size_t do_line_number() const override + { + return line_; + } + + size_t do_column_number() const override + { + return column_; + } +}; + +typedef basic_json_parser<char> json_parser; +typedef basic_json_parser<wchar_t> wjson_parser; + +} + +#endif + diff --git a/vendor/jsoncons-0.104.0/jsoncons/json_reader.hpp b/vendor/jsoncons-0.104.0/jsoncons/json_reader.hpp new file mode 100644 index 00000000..d419e2d8 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/json_reader.hpp @@ -0,0 +1,408 @@ +// Copyright 2015 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_READER_HPP +#define JSONCONS_JSON_READER_HPP + +#include <memory> +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <stdexcept> +#include <system_error> +#include <ios> +#include <jsoncons/json_exception.hpp> +#include <jsoncons/json_input_handler.hpp> +#include <jsoncons/parse_error_handler.hpp> +#include <jsoncons/json_parser.hpp> + +namespace jsoncons { + +// utf8_other_json_input_adapter + +template <class CharT> +class json_utf8_other_input_handler_adapter : public json_input_handler +{ +public: + using json_input_handler::string_view_type; +private: + basic_null_json_input_handler<CharT> default_input_handler_; + basic_json_input_handler<CharT>& other_handler_; + //parse_error_handler& err_handler_; + + // noncopyable and nonmoveable + json_utf8_other_input_handler_adapter<CharT>(const json_utf8_other_input_handler_adapter<CharT>&) = delete; + json_utf8_other_input_handler_adapter<CharT>& operator=(const json_utf8_other_input_handler_adapter<CharT>&) = delete; + +public: + json_utf8_other_input_handler_adapter() + : other_handler_(default_input_handler_) + { + } + + json_utf8_other_input_handler_adapter(basic_json_input_handler<CharT>& other_handler/*, + parse_error_handler& err_handler*/) + : other_handler_(other_handler)/*, + err_handler_(err_handler)*/ + { + } + +private: + + void do_begin_json() override + { + other_handler_.begin_json(); + } + + void do_end_json() override + { + other_handler_.end_json(); + } + + void do_begin_object(const parsing_context& context) override + { + other_handler_.begin_object(context); + } + + void do_end_object(const parsing_context& context) override + { + other_handler_.end_object(context); + } + + void do_begin_array(const parsing_context& context) override + { + other_handler_.begin_array(context); + } + + void do_end_array(const parsing_context& context) override + { + other_handler_.end_array(context); + } + + void do_name(const string_view_type& name, const parsing_context& context) override + { + std::basic_string<CharT> target; + auto result = unicons::convert( + name.begin(), name.end(), std::back_inserter(target), + unicons::conv_flags::strict); + if (result.ec != unicons::conv_errc()) + { + throw parse_error(result.ec,context.line_number(),context.column_number()); + } + other_handler_.name(target, context); + } + + void do_string_value(const string_view_type& value, const parsing_context& context) override + { + std::basic_string<CharT> target; + auto result = unicons::convert( + value.begin(), value.end(), std::back_inserter(target), + unicons::conv_flags::strict); + if (result.ec != unicons::conv_errc()) + { + throw parse_error(result.ec,context.line_number(),context.column_number()); + } + other_handler_.string_value(target, context); + } + + void do_integer_value(int64_t value, const parsing_context& context) override + { + other_handler_.integer_value(value, context); + } + + void do_uinteger_value(uint64_t value, const parsing_context& context) override + { + other_handler_.uinteger_value(value, context); + } + + void do_double_value(double value, const number_format& fmt, const parsing_context& context) override + { + other_handler_.double_value(value, fmt, context); + } + + void do_bool_value(bool value, const parsing_context& context) override + { + other_handler_.bool_value(value, context); + } + + void do_null_value(const parsing_context& context) override + { + other_handler_.null_value(context); + } +}; + +template<class CharT,class Allocator=std::allocator<char>> +class basic_json_reader +{ + static const size_t default_max_buffer_length = 16384; + + typedef CharT char_type; + typedef Allocator allocator_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<CharT> char_allocator_type; + + basic_json_parser<CharT,Allocator> parser_; + std::basic_istream<CharT>& is_; + bool eof_; + std::vector<CharT,char_allocator_type> buffer_; + size_t buffer_length_; + bool begin_; + + // Noncopyable and nonmoveable + basic_json_reader(const basic_json_reader&) = delete; + basic_json_reader& operator=(const basic_json_reader&) = delete; + +public: + + basic_json_reader(std::basic_istream<CharT>& is) + : parser_(), + is_(is), + eof_(false), + buffer_length_(default_max_buffer_length), + begin_(true) + { + buffer_.reserve(buffer_length_); + } + + basic_json_reader(std::basic_istream<CharT>& is, + parse_error_handler& err_handler) + : parser_(err_handler), + is_(is), + eof_(false), + buffer_length_(default_max_buffer_length), + begin_(true) + { + buffer_.reserve(buffer_length_); + } + + basic_json_reader(std::basic_istream<CharT>& is, + basic_json_input_handler<CharT>& handler) + : parser_(handler), + is_(is), + eof_(false), + buffer_length_(default_max_buffer_length), + begin_(true) + { + buffer_.reserve(buffer_length_); + } + + basic_json_reader(std::basic_istream<CharT>& is, + basic_json_input_handler<CharT>& handler, + parse_error_handler& err_handler) + : parser_(handler,err_handler), + is_(is), + eof_(false), + buffer_length_(default_max_buffer_length), + begin_(true) + { + buffer_.reserve(buffer_length_); + } + + size_t buffer_length() const + { + return buffer_length_; + } + + void buffer_length(size_t length) + { + buffer_length_ = length; + buffer_.reserve(buffer_length_); + } + + size_t max_nesting_depth() const + { + return parser_.max_nesting_depth(); + } + + void max_nesting_depth(size_t depth) + { + parser_.max_nesting_depth(depth); + } + + void read_next() + { + std::error_code ec; + read_next(ec); + if (ec) + { + throw parse_error(ec,parser_.line_number(),parser_.column_number()); + } + } + + void read_buffer(std::error_code& ec) + { + buffer_.clear(); + buffer_.resize(buffer_length_); + is_.read(buffer_.data(), buffer_length_); + buffer_.resize(static_cast<size_t>(is_.gcount())); + if (buffer_.size() == 0) + { + eof_ = true; + } + else if (begin_) + { + auto result = unicons::skip_bom(buffer_.begin(), buffer_.end()); + if (result.ec != unicons::encoding_errc()) + { + ec = result.ec; + return; + } + size_t offset = result.it - buffer_.begin(); + parser_.set_source(buffer_.data()+offset,buffer_.size()-offset); + begin_ = false; + } + else + { + parser_.set_source(buffer_.data(),buffer_.size()); + } + } + + void read_next(std::error_code& ec) + { + parser_.reset(); + while (!eof_ && !parser_.done()) + { + if (parser_.source_exhausted()) + { + if (!is_.eof()) + { + if (is_.fail()) + { + ec = json_parser_errc::source_error; + return; + } + read_buffer(ec); + if (ec) return; + } + else + { + eof_ = true; + } + } + if (!eof_) + { + parser_.parse_some(ec); + if (ec) return; + } + } + if (eof_) + { + parser_.end_parse(ec); + if (ec) return; + } + } + + void check_done() + { + std::error_code ec; + check_done(ec); + if (ec) + { + throw parse_error(ec,parser_.line_number(),parser_.column_number()); + } + } + + size_t line_number() const + { + return parser_.line_number(); + } + + size_t column_number() const + { + return parser_.column_number(); + } + + void check_done(std::error_code& ec) + { + if (eof_) + { + parser_.check_done(ec); + if (ec) return; + } + else + { + while (!eof_) + { + if (parser_.source_exhausted()) + { + if (!is_.eof()) + { + if (is_.fail()) + { + ec = json_parser_errc::source_error; + return; + } + read_buffer(ec); + if (ec) return; + } + else + { + eof_ = true; + } + } + if (!eof_) + { + parser_.check_done(ec); + if (ec) return; + } + } + } + } + + bool eof() const + { + return eof_; + } + + void read() + { + read_next(); + check_done(); + } + + void read(std::error_code& ec) + { + read_next(ec); + if (!ec) + { + check_done(ec); + } + } + +#if !defined(JSONCONS_NO_DEPRECATED) + + size_t buffer_capacity() const + { + return buffer_length_; + } + + void buffer_capacity(size_t length) + { + buffer_length_ = length; + buffer_.reserve(buffer_length_); + } + size_t max_depth() const + { + return parser_.max_nesting_depth(); + } + + void max_depth(size_t depth) + { + parser_.max_nesting_depth(depth); + } +#endif + +private: +}; + +typedef basic_json_reader<char> json_reader; +typedef basic_json_reader<wchar_t> wjson_reader; + +} + +#endif + diff --git a/vendor/jsoncons-0.104.0/jsoncons/json_serializer.hpp b/vendor/jsoncons-0.104.0/jsoncons/json_serializer.hpp new file mode 100644 index 00000000..42538671 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/json_serializer.hpp @@ -0,0 +1,585 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_SERIALIZER_HPP +#define JSONCONS_JSON_SERIALIZER_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <ostream> +#include <cstdlib> +#include <limits> // std::numeric_limits +#include <fstream> +#include <memory> +#include <jsoncons/json_exception.hpp> +#include <jsoncons/jsoncons_utilities.hpp> +#include <jsoncons/serialization_options.hpp> +#include <jsoncons/json_output_handler.hpp> +#include <jsoncons/detail/writer.hpp> +#include <jsoncons/detail/number_printers.hpp> + +namespace jsoncons { + +template<class CharT,class Writer=detail::ostream_buffered_writer<CharT>> +class basic_json_serializer final : public basic_json_output_handler<CharT> +{ +public: + using typename basic_json_output_handler<CharT>::string_view_type; + typedef Writer writer_type; + typedef typename Writer::output_type output_type; + +private: + static const size_t default_buffer_length = 16384; + + struct stack_item + { + stack_item(bool is_object) + : is_object_(is_object), count_(0), split_lines_(line_split_kind::same_line), indent_once_(false), unindent_at_end_(false) + { + } + stack_item(bool is_object, line_split_kind split_lines, bool indent_once = false) + : is_object_(is_object), count_(0), split_lines_(split_lines), indent_once_(indent_once), unindent_at_end_(false) + { + } + + size_t count() const + { + return count_; + } + + bool unindent_at_end() const + { + return unindent_at_end_; + } + + bool is_object() const + { + return is_object_; + } + + bool is_new_line() const + { + return split_lines_ != line_split_kind::same_line; + } + + bool is_multi_line() const + { + return split_lines_ == line_split_kind::multi_line; + } + + bool is_indent_once() const + { + return count_ == 0 ? indent_once_ : false; + } + + bool is_object_; + size_t count_; + line_split_kind split_lines_; + bool indent_once_; + bool unindent_at_end_; + }; + basic_serialization_options<CharT> options_; + std::vector<stack_item> stack_; + int indent_; + bool indenting_; + detail::print_double fp_; + Writer writer_; + + // Noncopyable and nonmoveable + basic_json_serializer(const basic_json_serializer&) = delete; + basic_json_serializer& operator=(const basic_json_serializer&) = delete; +public: + basic_json_serializer(output_type& os) + : indent_(0), + indenting_(false), + fp_(options_.precision()), + writer_(os) + { + } + + basic_json_serializer(output_type& os, bool pprint) + : indent_(0), + indenting_(pprint), + fp_(options_.precision()), + writer_(os) + { + } + + basic_json_serializer(output_type& os, const basic_serialization_options<CharT>& options) + : options_(options), + indent_(0), + indenting_(false), + fp_(options_.precision()), + writer_(os) + { + } + basic_json_serializer(output_type& os, const basic_serialization_options<CharT>& options, bool pprint) + : options_(options), + indent_(0), + indenting_(pprint), + fp_(options_.precision()), + writer_(os) + { + } + + ~basic_json_serializer() + { + } + +private: + void escape_string(const CharT* s, + size_t length, + const basic_serialization_options<CharT>& options, + writer_type& writer) + { + const CharT* begin = s; + const CharT* end = s + length; + for (const CharT* it = begin; it != end; ++it) + { + CharT c = *it; + switch (c) + { + case '\\': + writer.put('\\'); + writer.put('\\'); + break; + case '"': + writer.put('\\'); + writer.put('\"'); + break; + case '\b': + writer.put('\\'); + writer.put('b'); + break; + case '\f': + writer.put('\\'); + writer.put('f'); + break; + case '\n': + writer.put('\\'); + writer.put('n'); + break; + case '\r': + writer.put('\\'); + writer.put('r'); + break; + case '\t': + writer.put('\\'); + writer.put('t'); + break; + default: + if (options.escape_solidus() && c == '/') + { + writer.put('\\'); + writer.put('/'); + } + else if (is_control_character(c) || options.escape_all_non_ascii()) + { + // convert utf8 to codepoint + unicons::sequence_generator<const CharT*> g(it,end,unicons::conv_flags::strict); + if (g.done() || g.status() != unicons::conv_errc()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Invalid codepoint")); + } + uint32_t cp = g.get().codepoint(); + it += (g.get().length() - 1); + if (is_non_ascii_codepoint(cp) || is_control_character(c)) + { + if (cp > 0xFFFF) + { + cp -= 0x10000; + uint32_t first = (cp >> 10) + 0xD800; + uint32_t second = ((cp & 0x03FF) + 0xDC00); + + writer.put('\\'); + writer.put('u'); + writer.put(to_hex_character(first >> 12 & 0x000F)); + writer.put(to_hex_character(first >> 8 & 0x000F)); + writer.put(to_hex_character(first >> 4 & 0x000F)); + writer.put(to_hex_character(first & 0x000F)); + writer.put('\\'); + writer.put('u'); + writer.put(to_hex_character(second >> 12 & 0x000F)); + writer.put(to_hex_character(second >> 8 & 0x000F)); + writer.put(to_hex_character(second >> 4 & 0x000F)); + writer.put(to_hex_character(second & 0x000F)); + } + else + { + writer.put('\\'); + writer.put('u'); + writer.put(to_hex_character(cp >> 12 & 0x000F)); + writer.put(to_hex_character(cp >> 8 & 0x000F)); + writer.put(to_hex_character(cp >> 4 & 0x000F)); + writer.put(to_hex_character(cp & 0x000F)); + } + } + else + { + writer.put(c); + } + } + else + { + writer.put(c); + } + break; + } + } + } + // Implementing methods + void do_begin_json() override + { + } + + void do_end_json() override + { + writer_.flush(); + } + + void do_begin_object() override + { + if (!stack_.empty() && !stack_.back().is_object()) + { + if (!stack_.empty()) + { + if (stack_.back().count_ > 0) + { + writer_. put(','); + } + } + } + + if (indenting_) + { + if (!stack_.empty() && stack_.back().is_object()) + { + stack_.push_back(stack_item(true,options_.object_object_split_lines(), false)); + } + else if (!stack_.empty()) + { + if (options_.array_object_split_lines() != line_split_kind::same_line) + { + stack_.back().unindent_at_end_ = true; + stack_.push_back(stack_item(true,options_.array_object_split_lines(), false)); + write_indent1(); + } + else + { + stack_.push_back(stack_item(true,options_.array_object_split_lines(), false)); + } + } + else + { + stack_.push_back(stack_item(true, line_split_kind::multi_line, false)); + } + indent(); + } + else + { + stack_.push_back(stack_item(true)); + } + writer_.put('{'); + } + + void do_end_object() override + { + JSONCONS_ASSERT(!stack_.empty()); + if (indenting_) + { + unindent(); + if (stack_.back().unindent_at_end()) + { + write_indent(); + } + } + stack_.pop_back(); + writer_.put('}'); + + end_value(); + } + + + void do_begin_array() override + { + if (!stack_.empty() && !stack_.back().is_object()) + { + if (!stack_.empty()) + { + if (stack_.back().count_ > 0) + { + writer_. put(','); + } + } + } + if (indenting_) + { + if (!stack_.empty() && stack_.back().is_object()) + { + writer_.put('['); + indent(); + if (options_.object_array_split_lines() != line_split_kind::same_line) + { + stack_.push_back(stack_item(false,options_.object_array_split_lines(),true)); + } + else + { + stack_.push_back(stack_item(false,options_.object_array_split_lines(),false)); + } + } + else if (!stack_.empty()) + { + if (options_.array_array_split_lines() != line_split_kind::same_line) + { + write_indent(); + } + stack_.push_back(stack_item(false,options_.array_array_split_lines(), false)); + indent(); + writer_.put('['); + } + else + { + stack_.push_back(stack_item(false, line_split_kind::multi_line, false)); + indent(); + writer_.put('['); + } + } + else + { + stack_.push_back(stack_item(false)); + writer_.put('['); + } + } + + void do_end_array() override + { + JSONCONS_ASSERT(!stack_.empty()); + if (indenting_) + { + unindent(); + if (stack_.back().unindent_at_end()) + { + write_indent(); + } + } + stack_.pop_back(); + writer_.put(']'); + end_value(); + } + + void do_name(const string_view_type& name) override + { + if (!stack_.empty()) + { + if (stack_.back().count_ > 0) + { + writer_. put(','); + } + if (indenting_) + { + if (stack_.back().is_multi_line()) + { + write_indent(); + } + } + } + + writer_.put('\"'); + escape_string(name.data(), name.length(), options_, writer_); + writer_.put('\"'); + writer_.put(':'); + if (indenting_) + { + writer_.put(' '); + } + } + + void do_null_value() override + { + if (!stack_.empty() && !stack_.back().is_object()) + { + begin_scalar_value(); + } + + auto buf = detail::null_literal<CharT>(); + writer_.write(buf, 4); + + end_value(); + } + + void do_string_value(const string_view_type& value) override + { + if (!stack_.empty() && !stack_.back().is_object()) + { + begin_scalar_value(); + } + + writer_. put('\"'); + escape_string(value.data(), value.length(), options_, writer_); + writer_. put('\"'); + + end_value(); + } + + void do_byte_string_value(const uint8_t* data, size_t length) override + { + std::basic_string<CharT> s; + encode_base64url(data,data+length,s); + do_string_value(s); + } + + void do_double_value(double value, const number_format& fmt) override + { + if (!stack_.empty() && !stack_.back().is_object()) + { + begin_scalar_value(); + } + + if ((std::isnan)(value)) + { + writer_.write(options_.nan_replacement()); + } + else if (value == std::numeric_limits<double>::infinity()) + { + writer_.write(options_.pos_inf_replacement()); + } + else if (!(std::isfinite)(value)) + { + writer_.write(options_.neg_inf_replacement()); + } + else + { + fp_(value, fmt.precision(), writer_); + } + + end_value(); + } + + void do_integer_value(int64_t value) override + { + if (!stack_.empty() && !stack_.back().is_object()) + { + begin_scalar_value(); + } + detail::print_integer(value, writer_); + end_value(); + } + + void do_uinteger_value(uint64_t value) override + { + if (!stack_.empty() && !stack_.back().is_object()) + { + begin_scalar_value(); + } + detail::print_uinteger(value, writer_); + end_value(); + } + + void do_bool_value(bool value) override + { + if (!stack_.empty() && !stack_.back().is_object()) + { + begin_scalar_value(); + } + + if (value) + { + auto buf = detail::true_literal<CharT>(); + writer_.write(buf,4); + } + else + { + auto buf = detail::false_literal<CharT>(); + writer_.write(buf,5); + } + + end_value(); + } + + void begin_scalar_value() + { + if (!stack_.empty()) + { + if (stack_.back().count_ > 0) + { + writer_. put(','); + } + if (indenting_) + { + if (stack_.back().is_multi_line() || stack_.back().is_indent_once()) + { + write_indent(); + } + } + } + } + + void begin_value() + { + if (!stack_.empty()) + { + if (stack_.back().count_ > 0) + { + writer_. put(','); + } + if (indenting_) + { + if (stack_.back().is_new_line()) + { + write_indent(); + } + } + } + } + + void end_value() + { + if (!stack_.empty()) + { + ++stack_.back().count_; + } + } + + void indent() + { + indent_ += static_cast<int>(options_.indent()); + } + + void unindent() + { + indent_ -= static_cast<int>(options_.indent()); + } + + void write_indent() + { + if (!stack_.empty()) + { + stack_.back().unindent_at_end_ = true; + } + writer_. put('\n'); + for (int i = 0; i < indent_; ++i) + { + writer_. put(' '); + } + } + + void write_indent1() + { + writer_. put('\n'); + for (int i = 0; i < indent_; ++i) + { + writer_. put(' '); + } + } +}; + +typedef basic_json_serializer<char,detail::ostream_buffered_writer<char>> json_serializer; +typedef basic_json_serializer<wchar_t, detail::ostream_buffered_writer<wchar_t>> wjson_serializer; + +} +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/json_structures.hpp b/vendor/jsoncons-0.104.0/jsoncons/json_structures.hpp new file mode 100644 index 00000000..74aa1507 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/json_structures.hpp @@ -0,0 +1,1864 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_STRUCTURES_HPP +#define JSONCONS_JSON_STRUCTURES_HPP + +#include <string> +#include <vector> +#include <deque> +#include <exception> +#include <cstdlib> +#include <cstring> +#include <iostream> +#include <algorithm> +#include <sstream> +#include <iomanip> +#include <utility> +#include <initializer_list> +#include <jsoncons/json_exception.hpp> +#include <jsoncons/jsoncons_utilities.hpp> +#include <jsoncons/json_type_traits.hpp> + +namespace jsoncons { + +// json_array + +template <class Json> +class Json_array_base_ +{ +public: + typedef typename Json::allocator_type allocator_type; + +public: + Json_array_base_() + : self_allocator_() + { + } + Json_array_base_(const allocator_type& allocator) + : self_allocator_(allocator) + { + } + + allocator_type get_allocator() const + { + return self_allocator_; + } + + allocator_type self_allocator_; +}; + +// json_array + +template <class Json> +class json_array: public Json_array_base_<Json> +{ +public: + typedef typename Json::allocator_type allocator_type; + typedef Json value_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<value_type> val_allocator_type; + + typedef typename Json::array_storage_type array_storage_type; + + typedef typename array_storage_type::iterator iterator; + typedef typename array_storage_type::const_iterator const_iterator; + + typedef typename std::iterator_traits<iterator>::reference reference; + typedef typename std::iterator_traits<const_iterator>::reference const_reference; + + using Json_array_base_<Json>::get_allocator; + + json_array() + : Json_array_base_<Json>(), + elements_() + { + } + + explicit json_array(const allocator_type& allocator) + : Json_array_base_<Json>(allocator), + elements_(val_allocator_type(allocator)) + { + } + + explicit json_array(size_t n, + const allocator_type& allocator = allocator_type()) + : Json_array_base_<Json>(allocator), + elements_(n,Json(),val_allocator_type(allocator)) + { + } + + explicit json_array(size_t n, + const Json& value, + const allocator_type& allocator = allocator_type()) + : Json_array_base_<Json>(allocator), + elements_(n,value,val_allocator_type(allocator)) + { + } + + template <class InputIterator> + json_array(InputIterator begin, InputIterator end, const allocator_type& allocator = allocator_type()) + : Json_array_base_<Json>(allocator), + elements_(begin,end,val_allocator_type(allocator)) + { + } + json_array(const json_array& val) + : Json_array_base_<Json>(val.get_allocator()), + elements_(val.elements_) + { + } + json_array(const json_array& val, const allocator_type& allocator) + : Json_array_base_<Json>(allocator), + elements_(val.elements_,val_allocator_type(allocator)) + { + } + + json_array(json_array&& val) JSONCONS_NOEXCEPT + : Json_array_base_<Json>(val.get_allocator()), + elements_(std::move(val.elements_)) + { + } + json_array(json_array&& val, const allocator_type& allocator) + : Json_array_base_<Json>(allocator), + elements_(std::move(val.elements_),val_allocator_type(allocator)) + { + } + + json_array(std::initializer_list<Json> init) + : Json_array_base_<Json>(), + elements_(std::move(init)) + { + } + + json_array(std::initializer_list<Json> init, + const allocator_type& allocator) + : Json_array_base_<Json>(allocator), + elements_(std::move(init),val_allocator_type(allocator)) + { + } + ~json_array() + { + } + + void swap(json_array<Json>& val) + { + elements_.swap(val.elements_); + } + + size_t size() const {return elements_.size();} + + size_t capacity() const {return elements_.capacity();} + + void clear() {elements_.clear();} + + void shrink_to_fit() + { + for (size_t i = 0; i < elements_.size(); ++i) + { + elements_[i].shrink_to_fit(); + } + elements_.shrink_to_fit(); + } + + void reserve(size_t n) {elements_.reserve(n);} + + void resize(size_t n) {elements_.resize(n);} + + void resize(size_t n, const Json& val) {elements_.resize(n,val);} + + void remove_range(size_t from_index, size_t to_index) + { + JSONCONS_ASSERT(from_index <= to_index); + JSONCONS_ASSERT(to_index <= elements_.size()); + elements_.erase(elements_.begin()+from_index,elements_.begin()+to_index); + } + + void erase(const_iterator pos) + { + elements_.erase(pos); + } + + void erase(const_iterator first, const_iterator last) + { + elements_.erase(first,last); + } + + Json& operator[](size_t i) {return elements_[i];} + + const Json& operator[](size_t i) const {return elements_[i];} + + // push_back + + template <class T, class A=allocator_type> + typename std::enable_if<is_stateless<A>::value,void>::type + push_back(T&& value) + { + elements_.emplace_back(std::forward<T>(value)); + } + + template <class T, class A=allocator_type> + typename std::enable_if<!is_stateless<A>::value,void>::type + push_back(T&& value) + { + elements_.emplace_back(std::forward<T>(value),get_allocator()); + } + + template <class T, class A=allocator_type> + typename std::enable_if<is_stateless<A>::value,iterator>::type + insert(const_iterator pos, T&& value) + { +#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ < 9 + // work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54577 + iterator it = elements_.begin() + (pos - elements_.begin()); + return elements_.emplace(it, std::forward<T>(value)); +#else + return elements_.emplace(pos, std::forward<T>(value)); +#endif + } + template <class T, class A=allocator_type> + typename std::enable_if<!is_stateless<A>::value,iterator>::type + insert(const_iterator pos, T&& value) + { +#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ < 9 + // work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54577 + iterator it = elements_.begin() + (pos - elements_.begin()); + return elements_.emplace(it, std::forward<T>(value), get_allocator()); +#else + return elements_.emplace(pos, std::forward<T>(value), get_allocator()); +#endif + } + + template <class InputIt> + iterator insert(const_iterator pos, InputIt first, InputIt last) + { +#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ < 9 + // work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54577 + iterator it = elements_.begin() + (pos - elements_.begin()); + return elements_.insert(it, first, last); +#else + return elements_.insert(pos, first, last); +#endif + } + +#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ < 9 + // work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54577 + template <class A=allocator_type, class... Args> + typename std::enable_if<is_stateless<A>::value,iterator>::type + emplace(const_iterator pos, Args&&... args) + { + iterator it = elements_.begin() + (pos - elements_.begin()); + return elements_.emplace(it, std::forward<Args>(args)...); + } +#else + template <class A=allocator_type, class... Args> + typename std::enable_if<is_stateless<A>::value,iterator>::type + emplace(const_iterator pos, Args&&... args) + { + return elements_.emplace(pos, std::forward<Args>(args)...); + } +#endif + template <class... Args> + Json& emplace_back(Args&&... args) + { + elements_.emplace_back(std::forward<Args>(args)...); + return elements_.back(); + } + + iterator begin() {return elements_.begin();} + + iterator end() {return elements_.end();} + + const_iterator begin() const {return elements_.begin();} + + const_iterator end() const {return elements_.end();} + + bool operator==(const json_array<Json>& rhs) const + { + if (size() != rhs.size()) + { + return false; + } + for (size_t i = 0; i < size(); ++i) + { + if (elements_[i] != rhs.elements_[i]) + { + return false; + } + } + return true; + } +private: + array_storage_type elements_; + + json_array& operator=(const json_array<Json>&) = delete; +}; + +// json_object + +template <class BidirectionalIt,class BinaryPredicate> +BidirectionalIt last_wins_unique_sequence(BidirectionalIt first, BidirectionalIt last, BinaryPredicate compare) +{ + + if (first == last) + { + return last; + } + + typedef typename BidirectionalIt::value_type value_type; + typedef typename BidirectionalIt::pointer pointer; + std::vector<value_type> dups; + { + std::vector<pointer> v(std::distance(first,last)); + auto p = v.begin(); + for (auto it = first; it != last; ++it) + { + *p++ = &(*it); + } + std::sort(v.begin(), v.end(), [&](pointer a, pointer b){return compare(*a,*b)<0;}); + auto it = v.begin(); + auto end = v.end(); + for (auto begin = it+1; begin != end; ++it, ++begin) + { + if (compare(*(*it),*(*begin)) == 0) + { + dups.push_back(*(*it)); + } + } + } + if (dups.size() == 0) + { + return last; + } + + auto it = last; + for (auto p = first; p != last && p != it; ) + { + bool no_dup = true; + if (dups.size() > 0) + { + for (auto q = dups.begin(); no_dup && q != dups.end();) + { + if (compare(*p,*q) == 0) + { + dups.erase(q); + no_dup = false; + } + else + { + ++q; + } + } + } + if (!no_dup) + { + --it; + for (auto r = p; r != it; ++r) + { + *r = std::move(*(r+1)); + } + } + else + { + ++p; + } + } + + return it; +} + +template <class KeyT, class ValueT> +class key_value_pair +{ +public: + typedef KeyT key_storage_type; + typedef typename KeyT::value_type char_type; + typedef typename KeyT::allocator_type allocator_type; + typedef typename ValueT::string_view_type string_view_type; + + key_value_pair() + { + } + + key_value_pair(const key_storage_type& name, const ValueT& val) + : key_(name), value_(val) + { + } + + template <class T> + key_value_pair(key_storage_type&& name, T&& val) + : key_(std::forward<key_storage_type>(name)), + value_(std::forward<T>(val)) + { + } + + template <class T> + key_value_pair(key_storage_type&& name, + T&& val, + const allocator_type& allocator) + : key_(std::forward<key_storage_type>(name)), value_(std::forward<T>(val), allocator) + { + } + + key_value_pair(const key_value_pair& member) + : key_(member.key_), value_(member.value_) + { + } + + key_value_pair(key_value_pair&& member) + : key_(std::move(member.key_)), value_(std::move(member.value_)) + { + } + + string_view_type key() const + { + return string_view_type(key_.data(),key_.size()); + } + + ValueT& value() + { + return value_; + } + + const ValueT& value() const + { + return value_; + } + + template <class T> + void value(T&& value) + { + value_ = std::forward<T>(value); + } + + void swap(key_value_pair& member) + { + key_.swap(member.key_); + value_.swap(member.value_); + } + + key_value_pair& operator=(const key_value_pair& member) + { + if (this != & member) + { + key_ = member.key_; + value_ = member.value_; + } + return *this; + } + + key_value_pair& operator=(key_value_pair&& member) + { + if (this != &member) + { + key_.swap(member.key_); + value_.swap(member.value_); + } + return *this; + } + + void shrink_to_fit() + { + key_.shrink_to_fit(); + value_.shrink_to_fit(); + } +#if !defined(JSONCONS_NO_DEPRECATED) + const key_storage_type& name() const + { + return key_; + } +#endif +private: + key_storage_type key_; + ValueT value_; +}; + +template <class KeyT,class Json> +class Json_object_ +{ +public: + typedef typename Json::allocator_type allocator_type; + typedef typename Json::char_type char_type; + typedef typename Json::char_allocator_type char_allocator_type; + typedef KeyT key_storage_type; + typedef typename Json::string_view_type string_view_type; + typedef key_value_pair<KeyT,Json> value_type; + + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<value_type> kvp_allocator_type; + typedef typename Json::object_storage_type object_storage_type; + + typedef typename object_storage_type::iterator iterator; + typedef typename object_storage_type::const_iterator const_iterator; + +protected: + allocator_type self_allocator_; + object_storage_type members_; +public: + Json_object_() + : self_allocator_(), members_() + { + } + Json_object_(const allocator_type& allocator) + : self_allocator_(allocator), + members_(kvp_allocator_type(allocator)) + { + } + + Json_object_(const Json_object_& val) + : self_allocator_(val.get_allocator()), members_(val.members_) + { + } + + Json_object_(Json_object_&& val) + : self_allocator_(val.get_allocator()), + members_(std::move(val.members_)) + { + } + + Json_object_(const Json_object_& val, const allocator_type& allocator) : + self_allocator_(allocator), + members_(val.members_,kvp_allocator_type(allocator)) + { + } + + Json_object_(Json_object_&& val,const allocator_type& allocator) : + self_allocator_(allocator), members_(std::move(val.members_),kvp_allocator_type(allocator)) + { + } + + void swap(Json_object_& val) + { + members_.swap(val.members_); + } + + allocator_type get_allocator() const + { + return this->self_allocator_; + } +}; + +// json_object + +template <class KeyT,class Json,bool PreserveOrder> +class json_object +{ +}; + +// Do not preserve order +template <class KeyT,class Json> +class json_object<KeyT,Json,false> final : public Json_object_<KeyT,Json> +{ +public: + using typename Json_object_<KeyT,Json>::allocator_type; + using typename Json_object_<KeyT,Json>::char_type; + using typename Json_object_<KeyT,Json>::char_allocator_type; + using typename Json_object_<KeyT,Json>::key_storage_type; + using typename Json_object_<KeyT,Json>::string_view_type; + using typename Json_object_<KeyT,Json>::value_type; + using typename Json_object_<KeyT,Json>::kvp_allocator_type; + using typename Json_object_<KeyT,Json>::object_storage_type; + using typename Json_object_<KeyT,Json>::iterator; + using typename Json_object_<KeyT,Json>::const_iterator; + using Json_object_<KeyT,Json>::get_allocator; + + json_object() + : Json_object_<KeyT,Json>() + { + } + json_object(const allocator_type& allocator) + : Json_object_<KeyT,Json>(allocator) + { + } + + json_object(const json_object& val) + : Json_object_<KeyT,Json>(val) + { + } + + json_object(json_object&& val) + : Json_object_<KeyT,Json>(std::forward<json_object>(val)) + { + } + + json_object(const json_object& val, const allocator_type& allocator) + : Json_object_<KeyT,Json>(val,allocator) + { + } + + json_object(json_object&& val,const allocator_type& allocator) + : Json_object_<KeyT,Json>(std::forward<json_object>(val),allocator) + { + } + + json_object(std::initializer_list<std::pair<string_view_type,Json>> init) + : Json_object_<KeyT,Json>() + { + this->members_.reserve(init.size()); + for (auto& item : init) + { + insert_or_assign(item.first, std::move(item.second)); + } + } + + json_object(std::initializer_list<std::pair<string_view_type,Json>> init, + const allocator_type& allocator) + : Json_object_<KeyT,Json>(allocator) + { + this->members_.reserve(init.size()); + for (auto& item : init) + { + insert_or_assign(item.first, std::move(item.second), allocator); + } + } + + void swap(json_object& val) + { + Json_object_<KeyT,Json>::swap(val); + } + + iterator begin() + { + return this->members_.begin(); + } + + iterator end() + { + return this->members_.end(); + } + + const_iterator begin() const + { + return this->members_.begin(); + } + + const_iterator end() const + { + return this->members_.end(); + } + + size_t size() const {return this->members_.size();} + + size_t capacity() const {return this->members_.capacity();} + + void clear() {this->members_.clear();} + + void shrink_to_fit() + { + for (size_t i = 0; i < this->members_.size(); ++i) + { + this->members_[i].shrink_to_fit(); + } + this->members_.shrink_to_fit(); + } + + void reserve(size_t n) {this->members_.reserve(n);} + + Json& at(size_t i) + { + if (i >= this->members_.size()) + { + JSONCONS_THROW(json_exception_impl<std::out_of_range>("Invalid array subscript")); + } + return this->members_[i].value(); + } + + const Json& at(size_t i) const + { + if (i >= this->members_.size()) + { + JSONCONS_THROW(json_exception_impl<std::out_of_range>("Invalid array subscript")); + } + return this->members_[i].value(); + } + + iterator find(const string_view_type& name) + { + auto it = std::lower_bound(this->members_.begin(),this->members_.end(), name, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + auto result = (it != this->members_.end() && it->key() == name) ? it : this->members_.end(); + return result; + } + + const_iterator find(const string_view_type& name) const + { + auto it = std::lower_bound(this->members_.begin(),this->members_.end(), + name, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + auto result = (it != this->members_.end() && it->key() == name) ? it : this->members_.end(); + return result; + } + + void erase(const_iterator pos) + { + this->members_.erase(pos); + } + + void erase(const_iterator first, const_iterator last) + { + this->members_.erase(first,last); + } + + void erase(const string_view_type& name) + { + auto it = std::lower_bound(this->members_.begin(),this->members_.end(), name, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + if (it != this->members_.end() && it->key() == name) + { + this->members_.erase(it); + } + } + + template<class InputIt, class UnaryPredicate> + void insert(InputIt first, InputIt last, UnaryPredicate pred) + { + size_t count = std::distance(first,last); + this->members_.reserve(this->members_.size() + count); + for (auto s = first; s != last; ++s) + { + this->members_.emplace_back(pred(*s)); + } + std::stable_sort(this->members_.begin(),this->members_.end(), + [](const value_type& a, const value_type& b){return a.key().compare(b.key()) < 0;}); + auto it = std::unique(this->members_.rbegin(), this->members_.rend(), + [](const value_type& a, const value_type& b){ return !(a.key().compare(b.key()));}); + this->members_.erase(this->members_.begin(),it.base()); + } + + // merge + + void merge(const json_object& source) + { + for (auto it = source.begin(); it != source.end(); ++it) + { + try_emplace(it->key(),it->value()); + } + } + + void merge(json_object&& source) + { + auto it = std::make_move_iterator(source.begin()); + auto end = std::make_move_iterator(source.end()); + for (; it != end; ++it) + { + auto pos = std::lower_bound(this->members_.begin(),this->members_.end(), it->key(), + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + if (pos == this->members_.end() ) + { + this->members_.emplace_back(*it); + } + else if (it->key() != pos->key()) + { + this->members_.emplace(pos,*it); + } + } + } + + void merge(iterator hint, const json_object& source) + { + for (auto it = source.begin(); it != source.end(); ++it) + { + hint = try_emplace(hint, it->key(),it->value()); + } + } + + void merge(iterator hint, json_object&& source) + { + auto it = std::make_move_iterator(source.begin()); + auto end = std::make_move_iterator(source.end()); + for (; it != end; ++it) + { + iterator pos; + if (hint != this->members_.end() && hint->key() <= it->key()) + { + pos = std::lower_bound(hint,this->members_.end(), it->key(), + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + else + { + pos = std::lower_bound(this->members_.begin(),this->members_.end(), it->key(), + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + if (pos == this->members_.end() ) + { + this->members_.emplace_back(*it); + hint = this->members_.begin() + (this->members_.size() - 1); + } + else if (it->key() != pos->key()) + { + hint = this->members_.emplace(pos,*it); + } + } + } + + // merge_or_update + + void merge_or_update(const json_object& source) + { + for (auto it = source.begin(); it != source.end(); ++it) + { + insert_or_assign(it->key(),it->value()); + } + } + + void merge_or_update(json_object&& source) + { + auto it = std::make_move_iterator(source.begin()); + auto end = std::make_move_iterator(source.end()); + for (; it != end; ++it) + { + auto pos = std::lower_bound(this->members_.begin(),this->members_.end(), it->key(), + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + if (pos == this->members_.end() ) + { + this->members_.emplace_back(*it); + } + else + { + pos->value(it->value()); + } + } + } + + void merge_or_update(iterator hint, const json_object& source) + { + for (auto it = source.begin(); it != source.end(); ++it) + { + hint = insert_or_assign(hint, it->key(),it->value()); + } + } + + void merge_or_update(iterator hint, json_object&& source) + { + auto it = std::make_move_iterator(source.begin()); + auto end = std::make_move_iterator(source.end()); + for (; it != end; ++it) + { + iterator pos; + if (hint != this->members_.end() && hint->key() <= it->key()) + { + pos = std::lower_bound(hint,this->members_.end(), it->key(), + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + else + { + pos = std::lower_bound(this->members_.begin(),this->members_.end(), it->key(), + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + if (pos == this->members_.end() ) + { + this->members_.emplace_back(*it); + hint = this->members_.begin() + (this->members_.size() - 1); + } + else + { + pos->value(it->value()); + hint = pos; + } + } + } + + // insert_or_assign + + template <class T, class A=allocator_type> + typename std::enable_if<is_stateless<A>::value,std::pair<iterator,bool>>::type + insert_or_assign(const string_view_type& name, T&& value) + { + bool inserted; + auto it = std::lower_bound(this->members_.begin(),this->members_.end(), name, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + if (it == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(name.begin(),name.end()), + std::forward<T>(value)); + inserted = true; + it = this->members_.begin() + this->members_.size() - 1; + } + else if (it->key() == name) + { + it->value(Json(std::forward<T>(value))); + inserted = false; // assigned + } + else + { + it = this->members_.emplace(it, + key_storage_type(name.begin(),name.end()), + std::forward<T>(value)); + inserted = true; + } + return std::make_pair(it,inserted); + } + + template <class T, class A=allocator_type> + typename std::enable_if<!is_stateless<A>::value,std::pair<iterator,bool>>::type + insert_or_assign(const string_view_type& name, T&& value) + { + bool inserted; + auto it = std::lower_bound(this->members_.begin(),this->members_.end(), name, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + if (it == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(name.begin(),name.end(), get_allocator()), + std::forward<T>(value),get_allocator()); + inserted = true; + it = this->members_.begin() + this->members_.size() - 1; + } + else if (it->key() == name) + { + it->value(Json(std::forward<T>(value), get_allocator())); + inserted = false; // assigned + } + else + { + it = this->members_.emplace(it, + key_storage_type(name.begin(),name.end(), get_allocator()), + std::forward<T>(value),get_allocator()); + inserted = true; + } + return std::make_pair(it,inserted); + } + + // try_emplace + + template <class A=allocator_type, class... Args> + typename std::enable_if<is_stateless<A>::value,std::pair<iterator,bool>>::type + try_emplace(const string_view_type& name, Args&&... args) + { + bool inserted; + auto it = std::lower_bound(this->members_.begin(),this->members_.end(), name, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + if (it == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(name.begin(),name.end()), + std::forward<Args>(args)...); + it = this->members_.begin() + this->members_.size() - 1; + inserted = true; + } + else if (it->key() == name) + { + inserted = false; + } + else + { + it = this->members_.emplace(it, + key_storage_type(name.begin(),name.end()), + std::forward<Args>(args)...); + inserted = true; + } + return std::make_pair(it,inserted); + } + + template <class A=allocator_type, class... Args> + typename std::enable_if<!is_stateless<A>::value,std::pair<iterator,bool>>::type + try_emplace(const string_view_type& name, Args&&... args) + { + bool inserted; + auto it = std::lower_bound(this->members_.begin(),this->members_.end(), name, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + if (it == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(name.begin(),name.end(), get_allocator()), + std::forward<Args>(args)...); + it = this->members_.begin() + this->members_.size() - 1; + inserted = true; + } + else if (it->key() == name) + { + inserted = false; + } + else + { + it = this->members_.emplace(it, + key_storage_type(name.begin(),name.end(), get_allocator()), + std::forward<Args>(args)...); + inserted = true; + } + return std::make_pair(it,inserted); + } + + template <class A=allocator_type, class ... Args> + typename std::enable_if<is_stateless<A>::value,iterator>::type + try_emplace(iterator hint, const string_view_type& name, Args&&... args) + { + iterator it; + if (hint != this->members_.end() && hint->key() <= name) + { + it = std::lower_bound(hint,this->members_.end(), name, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + else + { + it = std::lower_bound(this->members_.begin(),this->members_.end(), name, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + + if (it == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(name.begin(),name.end()), + std::forward<Args>(args)...); + it = this->members_.begin() + (this->members_.size() - 1); + } + else if (it->key() == name) + { + } + else + { + it = this->members_.emplace(it, + key_storage_type(name.begin(),name.end()), + std::forward<Args>(args)...); + } + return it; + } + + template <class A=allocator_type, class ... Args> + typename std::enable_if<!is_stateless<A>::value,iterator>::type + try_emplace(iterator hint, const string_view_type& name, Args&&... args) + { + iterator it; + if (hint != this->members_.end() && hint->key() <= name) + { + it = std::lower_bound(hint,this->members_.end(), name, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + else + { + it = std::lower_bound(this->members_.begin(),this->members_.end(), name, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + + if (it == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(name.begin(),name.end(), get_allocator()), + std::forward<Args>(args)...); + it = this->members_.begin() + (this->members_.size() - 1); + } + else if (it->key() == name) + { + } + else + { + it = this->members_.emplace(it, + key_storage_type(name.begin(),name.end(), get_allocator()), + std::forward<Args>(args)...); + } + return it; + } + + // set_ + + template <class T, class A=allocator_type> + typename std::enable_if<is_stateless<A>::value,void>::type + set_(key_storage_type&& name, T&& value) + { + string_view_type s(name.data(), name.size()); + auto it = std::lower_bound(this->members_.begin(),this->members_.end(), s, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + if (it == this->members_.end()) + { + this->members_.emplace_back(std::forward<key_storage_type>(name), + std::forward<T>(value)); + } + else if (string_view_type(it->key().data(),it->key().length()) == s) + { + it->value(Json(std::forward<T>(value))); + } + else + { + this->members_.emplace(it, + std::forward<key_storage_type>(name), + std::forward<T>(value)); + } + } + + template <class T, class A=allocator_type> + typename std::enable_if<!is_stateless<A>::value,void>::type + set_(key_storage_type&& name, T&& value) + { + string_view_type s(name.data(), name.size()); + auto it = std::lower_bound(this->members_.begin(),this->members_.end(), s, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + if (it == this->members_.end()) + { + this->members_.emplace_back(std::forward<key_storage_type>(name), + std::forward<T>(value),get_allocator() ); + } + else if (string_view_type(it->key().data(), it->key().length()) == s) + { + it->value(Json(std::forward<T>(value),get_allocator() )); + } + else + { + this->members_.emplace(it, + std::forward<key_storage_type>(name), + std::forward<T>(value),get_allocator() ); + } + } + + template <class T, class A=allocator_type> + typename std::enable_if<is_stateless<A>::value,iterator>::type + insert_or_assign(iterator hint, const string_view_type& name, T&& value) + { + iterator it; + if (hint != this->members_.end() && hint->key() <= name) + { + it = std::lower_bound(hint,this->members_.end(), name, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + else + { + it = std::lower_bound(this->members_.begin(),this->members_.end(), name, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + + if (it == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(name.begin(),name.end()), + std::forward<T>(value)); + it = this->members_.begin() + (this->members_.size() - 1); + } + else if (it->key() == name) + { + it->value(Json(std::forward<T>(value))); + } + else + { + it = this->members_.emplace(it, + key_storage_type(name.begin(),name.end()), + std::forward<T>(value)); + } + return it; + } + + template <class T, class A=allocator_type> + typename std::enable_if<!is_stateless<A>::value,iterator>::type + insert_or_assign(iterator hint, const string_view_type& name, T&& value) + { + iterator it; + if (hint != this->members_.end() && hint->key() <= name) + { + it = std::lower_bound(hint,this->members_.end(), name, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + else + { + it = std::lower_bound(this->members_.begin(),this->members_.end(), name, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + + if (it == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(name.begin(),name.end(), get_allocator()), + std::forward<T>(value),get_allocator()); + it = this->members_.begin() + (this->members_.size() - 1); + } + else if (it->key() == name) + { + it->value(Json(std::forward<T>(value),get_allocator())); + } + else + { + it = this->members_.emplace(it, + key_storage_type(name.begin(),name.end(), get_allocator()), + std::forward<T>(value),get_allocator()); + } + return it; + } + + template <class T, class A=allocator_type> + typename std::enable_if<is_stateless<A>::value,iterator>::type + set_(iterator hint, key_storage_type&& name, T&& value) + { + string_view_type s(name.data(), name.size()); + iterator it; + if (hint != this->members_.end() && hint->key() <= s) + { + it = std::lower_bound(hint,this->members_.end(), s, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + else + { + it = std::lower_bound(this->members_.begin(),this->members_.end(), s, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + + if (it == this->members_.end()) + { + this->members_.emplace_back(std::forward<key_storage_type>(name), + std::forward<T>(value)); + it = this->members_.begin() + (this->members_.size() - 1); + } + else if (string_view_type(it->key().data(), it->key().length()) == s) + { + it->value(Json(std::forward<T>(value))); + } + else + { + it = this->members_.emplace(it, + std::forward<key_storage_type>(name), + std::forward<T>(value)); + } + return it; + } + + template <class T, class A=allocator_type> + typename std::enable_if<!is_stateless<A>::value,iterator>::type + set_(iterator hint, key_storage_type&& name, T&& value) + { + string_view_type s(name.data(), name.size()); + iterator it; + if (hint != this->members_.end() && hint->key() <= s) + { + it = std::lower_bound(hint,this->members_.end(), s, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + else + { + it = std::lower_bound(this->members_.begin(),this->members_.end(), s, + [](const value_type& a, const string_view_type& k){return a.key().compare(k) < 0;}); + } + + if (it == this->members_.end()) + { + this->members_.emplace_back(std::forward<key_storage_type>(name), + std::forward<T>(value),get_allocator() ); + it = this->members_.begin() + (this->members_.size() - 1); + } + else if (string_view_type(it->key().data(), it->key().length()) == s) + { + it->value(Json(std::forward<T>(value),get_allocator() )); + } + else + { + it = this->members_.emplace(it, + std::forward<key_storage_type>(name), + std::forward<T>(value),get_allocator() ); + } + return it; + } + + bool operator==(const json_object& rhs) const + { + if (size() != rhs.size()) + { + return false; + } + for (auto it = this->members_.begin(); it != this->members_.end(); ++it) + { + + auto rhs_it = std::lower_bound(rhs.begin(), rhs.end(), *it, + [](const value_type& a, const value_type& b){return a.key().compare(b.key()) < 0;}); + if (rhs_it == rhs.end() || rhs_it->key() != it->key() || rhs_it->value() != it->value()) + { + return false; + } + } + return true; + } +private: + json_object& operator=(const json_object&) = delete; +}; + +// Preserve order +template <class KeyT,class Json> +class json_object<KeyT,Json,true> final : public Json_object_<KeyT,Json> +{ +public: + using typename Json_object_<KeyT,Json>::allocator_type; + using typename Json_object_<KeyT,Json>::char_type; + using typename Json_object_<KeyT,Json>::char_allocator_type; + using typename Json_object_<KeyT,Json>::key_storage_type; + using typename Json_object_<KeyT,Json>::string_view_type; + using typename Json_object_<KeyT,Json>::value_type; + using typename Json_object_<KeyT,Json>::kvp_allocator_type; + using typename Json_object_<KeyT,Json>::object_storage_type; + using typename Json_object_<KeyT,Json>::iterator; + using typename Json_object_<KeyT,Json>::const_iterator; + using Json_object_<KeyT,Json>::get_allocator; + + json_object() + : Json_object_<KeyT,Json>() + { + } + json_object(const allocator_type& allocator) + : Json_object_<KeyT,Json>(allocator) + { + } + + json_object(const json_object& val) + : Json_object_<KeyT,Json>(val) + { + } + + json_object(json_object&& val) + : Json_object_<KeyT,Json>(std::forward<json_object>(val)) + { + } + + json_object(const json_object& val, const allocator_type& allocator) + : Json_object_<KeyT,Json>(val,allocator) + { + } + + json_object(json_object&& val,const allocator_type& allocator) + : Json_object_<KeyT,Json>(std::forward<json_object>(val),allocator) + { + } + + json_object(std::initializer_list<typename Json::array> init) + : Json_object_<KeyT,Json>() + { + for (const auto& element : init) + { + if (element.size() != 2 || !element[0].is_string()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Cannot create object from initializer list")); + break; + } + } + for (auto& element : init) + { + insert_or_assign(element[0].as_string_view(), std::move(element[1])); + } + } + + json_object(std::initializer_list<typename Json::array> init, + const allocator_type& allocator) + : Json_object_<KeyT,Json>(allocator) + { + for (const auto& element : init) + { + if (element.size() != 2 || !element[0].is_string()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Cannot create object from initializer list")); + break; + } + } + for (auto& element : init) + { + insert_or_assign(element[0].as_string_view(), std::move(element[1])); + } + } + + void swap(json_object& val) + { + Json_object_<KeyT,Json>::swap(val); + } + + iterator begin() + { + return this->members_.begin(); + } + + iterator end() + { + return this->members_.end(); + } + + const_iterator begin() const + { + return this->members_.begin(); + } + + const_iterator end() const + { + return this->members_.end(); + } + + size_t size() const {return this->members_.size();} + + size_t capacity() const {return this->members_.capacity();} + + void clear() {this->members_.clear();} + + void shrink_to_fit() + { + for (size_t i = 0; i < this->members_.size(); ++i) + { + this->members_[i].shrink_to_fit(); + } + this->members_.shrink_to_fit(); + } + + void reserve(size_t n) {this->members_.reserve(n);} + + Json& at(size_t i) + { + if (i >= this->members_.size()) + { + JSONCONS_THROW(json_exception_impl<std::out_of_range>("Invalid array subscript")); + } + return this->members_[i].value(); + } + + const Json& at(size_t i) const + { + if (i >= this->members_.size()) + { + JSONCONS_THROW(json_exception_impl<std::out_of_range>("Invalid array subscript")); + } + return this->members_[i].value(); + } + + iterator find(const string_view_type& name) + { + return std::find_if(this->members_.begin(),this->members_.end(), + [name](const value_type& kv){return kv.key() == name;}); + } + + const_iterator find(const string_view_type& name) const + { + return std::find_if(this->members_.begin(),this->members_.end(), + [name](const value_type& kv){return kv.key() == name;}); + } + + void erase(const_iterator first, const_iterator last) + { + this->members_.erase(first,last); + } + + void erase(const string_view_type& name) + { + auto it = std::find_if(this->members_.begin(),this->members_.end(), + [name](const value_type& kv){return kv.key() == name;}); + if (it != this->members_.end()) + { + this->members_.erase(it); + } + } + + template<class InputIt, class UnaryPredicate> + void insert(InputIt first, InputIt last, UnaryPredicate pred) + { + size_t count = std::distance(first,last); + this->members_.reserve(this->members_.size() + count); + for (auto s = first; s != last; ++s) + { + this->members_.emplace_back(pred(*s)); + } + auto it = last_wins_unique_sequence(this->members_.begin(), this->members_.end(), + [](const value_type& a, const value_type& b){ return a.key().compare(b.key());}); + this->members_.erase(it,this->members_.end()); + } + + // insert_or_assign + + template <class T, class A=allocator_type> + typename std::enable_if<is_stateless<A>::value,std::pair<iterator,bool>>::type + insert_or_assign(const string_view_type& name, T&& value) + { + bool inserted; + auto it = std::find_if(this->members_.begin(),this->members_.end(), + [name](const value_type& a){return a.key() == name;}); + + if (it == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(name.begin(),name.end()), + std::forward<T>(value)); + it = this->members_.begin() + this->members_.size() - 1; + inserted = true; + } + else + { + it->value(Json(std::forward<T>(value))); + inserted = false; // assigned + } + return std::make_pair(it,inserted); + } + + template <class T, class A=allocator_type> + typename std::enable_if<!is_stateless<A>::value,std::pair<iterator,bool>>::type + insert_or_assign(const string_view_type& name, T&& value) + { + bool inserted; + auto it = std::find_if(this->members_.begin(),this->members_.end(), + [name](const value_type& a){return a.key() == name;}); + + if (it == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(name.begin(),name.end(),get_allocator()), + std::forward<T>(value),get_allocator()); + it = this->members_.begin() + this->members_.size() - 1; + inserted = true; + } + else + { + it->value(Json(std::forward<T>(value),get_allocator())); + inserted = false; // assigned + } + return std::make_pair(it,inserted); + } + + template <class A=allocator_type, class T> + typename std::enable_if<is_stateless<A>::value,iterator>::type + insert_or_assign(iterator hint, const string_view_type& key, T&& value) + { + iterator it; + if (hint == this->members_.end()) + { + auto result = insert_or_assign(key, std::forward<T>(value)); + it = result.first; + } + else + { + it = std::find_if(this->members_.begin(),this->members_.end(), + [key](const value_type& a){return a.key() == key;}); + + if (it == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(key.begin(),key.end()), + std::forward<T>(value)); + it = this->members_.begin() + this->members_.size() - 1; + } + else + { + it->value(Json(std::forward<T>(value))); + } + } + return it; + } + + template <class A=allocator_type, class T> + typename std::enable_if<!is_stateless<A>::value,iterator>::type + insert_or_assign(iterator hint, const string_view_type& key, T&& value) + { + iterator it; + if (hint == this->members_.end()) + { + auto result = insert_or_assign(key, std::forward<T>(value)); + it = result.first; + } + else + { + it = std::find_if(this->members_.begin(),this->members_.end(), + [key](const value_type& a){return a.key() == key;}); + + if (it == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(key.begin(),key.end(),get_allocator()), + std::forward<T>(value),get_allocator()); + it = this->members_.begin() + this->members_.size() - 1; + } + else + { + it->value(Json(std::forward<T>(value),get_allocator())); + } + } + return it; + } + + // merge + + void merge(const json_object& source) + { + for (auto it = source.begin(); it != source.end(); ++it) + { + try_emplace(it->key(),it->value()); + } + } + + void merge(json_object&& source) + { + auto it = std::make_move_iterator(source.begin()); + auto end = std::make_move_iterator(source.end()); + for (; it != end; ++it) + { + auto pos = std::find_if(this->members_.begin(),this->members_.end(), + [it](const value_type& a){return a.key() == it->key();}); + if (pos == this->members_.end() ) + { + this->members_.emplace_back(*it); + } + } + } + + void merge(iterator hint, const json_object& source) + { + for (auto it = source.begin(); it != source.end(); ++it) + { + hint = try_emplace(hint, it->key(),it->value()); + } + } + + void merge(iterator hint, json_object&& source) + { + auto it = std::make_move_iterator(source.begin()); + auto end = std::make_move_iterator(source.end()); + for (; it != end; ++it) + { + auto pos = std::find_if(this->members_.begin(),this->members_.end(), + [it](const value_type& a){return a.key() == it->key();}); + if (pos == this->members_.end() ) + { + hint = this->members_.emplace(hint,*it); + } + } + } + + // merge_or_update + + void merge_or_update(const json_object& source) + { + for (auto it = source.begin(); it != source.end(); ++it) + { + insert_or_assign(it->key(),it->value()); + } + } + + void merge_or_update(json_object&& source) + { + auto it = std::make_move_iterator(source.begin()); + auto end = std::make_move_iterator(source.end()); + for (; it != end; ++it) + { + auto pos = std::find_if(this->members_.begin(),this->members_.end(), + [it](const value_type& a){return a.key() == it->key();}); + if (pos == this->members_.end() ) + { + this->members_.emplace_back(*it); + } + else + { + pos->value(it->value()); + } + } + } + + void merge_or_update(iterator hint, const json_object& source) + { + for (auto it = source.begin(); it != source.end(); ++it) + { + hint = insert_or_assign(hint, it->key(),it->value()); + } + } + + void merge_or_update(iterator hint, json_object&& source) + { + auto it = std::make_move_iterator(source.begin()); + auto end = std::make_move_iterator(source.end()); + for (; it != end; ++it) + { + auto pos = std::find_if(this->members_.begin(),this->members_.end(), + [it](const value_type& a){return a.key() == it->key();}); + if (pos == this->members_.end() ) + { + hint = this->members_.emplace(hint,*it); + } + else + { + pos->value(it->value()); + hint = pos; + } + } + } + + // try_emplace + template <class A=allocator_type, class... Args> + typename std::enable_if<is_stateless<A>::value,std::pair<iterator,bool>>::type + try_emplace(const string_view_type& key, Args&&... args) + { + bool inserted; + auto it = std::find_if(this->members_.begin(),this->members_.end(), + [key](const value_type& a){return a.key() == key;}); + + if (it == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(key.begin(),key.end()), + std::forward<Args>(args)...); + it = this->members_.begin() + this->members_.size() - 1; + inserted = true; + + } + else + { + inserted = false; + } + return std::make_pair(it,inserted); + } + + template <class A=allocator_type, class... Args> + typename std::enable_if<!is_stateless<A>::value,std::pair<iterator,bool>>::type + try_emplace(const string_view_type& key, Args&&... args) + { + bool inserted; + auto it = std::find_if(this->members_.begin(),this->members_.end(), + [key](const value_type& a){return a.key() == key;}); + + if (it == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(key.begin(),key.end(), get_allocator()), + std::forward<Args>(args)...); + it = this->members_.begin() + this->members_.size() - 1; + inserted = true; + + } + else + { + inserted = false; + } + return std::make_pair(it,inserted); + } + + template <class A=allocator_type, class ... Args> + typename std::enable_if<is_stateless<A>::value,iterator>::type + try_emplace(iterator hint, const string_view_type& key, Args&&... args) + { + auto it = std::find_if(this->members_.begin(),this->members_.end(), + [key](const value_type& a){return a.key() == key;}); + + if (it == this->members_.end()) + { + if (hint == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(key.begin(),key.end()), + std::forward<Args>(args)...); + it = this->members_.begin() + (this->members_.size() - 1); + } + else + { + it = this->members_.emplace(hint, + key_storage_type(key.begin(),key.end()), + std::forward<Args>(args)...); + } + } + return it; + } + + template <class A=allocator_type, class ... Args> + typename std::enable_if<!is_stateless<A>::value,iterator>::type + try_emplace(iterator hint, const string_view_type& key, Args&&... args) + { + auto it = std::find_if(this->members_.begin(),this->members_.end(), + [key](const value_type& a){return a.key() == key;}); + + if (it == this->members_.end()) + { + if (hint == this->members_.end()) + { + this->members_.emplace_back(key_storage_type(key.begin(),key.end(), get_allocator()), + std::forward<Args>(args)...); + it = this->members_.begin() + (this->members_.size() - 1); + } + else + { + it = this->members_.emplace(hint, + key_storage_type(key.begin(),key.end(), get_allocator()), + std::forward<Args>(args)...); + } + } + return it; + } + + // set_ + + template <class T, class A=allocator_type> + typename std::enable_if<is_stateless<A>::value,void>::type + set_(key_storage_type&& key, T&& value) + { + string_view_type s(key.data(),key.size()); + auto it = std::find_if(this->members_.begin(),this->members_.end(), + [s](const value_type& a){return a.key().compare(s) == 0;}); + + if (it == this->members_.end()) + { + this->members_.emplace_back(std::forward<key_storage_type>(key), + std::forward<T>(value)); + } + else + { + it->value(Json(std::forward<T>(value))); + } + } + + template <class T, class A=allocator_type> + typename std::enable_if<!is_stateless<A>::value,void>::type + set_(key_storage_type&& key, T&& value) + { + string_view_type s(key.data(),key.size()); + auto it = std::find_if(this->members_.begin(),this->members_.end(), + [s](const value_type& a){return a.key().compare(s) == 0;}); + + if (it == this->members_.end()) + { + this->members_.emplace_back(std::forward<key_storage_type>(key), + std::forward<T>(value),get_allocator()); + } + else + { + it->value(Json(std::forward<T>(value),get_allocator())); + } + } + + template <class T, class A=allocator_type> + typename std::enable_if<is_stateless<A>::value,iterator>::type + set_(iterator hint, key_storage_type&& key, T&& value) + { + iterator it = hint; + + if (it == this->members_.end()) + { + this->members_.emplace_back(std::forward<key_storage_type>(key), + std::forward<T>(value)); + it = this->members_.begin() + (this->members_.size() - 1); + } + else if (it->key() == key) + { + it->value(Json(std::forward<T>(value))); + } + else + { + it = this->members_.emplace(it, + std::forward<key_storage_type>(key), + std::forward<T>(value)); + } + return it; + } + + template <class T, class A=allocator_type> + typename std::enable_if<!is_stateless<A>::value,iterator>::type + set_(iterator hint, key_storage_type&& key, T&& value) + { + iterator it = hint; + + if (it == this->members_.end()) + { + this->members_.emplace_back(std::forward<key_storage_type>(key), + std::forward<T>(value), get_allocator()); + it = this->members_.begin() + (this->members_.size() - 1); + } + else if (it->key() == key) + { + it->value(Json(std::forward<T>(value), get_allocator())); + } + else + { + it = this->members_.emplace(it, + std::forward<key_storage_type>(key), + std::forward<T>(value), get_allocator()); + } + return it; + } + + bool operator==(const json_object& rhs) const + { + if (size() != rhs.size()) + { + return false; + } + for (auto it = this->members_.begin(); it != this->members_.end(); ++it) + { + auto rhs_it = std::find_if(rhs.begin(),rhs.end(), + [it](const value_type& a){return a.key() == it->key();}); + if (rhs_it == rhs.end() || rhs_it->key() != it->key() || rhs_it->value() != it->value()) + { + return false; + } + } + return true; + } +private: + json_object& operator=(const json_object&) = delete; +}; + +} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/json_type_traits.hpp b/vendor/jsoncons-0.104.0/jsoncons/json_type_traits.hpp new file mode 100644 index 00000000..1c76c4c0 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/json_type_traits.hpp @@ -0,0 +1,966 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSON_TYPE_TRAITS_HPP +#define JSONCONS_JSON_TYPE_TRAITS_HPP + +#include <array> +#include <string> +#include <vector> +#include <valarray> +#include <exception> +#include <cstdlib> +#include <cstring> +#include <utility> +#include <algorithm> +#include <fstream> +#include <limits> +#include <type_traits> +#include <jsoncons/jsoncons_utilities.hpp> +#include <jsoncons/detail/type_traits_helper.hpp> + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wswitch" +#endif + +namespace jsoncons { + +// null_type + +struct null_type +{ +}; + +// json_type_traits + +template <class Json, class T, class Enable=void> +struct json_type_traits +{ + static const bool is_compatible = false; + + static bool is(const Json&) + { + return false; + } +}; + +namespace detail { + +// is_incompatible +template<class Json, class T, class Enable = void> +struct is_incompatible : std::false_type {}; + + +// is_incompatible +template<class Json, class T> +struct is_incompatible<Json,T, + typename std::enable_if<!std::integral_constant<bool, json_type_traits<Json, T>::is_compatible>::value>::type +> : std::true_type {}; + +// is_compatible_string_type +template<class Json, class T, class Enable=void> +struct is_compatible_string_type : std::false_type {}; + +template<class Json, class T> +struct is_compatible_string_type<Json,T, + typename std::enable_if<!std::is_same<T,typename Json::array>::value && + detail::is_string_like<T>::value && + !is_incompatible<Json,typename std::iterator_traits<typename T::iterator>::value_type>::value +>::type> : std::true_type {}; + +// is_compatible_array_type +template<class Json, class T, class Enable=void> +struct is_compatible_array_type : std::false_type {}; + +template<class Json, class T> +struct is_compatible_array_type<Json,T, + typename std::enable_if<!std::is_same<T,typename Json::array>::value && + detail::is_vector_like<T>::value && + !is_incompatible<Json,typename std::iterator_traits<typename T::iterator>::value_type>::value +>::type> : std::true_type {}; + +// is_compatible_object_type +template<class Json, class T, class Enable=void> +struct is_compatible_object_type : std::false_type {}; + +template<class Json, class T> +struct is_compatible_object_type<Json,T, + typename std::enable_if< + !is_incompatible<Json,typename T::mapped_type>::value +>::type> : std::true_type {}; + +// is_std_array +template<class T> +struct is_std_array : std::false_type {}; + +template<class E, size_t N> +struct is_std_array<std::array<E, N>> : std::true_type {}; + +template <class Json, class T> +class json_array_input_iterator +{ +public: + typedef typename Json::const_array_iterator iterator_base; + typedef typename std::iterator_traits<iterator_base>::value_type value_type; + typedef typename std::iterator_traits<iterator_base>::difference_type difference_type; + typedef typename std::iterator_traits<iterator_base>::pointer pointer; + typedef T reference; + typedef std::input_iterator_tag iterator_category; + + json_array_input_iterator() + { + } + + json_array_input_iterator(iterator_base it) + : it_(it) + { + } + + json_array_input_iterator& operator=(json_array_input_iterator rhs) + { + swap(*this,rhs); + return *this; + } + + json_array_input_iterator& operator++() + { + ++it_; + return *this; + } + + json_array_input_iterator operator++(int) // postfix increment + { + json_array_input_iterator temp(*this); + ++it_; + return temp; + } + + json_array_input_iterator& operator--() + { + --it_; + return *this; + } + + json_array_input_iterator operator--(int) + { + json_array_input_iterator temp(*this); + --it_; + return temp; + } + + reference operator*() const + { + return json_type_traits<Json,T>::as(*it_); + } + + friend bool operator==(const json_array_input_iterator& it1, const json_array_input_iterator& it2) + { + return it1.it_ == it2.it_; + } + friend bool operator!=(const json_array_input_iterator& it1, const json_array_input_iterator& it2) + { + return !(it1.it_ == it2.it_); + } + friend void swap(json_array_input_iterator& lhs, json_array_input_iterator& rhs) + { + using std::swap; + swap(lhs.it_,rhs.it_); + swap(lhs.empty_,rhs.empty_); + } + +private: + iterator_base it_; +}; + +template <class Json, class T> +class json_object_input_iterator +{ +public: + typedef typename Json::const_object_iterator iterator_base; + typedef typename std::iterator_traits<iterator_base>::value_type value_type; + typedef typename std::iterator_traits<iterator_base>::difference_type difference_type; + typedef typename std::iterator_traits<iterator_base>::pointer pointer; + typedef T reference; + typedef std::input_iterator_tag iterator_category; + typedef typename T::first_type key_type; + typedef typename T::second_type mapped_type; + + json_object_input_iterator() + { + } + + json_object_input_iterator(iterator_base it) + : it_(it) + { + } + + json_object_input_iterator& operator=(json_object_input_iterator rhs) + { + swap(*this,rhs); + return *this; + } + + json_object_input_iterator& operator++() + { + ++it_; + return *this; + } + + json_object_input_iterator operator++(int) // postfix increment + { + json_object_input_iterator temp(*this); + ++it_; + return temp; + } + + json_object_input_iterator& operator--() + { + --it_; + return *this; + } + + json_object_input_iterator operator--(int) + { + json_object_input_iterator temp(*this); + --it_; + return temp; + } + + reference operator*() const + { + return T(key_type(it_->key()),json_type_traits<Json,mapped_type>::as(it_->value())); + } + + friend bool operator==(const json_object_input_iterator& it1, const json_object_input_iterator& it2) + { + return it1.it_ == it2.it_; + } + friend bool operator!=(const json_object_input_iterator& it1, const json_object_input_iterator& it2) + { + return !(it1.it_ == it2.it_); + } + friend void swap(json_object_input_iterator& lhs, json_object_input_iterator& rhs) + { + using std::swap; + swap(lhs.it_,rhs.it_); + swap(lhs.empty_,rhs.empty_); + } + +private: + iterator_base it_; +}; + +} + +template<class Json> +struct json_type_traits<Json, typename type_wrapper<typename Json::char_type>::const_pointer_type> +{ + typedef typename Json::char_type char_type; + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + return j.is_string(); + } + static const char_type* as(const Json& j) + { + return j.as_cstring(); + } + template <class ... Args> + static Json to_json(Args&&... args) + { + return Json(typename Json::variant(std::forward<Args>(args)...)); + } +}; + +template<class Json> +struct json_type_traits<Json, typename type_wrapper<typename Json::char_type>::pointer_type> +{ + typedef typename Json::char_type char_type; + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + return j.is_string(); + } + template <class ... Args> + static Json to_json(Args&&... args) + { + return Json(typename Json::variant(std::forward<Args>(args)...)); + } +}; + +// integral + +template<class Json, class T> +struct json_type_traits<Json, T, + typename std::enable_if<detail::is_integer_like<T>::value +>::type> +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + if (j.is_integer()) + { + return j.as_integer() >= (std::numeric_limits<T>::min)() && j.as_integer() <= (std::numeric_limits<T>::max)(); + } + else if (j.is_uinteger()) + { + return j.as_uinteger() <= static_cast<uint64_t>((std::numeric_limits<T>::max)()); + } + else + { + return false; + } + } + static T as(const Json& j) + { + return static_cast<T>(j.as_integer()); + } + template <class ... Args> + static Json to_json(Args&&... args) + { + return Json::from_integer(std::forward<Args>(args)...); + } +}; + +template<class Json, class T> +struct json_type_traits<Json, T, + typename std::enable_if<detail::is_uinteger_like<T>::value +>::type > +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + if (j.is_integer()) + { + return j.as_integer() >= 0 && static_cast<uint64_t>(j.as_integer()) <= (std::numeric_limits<T>::max)(); + } + else if (j.is_uinteger()) + { + return j.as_uinteger() <= (std::numeric_limits<T>::max)(); + } + else + { + return false; + } + } + static T as(const Json& j) + { + return static_cast<T>(j.as_uinteger()); + } + + template <class ... Args> + static Json to_json(Args&&... args) + { + return Json::from_uinteger(std::forward<Args>(args)...); + } +}; + +template<class Json,class T> +struct json_type_traits<Json, T, + typename std::enable_if<std::is_floating_point<T>::value +>::type> +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + return j.is_double(); + } + static T as(const Json& j) + { + return static_cast<T>(j.as_double()); + } + template <class ... Args> + static Json to_json(Args&&... args) + { + return Json::from_floating_point(std::forward<Args>(args)...); + } +}; + +template<class Json> +struct json_type_traits<Json, typename Json::object> +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + return j.is_object(); + } + template <class ... Args> + static Json to_json(Args&&... args) + { + return Json(typename Json::variant(std::forward<Args>(args)...)); + } +}; + +template<class Json> +struct json_type_traits<Json, typename Json::array> +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + return j.is_array(); + } + template <class ... Args> + static Json to_json(Args&&... args) + { + return Json(typename Json::variant(std::forward<Args>(args)...)); + } +}; + +template<class Json> +struct json_type_traits<Json, Json> +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json&) JSONCONS_NOEXCEPT + { + return true; + } + static Json as(Json j) + { + return j; + } + static Json to_json(const Json& val) + { + return val; + } + static Json to_json(const Json& val, allocator_type) + { + return val; + } +}; + +template<class Json> +struct json_type_traits<Json, jsoncons::null_type> +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + return j.is_null(); + } + static typename jsoncons::null_type as(const Json& j) + { + JSONCONS_ASSERT(j.is_null()); + return jsoncons::null_type(); + } + static Json to_json(jsoncons::null_type) + { + return Json::null(); + } + static Json to_json(jsoncons::null_type, allocator_type) + { + return Json::null(); + } +}; + +template<class Json> +struct json_type_traits<Json, bool> +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + return j.is_bool(); + } + static bool as(const Json& j) + { + return j.as_bool(); + } + template <class ... Args> + static Json to_json(Args&&... args) + { + return Json(typename Json::variant(std::forward<Args>(args)...)); + } +}; + +template<class Json,class T> +struct json_type_traits<Json, T, typename std::enable_if<std::is_same<T, + std::conditional<!std::is_same<bool,std::vector<bool>::const_reference>::value, + std::vector<bool>::const_reference, + void>::type>::value>::type> +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + return j.is_bool(); + } + static bool as(const Json& j) + { + return j.as_bool(); + } + template <class ... Args> + static Json to_json(Args&&... args) + { + return Json(typename Json::variant(std::forward<Args>(args)...)); + } +}; + +template<class Json> +struct json_type_traits<Json, std::vector<bool>::reference> +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + return j.is_bool(); + } + static bool as(const Json& j) + { + return j.as_bool(); + } + template <class ... Args> + static Json to_json(Args&&... args) + { + return Json(typename Json::variant(std::forward<Args>(args)...)); + } +}; + +template<class Json, typename T> +struct json_type_traits<Json, T, + typename std::enable_if<detail::is_compatible_array_type<Json,T>::value && + !detail::is_std_array<T>::value>::type> +{ + typedef typename std::iterator_traits<typename T::iterator>::value_type element_type; + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + bool result = j.is_array(); + if (result) + { + for (auto e : j.array_range()) + { + if (!e.template is<element_type>()) + { + result = false; + break; + } + } + } + return result; + } + + template <class Ty = element_type> + static typename std::enable_if<!(std::is_integral<Ty>::value && !std::is_same<Ty,bool>::value),T>::type + as(const Json& j) + { + if (j.is_array()) + { + T v(detail::json_array_input_iterator<Json, element_type>(j.array_range().begin()), + detail::json_array_input_iterator<Json, element_type>(j.array_range().end())); + return v; + } + else + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempt to cast json non-array to array")); + } + } + + template <class Ty = element_type> + static typename std::enable_if<std::is_integral<Ty>::value && !std::is_same<Ty,bool>::value,T>::type + as(const Json& j) + { + if (j.is_array()) + { + T v(detail::json_array_input_iterator<Json, element_type>(j.array_range().begin()), + detail::json_array_input_iterator<Json, element_type>(j.array_range().end())); + return v; + } + else if (j.is_byte_string()) + { + T v(j.as_byte_string_view().begin(),j.as_byte_string_view().end()); + return v; + } + else + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempt to cast json non-array to array")); + } + } + + static Json to_json(const T& val) + { + Json j = typename Json::array(); + auto first = std::begin(val); + auto last = std::end(val); + size_t size = std::distance(first,last); + j.reserve(size); + for (auto it = first; it != last; ++it) + { + j.push_back(*it); + } + return j; + } + + static Json to_json(const T& val, const allocator_type& allocator) + { + Json j = typename Json::array(allocator); + auto first = std::begin(val); + auto last = std::end(val); + size_t size = std::distance(first, last); + j.reserve(size); + for (auto it = first; it != last; ++it) + { + j.push_back(*it); + } + return j; + } +}; + +template<class Json, typename T> +struct json_type_traits<Json, T, + typename std::enable_if<detail::is_compatible_string_type<Json,T>::value>::type> +{ + typedef typename std::iterator_traits<typename T::iterator>::value_type element_type; + typedef typename Json::allocator_type allocator_type; + typedef typename T::allocator_type string_allocator_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + return j.is_string(); + } + + static T as(const Json& j) + { + if (j.is_string()) + { + return j.as_string(string_allocator_type()); + } + else + { + T s; + j.dump(s); + return s; + } + } + + static Json to_json(const T& val) + { + return Json(typename Json::variant(val.data(), val.size())); + } + + static Json to_json(const T& val, const allocator_type& allocator) + { + return Json(typename Json::variant(val.data(),val.size(),allocator)); + } +}; + +template<class Json, typename T> +struct json_type_traits<Json, T, + typename std::enable_if<detail::is_compatible_object_type<Json,T>::value>::type +> +{ + typedef typename T::mapped_type mapped_type; + typedef typename T::value_type value_type; + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + bool result = j.is_object(); + for (auto member : j.object_range()) + { + if (!member.value().template is<mapped_type>()) + { + result = false; + } + } + return result; + } + + static T as(const Json& j) + { + T v(detail::json_object_input_iterator<Json,value_type>(j.object_range().begin()), + detail::json_object_input_iterator<Json,value_type>(j.object_range().end())); + return v; + } + + static Json to_json(const T& val) + { + Json j; + j.reserve(val.size()); + for (auto p: val) + { + j.set(p.first, p.second); + } + return j; + } + + static Json to_json(const T& val, const allocator_type& allocator) + { + Json j(allocator); + j.reserve(val.size()); + for (auto p: val) + { + j.set(p.first, p.second); + } + return j; + } +}; + +template<class Json, class E, size_t N> +struct json_type_traits<Json, std::array<E, N>> +{ + typedef typename Json::allocator_type allocator_type; + + typedef E element_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + bool result = j.is_array() && j.size() == N; + if (result) + { + for (auto e : j.array_range()) + { + if (!e.template is<element_type>()) + { + result = false; + break; + } + } + } + return result; + } + + static std::array<E, N> as(const Json& j) + { + std::array<E, N> buff; + JSONCONS_ASSERT(j.size() == N); + for (size_t i = 0; i < N; i++) + { + buff[i] = j[i].template as<E>(); + } + return buff; + } + + static Json to_json(const std::array<E, N>& val) + { + Json j = typename Json::array(); + j.reserve(N); + for (auto it = val.begin(); it != val.end(); ++it) + { + j.push_back(*it); + } + return j; + } + + static Json to_json(const std::array<E, N>& val, + const allocator_type& allocator) + { + Json j = typename Json::array(allocator); + j.reserve(N); + for (auto it = val.begin(); it != val.end(); ++it) + { + j.push_back(*it); + } + return j; + } +}; + +namespace detail +{ + +template<size_t Pos, class Json, class Tuple> +struct json_tuple_helper +{ + using element_type = typename std::tuple_element<Pos - 1, Tuple>::type; + using next = json_tuple_helper<Pos - 1, Json, Tuple>; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + if(j[Pos - 1].template is<element_type>()) + { + return next::is(j); + } + else + { + return false; + } + } + + static void as(Tuple& tuple, const Json& j) + { + std::get<Pos - 1>(tuple) = j[Pos - 1].template as<element_type>(); + next::as(tuple, j); + } + + static void to_json(const Tuple& tuple, std::array<Json, std::tuple_size<Tuple>::value>& jsons) + { + jsons[Pos - 1] = json_type_traits<Json, element_type>::to_json(std::get<Pos-1>(tuple)); + next::to_json(tuple, jsons); + } +}; + +template<class Json, class Tuple> +struct json_tuple_helper<0, Json, Tuple> +{ + static bool is(const Json&) JSONCONS_NOEXCEPT + { + return true; + } + + static void as(Tuple&, const Json&) + { + } + + static void to_json(const Tuple&, std::array<Json, std::tuple_size<Tuple>::value>&) + { + } +}; + +} + +template<class Json, typename... E> +struct json_type_traits<Json, std::tuple<E...>> +{ +private: + using helper = detail::json_tuple_helper<sizeof...(E), Json, std::tuple<E...>>; + +public: + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + return helper::is(j); + } + + static std::tuple<E...> as(const Json& j) + { + std::tuple<E...> buff; + helper::as(buff, j); + return buff; + } + + static Json to_json(const std::tuple<E...>& val) + { + std::array<Json, sizeof...(E)> buf; + helper::to_json(val, buf); + return Json(typename Json::array(buf.begin(), buf.end())); + } +}; + +template<class Json, class T1, class T2> +struct json_type_traits<Json, std::pair<T1,T2>> +{ +public: + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + return j.is_array() && j.size() == 2; + } + + static std::pair<T1,T2> as(const Json& j) + { + return std::make_pair<T1,T2>(j[0]. template as<T1>(),j[1]. template as<T2>()); + } + + static Json to_json(const std::pair<T1,T2>& val) + { + return typename Json::array{val.first,val.second}; + } +}; + +template<class Json, class Allocator> +struct json_type_traits<Json, basic_byte_string<Allocator>> +{ +public: + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + return j.is_byte_string(); + } + + static basic_byte_string<Allocator> as(const Json& j) + { + return basic_byte_string<Allocator>(j.as_byte_string_view()); + } + + static Json to_json(const basic_byte_string<Allocator>& val) + { + return Json(val.data(),val.length()); + } +}; + +// std::valarray + +template<class Json, class T> +struct json_type_traits<Json, std::valarray<T>> +{ + typedef typename Json::allocator_type allocator_type; + + static bool is(const Json& j) JSONCONS_NOEXCEPT + { + bool result = j.is_array(); + if (result) + { + for (auto e : j.array_range()) + { + if (!e.template is<T>()) + { + result = false; + break; + } + } + } + return result; + } + + static std::valarray<T> as(const Json& j) + { + if (j.is_array()) + { + std::valarray<T> v(j.size()); + for (size_t i = 0; i < j.size(); ++i) + { + v[i] = j[i].template as<T>(); + } + return v; + } + else + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Attempt to cast json non-array to array")); + } + } + + static Json to_json(const std::valarray<T>& val) + { + Json j = typename Json::array(); + auto first = std::begin(val); + auto last = std::end(val); + size_t size = std::distance(first,last); + j.reserve(size); + for (auto it = first; it != last; ++it) + { + j.push_back(*it); + } + return j; + } + + static Json to_json(const std::valarray<T>& val, const allocator_type& allocator) + { + Json j = typename Json::array(allocator); + auto first = std::begin(val); + auto last = std::end(val); + size_t size = std::distance(first,last); + j.reserve(size); + for (auto it = first; it != last; ++it) + { + j.push_back(*it); + } + return j; + } +}; + +} + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/jsoncons_config.hpp b/vendor/jsoncons-0.104.0/jsoncons/jsoncons_config.hpp new file mode 100644 index 00000000..59c6b650 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/jsoncons_config.hpp @@ -0,0 +1,106 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONCONS_CONFIG_HPP +#define JSONCONS_JSONCONS_CONFIG_HPP + +#include <stdexcept> +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <ostream> +#include <iomanip> +#include <cstdlib> +#include <cmath> +#include <cstdarg> +#include <exception> +#include <limits> // std::numeric_limits + +// Uncomment the following line to suppress deprecated names (recommended for new code) +//#define JSONCONS_NO_DEPRECATED + +// The definitions below follow the definitions in compiler_support_p.h, https://github.com/01org/tinycbor +// MIT license + +#if defined(__GNUC__) || defined(__clang__) +#define JSONCONS_LIKELY(x) __builtin_expect(!!(x), 1) +#define JSONCONS_UNLIKELY(x) __builtin_expect(!!(x), 0) +#define JSONCONS_UNREACHABLE() __builtin_unreachable() +#elif defined(_MSC_VER) +#define JSONCONS_LIKELY(x) x +#define JSONCONS_UNLIKELY(x) x +#define JSONCONS_UNREACHABLE() __assume(0) +#else +#define JSONCONS_LIKELY(x) x +#define JSONCONS_UNLIKELY(x) x +#define JSONCONS_UNREACHABLE() do {} while (0) +#endif + +namespace jsoncons +{ + +#if _MSC_VER > 1800 // _MSC_VER == 1800 -> MS Visual Studio 2013 +#else +#define JSONCONS_NO_CONSTEXPR +#endif + +#define JSONCONS_NO_TO_CHARS + +#if defined(_MSC_VER) +#if _MSC_VER >= 1900 +#define JSONCONS_HAS_USER_DEFINED_LITERALS +#endif +#else +#define JSONCONS_HAS_USER_DEFINED_LITERALS +#endif + +//#define JSONCONS_HAS_STRING_VIEW + +#if defined(ANDROID) || defined(__ANDROID__) +#define JSONCONS_HAS_STRTOLD_L +#define JSONCONS_NO_LOCALECONV +#endif + +#if defined (__clang__) +#if defined(_GLIBCXX_USE_NOEXCEPT) +#define JSONCONS_NOEXCEPT _GLIBCXX_USE_NOEXCEPT +#else +#define JSONCONS_NOEXCEPT noexcept +#endif +#elif defined(__GNUC__) +#define JSONCONS_NOEXCEPT _GLIBCXX_USE_NOEXCEPT +#elif defined(_MSC_VER) +#if _MSC_VER >= 1900 +#define JSONCONS_NOEXCEPT noexcept +#else +#define JSONCONS_NOEXCEPT +#endif +#else +#define JSONCONS_NOEXCEPT +#endif + +#if defined(_MSC_VER) +#define JSONCONS_HAS_MSC__STRTOD_L +#define JSONCONS_HAS__ECVT_S +#define JSONCONS_HAS_FOPEN_S +#if _MSC_VER >= 1900 +#define JSONCONS_ALIGNOF alignof +#else +#define JSONCONS_ALIGNOF __alignof +#endif +#else +#define JSONCONS_ALIGNOF alignof +#endif + +#define JSONCONS_DEFINE_LITERAL( name, lit ) \ +template< class Ch > Ch const* name(); \ +template<> inline char const * name<char>() { return lit; } \ +template<> inline wchar_t const* name<wchar_t>() { return L ## lit; } + +} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/jsoncons_utilities.hpp b/vendor/jsoncons-0.104.0/jsoncons/jsoncons_utilities.hpp new file mode 100644 index 00000000..28a9eb71 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/jsoncons_utilities.hpp @@ -0,0 +1,954 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONCONSUTILITIES_HPP +#define JSONCONS_JSONCONSUTILITIES_HPP + +#include <stdexcept> +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <ostream> +#include <iomanip> +#include <cstdlib> +#include <cmath> +#include <cstdarg> +#include <locale> +#include <limits> +#include <type_traits> +#include <algorithm> +#include <memory> +#include <iterator> +#include <exception> +#include <array> +#include <initializer_list> +#include <jsoncons/jsoncons_config.hpp> +#include <jsoncons/json_exception.hpp> +#if !defined(JSONCONS_NO_TO_CHARS) +#include <charconv> +#endif +#include <jsoncons/detail/obufferedstream.hpp> + +namespace jsoncons +{ + +#if !defined(JSONCONS_HAS_STRING_VIEW) +template <class CharT, class Traits = std::char_traits<CharT>> +class Basic_string_view_ +{ +private: + const CharT* data_; + size_t length_; +public: + typedef CharT value_type; + typedef const CharT& const_reference; + typedef Traits traits_type; + typedef std::size_t size_type; + static const size_type npos = size_type(-1); + typedef const CharT* const_iterator; + typedef const CharT* iterator; + typedef std::reverse_iterator<const_iterator> const_reverse_iterator; + + Basic_string_view_() + : data_(nullptr), length_(0) + { + } + Basic_string_view_(const CharT* data, size_t length) + : data_(data), length_(length) + { + } + Basic_string_view_(const CharT* data) + : data_(data), length_(Traits::length(data)) + { + } + Basic_string_view_(const Basic_string_view_& other) = default; + + template <class Allocator> + Basic_string_view_(const std::basic_string<CharT,Traits,Allocator>& s) + : data_(s.data()), length_(s.length()) + { + } + + template <class Allocator> + explicit operator std::basic_string<CharT,Traits,Allocator>() const + { + return std::basic_string<CharT,Traits>(data_,length_); + } + + // iterator support + const_iterator begin() const JSONCONS_NOEXCEPT + { + return data_; + } + const_iterator end() const JSONCONS_NOEXCEPT + { + return data_ + length_; + } + const_iterator cbegin() const JSONCONS_NOEXCEPT + { + return data_; + } + const_iterator cend() const JSONCONS_NOEXCEPT + { + return data_ + length_; + } + const_reverse_iterator rbegin() const JSONCONS_NOEXCEPT + { + return const_reverse_iterator(end()); + } + const_reverse_iterator rend() const JSONCONS_NOEXCEPT + { + return const_reverse_iterator(begin()); + } + const_reverse_iterator crbegin() const JSONCONS_NOEXCEPT + { + return const_reverse_iterator(end()); + } + const_reverse_iterator crend() const JSONCONS_NOEXCEPT + { + return const_reverse_iterator(begin()); + } + + // capacity + + size_t size() const + { + return length_; + } + + size_t length() const + { + return length_; + } + size_type max_size() const JSONCONS_NOEXCEPT + { + return length_; + } + bool empty() const JSONCONS_NOEXCEPT + { + return length_ == 0; + } + + // element access + + const_reference operator[](size_type pos) const + { + return data_[pos]; + } + + const_reference at(size_t pos) const + { + if (pos >= length_) + { + JSONCONS_THROW(json_exception_impl<std::out_of_range>("pos exceeds length")); + } + return data_[pos]; + } + + const_reference front() const + { + return data_[0]; + } + const_reference back() const + { + return data_[length_-1]; + } + + const CharT* data() const + { + return data_; + } + + // string operations + + Basic_string_view_ substr(size_type pos, size_type n=npos) const + { + if (pos > length_) + { + JSONCONS_THROW(json_exception_impl<std::out_of_range>("pos exceeds size")); + } + if (n == npos || pos + n > length_) + { + n = length_ - pos; + } + return Basic_string_view_(data_ + pos, n); + } + + int compare(Basic_string_view_ s) const + { + const int rc = Traits::compare(data_, s.data_, (std::min)(length_, s.length_)); + return rc != 0 ? rc : (length_ == s.length_ ? 0 : length_ < s.length_ ? -1 : 1); + } + + int compare(const CharT* data) const + { + const size_t length = Traits::length(data); + const int rc = Traits::compare(data_, data, (std::min)(length_, length)); + return rc != 0 ? rc : (length_ == length? 0 : length_ < length? -1 : 1); + } + + template <class Allocator> + int compare(const std::basic_string<CharT,Traits,Allocator>& s) const + { + const int rc = Traits::compare(data_, s.data(), (std::min)(length_, s.length())); + return rc != 0 ? rc : (length_ == s.length() ? 0 : length_ < s.length() ? -1 : 1); + } + + size_type find(Basic_string_view_ s, size_type pos = 0) const JSONCONS_NOEXCEPT + { + if (pos > length_) + { + return npos; + } + if (s.length_ == 0) + { + return pos; + } + const_iterator it = std::search(cbegin() + pos, cend(), + s.cbegin(), s.cend(), Traits::eq); + return it == cend() ? npos : std::distance(cbegin(), it); + } + size_type find(CharT ch, size_type pos = 0) const JSONCONS_NOEXCEPT + { + return find(Basic_string_view_(&ch, 1), pos); + } + size_type find(const CharT* s, size_type pos, size_type n) const JSONCONS_NOEXCEPT + { + return find(Basic_string_view_(s, n), pos); + } + size_type find(const CharT* s, size_type pos = 0) const JSONCONS_NOEXCEPT + { + return find(Basic_string_view_(s), pos); + } + + size_type rfind(Basic_string_view_ s, size_type pos = npos) const JSONCONS_NOEXCEPT + { + if (length_ < s.length_) + { + return npos; + } + if (pos > length_ - s.length_) + { + pos = length_ - s.length_; + } + if (s.length_ == 0) + { + return pos; + } + for (const CharT* p = data_ + pos; true; --p) + { + if (Traits::compare(p, s.data_, s.length_) == 0) + { + return p - data_; + } + if (p == data_) + { + return npos; + } + }; + } + size_type rfind(CharT ch, size_type pos = npos) const JSONCONS_NOEXCEPT + { + return rfind(Basic_string_view_(&ch, 1), pos); + } + size_type rfind(const CharT* s, size_type pos, size_type n) const JSONCONS_NOEXCEPT + { + return rfind(Basic_string_view_(s, n), pos); + } + size_type rfind(const CharT* s, size_type pos = npos) const JSONCONS_NOEXCEPT + { + return rfind(Basic_string_view_(s), pos); + } + + size_type find_first_of(Basic_string_view_ s, size_type pos = 0) const JSONCONS_NOEXCEPT + { + if (pos >= length_ || s.length_ == 0) + { + return npos; + } + const_iterator it = std::find_first_of + (cbegin() + pos, cend(), s.cbegin(), s.cend(), Traits::eq); + return it == cend() ? npos : std::distance (cbegin(), it); + } + size_type find_first_of(CharT ch, size_type pos = 0) const JSONCONS_NOEXCEPT + { + return find_first_of(Basic_string_view_(&ch, 1), pos); + } + size_type find_first_of(const CharT* s, size_type pos, size_type n) const JSONCONS_NOEXCEPT + { + return find_first_of(Basic_string_view_(s, n), pos); + } + size_type find_first_of(const CharT* s, size_type pos = 0) const JSONCONS_NOEXCEPT + { + return find_first_of(Basic_string_view_(s), pos); + } + + size_type find_last_of(Basic_string_view_ s, size_type pos = npos) const JSONCONS_NOEXCEPT + { + if (s.length_ == 0) + { + return npos; + } + if (pos >= length_) + { + pos = 0; + } + else + { + pos = length_ - (pos+1); + } + const_reverse_iterator it = std::find_first_of + (crbegin() + pos, crend(), s.cbegin(), s.cend(), Traits::eq); + return it == crend() ? npos : (length_ - 1 - std::distance(crbegin(), it)); + } + size_type find_last_of(CharT ch, size_type pos = npos) const JSONCONS_NOEXCEPT + { + return find_last_of(Basic_string_view_(&ch, 1), pos); + } + size_type find_last_of(const CharT* s, size_type pos, size_type n) const JSONCONS_NOEXCEPT + { + return find_last_of(Basic_string_view_(s, n), pos); + } + size_type find_last_of(const CharT* s, size_type pos = npos) const JSONCONS_NOEXCEPT + { + return find_last_of(Basic_string_view_(s), pos); + } + + size_type find_first_not_of(Basic_string_view_ s, size_type pos = 0) const JSONCONS_NOEXCEPT + { + if (pos >= length_) + return npos; + if (s.length_ == 0) + return pos; + + const_iterator it = cend(); + for (auto p = cbegin()+pos; p != cend(); ++p) + { + if (Traits::find(s.data_, s.length_, *p) == 0) + { + it = p; + break; + } + } + return it == cend() ? npos : std::distance (cbegin(), it); + } + size_type find_first_not_of(CharT ch, size_type pos = 0) const JSONCONS_NOEXCEPT + { + return find_first_not_of(Basic_string_view_(&ch, 1), pos); + } + size_type find_first_not_of(const CharT* s, size_type pos, size_type n) const JSONCONS_NOEXCEPT + { + return find_first_not_of(Basic_string_view_(s, n), pos); + } + size_type find_first_not_of(const CharT* s, size_type pos = 0) const JSONCONS_NOEXCEPT + { + return find_first_not_of(Basic_string_view_(s), pos); + } + + size_type find_last_not_of(Basic_string_view_ s, size_type pos = npos) const JSONCONS_NOEXCEPT + { + if (pos >= length_) + { + pos = length_ - 1; + } + if (s.length_ == 0) + { + return pos; + } + pos = length_ - (pos+1); + + const_iterator it = crend(); + for (auto p = crbegin()+pos; p != crend(); ++p) + { + if (Traits::find(s.data_, s.length_, *p) == 0) + { + it = p; + break; + } + } + return it == crend() ? npos : (length_ - 1 - std::distance(crbegin(), it)); + } + size_type find_last_not_of(CharT ch, size_type pos = npos) const JSONCONS_NOEXCEPT + { + return find_last_not_of(Basic_string_view_(&ch, 1), pos); + } + size_type find_last_not_of(const CharT* s, size_type pos, size_type n) const JSONCONS_NOEXCEPT + { + return find_last_not_of(Basic_string_view_(s, n), pos); + } + size_type find_last_not_of(const CharT* s, size_type pos = npos) const JSONCONS_NOEXCEPT + { + return find_last_not_of(Basic_string_view_(s), pos); + } + + friend std::basic_ostream<CharT>& operator<<(std::basic_ostream<CharT>& os, const Basic_string_view_& sv) + { + os.write(sv.data_,sv.length_); + return os; + } +}; + +// == +template<class CharT,class Traits> +bool operator==(const Basic_string_view_<CharT,Traits>& lhs, + const Basic_string_view_<CharT,Traits>& rhs) +{ + return lhs.compare(rhs) == 0; +} +template<class CharT,class Traits,class Allocator> +bool operator==(const Basic_string_view_<CharT,Traits>& lhs, + const std::basic_string<CharT,Traits,Allocator>& rhs) +{ + return lhs.compare(rhs) == 0; +} +template<class CharT,class Traits,class Allocator> +bool operator==(const std::basic_string<CharT,Traits,Allocator>& lhs, + const Basic_string_view_<CharT,Traits>& rhs) +{ + return rhs.compare(lhs) == 0; +} +template<class CharT,class Traits> +bool operator==(const Basic_string_view_<CharT,Traits>& lhs, + const CharT* rhs) +{ + return lhs.compare(rhs) == 0; +} +template<class CharT,class Traits> +bool operator==(const CharT* lhs, + const Basic_string_view_<CharT,Traits>& rhs) +{ + return rhs.compare(lhs) == 0; +} + +// != +template<class CharT,class Traits> +bool operator!=(const Basic_string_view_<CharT,Traits>& lhs, + const Basic_string_view_<CharT,Traits>& rhs) +{ + return lhs.compare(rhs) != 0; +} +template<class CharT,class Traits,class Allocator> +bool operator!=(const Basic_string_view_<CharT,Traits>& lhs, + const std::basic_string<CharT,Traits,Allocator>& rhs) +{ + return lhs.compare(rhs) != 0; +} +template<class CharT,class Traits,class Allocator> +bool operator!=(const std::basic_string<CharT,Traits,Allocator>& lhs, + const Basic_string_view_<CharT,Traits>& rhs) +{ + return rhs.compare(lhs) != 0; +} +template<class CharT,class Traits> +bool operator!=(const Basic_string_view_<CharT,Traits>& lhs, + const CharT* rhs) +{ + return lhs.compare(rhs) != 0; +} +template<class CharT,class Traits> +bool operator!=(const CharT* lhs, + const Basic_string_view_<CharT,Traits>& rhs) +{ + return rhs.compare(lhs) != 0; +} + +// <= +template<class CharT,class Traits> +bool operator<=(const Basic_string_view_<CharT,Traits>& lhs, + const Basic_string_view_<CharT,Traits>& rhs) +{ + return lhs.compare(rhs) <= 0; +} +template<class CharT,class Traits,class Allocator> +bool operator<=(const Basic_string_view_<CharT,Traits>& lhs, + const std::basic_string<CharT,Traits,Allocator>& rhs) +{ + return lhs.compare(rhs) <= 0; +} +template<class CharT,class Traits,class Allocator> +bool operator<=(const std::basic_string<CharT,Traits,Allocator>& lhs, + const Basic_string_view_<CharT,Traits>& rhs) +{ + return rhs.compare(lhs) >= 0; +} + +// < +template<class CharT,class Traits> +bool operator<(const Basic_string_view_<CharT,Traits>& lhs, + const Basic_string_view_<CharT,Traits>& rhs) +{ + return lhs.compare(rhs) < 0; +} +template<class CharT,class Traits,class Allocator> +bool operator<(const Basic_string_view_<CharT,Traits>& lhs, + const std::basic_string<CharT,Traits,Allocator>& rhs) +{ + return lhs.compare(rhs) < 0; +} +template<class CharT,class Traits,class Allocator> +bool operator<(const std::basic_string<CharT,Traits,Allocator>& lhs, + const Basic_string_view_<CharT,Traits>& rhs) +{ + return rhs.compare(lhs) > 0; +} + +// >= +template<class CharT,class Traits> +bool operator>=(const Basic_string_view_<CharT,Traits>& lhs, + const Basic_string_view_<CharT,Traits>& rhs) +{ + return lhs.compare(rhs) >= 0; +} +template<class CharT,class Traits,class Allocator> +bool operator>=(const Basic_string_view_<CharT,Traits>& lhs, + const std::basic_string<CharT,Traits,Allocator>& rhs) +{ + return lhs.compare(rhs) >= 0; +} +template<class CharT,class Traits,class Allocator> +bool operator>=(const std::basic_string<CharT,Traits,Allocator>& lhs, + const Basic_string_view_<CharT,Traits>& rhs) +{ + return rhs.compare(lhs) <= 0; +} + +// > +template<class CharT,class Traits> +bool operator>(const Basic_string_view_<CharT,Traits>& lhs, + const Basic_string_view_<CharT,Traits>& rhs) +{ + return lhs.compare(rhs) > 0; +} +template<class CharT,class Traits,class Allocator> +bool operator>(const Basic_string_view_<CharT,Traits>& lhs, + const std::basic_string<CharT,Traits,Allocator>& rhs) +{ + return lhs.compare(rhs) > 0; +} +template<class CharT,class Traits,class Allocator> +bool operator>(const std::basic_string<CharT,Traits,Allocator>& lhs, + const Basic_string_view_<CharT,Traits>& rhs) +{ + return rhs.compare(lhs) < 0; +} +#endif + +#if !defined(JSONCONS_HAS_STRING_VIEW) +template <class CharT, class Traits = std::char_traits<CharT>> +using basic_string_view_ext = Basic_string_view_<CharT, Traits>; +#else +#include <string_view> +template <class CharT, class Traits = std::char_traits<CharT>> +using basic_string_view_ext = std::basic_string_view<CharT, Traits>; +#endif + +#if !defined(JSONCONS_NO_TO_CHARS) +using chars_format = std::chars_format; +#else +enum class chars_format : uint8_t {fixed=1,scientific=2,hex=4,general=fixed|scientific}; +#endif + +// number_format + +class number_format +{ + chars_format format_; + uint8_t precision_; + uint8_t decimal_places_; +public: + number_format() + : format_(chars_format::general), precision_(0), decimal_places_(0) + { + } + + number_format(uint8_t precision, uint8_t decimal_places) + : format_(chars_format::general), precision_(precision), decimal_places_(decimal_places) + { + } + + number_format(chars_format format, uint8_t precision, uint8_t decimal_places) + : format_(format), precision_(precision), decimal_places_(decimal_places) + { + } + + number_format(chars_format format) + : format_(format), precision_(0), decimal_places_(0) + { + } + + number_format(const number_format&) = default; + number_format(number_format&&) = default; + number_format& operator=(const number_format& e) = default; + number_format& operator=(number_format&& e) = default; + + uint8_t precision() const + { + return precision_; + } + + uint8_t decimal_places() const + { + return decimal_places_; + } + + chars_format floating_point_format() const + { + return format_; + } +}; + +// byte_string_view +class byte_string_view +{ + const uint8_t* data_; + size_t length_; +public: + typedef const uint8_t* const_iterator; + typedef const uint8_t* iterator; + typedef std::size_t size_type; + + byte_string_view(const uint8_t* data, size_t length) + : data_(data), length_(length) + { + } + + const uint8_t* data() const + { + return data_; + } + + size_t length() const + { + return length_; + } + + size_t size() const + { + return length_; + } + + // iterator support + const_iterator begin() const JSONCONS_NOEXCEPT + { + return data_; + } + const_iterator end() const JSONCONS_NOEXCEPT + { + return data_ + length_; + } + + uint8_t operator[](size_type pos) const + { + return data_[pos]; + } + + friend bool operator==(const byte_string_view& lhs, const byte_string_view& rhs) + { + if (lhs.length() != rhs.length()) + { + return false; + } + for (size_t i = 0; i < lhs.length(); ++i) + { + if (lhs[i] != rhs[i]) + { + return false; + } + } + return true; + } + + friend bool operator!=(const byte_string_view& lhs, const byte_string_view& rhs) + { + return !(lhs == rhs); + } + + template <class CharT> + friend std::basic_ostream<CharT>& operator<<(std::basic_ostream<CharT>& os, const byte_string_view& o) + { + std::basic_ostringstream<CharT> ss; + ss.flags(std::ios::hex | std::ios::showbase); + for (auto b : o) + { + ss << (int)b; + } + os << ss.str(); + return os; + } +}; + +// basic_byte_string +template <class Allocator = std::allocator<uint8_t>> +class basic_byte_string +{ + std::vector<uint8_t,Allocator> data_; +public: + typedef typename std::vector<uint8_t,Allocator>::const_iterator const_iterator; + typedef typename std::vector<uint8_t,Allocator>::const_iterator iterator; + typedef std::size_t size_type; + + basic_byte_string() = default; + + explicit basic_byte_string(const Allocator& alloc) + : data_(alloc) + { + } + + basic_byte_string(std::initializer_list<uint8_t> init) + : data_(std::move(init)) + { + } + + basic_byte_string(std::initializer_list<uint8_t> init, const Allocator& alloc) + : data_(std::move(init), alloc) + { + } + + explicit basic_byte_string(const byte_string_view& v) + : data_(v.begin(),v.end()) + { + } + + basic_byte_string(const byte_string_view& v, const Allocator& alloc) + : data_(v.begin(),v.end(),alloc) + { + } + + basic_byte_string(const char* s) + { + while (*s) + { + data_.push_back(*s++); + } + } + + basic_byte_string(const uint8_t* data, size_t length) + { + data_.insert(data,data+length); + } + + basic_byte_string(const basic_byte_string& s) = default; + + basic_byte_string(basic_byte_string&& s) = default; + + basic_byte_string& operator=(const basic_byte_string& s) = default; + + basic_byte_string& operator=(basic_byte_string&& s) = default; + + operator byte_string_view() const JSONCONS_NOEXCEPT + { + return byte_string_view(data(),length()); + } + + void push_back(uint8_t b) + { + data_.push_back(b); + } + + void assign(const uint8_t* s, size_t count) + { + data_.clear(); + data_.insert(s, s+count); + } + + void append(const uint8_t* s, size_t count) + { + data_.insert(s, s+count); + } + + void clear() + { + data_.clear(); + } + + uint8_t operator[](size_type pos) const + { + return data_[pos]; + } + + // iterator support + const_iterator begin() const JSONCONS_NOEXCEPT + { + return data_.begin(); + } + const_iterator end() const JSONCONS_NOEXCEPT + { + return data_.end(); + } + + const uint8_t* data() const + { + return data_.data(); + } + + size_t size() const + { + return data_.size(); + } + + size_t length() const + { + return data_.size(); + } + + friend bool operator==(const basic_byte_string& lhs, const basic_byte_string& rhs) + { + return byte_string_view(lhs) == byte_string_view(rhs); + } + + friend bool operator!=(const basic_byte_string& lhs, const basic_byte_string& rhs) + { + return byte_string_view(lhs) != byte_string_view(rhs); + } + + template <class CharT> + friend std::basic_ostream<CharT>& operator<<(std::basic_ostream<CharT>& os, const basic_byte_string& o) + { + os << byte_string_view(o); + return os; + } +}; + +typedef basic_byte_string<std::allocator<uint8_t>> byte_string; + +static const std::string base64_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/" + "="; +static const std::string base64url_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789-_" + "\0"; + +inline +static bool is_base64(uint8_t c) +{ + return isalnum(c) || c == '+' || c == '/'; +} + +template <class InputIt,class CharT> +void encode_base64(InputIt first, InputIt last, const std::string& alphabet, std::basic_string<CharT>& result) +{ + unsigned char a3[3]; + unsigned char a4[4]; + unsigned char fill = alphabet.back(); + int i = 0; + int j = 0; + + while (first != last) + { + a3[i++] = *first++; + if (i == 3) + { + a4[0] = (a3[0] & 0xfc) >> 2; + a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4); + a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6); + a4[3] = a3[2] & 0x3f; + + for (i = 0; i < 4; i++) + { + result.push_back(alphabet[a4[i]]); + } + i = 0; + } + } + + if (i > 0) + { + for (j = i; j < 3; ++j) + { + a3[j] = 0; + } + + a4[0] = (a3[0] & 0xfc) >> 2; + a4[1] = ((a3[0] & 0x03) << 4) + ((a3[1] & 0xf0) >> 4); + a4[2] = ((a3[1] & 0x0f) << 2) + ((a3[2] & 0xc0) >> 6); + + for (j = 0; j < i + 1; ++j) + { + result.push_back(alphabet[a4[j]]); + } + + if (fill != 0) + { + while (i++ < 3) + { + result.push_back(fill); + } + } + } +} + +template <class InputIt,class CharT> +void encode_base64url(InputIt first, InputIt last, std::basic_string<CharT>& result) +{ + return encode_base64(first,last,base64url_alphabet,result); +} + +template <class InputIt,class CharT> +void encode_base64(InputIt first, InputIt last, std::basic_string<CharT>& result) +{ + encode_base64(first,last,base64_alphabet,result); +} + +inline +std::string decode_base64(const std::string& base64_string) +{ + std::string result; + uint8_t a4[4], a3[3]; + uint8_t i = 0; + uint8_t j = 0; + + auto first = base64_string.begin(); + auto last = base64_string.end(); + + while (first != last && *first != '=') + { + JSONCONS_ASSERT(is_base64(*first)); + + a4[i++] = *first++; + if (i == 4) + { + for (i = 0; i < 4; ++i) + { + a4[i] = static_cast<uint8_t>(base64_alphabet.find(a4[i])); + } + + a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4); + a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2); + a3[2] = ((a4[2] & 0x3) << 6) + a4[3]; + + for (i = 0; i < 3; i++) + { + result.push_back(a3[i]); + } + i = 0; + } + } + + if (i > 0) + { + for (j = 0; j < i; ++j) + { + a4[j] = static_cast<uint8_t>(base64_alphabet.find(a4[j])); + } + + a3[0] = (a4[0] << 2) + ((a4[1] & 0x30) >> 4); + a3[1] = ((a4[1] & 0xf) << 4) + ((a4[2] & 0x3c) >> 2); + + for (j = 0; j < i - 1; ++j) + { + result.push_back(a3[j]); + } + } + + return result; +} + +} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/parse_error_handler.hpp b/vendor/jsoncons-0.104.0/jsoncons/parse_error_handler.hpp new file mode 100644 index 00000000..e38785ae --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/parse_error_handler.hpp @@ -0,0 +1,165 @@ +/// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_PARSE_ERROR_HANDLER_HPP +#define JSONCONS_PARSE_ERROR_HANDLER_HPP + +#include <jsoncons/json_exception.hpp> +#include <jsoncons/json_error_category.hpp> +#include <system_error> + +namespace jsoncons { + +class parse_error : public std::exception, public virtual json_exception +{ +public: + parse_error() + : line_number_(0), + column_number_(0) + { + } + parse_error(std::error_code ec, + size_t line, + size_t column) + : error_code_(ec), + line_number_(line), + column_number_(column) + { + } + parse_error(const parse_error& other) + : error_code_(other.error_code_), + line_number_(other.line_number_), + column_number_(other.column_number_) + { + } + + const char* what() const JSONCONS_NOEXCEPT override + { + try + { + std::ostringstream os; + os << error_code_.message() << " at line " << line_number_ << " and column " << column_number_; + const_cast<std::string&>(buffer_) = os.str(); + return buffer_.c_str(); + } + catch (...) + { + return ""; + } + } + + const std::error_code code() const + { + return error_code_; + } + + size_t line_number() const + { + return line_number_; + } + + size_t column_number() const + { + return column_number_; + } + + parse_error& operator=(const parse_error& e) + { + error_code_ = e.error_code_; + line_number_ = e.line_number_; + column_number_ = e.column_number_; + return *this; + } +private: + std::error_code error_code_; + std::string buffer_; + size_t line_number_; + size_t column_number_; +}; + +#if !defined(JSONCONS_NO_DEPRECATED) +typedef parse_error json_parse_exception; +typedef parse_error parse_exception; +#endif + +class parsing_context +{ +public: + virtual ~parsing_context() = default; + + size_t line_number() const + { + return do_line_number(); + } + size_t column_number() const + { + return do_column_number(); + } + +private: + virtual size_t do_line_number() const = 0; + virtual size_t do_column_number() const = 0; +}; + +class parse_error_handler +{ +public: + virtual ~parse_error_handler() + { + } + + bool error(std::error_code ec, + const parsing_context& context) JSONCONS_NOEXCEPT + { + return do_error(ec,context); + } + + void fatal_error(std::error_code ec, + const parsing_context& context) JSONCONS_NOEXCEPT + { + do_fatal_error(ec,context); + } + +private: + virtual bool do_error(std::error_code, + const parsing_context& context) JSONCONS_NOEXCEPT = 0; + + virtual void do_fatal_error(std::error_code, + const parsing_context&) JSONCONS_NOEXCEPT + { + } +}; + +class default_parse_error_handler : public parse_error_handler +{ +private: + bool do_error(std::error_code code, + const parsing_context&) JSONCONS_NOEXCEPT override + { + static const std::error_code illegal_comment = make_error_code(json_parser_errc::illegal_comment); + + if (code == illegal_comment) + { + return false; + } + else + { + return true; + } + } +}; + +class strict_parse_error_handler : public parse_error_handler +{ +private: + bool do_error(std::error_code, const parsing_context&) JSONCONS_NOEXCEPT override + { + return true; + } +}; + +} +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/serialization_options.hpp b/vendor/jsoncons-0.104.0/jsoncons/serialization_options.hpp new file mode 100644 index 00000000..18be2ce3 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/serialization_options.hpp @@ -0,0 +1,279 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_SERIALIZATION_OPTIONS_HPP +#define JSONCONS_SERIALIZATION_OPTIONS_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <ostream> +#include <cstdlib> +#include <limits> +#include <cwchar> +#include <jsoncons/json_exception.hpp> +#include <jsoncons/jsoncons_utilities.hpp> +#include <jsoncons/detail/type_traits_helper.hpp> + +namespace jsoncons { + +#if !defined(JSONCONS_NO_DEPRECATED) +enum class block_options {next_line,same_line}; +#endif + +enum class line_split_kind{same_line,new_line,multi_line}; + +template <class CharT,class Allocator=std::allocator<CharT>> +class basic_serialization_options +{ +public: + typedef basic_string_view_ext<CharT> string_view_type; + typedef CharT char_type; + typedef Allocator allocator_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<CharT> char_allocator_type; + typedef std::basic_string<CharT,std::char_traits<CharT>,char_allocator_type> string_type; +private: + int indent_; + uint8_t precision_; + uint8_t decimal_places_; + bool replace_nan_; + bool replace_pos_inf_; + bool replace_neg_inf_; + string_type nan_replacement_; + string_type pos_inf_replacement_; + string_type neg_inf_replacement_; + bool escape_all_non_ascii_; + bool escape_solidus_; + + line_split_kind object_object_split_lines_; + line_split_kind object_array_split_lines_; + line_split_kind array_array_split_lines_; + line_split_kind array_object_split_lines_; + + chars_format floating_point_format_; +public: + static const size_t default_indent = 4; + +// Constructors + + basic_serialization_options() + : + indent_(default_indent), + precision_(0), + replace_nan_(true), + replace_pos_inf_(true), + replace_neg_inf_(true), + nan_replacement_(detail::null_literal<CharT>()), + pos_inf_replacement_(detail::null_literal<CharT>()), + neg_inf_replacement_(detail::null_literal<CharT>()), + escape_all_non_ascii_(false), + escape_solidus_(false), + object_object_split_lines_(line_split_kind::multi_line), + object_array_split_lines_(line_split_kind::same_line), + array_array_split_lines_(line_split_kind::new_line), + array_object_split_lines_(line_split_kind::multi_line) + { + } + +// Accessors + line_split_kind object_object_split_lines() const {return object_object_split_lines_;} + line_split_kind array_object_split_lines() const {return array_object_split_lines_;} + line_split_kind object_array_split_lines() const {return object_array_split_lines_;} + line_split_kind array_array_split_lines() const {return array_array_split_lines_;} + + basic_serialization_options<CharT>& object_object_split_lines(line_split_kind value) {object_object_split_lines_ = value; return *this;} + basic_serialization_options<CharT>& array_object_split_lines(line_split_kind value) {array_object_split_lines_ = value; return *this;} + basic_serialization_options<CharT>& object_array_split_lines(line_split_kind value) {object_array_split_lines_ = value; return *this;} + basic_serialization_options<CharT>& array_array_split_lines(line_split_kind value) {array_array_split_lines_ = value; return *this;} + +#if !defined(JSONCONS_NO_DEPRECATED) + block_options array_array_block_option() + { + return (array_array_split_lines_ == line_split_kind::same_line) ? block_options::same_line : block_options::next_line; + } + + basic_serialization_options<CharT>& array_array_block_option(block_options value) + { + array_array_split_lines_ = (value == block_options::same_line) ? line_split_kind::same_line : line_split_kind::new_line; + return *this; + } + + block_options array_object_block_option() + { + return (array_object_split_lines_ == line_split_kind::same_line) ? block_options::same_line : block_options::next_line; + } + + basic_serialization_options<CharT>& array_object_block_option(block_options value) + { + array_object_split_lines_ = (value == block_options::same_line) ? line_split_kind::same_line : line_split_kind::new_line; + return *this; + } + + block_options object_array_block_option() + { + return (object_array_split_lines_ == line_split_kind::same_line) ? block_options::same_line : block_options::next_line; + } + + basic_serialization_options<CharT>& object_array_block_option(block_options value) + { + object_array_split_lines_ = (value == block_options::same_line) ? line_split_kind::same_line : line_split_kind::new_line; + return *this; + } + + block_options object_object_block_option() + { + return (object_object_split_lines_ == line_split_kind::same_line) ? block_options::same_line : block_options::next_line; + } + + basic_serialization_options<CharT>& object_object_block_option(block_options value) + { + object_object_split_lines_ = (value == block_options::same_line) ? line_split_kind::same_line : line_split_kind::new_line; + return *this; + } +#endif + + int indent() const + { + return indent_; + } + + basic_serialization_options<CharT>& indent(int value) + { + indent_ = value; + return *this; + } + + chars_format floating_point_format() const + { + return floating_point_format_; + } + + basic_serialization_options<CharT>& floating_point_format(chars_format value) + { + floating_point_format_ = value; + return *this; + } + + uint8_t precision() const + { + return precision_; + } + + basic_serialization_options<CharT>& precision(uint8_t value) + { + precision_ = value; + return *this; + } + + uint8_t decimal_places() const + { + return decimal_places_; + } + + basic_serialization_options<CharT>& decimal_places(uint8_t value) + { + decimal_places_ = value; + return *this; + } + + bool escape_all_non_ascii() const + { + return escape_all_non_ascii_; + } + + basic_serialization_options<CharT>& escape_all_non_ascii(bool value) + { + escape_all_non_ascii_ = value; + return *this; + } + + bool escape_solidus() const + { + return escape_solidus_; + } + + basic_serialization_options<CharT>& escape_solidus(bool value) + { + escape_solidus_ = value; + return *this; + } + + bool replace_nan() const {return replace_nan_;} + + basic_serialization_options<CharT>& replace_nan(bool replace) + { + replace_nan_ = replace; + return *this; + } + + bool replace_pos_inf() const {return replace_pos_inf_;} + + bool replace_neg_inf() const {return replace_neg_inf_;} + + basic_serialization_options<CharT>& replace_inf(bool replace) + { + replace_pos_inf_ = replace; + replace_neg_inf_ = replace; + return *this; + } + + basic_serialization_options<CharT>& replace_pos_inf(bool replace) + { + replace_pos_inf_ = replace; + return *this; + } + + basic_serialization_options<CharT>& replace_neg_inf(bool replace) + { + replace_neg_inf_ = replace; + return *this; + } + + const string_type& nan_replacement() const + { + return nan_replacement_; + } + + basic_serialization_options<CharT>& nan_replacement(const string_type& replacement) + { + nan_replacement_ = replacement; + return *this; + } + + basic_serialization_options<CharT>& neg_inf_replacement(const string_type& replacement) + { + neg_inf_replacement_ = replacement; + return *this; + } + + const string_type& pos_inf_replacement() const + { + return pos_inf_replacement_; + } + + basic_serialization_options<CharT>& pos_inf_replacement(const string_type& replacement) + { + pos_inf_replacement_ = replacement; + return *this; + } + + const string_type& neg_inf_replacement() const + { + return neg_inf_replacement_; + } +}; + +typedef basic_serialization_options<char> serialization_options; +typedef basic_serialization_options<wchar_t> wserialization_options; + +#if !defined(JSONCONS_NO_DEPRECATED) +typedef basic_serialization_options<char> output_format; +typedef basic_serialization_options<wchar_t> woutput_format; +#endif + +} +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons/serialization_traits.hpp b/vendor/jsoncons-0.104.0/jsoncons/serialization_traits.hpp new file mode 100644 index 00000000..aa22769f --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/serialization_traits.hpp @@ -0,0 +1,315 @@ +// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_SERIALIZATION_TRAITS_HPP +#define JSONCONS_SERIALIZATION_TRAITS_HPP + +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wswitch" +#endif + +#include <iostream> +#include <string> +#include <tuple> +#include <array> +#include <type_traits> +#include <memory> +#include <jsoncons/json_output_handler.hpp> +#include <jsoncons/serialization_options.hpp> +#include <jsoncons/json_serializer.hpp> +#include <jsoncons/jsoncons_utilities.hpp> + +namespace jsoncons { + +// serialization_traits + +template <class T, class Enable = void> +struct serialization_traits +{ + template <class CharT> + static void encode(const T&, basic_json_output_handler<CharT>&) + { + } +}; + +// dump + +template <class CharT, class T> +void dump(const T& val, basic_json_output_handler<CharT>& handler) +{ + handler.begin_json(); + serialization_traits<T>::encode(val,handler); + handler.end_json(); +} + +#if !defined(JSONCONS_NO_DEPRECATED) +template <class CharT, class T> +void dump_body(const T& val, basic_json_output_handler<CharT>& handler) +{ + dump_fragment(val,handler); +} +#endif + +template <class CharT, class T> +void dump_fragment(const T& val, basic_json_output_handler<CharT>& handler) +{ + serialization_traits<T>::encode(val,handler); +} + +template <class CharT, class T> +void dump(const T& val, std::basic_ostream<CharT>& os) +{ + basic_json_serializer<CharT> serializer(os); + dump(val, serializer); +} + +template <class CharT, class T> +void dump(const T& val, const basic_serialization_options<CharT>& options, + std::basic_ostream<CharT>& os) +{ + basic_json_serializer<CharT> serializer(os, options); + dump(val, serializer); +} + +template <class CharT, class T> +void dump(const T& val, std::basic_ostream<CharT>& os, bool pprint) +{ + basic_json_serializer<CharT> serializer(os, pprint); + dump(val, serializer); +} + +template <class CharT, class T> +void dump(const T& val, const basic_serialization_options<CharT>& options, + std::basic_ostream<CharT>& os, bool pprint) +{ + basic_json_serializer<CharT> serializer(os, options, pprint); + dump(val, serializer); +} + +// integer + +template<class T> +struct serialization_traits<T, + typename std::enable_if<detail::is_integer_like<T>::value +>::type> +{ + template <class CharT> + static void encode(T val, basic_json_output_handler<CharT>& handler) + { + handler.integer_value(val); + } +}; + +// uinteger + +template<class T> +struct serialization_traits<T, + typename std::enable_if<detail::is_uinteger_like<T>::value +>::type> +{ + template <class CharT> + static void encode(T val, basic_json_output_handler<CharT>& handler) + { + handler.uinteger_value(val); + } +}; + +// double + +template<class T> +struct serialization_traits<T, + typename std::enable_if<detail::is_floating_point_like<T>::value +>::type> +{ + template <class CharT> + static void encode(T val, basic_json_output_handler<CharT>& handler) + { + handler.double_value(val); + } +}; + +// bool + +template<> +struct serialization_traits<bool> +{ + template <class CharT> + static void encode(bool val, basic_json_output_handler<CharT>& handler) + { + handler.bool_value(val); + } +}; + +// string + +template<class T> +struct serialization_traits<T, + typename std::enable_if<detail::is_string_like<T>::value +>::type> +{ + template <class CharT> + static void encode(const T& val, basic_json_output_handler<CharT>& handler) + { + handler.string_value(val); + } +}; + +/*template<> +struct serialization_traits<typename type_wrapper<CharT>::const_pointer_type> +{ + template <class CharT> + static void encode(typename type_wrapper<CharT>::const_pointer_type val, basic_json_output_handler<CharT>& handler) + { + handler.string_value(val); + } +};*/ + +// sequence container (except string and array) + +template<class T> +struct serialization_traits<T, + typename std::enable_if<detail::is_vector_like<T>::value +>::type> +{ + typedef typename std::iterator_traits<typename T::iterator>::value_type value_type; + + template <class CharT> + static void encode(const T& val, basic_json_output_handler<CharT>& handler) + { + handler.begin_array(); + for (auto it = std::begin(val); it != std::end(val); ++it) + { + serialization_traits<value_type>::encode(*it,handler); + } + handler.end_array(); + } +}; + +// std::array + +template<class T, size_t N> +struct serialization_traits<std::array<T,N>> +{ + typedef typename std::array<T,N>::value_type value_type; +public: + + template <class CharT> + static void encode(const std::array<T, N>& val, basic_json_output_handler<CharT>& handler) + { + handler.begin_array(); + for (auto it = std::begin(val); it != std::end(val); ++it) + { + serialization_traits<value_type>::encode(*it,handler); + } + handler.end_array(); + } +}; + +// associative container + +template<class T> +struct serialization_traits<T, + typename std::enable_if<detail::is_map_like<T>::value +>::type> +{ + typedef typename T::mapped_type mapped_type; + typedef typename T::value_type value_type; + + template <class CharT> + static void encode(const T& val, basic_json_output_handler<CharT>& handler) + { + handler.begin_object(); + for (auto it = std::begin(val); it != std::end(val); ++it) + { + handler.name(it->first); + serialization_traits<mapped_type>::encode(it->second,handler); + } + handler.end_object(); + } +}; + +namespace detail { namespace streaming { + +template<size_t Pos, class Tuple> +struct tuple_helper +{ + using element_type = typename std::tuple_element<std::tuple_size<Tuple>::value - Pos, Tuple>::type; + using next = tuple_helper<Pos - 1, Tuple>; + + template <class CharT> + static void encode(const Tuple& tuple, basic_json_output_handler<CharT>& handler) + { + serialization_traits<element_type>::encode(std::get<std::tuple_size<Tuple>::value - Pos>(tuple),handler); + next::encode(tuple, handler); + } +}; + +template<class Tuple> +struct tuple_helper<0, Tuple> +{ + template <class CharT> + static void encode(const Tuple&, basic_json_output_handler<CharT>&) + { + } +}; + +}} + +template<typename... E> +struct serialization_traits<std::tuple<E...>> +{ +private: + using helper = detail::streaming::tuple_helper<sizeof...(E), std::tuple<E...>>; + +public: + template <class CharT> + static void encode(const std::tuple<E...>& value, basic_json_output_handler<CharT>& handler) + { + handler.begin_array(); + helper::encode(value, handler); + handler.end_array(); + } +}; + +template<class T1, class T2> +struct serialization_traits<std::pair<T1,T2>> +{ +public: + + template <class CharT> + static void encode(const std::pair<T1,T2>& value, basic_json_output_handler<CharT>& handler) + { + handler.begin_array(); + serialization_traits<T1>::encode(value.first, handler); + serialization_traits<T2>::encode(value.second, handler); + handler.end_array(); + } +}; + +#if !defined(JSONCONS_NO_DEPRECATED) +template<class T> +struct serialization_traits<std::shared_ptr<T>> +{ +public: + + template <class CharT> + static void encode(std::shared_ptr<T> p, basic_json_output_handler<CharT>& handler) + { + serialization_traits<T>::encode(*p, handler); + } +}; +#endif + +} + +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + +#endif + + diff --git a/vendor/jsoncons-0.104.0/jsoncons/version.hpp b/vendor/jsoncons-0.104.0/jsoncons/version.hpp new file mode 100644 index 00000000..c7971685 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons/version.hpp @@ -0,0 +1,50 @@ +// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_VERSION_HPP +#define JSONCONS_VERSION_HPP + +#include <iostream> + +namespace jsoncons { + +struct versioning_info +{ + versioning_info(unsigned int major, + unsigned int minor, + unsigned int patch) + : major_(major), + minor_(minor), + patch_(patch) + {} + + unsigned int const major_; + unsigned int const minor_; + unsigned int const patch_; + + friend std::ostream& operator<<(std::ostream& os, const versioning_info& ver) + { + os << ver.major_ << '.' + << ver.minor_ << '.' + << ver.patch_; + return os; + } + + versioning_info(const versioning_info&) = default; + versioning_info() = delete; + versioning_info& operator=(const versioning_info&) = delete; +}; + +inline +versioning_info version() +{ + static versioning_info ver(0, 104, 0); + return ver; +} + +} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons_ext/binary/binary_utilities.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/binary/binary_utilities.hpp new file mode 100644 index 00000000..4d350e06 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/binary/binary_utilities.hpp @@ -0,0 +1,354 @@ +// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_BINARY_BINARY_UTILITIES_HPP +#define JSONCONS_BINARY_BINARY_UTILITIES_HPP + +#include <assert.h> +#include <cfloat> +#include <cstddef> +#include <cstdint> +#include <cstdlib> +#include <cstring> +#include <istream> +#include <limits> +#include <memory> +#include <sstream> +#include <vector> + +// The definitions below follow the definitions in compiler_support_p.h, https://github.com/01org/tinycbor +// MIT license + +#ifdef __F16C__ +# include <immintrin.h> +#endif + +#ifndef __has_builtin +# define __has_builtin(x) 0 +#endif + +#if (defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__ >= 403)) || \ + (__has_builtin(__builtin_bswap64) && __has_builtin(__builtin_bswap32)) +# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define JSONCONS_BINARY_TO_BE64 __builtin_bswap64 +# define JSONCONS_BINARY_FROM_BE64 __builtin_bswap64 +# define JSONCONS_BINARY_TO_BE32 __builtin_bswap32 +# define JSONCONS_BINARY_FROM_BE32 __builtin_bswap32 +# ifdef __INTEL_COMPILER +# define JSONCONS_BINARY_TO_BE16 _bswap16 +# define JSONCONS_BINARY_FROM_BE16 _bswap16 +# elif (__GNUC__ * 100 + __GNUC_MINOR__ >= 608) || __has_builtin(__builtin_bswap16) +# define JSONCONS_BINARY_TO_BE16 __builtin_bswap16 +# define JSONCONS_BINARY_FROM_BE16 __builtin_bswap16 +# else +# define JSONCONS_BINARY_TO_BE16(x) (((uint16_t)x >> 8) | ((uint16_t)x << 8)) +# define JSONCONS_BINARY_FROM_BE16 JSONCONS_BINARY_TO_BE16 +# endif +# else +# define JSONCONS_BINARY_TO_BE64 +# define JSONCONS_BINARY_FROM_BE64 +# define JSONCONS_BINARY_TO_BE32 +# define JSONCONS_BINARY_FROM_BE32 +# define JSONCONS_BINARY_TO_BE16 +# define JSONCONS_BINARY_FROM_BE16 +# endif +#elif defined(__sun) +# include <sys/byteorder.h> +#elif defined(_MSC_VER) +/* MSVC, which implies Windows, which implies little-endian and sizeof(long) == 4 */ +# define JSONCONS_BINARY_TO_BE64 _byteswap_uint64 +# define JSONCONS_BINARY_FROM_BE64 _byteswap_uint64 +# define JSONCONS_BINARY_TO_BE32 _byteswap_ulong +# define JSONCONS_BINARY_FROM_BE32 _byteswap_ulong +# define JSONCONS_BINARY_TO_BE16 _byteswap_ushort +# define JSONCONS_BINARY_FROM_BE16 _byteswap_ushort +#endif +#ifndef JSONCONS_BINARY_TO_BE16 +# include <arpa/inet.h> +# define JSONCONS_BINARY_TO_BE16 ntohs +# define JSONCONS_BINARY_FROM_BE16 htons +#endif +#ifndef JSONCONS_BINARY_TO_BE32 +# include <arpa/inet.h> +# define JSONCONS_BINARY_TO_BE32 ntohl +# define JSONCONS_BINARY_FROM_BE32 htonl +#endif +#ifndef JSONCONS_BINARY_TO_BE64 +# define JSONCONS_BINARY_TO_BE64 ntohll +# define JSONCONS_BINARY_FROM_BE64 htonll +/* ntohll isn't usually defined */ +# ifndef ntohll +# if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define ntohll +# define htonll +# elif defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define ntohll(x) ((ntohl((uint32_t)(x)) * UINT64_C(0x100000000)) + (ntohl((x) >> 32))) +# define htonll ntohll +# else +# error "Unable to determine byte order!" +# endif +# endif +#endif + +namespace jsoncons { namespace binary { + +class read_nbytes_failed : public std::invalid_argument, public virtual json_exception +{ +public: + explicit read_nbytes_failed(size_t count) JSONCONS_NOEXCEPT + : std::invalid_argument("") + { + buffer_.append("Failed attempting to read "); + buffer_.append(std::to_string(count)); + buffer_.append(" bytes from vector"); + } + ~read_nbytes_failed() JSONCONS_NOEXCEPT + { + } + const char* what() const JSONCONS_NOEXCEPT override + { + return buffer_.c_str(); + } +private: + std::string buffer_; +}; + +namespace detail { + +static inline bool add_check_overflow(size_t v1, size_t v2, size_t *r) +{ +#if ((defined(__GNUC__) && (__GNUC__ >= 5)) && !defined(__INTEL_COMPILER)) || __has_builtin(__builtin_add_overflow) + return __builtin_add_overflow(v1, v2, r); +#else + /* unsigned additions are well-defined */ + *r = v1 + v2; + return v1 > v1 + v2; +#endif +} + +} + +inline +uint16_t encode_half(double val) +{ +#ifdef __F16C__ + return _cvtss_sh(val, 3); +#else + uint64_t v; + memcpy(&v, &val, sizeof(v)); + int sign = v >> 63 << 15; + int exp = (v >> 52) & 0x7ff; + int mant = v << 12 >> 12 >> (53-11); /* keep only the 11 most significant bits of the mantissa */ + exp -= 1023; + if (exp == 1024) { + /* infinity or NaN */ + exp = 16; + mant >>= 1; + } else if (exp >= 16) { + /* overflow, as largest number */ + exp = 15; + mant = 1023; + } else if (exp >= -14) { + /* regular normal */ + } else if (exp >= -24) { + /* subnormal */ + mant |= 1024; + mant >>= -(exp + 14); + exp = -15; + } else { + /* underflow, make zero */ + return 0; + } + + /* safe cast here as bit operations above guarantee not to overflow */ + return (uint16_t)(sign | ((exp + 15) << 10) | mant); +#endif +} + +/* this function was copied & adapted from RFC 7049 Appendix D */ +inline +double decode_half(uint16_t half) +{ +#ifdef __F16C__ + return _cvtsh_ss(half); +#else + int exp = (half >> 10) & 0x1f; + int mant = half & 0x3ff; + double val; + if (exp == 0) + { + val = ldexp(mant, -24); + } + else if (exp != 31) + { + val = ldexp(mant + 1024, exp - 25); + } + else + { + val = mant == 0 ? INFINITY : NAN; + } + return half & 0x8000 ? -val : val; +#endif +} + +// to_big_endian + +template<typename T> +typename std::enable_if<std::is_integral<T>::value && sizeof(T) == sizeof(uint8_t),void>::type +to_big_endian(T val, std::vector<uint8_t>& v) +{ + v.push_back(static_cast<uint8_t>((val) & 0xff)); +} + +template<typename T> +typename std::enable_if<std::is_integral<T>::value && +sizeof(T) == sizeof(uint16_t),void>::type +to_big_endian(T val, std::vector<uint8_t>& v) +{ + T x = JSONCONS_BINARY_FROM_BE16(val); + + uint8_t where[sizeof(T)]; + memcpy(where, &x, sizeof(T)); + + for (auto e : where) + { + v.push_back(e); + } +} + +template<typename T> +typename std::enable_if<std::is_integral<T>::value && +sizeof(T) == sizeof(uint32_t),void>::type +to_big_endian(T val, std::vector<uint8_t>& v) +{ + T x = JSONCONS_BINARY_FROM_BE32(val); + + uint8_t where[sizeof(T)]; + memcpy(where, &x, sizeof(T)); + + for (auto e : where) + { + v.push_back(e); + } +} + +template<typename T> +typename std::enable_if<std::is_integral<T>::value && +sizeof(T) == sizeof(uint64_t),void>::type +to_big_endian(T val, std::vector<uint8_t>& v) +{ + T x = JSONCONS_BINARY_FROM_BE64(val); + + uint8_t where[sizeof(T)]; + memcpy(where, &x, sizeof(T)); + + for (auto e : where) + { + v.push_back(e); + } +} + +inline +void to_big_endian(float val, std::vector<uint8_t>& v) +{ + to_big_endian(*reinterpret_cast<uint32_t*>(&val), v); +} + +inline +void to_big_endian(double val, std::vector<uint8_t>& v) +{ + to_big_endian(*reinterpret_cast<uint64_t*>(&val), v); +} + +// from_big_endian + +template<class T> +typename std::enable_if<std::is_integral<T>::value && +sizeof(T) == sizeof(uint8_t),T>::type +from_big_endian(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + if (first + sizeof(T) > last) + { + *endp = first; + return 0; + } + else + { + *endp = first + sizeof(T); + return static_cast<T>(*(first)); + } +} + +template<class T> +typename std::enable_if<std::is_integral<T>::value && +sizeof(T) == sizeof(uint16_t),T>::type +from_big_endian(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + if (first + sizeof(T) > last) + { + *endp = first; + return 0; + } + else + { + *endp = first + sizeof(T); + return JSONCONS_BINARY_TO_BE16(*reinterpret_cast<const uint16_t*>(first)); + } +} + +template<class T> +typename std::enable_if<std::is_integral<T>::value && sizeof(T) == sizeof(uint32_t),T>::type +from_big_endian(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + if (first + sizeof(T) > last) + { + *endp = first; + return 0; + } + else + { + *endp = first + sizeof(T); + return JSONCONS_BINARY_TO_BE32(*reinterpret_cast<const uint32_t*>(first)); + } +} + +template<class T> +typename std::enable_if<std::is_integral<T>::value && sizeof(T) == sizeof(uint64_t),T>::type +from_big_endian(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + if (first + sizeof(T) > last) + { + *endp = first; + return 0; + } + else + { + *endp = first + sizeof(T); + return JSONCONS_BINARY_TO_BE64(*reinterpret_cast<const uint64_t*>(first)); + } +} + +template<class T> +typename std::enable_if<std::is_floating_point<T>::value && +sizeof(T) == sizeof(uint32_t),T>::type +from_big_endian(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + uint32_t data = from_big_endian<uint32_t>(first,last,endp); + return *reinterpret_cast<T*>(&data); +} + +template<class T> +typename std::enable_if<std::is_floating_point<T>::value && +sizeof(T) == sizeof(uint64_t),T>::type +from_big_endian(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + uint64_t data = from_big_endian<uint64_t>(first,last,endp); + return *reinterpret_cast<T*>(&data); +} + +}} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons_ext/cbor/cbor.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/cbor/cbor.hpp new file mode 100644 index 00000000..73f0cbcd --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/cbor/cbor.hpp @@ -0,0 +1,2792 @@ +// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CBOR_CBOR_HPP +#define JSONCONS_CBOR_CBOR_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <memory> +#include <limits> +#include <cassert> +#include <iterator> +#include <jsoncons/json.hpp> +#include <jsoncons_ext/binary/binary_utilities.hpp> + +// Positive integer 0x00..0x17 (0..23) +#define JSONCONS_CBOR_0x00_0x17 \ + 0x00:case 0x01:case 0x02:case 0x03:case 0x04:case 0x05:case 0x06:case 0x07:case 0x08:case 0x09:case 0x0a:case 0x0b:case 0x0c:case 0x0d:case 0x0e:case 0x0f:case 0x10:case 0x11:case 0x12:case 0x13:case 0x14:case 0x15:case 0x16:case 0x17 + +// Negative integer -1-0x00..-1-0x17 (-1..-24) +#define JSONCONS_CBOR_0x20_0x37 \ + 0x20:case 0x21:case 0x22:case 0x23:case 0x24:case 0x25:case 0x26:case 0x27:case 0x28:case 0x29:case 0x2a:case 0x2b:case 0x2c:case 0x2d:case 0x2e:case 0x2f:case 0x30:case 0x31:case 0x32:case 0x33:case 0x34:case 0x35:case 0x36:case 0x37 + +// byte string (0x00..0x17 bytes follow) +#define JSONCONS_CBOR_0x40_0x57 \ + 0x40:case 0x41:case 0x42:case 0x43:case 0x44:case 0x45:case 0x46:case 0x47:case 0x48:case 0x49:case 0x4a:case 0x4b:case 0x4c:case 0x4d:case 0x4e:case 0x4f:case 0x50:case 0x51:case 0x52:case 0x53:case 0x54:case 0x55:case 0x56:case 0x57 + +// UTF-8 string (0x00..0x17 bytes follow) +#define JSONCONS_CBOR_0x60_0x77 \ + 0x60:case 0x61:case 0x62:case 0x63:case 0x64:case 0x65:case 0x66:case 0x67:case 0x68:case 0x69:case 0x6a:case 0x6b:case 0x6c:case 0x6d:case 0x6e:case 0x6f:case 0x70:case 0x71:case 0x72:case 0x73:case 0x74:case 0x75:case 0x76:case 0x77 + +// array (0x00..0x17 data items follow) +#define JSONCONS_CBOR_0x80_0x97 \ + 0x80:case 0x81:case 0x82:case 0x83:case 0x84:case 0x85:case 0x86:case 0x87:case 0x88:case 0x89:case 0x8a:case 0x8b:case 0x8c:case 0x8d:case 0x8e:case 0x8f:case 0x90:case 0x91:case 0x92:case 0x93:case 0x94:case 0x95:case 0x96:case 0x97 + +// map (0x00..0x17 pairs of data items follow) +#define JSONCONS_CBOR_0xa0_0xb7 \ + 0xa0:case 0xa1:case 0xa2:case 0xa3:case 0xa4:case 0xa5:case 0xa6:case 0xa7:case 0xa8:case 0xa9:case 0xaa:case 0xab:case 0xac:case 0xad:case 0xae:case 0xaf:case 0xb0:case 0xb1:case 0xb2:case 0xb3:case 0xb4:case 0xb5:case 0xb6:case 0xb7 + +namespace jsoncons { namespace cbor { + +class cbor_decode_error : public std::invalid_argument, public virtual json_exception +{ +public: + explicit cbor_decode_error(size_t pos) JSONCONS_NOEXCEPT + : std::invalid_argument("") + { + buffer_.append("Error decoding a cbor at position "); + buffer_.append(std::to_string(pos)); + } + ~cbor_decode_error() JSONCONS_NOEXCEPT + { + } + const char* what() const JSONCONS_NOEXCEPT override + { + return buffer_.c_str(); + } +private: + std::string buffer_; +}; + +namespace detail { + +void walk(const uint8_t* first, const uint8_t* last, const uint8_t** endp); + +inline +size_t get_byte_string_length(const uint8_t* first, const uint8_t* last, + const uint8_t** endp) +{ + size_t length = 0; + if (JSONCONS_UNLIKELY(last <= first)) + { + *endp = first; + } + else + { + const uint8_t* p = first+1; + switch (*first) + { + case JSONCONS_CBOR_0x40_0x57: // byte string (0x00..0x17 bytes follow) + { + length = *first & 0x1f; + *endp = p; + break; + } + case 0x58: // byte string (one-byte uint8_t for n follows) + { + length = binary::from_big_endian<uint8_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + break; + } + case 0x59: // byte string (two-byte uint16_t for n follow) + { + length = binary::from_big_endian<uint16_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + break; + } + case 0x5a: // byte string (four-byte uint32_t for n follow) + { + length = binary::from_big_endian<uint32_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + break; + } + case 0x5b: // byte string (eight-byte uint64_t for n follow) + { + length = binary::from_big_endian<uint64_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + break; + } + case 0x5f: // byte string, byte strings follow, terminated by "break" + { + length = 0; + while (*p != 0xff) + { + size_t len = detail::get_byte_string_length(p,last,endp); + if (*endp == p) + { + *endp = first; + break; + } + length += len; + } + break; + } + default: + { + *endp = first; + } + } + } + return length; +} + +inline +std::vector<uint8_t> get_byte_string(const uint8_t* first, const uint8_t* last, + const uint8_t** endp) +{ + std::vector<uint8_t> v; + if (JSONCONS_UNLIKELY(last <= first)) + { + *endp = first; + } + else + { + const uint8_t* p = first+1; + switch (*first) + { + case JSONCONS_CBOR_0x40_0x57: // byte string (0x00..0x17 bytes follow) + { + size_t length = *first & 0x1f; + *endp = p + length; + v = std::vector<uint8_t>(p, *endp); + break; + } + case 0x58: // byte string (one-byte uint8_t for n follows) + { + const auto length = binary::from_big_endian<uint8_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + *endp = p + length; + v = std::vector<uint8_t>(p, *endp); + } + break; + } + case 0x59: // byte string (two-byte uint16_t for n follow) + { + const auto length = binary::from_big_endian<uint16_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + *endp = p + length; + v = std::vector<uint8_t>(p, *endp); + } + break; + } + case 0x5a: // byte string (four-byte uint32_t for n follow) + { + const auto length = binary::from_big_endian<uint32_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + *endp = p + length; + v = std::vector<uint8_t>(p, *endp); + } + break; + } + case 0x5b: // byte string (eight-byte uint64_t for n follow) + { + const auto length = binary::from_big_endian<uint64_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + *endp = p + length; + v = std::vector<uint8_t>(p, *endp); + } + break; + } + case 0x5f: // byte string, byte strings follow, terminated by "break" + { + while (*p != 0xff) + { + std::vector<uint8_t> ss = detail::get_byte_string(p,last,endp); + if (*endp == p) + { + *endp = first; + break; + } + else + { + p = *endp; + v.insert(v.end(),ss.begin(),ss.end()); + } + } + break; + } + default: + { + *endp = first; + } + } + } + return v; +} + +inline +size_t get_text_string_length(const uint8_t* first, const uint8_t* last, + const uint8_t** endp) +{ + size_t length = 0; + if (JSONCONS_UNLIKELY(last <= first)) + { + *endp = first; + } + else + { + const uint8_t* p = first+1; + switch (*first) + { + case JSONCONS_CBOR_0x60_0x77: // UTF-8 string (0x00..0x17 bytes follow) + { + length = *first & 0x1f; + *endp = p; + break; + } + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + { + length = binary::from_big_endian<uint8_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + break; + } + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + { + length = binary::from_big_endian<uint16_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + break; + } + case 0x7a: // UTF-8 string (four-byte uint32_t for n follow) + { + length = binary::from_big_endian<uint32_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + break; + } + case 0x7b: // UTF-8 string (eight-byte uint64_t for n follow) + { + length = binary::from_big_endian<uint64_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + break; + } + case 0x7f: // UTF-8 string, text strings follow, terminated by "break" + { + length = 0; + while (*p != 0xff) + { + size_t len = detail::get_text_string_length(p,last,endp); + if (*endp == p) + { + *endp = first; + break; + } + length += len; + } + break; + } + default: + *endp = first; + break; + } + } + return length; +} + +inline +std::string get_text_string(const uint8_t* first, const uint8_t* last, + const uint8_t** endp) +{ + std::string s; + if (JSONCONS_UNLIKELY(last <= first)) + { + *endp = first; + } + else + { + const uint8_t* p = first+1; + switch (*first) + { + case JSONCONS_CBOR_0x60_0x77: // UTF-8 string (0x00..0x17 bytes follow) + { + size_t length = *first & 0x1f; + *endp = p + length; + s = std::string(p, *endp); + break; + } + case 0x78: // UTF-8 string (one-byte uint8_t for n follows) + { + const auto length = binary::from_big_endian<uint8_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + *endp = p + length; + s = std::string(p, *endp); + } + break; + } + case 0x79: // UTF-8 string (two-byte uint16_t for n follow) + { + const auto length = binary::from_big_endian<uint16_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + *endp = p + length; + s = std::string(p, *endp); + } + break; + } + case 0x7a: // UTF-8 string (four-byte uint32_t for n follow) + { + const auto length = binary::from_big_endian<uint32_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + *endp = p + length; + s = std::string(p, *endp); + } + break; + } + case 0x7b: // UTF-8 string (eight-byte uint64_t for n follow) + { + const auto length = binary::from_big_endian<uint64_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + *endp = p + length; + s = std::string(p, *endp); + } + break; + } + case 0x7f: // UTF-8 string, text strings follow, terminated by "break" + { + while (*p != 0xff) + { + std::string ss = detail::get_text_string(p,last,endp); + if (*endp == p) + { + *endp = first; + break; + } + else + { + p = *endp; + s.append(std::move(ss)); + } + } + break; + } + default: + *endp = first; + break; + } + } + return s; +} + +inline +void walk_object(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + size_t size = 0; + + if (JSONCONS_UNLIKELY(last <= first)) + { + *endp = first; + } + else + { + const uint8_t* p = first+1; + switch (*first) + { + case JSONCONS_CBOR_0xa0_0xb7: // map (0x00..0x17 pairs of data items follow) + { + size = *first & 0x1f; + *endp = p; + for (size_t i = 0; i < size; ++i) + { + walk(*endp, last, endp); + walk(*endp, last, endp); + } + break; + } + + case 0xb8: // map (one-byte uint8_t for n follows) + { + size = binary::from_big_endian<uint8_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + for (size_t i = 0; i < size; ++i) + { + walk(*endp, last, endp); + walk(*endp, last, endp); + } + } + break; + } + + case 0xb9: // map (two-byte uint16_t for n follow) + { + size = binary::from_big_endian<uint16_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + for (size_t i = 0; i < size; ++i) + { + walk(*endp, last, endp); + walk(*endp, last, endp); + } + } + break; + } + + case 0xba: // map (four-byte uint32_t for n follow) + { + size = binary::from_big_endian<uint32_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + for (size_t i = 0; i < size; ++i) + { + walk(*endp, last, endp); + walk(*endp, last, endp); + } + } + break; + } + + case 0xbb: // map (eight-byte uint64_t for n follow) + { + size = binary::from_big_endian<uint64_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + for (size_t i = 0; i < size; ++i) + { + walk(*endp, last, endp); + walk(*endp, last, endp); + } + } + break; + } + case 0xbf: + { + *endp = p; + while (*p != 0xff) + { + walk_object(p, last, endp); + if (*endp == p) + { + *endp = first; + break; + } + } + break; + } + default: + { + *endp = first; + } + } + } +} + +inline +void walk_array(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + size_t size = 0; + + if (JSONCONS_UNLIKELY(last <= first)) + { + *endp = first; + } + else + { + const uint8_t* p = first+1; + switch (*first) + { + case JSONCONS_CBOR_0x80_0x97: // array (0x00..0x17 data items follow) + { + size = *first & 0x1f; + *endp = p; + for (size_t i = 0; i < size; ++i) + { + walk(*endp, last, endp); + } + break; + } + + case 0x98: // array (one-byte uint8_t for n follows) + { + size = binary::from_big_endian<uint8_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + for (size_t i = 0; i < size; ++i) + { + walk(*endp, last, endp); + } + } + break; + } + + case 0x99: // array (two-byte uint16_t for n follow) + { + size = binary::from_big_endian<uint16_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + for (size_t i = 0; i < size; ++i) + { + walk(*endp, last, endp); + } + } + break; + } + + case 0x9a: // array (four-byte uint32_t for n follow) + { + size = binary::from_big_endian<uint32_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + for (size_t i = 0; i < size; ++i) + { + walk(*endp, last, endp); + } + } + break; + } + + case 0x9b: // array (eight-byte uint64_t for n follow) + { + size = binary::from_big_endian<uint64_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + for (size_t i = 0; i < size; ++i) + { + walk(*endp, last, endp); + } + } + break; + } + case 0x9f: // array (indefinite length) + { + *endp = p; + while (*p != 0xff) + { + walk_array(p, last, endp); + if (*endp == p) + { + *endp = first; + break; + } + } + break; + } + default: + { + *endp = first; + } + } + } +} + +inline +uint64_t get_uinteger(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + uint64_t val = 0; + if (JSONCONS_UNLIKELY(last <= first)) + { + *endp = first; + } + else + { + const size_t length = last - first; + const uint8_t* p = first+1; + switch (*first) + { + case JSONCONS_CBOR_0x00_0x17: // Integer 0x00..0x17 (0..23) + val = *first; + *endp = p; + break; + + case 0x18: // Unsigned integer (one-byte uint8_t follows) + { + val = binary::from_big_endian<uint8_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + break; + } + + case 0x19: // Unsigned integer (two-byte uint16_t follows) + { + val = binary::from_big_endian<uint16_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + break; + } + + case 0x1a: // Unsigned integer (four-byte uint32_t follows) + { + val = binary::from_big_endian<uint32_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + break; + } + + case 0x1b: // Unsigned integer (eight-byte uint64_t follows) + { + val = binary::from_big_endian<uint64_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + break; + } + default: + { + *endp = first; + } + } + } + return val; +} + +inline +int64_t get_integer(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + int64_t val = 0; + if (JSONCONS_UNLIKELY(last <= first)) + { + *endp = first; + } + else + { + const size_t length = last - first; + const uint8_t* p = first+1; + switch (*first) + { + case JSONCONS_CBOR_0x20_0x37: // Negative integer -1-0x00..-1-0x17 (-1..-24) + val = static_cast<int8_t>(0x20 - 1 - *first); + *endp = p; + break; + + case 0x38: // Negative integer (one-byte uint8_t follows) + { + auto x = binary::from_big_endian<uint8_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + val = static_cast<int64_t>(-1)- x; + } + break; + } + + case 0x39: // Negative integer -1-n (two-byte uint16_t follows) + { + auto x = binary::from_big_endian<uint16_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + val = static_cast<int64_t>(-1)- x; + } + break; + } + + case 0x3a: // Negative integer -1-n (four-byte uint32_t follows) + { + auto x = binary::from_big_endian<uint32_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + val = static_cast<int64_t>(-1)- x; + } + break; + } + + case 0x3b: // Negative integer -1-n (eight-byte uint64_t follows) + { + auto x = binary::from_big_endian<uint64_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + val = static_cast<int64_t>(-1)- static_cast<int64_t>(x); + } + break; + } + case JSONCONS_CBOR_0x00_0x17: // Integer 0x00..0x17 (0..23) + // FALLTHRU + case 0x18: // Unsigned integer (one-byte uint8_t follows) + // FALLTHRU + case 0x19: // Unsigned integer (two-byte uint16_t follows) + // FALLTHRU + case 0x1a: // Unsigned integer (four-byte uint32_t follows) + // FALLTHRU + case 0x1b: // Unsigned integer (eight-byte uint64_t follows) + { + uint64_t x = detail::get_uinteger(first,last,endp); + if (*endp != first) + { + if (x <= static_cast<uint64_t>((std::numeric_limits<int64_t>::max)())) + { + val = x; + } + else + { + *endp = first; + } + } + break; + } + default: + { + *endp = first; + } + } + } + return val; +} + +inline +double get_double(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + double val = 0; + if (JSONCONS_UNLIKELY(last <= first)) + { + *endp = first; + } + else + { + const size_t length = last - first; + const uint8_t* p = first+1; + switch (*first) + { + case 0xf9: // Half-Precision Float (two-byte IEEE 754) + { + if (JSONCONS_UNLIKELY(1+sizeof(uint16_t) > length)) + { + *endp = first; + } + else + { + uint16_t x = binary::from_big_endian<uint16_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + val = binary::decode_half(x); + } + } + } + break; + + + case 0xfa: // Single-Precision Float (four-byte IEEE 754) + { + if (JSONCONS_UNLIKELY(1+sizeof(float) > length)) + { + *endp = first; + } + else + { + val = binary::from_big_endian<float>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + } + } + break; + + case 0xfb: // Double-Precision Float (eight-byte IEEE 754) + { + if (JSONCONS_UNLIKELY(1+sizeof(double) > length)) + { + *endp = first; + } + else + { + val = binary::from_big_endian<double>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + } + } + break; + default: + { + *endp = first; + } + } + } + return val; +} + +inline +bool is_array(uint8_t b) +{ + return (b >= 0x80 && b <= 0x9b) || b == 0x9f; +} + +inline +bool is_object(uint8_t b) +{ + return (b >= 0xa0 && b <= 0xbb) || b == 0xb8; +} + +inline +bool is_string(uint8_t b) +{ + return (b >= 0x60 && b <= 0x7b) || b == 0x7f; +} + +inline +bool is_bool(uint8_t b) +{ + return b == 0xf5 || b == 0xf4; +} + +inline +bool is_double(uint8_t b) +{ + return b == 0xf9 || b == 0xfa || b == 0xfb; +} + +inline +bool is_integer(const uint8_t* first, const uint8_t* last) +{ + bool result; + + switch (*first) + { + case JSONCONS_CBOR_0x20_0x37: // Negative integer -1-0x00..-1-0x17 (-1..-24) + case 0x38: // Negative integer (one-byte uint8_t follows) + case 0x39: // Negative integer -1-n (two-byte uint16_t follows) + case 0x3a: // Negative integer -1-n (four-byte uint32_t follows) + case 0x3b: // Negative integer -1-n (eight-byte uint64_t follows) + case JSONCONS_CBOR_0x00_0x17: // Integer 0x00..0x17 (0..23) + case 0x18: // Unsigned integer (one-byte uint8_t follows) + case 0x19: // Unsigned integer (two-byte uint16_t follows) + case 0x1a: // Unsigned integer (four-byte uint32_t follows) + result = true; + break; + case 0x1b: // Unsigned integer (eight-byte uint64_t follows) + { + const uint8_t* endp; + uint64_t x = detail::get_uinteger(first,last,&endp); + if (endp != first) + { + if (x <= static_cast<uint64_t>((std::numeric_limits<int64_t>::max)())) + { + result = true; + } + else + { + result = false; + } + } + else + { + result = false; + } + break; + } + default: + result = false; + break; + } + return result; +} + +inline +bool is_uinteger(uint8_t b) +{ + bool result; + + switch (b) + { + case JSONCONS_CBOR_0x00_0x17: // Integer 0x00..0x17 (0..23) + // FALLTHRU + case 0x18: // Unsigned integer (one-byte uint8_t follows) + // FALLTHRU + case 0x19: // Unsigned integer (two-byte uint16_t follows) + // FALLTHRU + case 0x1a: // Unsigned integer (four-byte uint32_t follows) + // FALLTHRU + case 0x1b: // Unsigned integer (eight-byte uint64_t follows) + result = true; + break; + default: + result = false; + break; + } + return result; +} + +inline +void walk(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + if (first >= last) + { + *endp = first; + } + else + { + const uint8_t* p = first+1; + switch (*first) + { + case JSONCONS_CBOR_0x00_0x17: // Integer 0x00..0x17 (0..23) + { + *endp = p; + break; + } + + case 0x18: // Unsigned integer (one-byte uint8_t follows) + { + p += sizeof(uint8_t); + *endp = p; + break; + } + + + case 0x19: // Unsigned integer (two-byte uint16_t follows) + { + p += sizeof(uint16_t); + *endp = p; + break; + } + + + case 0x1a: // Unsigned integer (four-byte uint32_t follows) + { + p += sizeof(uint32_t); + *endp = p; + break; + } + + + case 0x1b: // Unsigned integer (eight-byte uint64_t follows) + { + p += sizeof(uint64_t); + *endp = p; + break; + } + + case JSONCONS_CBOR_0x20_0x37: // Negative integer -1-0x00..-1-0x17 (-1..-24) + { + *endp = p; + break; + } + + case 0x38: // Negative integer (one-byte uint8_t follows) + { + p += sizeof(uint8_t); + *endp = p; + break; + } + + + case 0x39: // Negative integer -1-n (two-byte uint16_t follows) + { + p += sizeof(uint16_t); + *endp = p; + break; + } + + + case 0x3a: // Negative integer -1-n (four-byte uint32_t follows) + { + p += sizeof(uint32_t); + *endp = p; + break; + } + + + case 0x3b: // Negative integer -1-n (eight-byte uint64_t follows) + { + p += sizeof(uint64_t); + *endp = p; + break; + } + + + case JSONCONS_CBOR_0x40_0x57: // byte string (0x00..0x17 bytes follow) + { + size_t len = *first & 0x1f; + *endp = p + len; + break; + } + + case 0x58: // byte string (one-byte uint8_t for n follows) + { + const auto len = binary::from_big_endian<uint8_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + } + *endp = p + len; + break; + } + + case 0x59: // byte string (two-byte uint16_t for n follow) + { + const auto len = binary::from_big_endian<uint16_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + } + *endp = p + len; + break; + } + + case 0x5a: // byte string (four-byte uint32_t for n follow) + { + const auto len = binary::from_big_endian<uint32_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + } + *endp = p + len; + break; + } + + case 0x5b: // byte string (eight-byte uint64_t for n follow) + { + const auto len = binary::from_big_endian<uint64_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + } + *endp = p + len; + break; + } + + case 0x5f: // byte string (indefinite length) + { + while (*p != 0xff) + { + if (p == last) + { + JSONCONS_THROW(json_exception_impl<std::invalid_argument>("eof")); + } + walk(p, last, &p); + } + *endp = p; + break; + } + + // UTF-8 string (0x00..0x17 bytes follow) + case JSONCONS_CBOR_0x60_0x77: + { + size_t len = *first & 0x1f; + *endp = p + len; + break; + } + // UTF-8 string (one-byte uint8_t for n follows) + case 0x78: + { + const auto len = binary::from_big_endian<uint8_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + } + *endp = p + len; + break; + } + // UTF-8 string (two-byte uint16_t for n follow) + case 0x79: + { + const auto len = binary::from_big_endian<uint16_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + } + *endp = p + len; + break; + } + // UTF-8 string (four-byte uint32_t for n follow) + case 0x7a: + { + const auto len = binary::from_big_endian<uint32_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + } + *endp = p + len; + break; + } + // UTF-8 string (eight-byte uint64_t for n follow) + case 0x7b: + { + const auto len = binary::from_big_endian<uint64_t>(p,last,endp); + if (*endp == p) + { + *endp = first; + } + else + { + p = *endp; + } + *endp = p + len; + break; + } + // UTF-8 string (indefinite length) + case 0x7f: + { + while (*p != 0xff) + { + if (p == last) + { + JSONCONS_THROW(json_exception_impl<std::invalid_argument>("eof")); + } + walk(p, last, &p); + } + *endp = p; + break; + } + + + case JSONCONS_CBOR_0x80_0x97: // array (0x00..0x17 data items follow) + // FALLTHRU + case 0x98: // array (one-byte uint8_t for n follows) + // FALLTHRU + case 0x99: // array (two-byte uint16_t for n follow) + // FALLTHRU + case 0x9a: // array (four-byte uint32_t for n follow) + // FALLTHRU + case 0x9b: // array (eight-byte uint64_t for n follow) + // FALLTHRU + case 0x9f: // array (indefinite length) + { + walk_array(first,last,endp); + break; + } + + case JSONCONS_CBOR_0xa0_0xb7: // map (0x00..0x17 pairs of data items follow) + // FALLTHRU + case 0xb8: // map (one-byte uint8_t for n follows) + // FALLTHRU + case 0xb9: // map (two-byte uint16_t for n follow) + // FALLTHRU + case 0xba: // map (four-byte uint32_t for n follow) + // FALLTHRU + case 0xbb: // map (eight-byte uint64_t for n follow) + // FALLTHRU + case 0xbf: + { + walk_object(first,last,endp); + break; + } + + // False + case 0xf4: + { + *endp = p; + break; + } + + // True + case 0xf5: + { + *endp = p; + break; + } + + // Null + case 0xf6: + { + *endp = p; + break; + } + + // Half-Precision Float (two-byte IEEE 754) + case 0xf9: + { + p += sizeof(uint16_t); + *endp = p; + break; + } + + // Single-Precision Float (four-byte IEEE 754) + case 0xfa: + { + p += sizeof(float); + *endp = p; + break; + } + + // Double-Precision Float (eight-byte IEEE 754) + case 0xfb: + { + p += sizeof(double); + *endp = p; + break; + } + + default: + { + *endp = first; + break; + } + } + } +} + +inline +size_t get_size(const uint8_t* first, const uint8_t* last, const uint8_t** endp) +{ + const uint8_t* p = first + 1; + switch (*first) + { + // array (0x00..0x17 data items follow) + case JSONCONS_CBOR_0x80_0x97: + { + *endp = p; + return *first & 0x1f; + } + + // array (one-byte uint8_t for n follows) + case 0x98: + { + const auto len = binary::from_big_endian<uint8_t>(p,last,endp); + if (*endp == p) + { + JSONCONS_THROW(cbor_decode_error(last-p)); + } + else + { + p = *endp; + } + *endp = p; + return len; + } + + // array (two-byte uint16_t for n follow) + case 0x99: + { + const auto len = binary::from_big_endian<uint16_t>(p,last,endp); + if (*endp == p) + { + JSONCONS_THROW(cbor_decode_error(last-p)); + } + else + { + p = *endp; + } + *endp = p; + return len; + } + + // array (four-byte uint32_t for n follow) + case 0x9a: + { + const auto len = binary::from_big_endian<int32_t>(p,last,endp); + if (*endp == p) + { + JSONCONS_THROW(cbor_decode_error(last-p)); + } + else + { + p = *endp; + } + *endp = p; + return len; + } + + // array (eight-byte uint64_t for n follow) + case 0x9b: + { + const auto len = binary::from_big_endian<int64_t>(p,last,endp); + if (*endp == p) + { + JSONCONS_THROW(cbor_decode_error(last-p)); + } + else + { + p = *endp; + } + *endp = p; + return len; + } + + // array (indefinite length) + case 0x9f: + { + size_t len = 0; + while (*p != 0xff) + { + size_t sz = get_size(p,last,&p); + len += sz; + walk(p, last, &p); + } + *endp = first + 1; + return len; + } + + // map (0x00..0x17 pairs of data items follow) + case JSONCONS_CBOR_0xa0_0xb7: + { + *endp = p; + return *first & 0x1f; + } + + // map (one-byte uint8_t for n follows) + case 0xb8: + { + const auto len = binary::from_big_endian<uint8_t>(p,last,endp); + if (*endp == p) + { + JSONCONS_THROW(cbor_decode_error(last-p)); + } + else + { + p = *endp; + } + *endp = p; + return len; + } + + // map (two-byte uint16_t for n follow) + case 0xb9: + { + const auto len = binary::from_big_endian<uint16_t>(p,last,endp); + if (*endp == p) + { + JSONCONS_THROW(cbor_decode_error(last-p)); + } + else + { + p = *endp; + } + *endp = p; + return len; + } + + // map (four-byte uint32_t for n follow) + case 0xba: + { + const auto len = binary::from_big_endian<uint32_t>(p,last,endp); + if (*endp == p) + { + JSONCONS_THROW(cbor_decode_error(last-p)); + } + else + { + p = *endp; + } + *endp = p; + return len; + } + + // map (eight-byte uint64_t for n follow) + case 0xbb: + { + const auto len = binary::from_big_endian<uint64_t>(p,last,endp); + if (*endp == p) + { + JSONCONS_THROW(cbor_decode_error(last-p)); + } + else + { + p = *endp; + } + *endp = p; + return len; + } + + // map (indefinite length) + case 0xbf: + { + size_t len = 0; + while (*p != 0xff) + { + walk(p, last, &p); + walk(p, last, &p); + } + *endp = first + 1; + return len; + } + default: + *endp = last; + return 0; + } +} + +template <class T> +class const_array_iterator +{ + const uint8_t* p_; + const uint8_t* last_; + T current_; +public: + typedef typename T::difference_type difference_type; + typedef typename T::value_type value_type; + typedef typename T::const_reference reference; + typedef typename T::const_pointer pointer; + typedef std::forward_iterator_tag iterator_catagory; + + const_array_iterator() + : p_(nullptr), last_(nullptr) + { + } + + const_array_iterator(const uint8_t* p, const uint8_t* last) + : p_(p), last_(last) + { + } + + const_array_iterator(const const_array_iterator& other) = default; + + friend bool operator==(const const_array_iterator& lhs, const const_array_iterator& rhs) + { + return lhs.p_ == rhs.p_; + } + + friend bool operator!=(const const_array_iterator& lhs, const const_array_iterator& rhs) + { + return lhs.p_ != rhs.p_; + } + + friend bool operator<(const const_array_iterator& lhs, const const_array_iterator& rhs) + { + return lhs.p_ == rhs.p_; + } + + const_array_iterator& operator++() + { + detail::walk(p_, last_, &p_); + return *this; + } + + reference operator*() const + { + const uint8_t* endp; + detail::walk(p_, last_, &endp); + const_cast<T*>(¤t_)->first_ = p_; + const_cast<T*>(¤t_)->last_ = endp; + return current_; + } + + pointer operator->() const + { + const uint8_t* endp; + detail::walk(p_, last_, &endp); + const_cast<T*>(¤t_)->first_ = p_; + const_cast<T*>(¤t_)->last_ = endp; + return ¤t_; + } +}; + +template <class T> +class const_object_iterator; + +template <class T> +class key_value_pair_view +{ + const uint8_t* key_begin_; + const uint8_t* key_end_; + const uint8_t* val_begin_; + const uint8_t* val_end_; + +public: + friend class const_object_iterator<T>; + + key_value_pair_view() + : key_begin_(nullptr), key_end_(nullptr), val_begin_(nullptr), val_end_(nullptr) + { + } + key_value_pair_view(const uint8_t* key_begin, const uint8_t* key_end, const uint8_t* val_begin, const uint8_t* val_end) + : key_begin_(key_begin), key_end_(key_end), val_begin_(val_begin), val_end_(val_end) + { + } + key_value_pair_view(const key_value_pair_view& other) = default; + + std::string key() const + { + const uint8_t* endp; + return get_text_string(key_begin_, key_end_, &endp); + } + + T value() const + { + return T(val_begin_, val_end_ - val_begin_); + } +}; + +template <class T> +class const_object_iterator +{ + const uint8_t* p_; + const uint8_t* last_; + key_value_pair_view<T> kvpair_; +public: + typedef typename T::difference_type difference_type; + typedef key_value_pair_view<T> value_type; + typedef const key_value_pair_view<T>& reference; + typedef const key_value_pair_view<T>* pointer; + typedef std::forward_iterator_tag iterator_catagory; + + const_object_iterator() + : p_(nullptr), last_(nullptr) + { + } + + const_object_iterator(const uint8_t* p, const uint8_t* last) + : p_(p), last_(last) + { + } + + const_object_iterator(const const_object_iterator& other) = default; + + friend bool operator==(const const_object_iterator& lhs, const const_object_iterator& rhs) + { + return lhs.p_ == rhs.p_; + } + + friend bool operator!=(const const_object_iterator& lhs, const const_object_iterator& rhs) + { + return lhs.p_ != rhs.p_; + } + + friend bool operator<(const const_object_iterator& lhs, const const_object_iterator& rhs) + { + return lhs.p_ == rhs.p_; + } + + const_object_iterator& operator++() + { + detail::walk(p_, last_, &p_); + detail::walk(p_, last_, &p_); + return *this; + } + + reference operator*() const + { + const uint8_t* endp; + + const_cast<key_value_pair_view<T>*>(&kvpair_)->key_begin_ = p_; + detail::walk(kvpair_.key_begin_, last_, &endp); + const_cast<key_value_pair_view<T>*>(&kvpair_)->key_end_ = endp; + const_cast<key_value_pair_view<T>*>(&kvpair_)->val_begin_ = kvpair_.key_end_; + detail::walk(kvpair_.val_begin_, last_, &endp); + const_cast<key_value_pair_view<T>*>(&kvpair_)->val_end_ = endp; + + return kvpair_; + } + + pointer operator->() const + { + const uint8_t* endp; + + const_cast<key_value_pair_view<T>*>(&kvpair_)->key_begin_ = p_; + detail::walk(kvpair_.key_begin_, last_, &endp); + const_cast<key_value_pair_view<T>*>(&kvpair_)->key_end_ = endp; + const_cast<key_value_pair_view<T>*>(&kvpair_)->val_begin_ = kvpair_.key_end_; + detail::walk(kvpair_.val_begin_, last_, &endp); + const_cast<key_value_pair_view<T>*>(&kvpair_)->val_end_ = endp; + + return &kvpair_; + } +}; + +} // namespace detail + +class cbor_view +{ + const uint8_t* first_; + const uint8_t* last_; +public: + typedef std::ptrdiff_t difference_type; + typedef cbor_view value_type; + typedef cbor_view& reference; + typedef const cbor_view& const_reference; + typedef cbor_view* pointer; + typedef const cbor_view* const_pointer; + typedef std::string string_type; + typedef char char_type; + typedef std::char_traits<char_type> char_traits_type; + typedef basic_string_view_ext<char_type> string_view_type; + typedef detail::const_object_iterator<cbor_view> object_iterator; + typedef detail::const_object_iterator<cbor_view> const_object_iterator; + typedef detail::const_array_iterator<cbor_view> array_iterator; + typedef detail::const_array_iterator<cbor_view> const_array_iterator; + typedef detail::key_value_pair_view<cbor_view> key_value_pair_type; + + friend class detail::const_array_iterator<cbor_view>; + + range<const_object_iterator> object_range() const + { + const uint8_t* endp; + const uint8_t* begin; + + switch (*first_) + { + case JSONCONS_CBOR_0xa0_0xb7: // map (0x00..0x17 pairs of data items follow) + // FALLTHRU + case 0xb8: // map (one-byte uint8_t for n follows) + // FALLTHRU + case 0xb9: // map (two-byte uint16_t for n follow) + // FALLTHRU + case 0xba: // map (four-byte uint32_t for n follow) + // FALLTHRU + case 0xbb: // map (eight-byte uint64_t for n follow) + // FALLTHRU + case 0xbf: + detail::get_size(first_,last_,&begin); + break; + default: + JSONCONS_THROW(json_exception_impl<std::invalid_argument>("Not an object")); + break; + } + detail::walk_object(first_,last_,&endp); + + return range<const_object_iterator>(const_object_iterator(begin,endp), const_object_iterator(endp, endp)); + } + + range<const_array_iterator> array_range() const + { + const uint8_t* endp; + const uint8_t* begin; + + switch (*first_) + { + case JSONCONS_CBOR_0x80_0x97: // array (0x00..0x17 data items follow) + // FALLTHRU + case 0x98: // array (one-byte uint8_t for n follows) + // FALLTHRU + case 0x99: // array (two-byte uint16_t for n follow) + // FALLTHRU + case 0x9a: // array (four-byte uint32_t for n follow) + // FALLTHRU + case 0x9b: // array (eight-byte uint64_t for n follow) + // FALLTHRU + case 0x9f: // array (indefinite length) + detail::get_size(first_,last_,&begin); + break; + default: + JSONCONS_THROW(json_exception_impl<std::invalid_argument>("Not an array")); + break; + } + detail::walk_array(first_,last_,&endp); + return range<const_array_iterator>(const_array_iterator(begin,endp), const_array_iterator(endp, endp)); + } + + cbor_view() + : first_(nullptr), last_(nullptr) + { + } + + cbor_view(const uint8_t* buffer, size_t buflen) + : first_(buffer), last_(buffer+buflen) + { + } + + cbor_view(const std::vector<uint8_t>& v) + : first_(v.data()), last_(v.data()+v.size()) + { + } + + cbor_view(const cbor_view& other) + : first_(other.first_), last_(other.last_) + { + } + + cbor_view& operator=(const cbor_view&) = default; + + friend bool operator==(const cbor_view& lhs, const cbor_view& rhs) + { + return lhs.first_ == rhs.first_ && lhs.last_ == rhs.last_; + } + + friend bool operator!=(const cbor_view& lhs, const cbor_view& rhs) + { + return !(lhs == rhs); + } + + const uint8_t* buffer() const + { + return first_; + } + + const size_t buflen() const + { + return last_ - first_; + } + + bool is_null() const + { + JSONCONS_ASSERT(buflen() > 0); + return first_[0] == 0xf6; + } + + bool empty() const + { + bool is_empty; + if (is_array() || is_object()) + { + is_empty = (size() == 0); + } + else if (is_string()) + { + const uint8_t* endp; + size_t length = detail::get_text_string_length(first_,last_,&endp); + is_empty = (length == 0); + } + else if (is_byte_string()) + { + const uint8_t* endp; + size_t length = detail::get_byte_string_length(first_, last_, &endp); + is_empty = (length == 0); + } + else + { + is_empty = false; + } + + return is_empty; + } + + bool is_array() const + { + JSONCONS_ASSERT(buflen() > 0); + return detail::is_array(first_[0]); + } + + bool is_object() const + { + JSONCONS_ASSERT(buflen() > 0); + return detail::is_object(first_[0]); + } + + bool is_string() const + { + JSONCONS_ASSERT(buflen() > 0); + return detail::is_string(first_[0]); + } + + bool is_byte_string() const + { + JSONCONS_ASSERT(buflen() > 0); + + bool result; + switch (first_[0]) + { + case JSONCONS_CBOR_0x40_0x57: // byte string (0x00..0x17 bytes follow) + // FALLTHRU + case 0x58: // byte string (one-byte uint8_t for n follows) + // FALLTHRU + case 0x59: // byte string (two-byte uint16_t for n follow) + // FALLTHRU + case 0x5a: // byte string (four-byte uint32_t for n follow) + // FALLTHRU + case 0x5b: // byte string (eight-byte uint64_t for n follow) + // FALLTHRU + case 0x5f: // byte string, byte strings follow, terminated by "break" + result = true; + break; + default: + result = false; + break; + } + return result; + } + + bool is_bool() const + { + JSONCONS_ASSERT(buflen() > 0); + return detail::is_bool(first_[0]); + } + + bool is_double() const + { + JSONCONS_ASSERT(buflen() > 0); + return detail::is_double(first_[0]); + } + + bool is_integer() const + { + JSONCONS_ASSERT(buflen() > 0); + return detail::is_integer(first_,last_); + } + + bool is_uinteger() const + { + JSONCONS_ASSERT(buflen() > 0); + return detail::is_uinteger(first_[0]); + } + + size_t size() const + { + const uint8_t* it; + size_t len = detail::get_size(first_,last_,&it); + return len; + } + + cbor_view at(size_t index) const + { + JSONCONS_ASSERT(is_array()); + const uint8_t* it = first_; + + size_t len = detail::get_size(it, last_, &it); + + for (size_t i = 0; i < index; ++i) + { + detail::walk(it, last_, &it); + } + + const uint8_t* endp; + detail::walk(it, last_, &endp); + + return cbor_view(it,endp-it); + } + + cbor_view at(const string_view_type& key) const + { + JSONCONS_ASSERT(is_object()); + const uint8_t* it = first_; + + size_t len = detail::get_size(first_, last_, &it); + + for (size_t i = 0; i < len; ++i) + { + const uint8_t* endp; + string_type a_key = detail::get_text_string(it, last_, &endp); + if (endp == it) + { + JSONCONS_THROW(cbor_decode_error(last_-it)); + } + else + { + it = endp; + } + if (a_key == key) + { + const uint8_t* last; + detail::walk(it, last_, &last); + JSONCONS_ASSERT(last >= it); + return cbor_view(it,last-it); + } + const uint8_t* last; + detail::walk(it, last_, &last); + it = last; + } + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Key not found")); + } + + bool has_key(const string_view_type& key) const + { + if (!is_object()) + { + return false; + } + const uint8_t* it = first_; + + size_t len = detail::get_size(it, last_, &it); + + for (size_t i = 0; i < len; ++i) + { + const uint8_t* endp; + string_type a_key = detail::get_text_string(it, last_,&endp); + if (endp == it) + { + JSONCONS_THROW(cbor_decode_error(last_-it)); + } + else + { + it = endp; + } + if (a_key == key) + { + return true; + } + detail::walk(it, last_, &it); + } + return false; + } + + int64_t as_integer() const + { + const uint8_t* endp; + int64_t val = detail::get_integer(first_,last_,&endp); + if (endp == first_) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an integer")); + } + return val; + } + + bool as_bool() const + { + if (*first_ == 0xf5) + { + return true; + } + else if (*first_ == 0xf4) + { + return false; + } + else + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not a bool")); + } + } + + uint64_t as_uinteger() const + { + const uint8_t* endp; + uint64_t val = detail::get_uinteger(first_, last_, &endp); + if (endp == first_) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not an unsigned integer")); + } + return val; + } + + double as_double() const + { + double val; + + if (is_double()) + { + const uint8_t* endp; + val = detail::get_double(first_,last_,&endp); + if (endp == first_) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Invalid CBOR")); + } + } + else if (is_uinteger()) + { + val = static_cast<double>(as_uinteger()); + } + else if (is_integer()) + { + val = static_cast<double>(as_integer()); + } + else + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not a double")); + } + return val; + } + + std::string as_string() const + { + const uint8_t* endp; + std::string val = detail::get_text_string(first_,last_,&endp); + if (endp == first_) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Not a string")); + } + return val; + } +}; + +struct Encode_cbor_ +{ + template <typename T> + void operator()(T val, std::vector<uint8_t>& v) + { + binary::to_big_endian(val,v); + } +}; + +struct Calculate_size_ +{ + template <typename T> + void operator()(T, size_t& size) + { + size += sizeof(T); + } +}; + +template<class Json> +struct cbor_Encoder_ +{ + typedef typename Json::string_view_type string_view_type; + + static size_t calculate_size(const Json& j) + { + size_t n = 0; + cbor_Encoder_<Json>::encode(j,Calculate_size_(),n); + return n; + } + + template <class Action, class Result> + static void encode(const Json& jval, Action action, Result& v) + { + switch (jval.type_id()) + { + case json_type_tag::null_t: + { + action(static_cast<uint8_t>(0xf6), v); + break; + } + + case json_type_tag::bool_t: + { + action(static_cast<uint8_t>(jval.as_bool() ? 0xf5 : 0xf4), v); + break; + } + + case json_type_tag::integer_t: + { + int64_t val = jval.as_integer(); + if (val >= 0) + { + if (val <= 0x17) + { + action(static_cast<uint8_t>(val), v); + } else if (val <= (std::numeric_limits<uint8_t>::max)()) + { + action(static_cast<uint8_t>(0x18), v); + action(static_cast<uint8_t>(val), v); + } else if (val <= (std::numeric_limits<uint16_t>::max)()) + { + action(static_cast<uint8_t>(0x19), v); + action(static_cast<uint16_t>(val), v); + } else if (val <= (std::numeric_limits<uint32_t>::max)()) + { + action(static_cast<uint8_t>(0x1a), v); + action(static_cast<uint32_t>(val), v); + } else if (val <= (std::numeric_limits<int64_t>::max)()) + { + action(static_cast<uint8_t>(0x1b), v); + action(static_cast<int64_t>(val), v); + } + } else + { + const auto posnum = -1 - val; + if (val >= -24) + { + action(static_cast<uint8_t>(0x20 + posnum), v); + } else if (posnum <= (std::numeric_limits<uint8_t>::max)()) + { + action(static_cast<uint8_t>(0x38), v); + action(static_cast<uint8_t>(posnum), v); + } else if (posnum <= (std::numeric_limits<uint16_t>::max)()) + { + action(static_cast<uint8_t>(0x39), v); + action(static_cast<uint16_t>(posnum), v); + } else if (posnum <= (std::numeric_limits<uint32_t>::max)()) + { + action(static_cast<uint8_t>(0x3a), v); + action(static_cast<uint32_t>(posnum), v); + } else if (posnum <= (std::numeric_limits<int64_t>::max)()) + { + action(static_cast<uint8_t>(0x3b), v); + action(static_cast<int64_t>(posnum), v); + } + } + break; + } + + case json_type_tag::uinteger_t: + { + uint64_t val = jval.as_uinteger(); + if (val <= 0x17) + { + action(static_cast<uint8_t>(val),v); + } else if (val <=(std::numeric_limits<uint8_t>::max)()) + { + action(static_cast<uint8_t>(0x18), v); + action(static_cast<uint8_t>(val),v); + } else if (val <=(std::numeric_limits<uint16_t>::max)()) + { + action(static_cast<uint8_t>(0x19), v); + action(static_cast<uint16_t>(val),v); + } else if (val <=(std::numeric_limits<uint32_t>::max)()) + { + action(static_cast<uint8_t>(0x1a), v); + action(static_cast<uint32_t>(val),v); + } else if (val <=(std::numeric_limits<uint64_t>::max)()) + { + action(static_cast<uint8_t>(0x1b), v); + action(static_cast<uint64_t>(val),v); + } + break; + } + + case json_type_tag::double_t: + { + action(static_cast<uint8_t>(0xfb), v); + action(jval.as_double(),v); + break; + } + + case json_type_tag::byte_string_t: + { + encode_byte_string(jval. template as<std::vector<uint8_t>>(), action, v); + break; + } + + case json_type_tag::small_string_t: + case json_type_tag::string_t: + { + encode_string(jval.as_string_view(), action, v); + break; + } + + case json_type_tag::array_t: + { + const auto length = jval.array_value().size(); + if (length <= 0x17) + { + action(static_cast<uint8_t>(static_cast<uint8_t>(0x80 + length)), v); + } else if (length <= 0xff) + { + action(static_cast<uint8_t>(0x98), v); + action(static_cast<uint8_t>(static_cast<uint8_t>(length)), v); + } else if (length <= 0xffff) + { + action(static_cast<uint8_t>(0x99), v); + action(static_cast<uint16_t>(length),v); + } else if (length <= 0xffffffff) + { + action(static_cast<uint8_t>(0x9a), v); + action(static_cast<uint32_t>(length),v); + } else if (length <= 0xffffffffffffffff) + { + action(static_cast<uint8_t>(0x9b), v); + action(static_cast<uint64_t>(length),v); + } + + // append each element + for (const auto& el : jval.array_range()) + { + encode(el,action,v); + } + break; + } + + case json_type_tag::object_t: + { + const auto length = jval.object_value().size(); + if (length <= 0x17) + { + action(static_cast<uint8_t>(static_cast<uint8_t>(0xa0 + length)), v); + } else if (length <= 0xff) + { + action(static_cast<uint8_t>(0xb8), v); + action(static_cast<uint8_t>(static_cast<uint8_t>(length)), v); + } else if (length <= 0xffff) + { + action(static_cast<uint8_t>(0xb9), v); + action(static_cast<uint16_t>(length),v); + } else if (length <= 0xffffffff) + { + action(static_cast<uint8_t>(0xba), v); + action(static_cast<uint32_t>(length),v); + } else if (length <= 0xffffffffffffffff) + { + action(static_cast<uint8_t>(0xbb), v); + action(static_cast<uint64_t>(length),v); + } + + // append each element + for (const auto& kv: jval.object_range()) + { + encode_string(kv.key(), action, v); + encode(kv.value(), action, v); + } + break; + } + + default: + { + break; + } + } + } + + template <class Action,class Result> + static void encode_string(const string_view_type& sv, Action action, Result& v) + { + std::basic_string<uint8_t> target; + auto result = unicons::convert( + sv.begin(), sv.end(), std::back_inserter(target), + unicons::conv_flags::strict); + if (result.ec != unicons::conv_errc()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Illegal unicode")); + } + + const size_t length = target.length(); + if (length <= 0x17) + { + // fixstr stores a byte array whose length is upto 31 bytes + action(static_cast<uint8_t>(static_cast<uint8_t>(0x60 + length)), v); + } + else if (length <= 0xff) + { + action(static_cast<uint8_t>(0x78), v); + action(static_cast<uint8_t>(static_cast<uint8_t>(length)), v); + } + else if (length <= 0xffff) + { + action(static_cast<uint8_t>(0x79), v); + action(static_cast<uint16_t>(length), v); + } + else if (length <= 0xffffffff) + { + action(static_cast<uint8_t>(0x7a), v); + action(static_cast<uint32_t>(length), v); + } + else if (length <= 0xffffffffffffffff) + { + action(static_cast<uint8_t>(0x7b), v); + action(static_cast<uint64_t>(length),v); + } + + for (size_t i = 0; i < length; ++i) + { + action(static_cast<uint8_t>(target.data()[i]), v); + } + } + + template <class Action,class Result> + static void encode_byte_string(const std::vector<uint8_t>& target, Action action, Result& v) + { + const size_t length = target.size(); + if (length <= 0x17) + { + // fixstr stores a byte array whose length is upto 31 bytes + action(static_cast<uint8_t>(static_cast<uint8_t>(0x40 + length)), v); + } + else if (length <= 0xff) + { + action(static_cast<uint8_t>(0x58), v); + action(static_cast<uint8_t>(static_cast<uint8_t>(length)), v); + } + else if (length <= 0xffff) + { + action(static_cast<uint8_t>(0x59), v); + action(static_cast<uint16_t>(length), v); + } + else if (length <= 0xffffffff) + { + action(static_cast<uint8_t>(0x5a), v); + action(static_cast<uint32_t>(length), v); + } + else if (length <= 0xffffffffffffffff) + { + action(static_cast<uint8_t>(0x5b), v); + action(static_cast<uint64_t>(length),v); + } + + for (size_t i = 0; i < length; ++i) + { + action(static_cast<uint8_t>(target.data()[i]), v); + } + } +}; + +// decode_cbor + +template<class Json> +class Decode_cbor_ +{ + const uint8_t* begin_; + const uint8_t* end_; + const uint8_t* it_; +public: + typedef typename Json::char_type char_type; + + Decode_cbor_(const uint8_t* begin, const uint8_t* end) + : begin_(begin), end_(end), it_(begin) + { + } + + Json decode() + { + const uint8_t* pos = it_++; + switch (*pos) + { + + case JSONCONS_CBOR_0x00_0x17: // Integer 0x00..0x17 (0..23) + // FALLTHRU + case 0x18: // Unsigned integer (one-byte uint8_t follows) + // FALLTHRU + case 0x19: // Unsigned integer (two-byte uint16_t follows) + // FALLTHRU + case 0x1a: // Unsigned integer (four-byte uint32_t follows) + // FALLTHRU + case 0x1b: // Unsigned integer (eight-byte uint64_t follows) + { + const uint8_t* endp; + uint64_t val = detail::get_uinteger(pos,end_,&endp); + if (endp == pos) + { + JSONCONS_THROW(cbor_decode_error(endp-begin_)); + } + it_ = endp; + return Json(val); + } + break; + + case JSONCONS_CBOR_0x20_0x37: // Negative integer -1-0x00..-1-0x17 (-1..-24) + // FALLTHRU + case 0x38: // Negative integer (one-byte uint8_t follows) + // FALLTHRU + case 0x39: // Negative integer -1-n (two-byte uint16_t follows) + // FALLTHRU + case 0x3a: // Negative integer -1-n (four-byte uint32_t follows) + // FALLTHRU + case 0x3b: // Negative integer -1-n (eight-byte uint64_t follows) + { + const uint8_t* endp; + int64_t val = detail::get_integer(pos,end_,&endp); + if (endp == pos) + { + JSONCONS_THROW(cbor_decode_error(endp-begin_)); + } + it_ = endp; + return Json(val); + } + break; + // byte string (0x00..0x17 bytes follow) + case JSONCONS_CBOR_0x40_0x57: + case 0x58: + case 0x59: + case 0x5a: + case 0x5b: + case 0x5f: + { + const uint8_t* endp; + std::vector<uint8_t> v = detail::get_byte_string(pos,end_,&endp); + if (endp == pos) + { + JSONCONS_THROW(cbor_decode_error(end_-pos)); + } + else + { + it_ = endp; + } + + return Json(v.data(),v.size()); + } + + // UTF-8 string (0x00..0x17 bytes follow) + case JSONCONS_CBOR_0x60_0x77: + case 0x78: + case 0x79: + case 0x7a: + case 0x7b: + case 0x7f: + { + const uint8_t* endp; + std::string s = detail::get_text_string(pos,end_,&endp); + if (endp == pos) + { + JSONCONS_THROW(cbor_decode_error(end_-pos)); + } + else + { + it_ = endp; + } + std::basic_string<char_type> target; + auto result = unicons::convert(s.begin(),s.end(),std::back_inserter(target),unicons::conv_flags::strict); + if (result.ec != unicons::conv_errc()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Illegal unicode")); + } + return Json(target); + } + + // array (0x00..0x17 data items follow) + case JSONCONS_CBOR_0x80_0x97: + { + return get_fixed_length_array(*pos & 0x1f); + } + + // array (one-byte uint8_t for n follows) + case 0x98: + { + const uint8_t* endp; + const auto len = binary::from_big_endian<uint8_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(cbor_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return get_fixed_length_array(len); + } + + // array (two-byte uint16_t for n follow) + case 0x99: + { + const uint8_t* endp; + const auto len = binary::from_big_endian<uint16_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(cbor_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return get_fixed_length_array(len); + } + + // array (four-byte uint32_t for n follow) + case 0x9a: + { + const uint8_t* endp; + const auto len = binary::from_big_endian<int32_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(cbor_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return get_fixed_length_array(len); + } + + // array (eight-byte uint64_t for n follow) + case 0x9b: + { + const uint8_t* endp; + const auto len = binary::from_big_endian<int64_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(cbor_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return get_fixed_length_array(len); + } + + // array (indefinite length) + case 0x9f: + { + Json result = typename Json::array(); + while (*pos != 0xff) + { + result.push_back(decode()); + pos = it_; + } + return result; + } + + // map (0x00..0x17 pairs of data items follow) + case JSONCONS_CBOR_0xa0_0xb7: + { + return get_fixed_length_map(*pos & 0x1f); + } + + // map (one-byte uint8_t for n follows) + case 0xb8: + { + const uint8_t* endp; + const auto len = binary::from_big_endian<uint8_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(cbor_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return get_fixed_length_map(len); + } + + // map (two-byte uint16_t for n follow) + case 0xb9: + { + const uint8_t* endp; + const auto len = binary::from_big_endian<uint16_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(cbor_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return get_fixed_length_map(len); + } + + // map (four-byte uint32_t for n follow) + case 0xba: + { + const uint8_t* endp; + const auto len = binary::from_big_endian<uint32_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(cbor_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return get_fixed_length_map(len); + } + + // map (eight-byte uint64_t for n follow) + case 0xbb: + { + const uint8_t* endp; + const auto len = binary::from_big_endian<uint64_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(cbor_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return get_fixed_length_map(len); + } + + // map (indefinite length) + case 0xbf: + { + Json result = typename Json::object(); + while (*pos != 0xff) + { + auto j = decode(); + result.set(j.as_string_view(),decode()); + pos = it_; + } + return result; + } + + // False + case 0xf4: + { + return Json(false); + } + + // True + case 0xf5: + { + return Json(true); + } + + // Null + case 0xf6: + { + return Json::null(); + } + + + case 0xf9: // Half-Precision Float (two-byte IEEE 754) + // FALLTHRU + case 0xfa: // Single-Precision Float (four-byte IEEE 754) + // FALLTHRU + case 0xfb: // Double-Precision Float (eight-byte IEEE 754) + { + const uint8_t* endp; + double val = detail::get_double(pos,end_,&endp); + if (endp == pos) + { + JSONCONS_THROW(cbor_decode_error(endp-begin_)); + } + it_ = endp; + return Json(val); + } + + default: + { + JSONCONS_THROW(cbor_decode_error(end_-pos)); + } + } + } + + template<typename T> + Json get_fixed_length_array(const T len) + { + Json result = typename Json::array(); + result.reserve(len); + for (T i = 0; i < len; ++i) + { + result.push_back(decode()); + } + return result; + } + + template<typename T> + Json get_fixed_length_map(const T len) + { + Json result = typename Json::object(); + result.reserve(len); + for (T i = 0; i < len; ++i) + { + auto j = decode(); + result.set(j.as_string_view(),decode()); + } + return result; + } +}; + +template<class Json> +void encode_cbor(const Json& j, std::vector<uint8_t>& v) +{ + size_t n = 0; + cbor_Encoder_<Json>::encode(j,Calculate_size_(),n); + + v.reserve(n); + cbor_Encoder_<Json>::encode(j,Encode_cbor_(),v); +} + +template<class Json> +Json decode_cbor(const cbor_view& v) +{ + Decode_cbor_<Json> decoder(v.buffer(),v.buffer()+v.buflen()); + return decoder.decode(); +} + +#if !defined(JSONCONS_NO_DEPRECATED) +template<class Json> +std::vector<uint8_t> encode_cbor(const Json& j) +{ + std::vector<uint8_t> v; + encode_cbor(j, v); + return v; +} +#endif + +}} + +#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons_ext/csv/csv_error_category.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/csv/csv_error_category.hpp index 5056d380..0e986cda 100644 --- a/vendor/jsoncons-0.99.2/jsoncons_ext/csv/csv_error_category.hpp +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/csv/csv_error_category.hpp @@ -4,21 +4,22 @@ // See https://github.com/danielaparker/jsoncons for latest version -#ifndef JSONCONS_CSV_CSV_TEXT_ERROR_CATEGORY_HPP -#define JSONCONS_CSV_CSV_TEXT_ERROR_CATEGORY_HPP +#ifndef JSONCONS_CSV_CSV_ERROR_CATEGORY_HPP +#define JSONCONS_CSV_CSV_ERROR_CATEGORY_HPP -#include "jsoncons/jsoncons.hpp" #include <system_error> +#include <jsoncons/json_exception.hpp> namespace jsoncons { namespace csv { -namespace csv_parser_errc -{ - const int unexpected_eof = 1; - const int expected_quote = 2; - const int invalid_csv_text = 3; - const int invalid_state = 4; -} + enum class csv_parser_errc : int + { + ok = 0, + unexpected_eof = 1, + expected_quote = 2, + invalid_csv_text = 3, + invalid_state = 4 + }; class csv_error_category_impl : public std::error_category @@ -30,7 +31,7 @@ public: } virtual std::string message(int ev) const { - switch (ev) + switch (static_cast<csv_parser_errc>(ev)) { case csv_parser_errc::unexpected_eof: return "Unexpected end of file"; @@ -51,5 +52,19 @@ const std::error_category& csv_error_category() return instance; } +inline +std::error_code make_error_code(csv_parser_errc result) +{ + return std::error_code(static_cast<int>(result),csv_error_category()); +} + }} + +namespace std { + template<> + struct is_error_code_enum<jsoncons::csv::csv_parser_errc> : public true_type + { + }; +} + #endif diff --git a/vendor/jsoncons-0.104.0/jsoncons_ext/csv/csv_parameters.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/csv/csv_parameters.hpp new file mode 100644 index 00000000..61b635f3 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/csv/csv_parameters.hpp @@ -0,0 +1,635 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CSV_CSV_PARAMETERS_HPP +#define JSONCONS_CSV_CSV_PARAMETERS_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <unordered_map> +#include <istream> +#include <ostream> +#include <cstdlib> +#include <limits> +#include <cwchar> + +namespace jsoncons { namespace csv { + +namespace detail { + JSONCONS_DEFINE_LITERAL(string_literal,"string") + JSONCONS_DEFINE_LITERAL(integer_literal,"integer") + JSONCONS_DEFINE_LITERAL(float_literal,"float") + JSONCONS_DEFINE_LITERAL(boolean_literal,"boolean") +} + +enum class csv_column_type +{ + string_t,integer_t,float_t,boolean_t,repeat_t +}; + +enum class quote_style_type +{ + all,minimal,none,nonnumeric +}; + +typedef quote_style_type quote_styles; + +enum class mapping_type +{ + n_rows, + n_objects, + m_columns +}; + +enum class column_state {sequence,label}; + +struct csv_type_info +{ + csv_type_info() = default; + csv_type_info(const csv_type_info&) = default; + csv_type_info(csv_type_info&&) = default; + + csv_type_info(csv_column_type ctype, size_t lev, size_t repcount = 0) + { + col_type = ctype; + level = lev; + rep_count = repcount; + } + + csv_column_type col_type; + size_t level; + size_t rep_count; +}; + +template <class CharT,class Allocator=std::allocator<CharT>> +class basic_csv_parameters +{ + typedef CharT char_type; + typedef Allocator allocator_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<CharT> char_allocator_type; + typedef std::basic_string<CharT,std::char_traits<CharT>,char_allocator_type> string_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<string_type> string_allocator_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<csv_type_info> csv_type_info_allocator_type; + + bool assume_header_; + bool ignore_empty_values_; + bool ignore_empty_lines_; + bool trim_leading_; + bool trim_trailing_; + bool trim_leading_inside_quotes_; + bool trim_trailing_inside_quotes_; + bool unquoted_empty_value_is_null_; + CharT field_delimiter_; + CharT quote_char_; + CharT quote_escape_char_; + CharT comment_starter_; + quote_style_type quote_style_; + std::pair<mapping_type,bool> mapping_; + unsigned long max_lines_; + size_t header_lines_; + string_type line_delimiter_; + bool infer_types_; + + std::vector<string_type,string_allocator_type> column_names_; + std::vector<csv_type_info,csv_type_info_allocator_type> column_types_; + std::vector<string_type,string_allocator_type> column_defaults_; +public: + static const size_t default_indent = 4; + +// Constructors + + basic_csv_parameters() + : + assume_header_(false), + ignore_empty_values_(false), + ignore_empty_lines_(true), + trim_leading_(false), + trim_trailing_(false), + trim_leading_inside_quotes_(false), + trim_trailing_inside_quotes_(false), + unquoted_empty_value_is_null_(false), + field_delimiter_(','), + quote_char_('\"'), + quote_escape_char_('\"'), + comment_starter_('\0'), + quote_style_(quote_style_type::minimal), + mapping_({mapping_type::n_rows,false}), + max_lines_((std::numeric_limits<unsigned long>::max)()), + header_lines_(0), + infer_types_(true) + { + line_delimiter_.push_back('\n'); + } + +// Properties + + size_t header_lines() const + { + return (assume_header_ && header_lines_ <= 1) ? 1 : header_lines_; + } + + basic_csv_parameters& header_lines(size_t value) + { + header_lines_ = value; + return *this; + } + + bool assume_header() const + { + return assume_header_; + } + + basic_csv_parameters& assume_header(bool value) + { + assume_header_ = value; + return *this; + } + + bool ignore_empty_values() const + { + return ignore_empty_values_; + } + + basic_csv_parameters& ignore_empty_values(bool value) + { + ignore_empty_values_ = value; + return *this; + } + + bool ignore_empty_lines() const + { + return ignore_empty_lines_; + } + + basic_csv_parameters& ignore_empty_lines(bool value) + { + ignore_empty_lines_ = value; + return *this; + } + + bool trim_leading() const + { + return trim_leading_; + } + + basic_csv_parameters& trim_leading(bool value) + { + trim_leading_ = value; + return *this; + } + + bool trim_trailing() const + { + return trim_trailing_; + } + + basic_csv_parameters& trim_trailing(bool value) + { + trim_trailing_ = value; + return *this; + } + + bool trim_leading_inside_quotes() const + { + return trim_leading_inside_quotes_; + } + + basic_csv_parameters& trim_leading_inside_quotes(bool value) + { + trim_leading_inside_quotes_ = value; + return *this; + } + + bool trim_trailing_inside_quotes() const + { + return trim_trailing_inside_quotes_; + } + + basic_csv_parameters& trim_trailing_inside_quotes(bool value) + { + trim_trailing_inside_quotes_ = value; + return *this; + } + + bool trim() const + { + return trim_leading_ && trim_trailing_; + } + + basic_csv_parameters& trim(bool value) + { + trim_leading_ = value; + trim_trailing_ = value; + return *this; + } + + bool trim_inside_quotes() const + { + return trim_leading_inside_quotes_ && trim_trailing_inside_quotes_; + } + + basic_csv_parameters& trim_inside_quotes(bool value) + { + trim_leading_inside_quotes_ = value; + trim_trailing_inside_quotes_ = value; + return *this; + } + + bool unquoted_empty_value_is_null() const + { + return unquoted_empty_value_is_null_; + } + + basic_csv_parameters& unquoted_empty_value_is_null(bool value) + { + unquoted_empty_value_is_null_ = value; + return *this; + } + + std::vector<string_type,string_allocator_type> column_names() const + { + return column_names_; + } + +#if !defined(JSONCONS_NO_DEPRECATED) + basic_csv_parameters& column_names(const std::vector<string_type,string_allocator_type>& value) + { + column_names_ = value; + return *this; + } + + basic_csv_parameters& column_defaults(const std::vector<string_type,string_allocator_type>& value) + { + column_defaults_ = value; + return *this; + } + + basic_csv_parameters& column_types(const std::vector<string_type,string_allocator_type>& value) + { + if (value.size() > 0) + { + column_types_.reserve(value.size()); + for (size_t i = 0; i < value.size(); ++i) + { + if (value[i] == detail::string_literal<CharT>()()) + { + column_types_.emplace_back(csv_column_type::string_t,0); + } + else if (value[i] == detail::integer_literal<CharT>()()) + { + column_types_.emplace_back(csv_column_type::integer_t,0); + } + else if (value[i] == detail::float_literal<CharT>()()) + { + column_types_.emplace_back(csv_column_type::float_t,0); + } + else if (value[i] == detail::boolean_literal<CharT>()()) + { + column_types_.emplace_back(csv_column_type::boolean_t,0); + } + } + } + return *this; + } +#endif + basic_csv_parameters& column_names(const string_type& names) + { + column_names_ = parse_column_names(names); + return *this; + } + + std::vector<csv_type_info,csv_type_info_allocator_type> column_types() const + { + return column_types_; + } + + basic_csv_parameters& column_types(const string_type& types) + { + column_types_ = parse_column_types(types); + return *this; + } + + std::vector<string_type,string_allocator_type> column_defaults() const + { + return column_defaults_; + } + + basic_csv_parameters& column_defaults(const string_type& defaults) + { + column_defaults_ = parse_column_names(defaults); + return *this; + } + + CharT field_delimiter() const + { + return field_delimiter_; + } + + basic_csv_parameters& field_delimiter(CharT value) + { + field_delimiter_ = value; + return *this; + } + + string_type line_delimiter() const + { + return line_delimiter_; + } + + basic_csv_parameters& line_delimiter(string_type value) + { + line_delimiter_ = value; + return *this; + } + + CharT quote_char() const + { + return quote_char_; + } + + basic_csv_parameters& quote_char(CharT value) + { + quote_char_ = value; + return *this; + } + + bool infer_types() const + { + return infer_types_; + } + + basic_csv_parameters& infer_types(bool value) + { + infer_types_ = value; + return *this; + } + + CharT quote_escape_char() const + { + return quote_escape_char_; + } + + basic_csv_parameters& quote_escape_char(CharT value) + { + quote_escape_char_ = value; + return *this; + } + + CharT comment_starter() const + { + return comment_starter_; + } + + basic_csv_parameters& comment_starter(CharT value) + { + comment_starter_ = value; + return *this; + } + + quote_style_type quote_style() const + { + return quote_style_; + } + + mapping_type mapping() const + { + return mapping_.second ? (mapping_.first) : (assume_header() || column_names_.size() > 0 ? mapping_type::n_objects : mapping_type::n_rows); + } + + basic_csv_parameters& quote_style(quote_style_type value) + { + quote_style_ = value; + return *this; + } + + basic_csv_parameters& mapping(mapping_type value) + { + mapping_ = {value,true}; + return *this; + } + + unsigned long max_lines() const + { + return max_lines_; + } + + basic_csv_parameters& max_lines(unsigned long value) + { + max_lines_ = value; + return *this; + } + + static std::vector<string_type,string_allocator_type> parse_column_names(const string_type& names) + { + std::vector<string_type,string_allocator_type> column_names; + + column_state state = column_state::sequence; + string_type buffer; + + auto p = names.begin(); + while (p != names.end()) + { + switch (state) + { + case column_state::sequence: + { + switch (*p) + { + case ' ': case '\t':case '\r': case '\n': + ++p; + break; + default: + buffer.clear(); + state = column_state::label; + break; + } + break; + } + case column_state::label: + { + switch (*p) + { + case ',': + column_names.push_back(buffer); + buffer.clear(); + ++p; + state = column_state::sequence; + break; + default: + buffer.push_back(*p); + ++p; + break; + } + break; + } + } + } + if (state == column_state::label) + { + column_names.push_back(buffer); + buffer.clear(); + } + return column_names; + } + + static std::vector<csv_type_info,csv_type_info_allocator_type> parse_column_types(const string_type& types) + { + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<std::pair<const string_type,csv_column_type>> pair_allocator_type; + + const std::unordered_map<string_type,csv_column_type, std::hash<string_type>,std::equal_to<string_type>,pair_allocator_type> type_dictionary = + { + + {detail::string_literal<char_type>(),csv_column_type::string_t}, + {detail::integer_literal<char_type>(),csv_column_type::integer_t}, + {detail::float_literal<char_type>(),csv_column_type::float_t}, + {detail::boolean_literal<char_type>(),csv_column_type::boolean_t} + }; + + std::vector<csv_type_info,csv_type_info_allocator_type> column_types; + + column_state state = column_state::sequence; + int depth = 0; + string_type buffer; + + auto p = types.begin(); + while (p != types.end()) + { + switch (state) + { + case column_state::sequence: + { + switch (*p) + { + case ' ': case '\t':case '\r': case '\n': + ++p; + break; + case '[': + ++depth; + ++p; + break; + case ']': + JSONCONS_ASSERT(depth > 0); + --depth; + ++p; + break; + case '*': + { + JSONCONS_ASSERT(column_types.size() != 0); + size_t offset = 0; + size_t level = column_types.size() > 0 ? column_types.back().level: 0; + if (level > 0) + { + for (auto it = column_types.rbegin(); + it != column_types.rend() && level == it->level; + ++it) + { + ++offset; + } + } + else + { + offset = 1; + } + column_types.emplace_back(csv_column_type::repeat_t,depth,offset); + ++p; + break; + } + default: + buffer.clear(); + state = column_state::label; + break; + } + break; + } + case column_state::label: + { + switch (*p) + { + case '*': + { + auto it = type_dictionary.find(buffer); + if (it != type_dictionary.end()) + { + column_types.emplace_back(it->second,depth); + buffer.clear(); + } + else + { + JSONCONS_ASSERT(false); + } + state = column_state::sequence; + } + break; + case ',': + { + auto it = type_dictionary.find(buffer); + if (it != type_dictionary.end()) + { + column_types.emplace_back(it->second,depth); + buffer.clear(); + } + else + { + JSONCONS_ASSERT(false); + } + ++p; + state = column_state::sequence; + } + break; + case ']': + { + JSONCONS_ASSERT(depth > 0); + auto it = type_dictionary.find(buffer); + if (it != type_dictionary.end()) + { + column_types.emplace_back(it->second,depth); + buffer.clear(); + } + else + { + JSONCONS_ASSERT(false); + } + --depth; + ++p; + state = column_state::sequence; + } + break; + default: + { + buffer.push_back(*p); + ++p; + } + break; + } + break; + } + } + } + if (state == column_state::label) + { + auto it = type_dictionary.find(buffer); + if (it != type_dictionary.end()) + { + column_types.emplace_back(it->second,depth); + buffer.clear(); + } + else + { + JSONCONS_ASSERT(false); + } + } + return column_types; + } + +}; + +typedef basic_csv_parameters<char> csv_parameters; +typedef basic_csv_parameters<wchar_t> wcsv_parameters; + + +}} +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons_ext/csv/csv_parser.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/csv/csv_parser.hpp new file mode 100644 index 00000000..c870c28b --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/csv/csv_parser.hpp @@ -0,0 +1,1260 @@ +// Copyright 2015 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CSV_CSV_PARSER_HPP +#define JSONCONS_CSV_CSV_PARSER_HPP + +#include <memory> +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <stdexcept> +#include <system_error> +#include <cctype> +#include <jsoncons/json_exception.hpp> +#include <jsoncons/json_input_handler.hpp> +#include <jsoncons/parse_error_handler.hpp> +#include <jsoncons/json_reader.hpp> +#include <jsoncons/json_filter.hpp> +#include <jsoncons/json.hpp> +#include <jsoncons/detail/number_parsers.hpp> +#include <jsoncons_ext/csv/csv_error_category.hpp> +#include <jsoncons_ext/csv/csv_parameters.hpp> + +namespace jsoncons { namespace csv { + +enum class csv_mode_type +{ + initial, + header, + data +}; + +enum class csv_state_type +{ + start, + comment, + expect_value, + between_fields, + quoted_string, + unquoted_string, + escaped_value, + minus, + zero, + integer, + fraction, + exp1, + exp2, + exp3, + done +}; + +template<class CharT,class Allocator=std::allocator<CharT>> +class basic_csv_parser : private parsing_context +{ + typedef basic_string_view_ext<CharT> string_view_type; + typedef CharT char_type; + typedef Allocator allocator_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<CharT> char_allocator_type; + typedef std::basic_string<CharT,std::char_traits<CharT>,char_allocator_type> string_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<string_type> string_allocator_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<csv_mode_type> csv_mode_allocator_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<csv_type_info> csv_type_info_allocator_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<std::vector<string_type,string_allocator_type>> string_vector_allocator_type; + typedef basic_json<CharT,preserve_order_policy,Allocator> json_type; + + static const int default_depth = 3; + + default_parse_error_handler default_err_handler_; + csv_state_type state_; + int top_; + std::vector<csv_mode_type,csv_mode_allocator_type> stack_; + basic_json_input_handler<CharT>& handler_; + parse_error_handler& err_handler_; + size_t index_; + unsigned long column_; + unsigned long line_; + CharT curr_char_; + CharT prev_char_; + string_type value_buffer_; + int depth_; + basic_csv_parameters<CharT,Allocator> parameters_; + std::vector<string_type,string_allocator_type> column_names_; + std::vector<std::vector<string_type,string_allocator_type>,string_vector_allocator_type> column_values_; + std::vector<csv_type_info,csv_type_info_allocator_type> column_types_; + std::vector<string_type,string_allocator_type> column_defaults_; + size_t column_index_; + basic_json_fragment_filter<CharT> filter_; + size_t level_; + size_t offset_; + jsoncons::detail::string_to_double to_double_; + std::vector<json_decoder<json_type>> decoders_; + +public: + basic_csv_parser(basic_json_input_handler<CharT>& handler) + : top_(-1), + stack_(default_depth), + handler_(handler), + err_handler_(default_err_handler_), + index_(0), + filter_(handler), + level_(0), + offset_(0) + { + depth_ = default_depth; + state_ = csv_state_type::start; + top_ = -1; + line_ = 1; + column_ = 0; + column_index_ = 0; + } + + basic_csv_parser(basic_json_input_handler<CharT>& handler, + basic_csv_parameters<CharT,Allocator> params) + : top_(-1), + stack_(default_depth), + handler_(handler), + err_handler_(default_err_handler_), + index_(0), + parameters_(params), + filter_(handler), + level_(0), + offset_(0) + { + depth_ = default_depth; + state_ = csv_state_type::start; + top_ = -1; + line_ = 1; + column_ = 0; + column_index_ = 0; + } + + basic_csv_parser(basic_json_input_handler<CharT>& handler, + parse_error_handler& err_handler) + : top_(-1), + stack_(default_depth), + handler_(handler), + err_handler_(err_handler), + index_(0), + filter_(handler), + level_(0), + offset_(0) + { + depth_ = default_depth; + state_ = csv_state_type::start; + top_ = -1; + line_ = 1; + column_ = 0; + column_index_ = 0; + } + + basic_csv_parser(basic_json_input_handler<CharT>& handler, + parse_error_handler& err_handler, + basic_csv_parameters<CharT,Allocator> params) + : top_(-1), + stack_(default_depth), + handler_(handler), + err_handler_(err_handler), + index_(0), + parameters_(params), + filter_(handler), + level_(0), + offset_(0) + { + depth_ = default_depth; + state_ = csv_state_type::start; + top_ = -1; + line_ = 1; + column_ = 0; + column_index_ = 0; + } + + ~basic_csv_parser() + { + } + + const parsing_context& parsing_context() const + { + return *this; + } + + bool done() const + { + return state_ == csv_state_type::done; + } + + const std::vector<std::basic_string<CharT>>& column_labels() const + { + return column_names_; + } + + void after_field() + { + ++column_index_; + } + + void before_record() + { + offset_ = 0; + if (stack_[top_] == csv_mode_type::data) + { + switch (parameters_.mapping()) + { + case mapping_type::n_rows: + handler_.begin_array(*this); + break; + case mapping_type::n_objects: + handler_.begin_object(*this); + break; + case mapping_type::m_columns: + break; + default: + break; + } + } + } + + void after_record() + { + if (column_types_.size() > 0) + { + if (level_ > 0) + { + handler_.end_array(*this); + level_ = 0; + } + } + if (stack_[top_] == csv_mode_type::header) + { + if (line_ >= parameters_.header_lines()) + { + flip(csv_mode_type::header, csv_mode_type::data); + } + column_values_.resize(column_names_.size()); + switch (parameters_.mapping()) + { + case mapping_type::n_rows: + if (column_names_.size() > 0) + { + handler_.begin_array(*this); + for (const auto& name : column_names_) + { + handler_.string_value(name, *this); + } + handler_.end_array(*this); + } + break; + case mapping_type::m_columns: + for (const auto& name : column_names_) + { + decoders_.push_back(json_decoder<json_type>()); + decoders_.back().begin_json(); + decoders_.back().begin_array(*this); + } + break; + default: + break; + } + } + else if (stack_[top_] == csv_mode_type::data) + { + switch (parameters_.mapping()) + { + case mapping_type::n_rows: + handler_.end_array(*this); + break; + case mapping_type::n_objects: + handler_.end_object(*this); + break; + default: + break; + } + } + column_index_ = 0; + } + + void reset() + { + push_mode(csv_mode_type::initial); + handler_.begin_json(); + + for (auto name : parameters_.column_names()) + { + column_names_.emplace_back(name.data(),name.size()); + } + for (auto name : parameters_.column_types()) + { + column_types_.push_back(name); + } + for (auto name : parameters_.column_defaults()) + { + column_defaults_.emplace_back(name.data(), name.size()); + } + if (parameters_.header_lines() > 0) + { + push_mode(csv_mode_type::header); + } + else + { + push_mode(csv_mode_type::data); + } + if (parameters_.mapping() != mapping_type::m_columns) + { + handler_.begin_array(*this); + } + state_ = csv_state_type::expect_value; + column_index_ = 0; + prev_char_ = 0; + curr_char_ = 0; + column_ = 1; + level_ = 0; + } + + void parse(const CharT* p, size_t start, size_t length) + { + std::error_code ec; + parse(p, start, length, ec); + if (ec) + { + throw parse_error(ec,line_,column_); + } + } + + void parse(const CharT* p, size_t start, size_t length, std::error_code& ec) + { + index_ = start; + for (; index_ < length && state_ != csv_state_type::done; ++index_) + { + curr_char_ = p[index_]; +all_csv_states: + switch (state_) + { + case csv_state_type::comment: + if (curr_char_ == '\n') + { + state_ = csv_state_type::expect_value; + } + else if (prev_char_ == '\r') + { + state_ = csv_state_type::expect_value; + goto all_csv_states; + } + break; + case csv_state_type::expect_value: + if (column_ == 1 && curr_char_ == parameters_.comment_starter()) + { + state_ = csv_state_type::comment; + } + else + { + state_ = csv_state_type::unquoted_string; + goto all_csv_states; + } + break; + case csv_state_type::between_fields: + if (curr_char_ == '\r' || (prev_char_ != '\r' && curr_char_ == '\n')) + { + after_record(); + state_ = csv_state_type::expect_value; + } + else if (curr_char_ == parameters_.field_delimiter()) + { + state_ = csv_state_type::expect_value; + } + break; + case csv_state_type::escaped_value: + { + if (curr_char_ == parameters_.quote_char()) + { + value_buffer_.push_back(static_cast<CharT>(curr_char_)); + state_ = csv_state_type::quoted_string; + } + else if (parameters_.quote_escape_char() == parameters_.quote_char()) + { + if (column_index_ == 0) + { + before_record(); + } + end_quoted_string_value(ec); + if (ec) return; + after_field(); + state_ = csv_state_type::between_fields; + goto all_csv_states; + } + } + break; + case csv_state_type::quoted_string: + { + if (curr_char_ == parameters_.quote_escape_char()) + { + state_ = csv_state_type::escaped_value; + } + else if (curr_char_ == parameters_.quote_char()) + { + if (column_index_ == 0) + { + before_record(); + } + end_quoted_string_value(ec); + if (ec) return; + after_field(); + state_ = csv_state_type::between_fields; + } + else + { + value_buffer_.push_back(static_cast<CharT>(curr_char_)); + } + } + break; + case csv_state_type::unquoted_string: + { + if (curr_char_ == '\r' || (prev_char_ != '\r' && curr_char_ == '\n')) + { + if (parameters_.trim_leading() || parameters_.trim_trailing()) + { + trim_string_buffer(parameters_.trim_leading(),parameters_.trim_trailing()); + } + if (!parameters_.ignore_empty_lines() || (column_index_ > 0 || value_buffer_.length() > 0)) + { + if (column_index_ == 0) + { + before_record(); + } + end_unquoted_string_value(); + after_field(); + after_record(); + } + state_ = csv_state_type::expect_value; + } + else if (curr_char_ == '\n') + { + if (prev_char_ != '\r') + { + if (parameters_.trim_leading() || parameters_.trim_trailing()) + { + trim_string_buffer(parameters_.trim_leading(),parameters_.trim_trailing()); + } + if (!parameters_.ignore_empty_lines() || (column_index_ > 0 || value_buffer_.length() > 0)) + { + if (column_index_ == 0) + { + before_record(); + } + end_unquoted_string_value(); + after_field(); + after_record(); + } + state_ = csv_state_type::expect_value; + } + } + else if (curr_char_ == parameters_.field_delimiter()) + { + if (parameters_.trim_leading() || parameters_.trim_trailing()) + { + trim_string_buffer(parameters_.trim_leading(),parameters_.trim_trailing()); + } + if (column_index_ == 0) + { + before_record(); + } + end_unquoted_string_value(); + after_field(); + state_ = csv_state_type::expect_value; + } + else if (curr_char_ == parameters_.quote_char()) + { + value_buffer_.clear(); + state_ = csv_state_type::quoted_string; + } + else + { + value_buffer_.push_back(static_cast<CharT>(curr_char_)); + } + } + break; + default: + err_handler_.fatal_error(csv_parser_errc::invalid_state, *this); + ec = csv_parser_errc::invalid_state; + return; + } + if (line_ > parameters_.max_lines()) + { + state_ = csv_state_type::done; + } + switch (curr_char_) + { + case '\r': + ++line_; + column_ = 1; + break; + case '\n': + if (prev_char_ != '\r') + { + ++line_; + } + column_ = 1; + break; + default: + ++column_; + break; + } + prev_char_ = curr_char_; + } + } + + void end_parse() + { + std::error_code ec; + end_parse(ec); + if (ec) + { + throw parse_error(ec,line_,column_); + } + } + + void end_parse(std::error_code& ec) + { + switch (state_) + { + case csv_state_type::unquoted_string: + if (parameters_.trim_leading() || parameters_.trim_trailing()) + { + trim_string_buffer(parameters_.trim_leading(),parameters_.trim_trailing()); + } + if (!parameters_.ignore_empty_lines() || (column_index_ > 0 || value_buffer_.length() > 0)) + { + if (column_index_ == 0) + { + before_record(); + } + end_unquoted_string_value(); + after_field(); + } + break; + case csv_state_type::escaped_value: + if (parameters_.quote_escape_char() == parameters_.quote_char()) + { + if (column_index_ == 0) + { + before_record(); + } + end_quoted_string_value(ec); + if (ec) return; + after_field(); + } + break; + default: + break; + } + if (column_index_ > 0) + { + after_record(); + } + switch (stack_[top_]) + { + case csv_mode_type::header: + pop_mode(csv_mode_type::header); + break; + case csv_mode_type::data: + pop_mode(csv_mode_type::data); + break; + default: + break; + } + if (parameters_.mapping() == mapping_type::m_columns) + { + basic_json_fragment_filter<CharT> fragment_filter(handler_); + handler_.begin_object(*this); + for (size_t i = 0; i < column_names_.size(); ++i) + { + handler_.name(column_names_[i],*this); + decoders_[i].end_array(*this); + decoders_[i].end_json(); + decoders_[i].get_result().dump_fragment(fragment_filter); + } + handler_.end_object(*this); + } + else + { + handler_.end_array(*this); + } + if (!pop_mode(csv_mode_type::initial)) + { + err_handler_.fatal_error(csv_parser_errc::unexpected_eof, *this); + ec = csv_parser_errc::unexpected_eof; + return; + } + handler_.end_json(); + } + + csv_state_type state() const + { + return state_; + } + + size_t index() const + { + return index_; + } +private: + + void trim_string_buffer(bool trim_leading, bool trim_trailing) + { + size_t start = 0; + size_t length = value_buffer_.length(); + if (trim_leading) + { + bool done = false; + while (!done && start < value_buffer_.length()) + { + if ((value_buffer_[start] < 256) && std::isspace(value_buffer_[start])) + { + ++start; + } + else + { + done = true; + } + } + } + if (trim_trailing) + { + bool done = false; + while (!done && length > 0) + { + if ((value_buffer_[length-1] < 256) && std::isspace(value_buffer_[length-1])) + { + --length; + } + else + { + done = true; + } + } + } + if (start != 0 || length != value_buffer_.size()) + { + value_buffer_ = value_buffer_.substr(start,length-start); + } + } + + void end_unquoted_string_value() + { + switch (stack_[top_]) + { + case csv_mode_type::header: + if (parameters_.assume_header() && line_ == 1) + { + column_names_.push_back(value_buffer_); + } + break; + case csv_mode_type::data: + switch (parameters_.mapping()) + { + case mapping_type::n_rows: + if (parameters_.unquoted_empty_value_is_null() && value_buffer_.length() == 0) + { + handler_.null_value(*this); + } + else + { + end_value(value_buffer_,column_index_,parameters_.infer_types(),handler_); + } + break; + case mapping_type::n_objects: + if (!(parameters_.ignore_empty_values() && value_buffer_.size() == 0)) + { + if (column_index_ < column_names_.size() + offset_) + { + handler_.name(column_names_[column_index_ - offset_], *this); + if (parameters_.unquoted_empty_value_is_null() && value_buffer_.length() == 0) + { + handler_.null_value(*this); + } + else + { + end_value(value_buffer_,column_index_,parameters_.infer_types(),handler_); + } + } + else if (level_ > 0) + { + if (parameters_.unquoted_empty_value_is_null() && value_buffer_.length() == 0) + { + handler_.null_value(*this); + } + else + { + end_value(value_buffer_,column_index_,parameters_.infer_types(),handler_); + } + } + } + break; + case mapping_type::m_columns: + if (column_index_ < decoders_.size()) + { + end_value(value_buffer_,column_index_,parameters_.infer_types(),decoders_[column_index_]); + } + break; + } + break; + default: + break; + } + state_ = csv_state_type::expect_value; + value_buffer_.clear(); + } + + void end_quoted_string_value(std::error_code& ec) + { + if (parameters_.trim_leading_inside_quotes() | parameters_.trim_trailing_inside_quotes()) + { + trim_string_buffer(parameters_.trim_leading_inside_quotes(),parameters_.trim_trailing_inside_quotes()); + } + switch (stack_[top_]) + { + case csv_mode_type::header: + if (parameters_.assume_header() && line_ == 1) + { + column_names_.push_back(value_buffer_); + } + break; + case csv_mode_type::data: + switch (parameters_.mapping()) + { + case mapping_type::n_rows: + end_value(value_buffer_,column_index_,false,handler_); + break; + case mapping_type::n_objects: + if (!(parameters_.ignore_empty_values() && value_buffer_.size() == 0)) + { + if (column_index_ < column_names_.size() + offset_) + { + handler_.name(column_names_[column_index_ - offset_], *this); + if (parameters_.unquoted_empty_value_is_null() && value_buffer_.length() == 0) + { + handler_.null_value(*this); + } + else + { + end_value(value_buffer_,column_index_,false,handler_); + } + } + else if (level_ > 0) + { + if (parameters_.unquoted_empty_value_is_null() && value_buffer_.length() == 0) + { + handler_.null_value(*this); + } + else + { + end_value(value_buffer_,column_index_,false,handler_); + } + } + } + break; + case mapping_type::m_columns: + if (column_index_ < decoders_.size()) + { + end_value(value_buffer_,column_index_,parameters_.infer_types(),decoders_[column_index_]); + } + break; + } + break; + default: + err_handler_.fatal_error(csv_parser_errc::invalid_csv_text, *this); + ec = csv_parser_errc::invalid_csv_text; + return; + } + state_ = csv_state_type::expect_value; + value_buffer_.clear(); + } + + void end_value(const string_view_type& value, size_t column_index, bool infer_types, basic_json_input_handler<CharT>& handler) + { + if (column_index < column_types_.size() + offset_) + { + if (column_types_[column_index - offset_].col_type == csv_column_type::repeat_t) + { + offset_ = offset_ + column_types_[column_index - offset_].rep_count; + if (column_index - offset_ + 1 < column_types_.size()) + { + if (column_index == offset_ || level_ > column_types_[column_index-offset_].level) + { + handler.end_array(*this); + } + level_ = column_index == offset_ ? 0 : column_types_[column_index - offset_].level; + } + } + if (level_ < column_types_[column_index - offset_].level) + { + handler.begin_array(*this); + level_ = column_types_[column_index - offset_].level; + } + else if (level_ > column_types_[column_index - offset_].level) + { + handler.end_array(*this); + level_ = column_types_[column_index - offset_].level; + } + switch (column_types_[column_index - offset_].col_type) + { + case csv_column_type::integer_t: + { + std::istringstream iss{ std::string(value) }; + int64_t val; + iss >> val; + if (!iss.fail()) + { + handler.integer_value(val, *this); + } + else + { + if (column_index - offset_ < column_defaults_.size() && column_defaults_[column_index - offset_].length() > 0) + { + basic_json_parser<CharT> parser(filter_,err_handler_); + parser.set_source(column_defaults_[column_index - offset_].data(),column_defaults_[column_index - offset_].length()); + parser.parse_some(); + parser.end_parse(); + } + else + { + handler.null_value(*this); + } + } + } + break; + case csv_column_type::float_t: + { + std::istringstream iss{ std::string(value) }; + double val; + iss >> val; + if (!iss.fail()) + { + handler.double_value(val, *this); + } + else + { + if (column_index - offset_ < column_defaults_.size() && column_defaults_[column_index - offset_].length() > 0) + { + basic_json_parser<CharT> parser(filter_,err_handler_); + parser.set_source(column_defaults_[column_index - offset_].data(),column_defaults_[column_index - offset_].length()); + parser.parse_some(); + parser.end_parse(); + } + else + { + handler.null_value(*this); + } + } + } + break; + case csv_column_type::boolean_t: + { + if (value.length() == 1 && value[0] == '0') + { + handler.bool_value(false, *this); + } + else if (value.length() == 1 && value[0] == '1') + { + handler.bool_value(true, *this); + } + else if (value.length() == 5 && ((value[0] == 'f' || value[0] == 'F') && (value[1] == 'a' || value[1] == 'A') && (value[2] == 'l' || value[2] == 'L') && (value[3] == 's' || value[3] == 'S') && (value[4] == 'e' || value[4] == 'E'))) + { + handler.bool_value(false, *this); + } + else if (value.length() == 4 && ((value[0] == 't' || value[0] == 'T') && (value[1] == 'r' || value[1] == 'R') && (value[2] == 'u' || value[2] == 'U') && (value[3] == 'e' || value[3] == 'E'))) + { + handler.bool_value(true, *this); + } + else + { + if (column_index - offset_ < column_defaults_.size() && column_defaults_[column_index - offset_].length() > 0) + { + basic_json_parser<CharT> parser(filter_,err_handler_); + parser.set_source(column_defaults_[column_index - offset_].data(),column_defaults_[column_index - offset_].length()); + parser.parse_some(); + parser.end_parse(); + } + else + { + handler.null_value(*this); + } + } + } + break; + default: + if (value.length() > 0) + { + handler.string_value(value, *this); + } + else + { + if (column_index < column_defaults_.size() + offset_ && column_defaults_[column_index - offset_].length() > 0) + { + basic_json_parser<CharT> parser(filter_,err_handler_); + parser.set_source(column_defaults_[column_index - offset_].data(),column_defaults_[column_index - offset_].length()); + parser.parse_some(); + parser.end_parse(); + } + else + { + handler.string_value(string_view_type(), *this); + } + } + break; + } + } + else + { + if (infer_types) + { + end_value_with_numeric_check(value, handler); + } + else + { + handler.string_value(value, *this); + } + } + } + + enum class numeric_check_state + { + initial, + null, + boolean_true, + boolean_false, + minus, + zero, + integer, + fraction1, + fraction, + exp1, + exp, + done + }; + + void end_value_with_numeric_check(const string_view_type& value, basic_json_input_handler<CharT>& handler) + { + numeric_check_state state = numeric_check_state::initial; + bool is_negative = false; + uint8_t precision = 0; + uint8_t decimal_places = 0; + chars_format format = chars_format::general; + + auto last = value.end(); + + std::string buffer; + for (auto p = value.begin(); state != numeric_check_state::done && p != last; ++p) + { + switch (state) + { + case numeric_check_state::initial: + { + switch (*p) + { + case 'n':case 'N': + if ((last-p) == 4 && (p[1] == 'u' || p[1] == 'U') && (p[2] == 'l' || p[2] == 'L') && (p[3] == 'l' || p[3] == 'L')) + { + state = numeric_check_state::null; + } + else + { + state = numeric_check_state::done; + } + break; + case 't':case 'T': + if ((last-p) == 4 && (p[1] == 'r' || p[1] == 'R') && (p[2] == 'u' || p[2] == 'U') && (p[3] == 'e' || p[3] == 'U')) + { + state = numeric_check_state::boolean_true; + } + else + { + state = numeric_check_state::done; + } + break; + case 'f':case 'F': + if ((last-p) == 5 && (p[1] == 'a' || p[1] == 'A') && (p[2] == 'l' || p[2] == 'L') && (p[3] == 's' || p[3] == 'S') && (p[4] == 'e' || p[4] == 'E')) + { + state = numeric_check_state::boolean_false; + } + else + { + state = numeric_check_state::done; + } + break; + case '-': + is_negative = true; + buffer.push_back(*p); + state = numeric_check_state::minus; + break; + case '0': + ++precision; + buffer.push_back(*p); + state = numeric_check_state::zero; + break; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + ++precision; + buffer.push_back(*p); + state = numeric_check_state::integer; + break; + default: + state = numeric_check_state::done; + break; + } + break; + } + case numeric_check_state::zero: + { + switch (*p) + { + case '.': + buffer.push_back(to_double_.get_decimal_point()); + state = numeric_check_state::fraction1; + break; + case 'e':case 'E': + buffer.push_back(*p); + state = numeric_check_state::exp1; + break; + default: + state = numeric_check_state::done; + break; + } + break; + } + case numeric_check_state::integer: + { + switch (*p) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + ++precision; + buffer.push_back(*p); + break; + case '.': + buffer.push_back(to_double_.get_decimal_point()); + state = numeric_check_state::fraction1; + break; + case 'e':case 'E': + buffer.push_back(*p); + state = numeric_check_state::exp1; + break; + default: + state = numeric_check_state::done; + break; + } + break; + } + case numeric_check_state::minus: + { + switch (*p) + { + case '0': + ++precision; + buffer.push_back(*p); + state = numeric_check_state::zero; + break; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + ++precision; + buffer.push_back(*p); + state = numeric_check_state::integer; + break; + case 'e':case 'E': + buffer.push_back(*p); + state = numeric_check_state::exp1; + break; + default: + state = numeric_check_state::done; + break; + } + break; + } + case numeric_check_state::fraction1: + { + format = chars_format::fixed; + switch (*p) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + ++precision; + ++decimal_places; + buffer.push_back(*p); + state = numeric_check_state::fraction; + break; + default: + state = numeric_check_state::done; + break; + } + break; + } + case numeric_check_state::fraction: + { + switch (*p) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + ++precision; + ++decimal_places; + buffer.push_back(*p); + break; + case 'e':case 'E': + buffer.push_back(*p); + state = numeric_check_state::exp1; + break; + default: + state = numeric_check_state::done; + break; + } + break; + } + case numeric_check_state::exp1: + { + format = chars_format::scientific; + switch (*p) + { + case '-': + buffer.push_back(*p); + state = numeric_check_state::exp; + break; + case '+': + state = numeric_check_state::exp; + break; + case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + buffer.push_back(*p); + state = numeric_check_state::integer; + break; + default: + state = numeric_check_state::done; + break; + } + break; + } + case numeric_check_state::exp: + { + switch (*p) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + buffer.push_back(*p); + break; + default: + state = numeric_check_state::done; + break; + } + break; + } + } + } + + switch (state) + { + case numeric_check_state::null: + handler.null_value(*this); + break; + case numeric_check_state::boolean_true: + handler.bool_value(true,*this); + break; + case numeric_check_state::boolean_false: + handler.bool_value(false,*this); + break; + case numeric_check_state::zero: + case numeric_check_state::integer: + { + if (is_negative) + { + jsoncons::detail::to_integer_result result = jsoncons::detail::to_integer(value.data(), value.length()); + if (!result.overflow) + { + handler.integer_value(result.value,*this); + } + else + { + double d = to_double_(buffer.data(), buffer.length()); + handler.double_value(d, number_format(format), *this); + } + } + else + { + jsoncons::detail::to_uinteger_result result = jsoncons::detail::to_uinteger(value.data(), value.length()); + if (!result.overflow) + { + handler.uinteger_value(result.value,*this); + } + else + { + double d = to_double_(buffer.data(), buffer.length()); + handler.double_value(d, number_format(format), *this); + } + } + break; + } + case numeric_check_state::fraction: + case numeric_check_state::exp: + { + double d = to_double_(buffer.data(), buffer.length()); + handler.double_value(d, number_format(format, precision, decimal_places), *this); + break; + } + default: + handler.string_value(value, *this); + } + } + + size_t do_line_number() const override + { + return line_; + } + + size_t do_column_number() const override + { + return column_; + } + + void push_mode(csv_mode_type mode) + { + ++top_; + if (top_ >= depth_) + { + depth_ *= 2; + stack_.resize(depth_); + } + stack_[top_] = mode; + } + + int peek() + { + return stack_[top_]; + } + + bool peek(csv_mode_type mode) + { + return stack_[top_] == mode; + } + + bool flip(csv_mode_type mode1, csv_mode_type mode2) + { + if (top_ < 0 || stack_[top_] != mode1) + { + return false; + } + stack_[top_] = mode2; + return true; + } + + bool pop_mode(csv_mode_type mode) + { + if (top_ < 0 || stack_[top_] != mode) + { + return false; + } + --top_; + return true; + } +}; + +typedef basic_csv_parser<char> csv_parser; +typedef basic_csv_parser<wchar_t> wcsv_parser; + +}} + +#endif + diff --git a/vendor/jsoncons-0.104.0/jsoncons_ext/csv/csv_reader.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/csv/csv_reader.hpp new file mode 100644 index 00000000..5834b1a0 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/csv/csv_reader.hpp @@ -0,0 +1,235 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CSV_CSV_READER_HPP +#define JSONCONS_CSV_CSV_READER_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <stdexcept> +#include <jsoncons/json_exception.hpp> +#include <jsoncons/json_input_handler.hpp> +#include <jsoncons/parse_error_handler.hpp> +#include <jsoncons_ext/csv/csv_error_category.hpp> +#include <jsoncons_ext/csv/csv_parser.hpp> +#include <jsoncons/json.hpp> +#include <jsoncons/json_reader.hpp> +#include <jsoncons/json_decoder.hpp> +#include <jsoncons_ext/csv/csv_parameters.hpp> + +namespace jsoncons { namespace csv { + +template<class CharT,class Allocator=std::allocator<char>> +class basic_csv_reader +{ + struct stack_item + { + stack_item() + : array_begun_(false) + { + } + + bool array_begun_; + }; + typedef CharT char_type; + typedef Allocator allocator_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<CharT> char_allocator_type; + + basic_csv_reader(const basic_csv_reader&) = delete; + basic_csv_reader& operator = (const basic_csv_reader&) = delete; + + basic_csv_parser<CharT,Allocator> parser_; + std::basic_istream<CharT>& is_; + std::vector<CharT,char_allocator_type> buffer_; + size_t buffer_length_; + size_t buffer_position_; + bool eof_; + size_t index_; +public: + // Structural characters + static const size_t default_max_buffer_length = 16384; + //! Parse an input stream of CSV text into a json object + /*! + \param is The input stream to read from + */ + + basic_csv_reader(std::basic_istream<CharT>& is, + basic_json_input_handler<CharT>& handler) + + : parser_(handler), + is_(is), + buffer_length_(default_max_buffer_length), + buffer_position_(0), + eof_(false), + index_(0) + { + buffer_.reserve(buffer_length_); + } + + basic_csv_reader(std::basic_istream<CharT>& is, + basic_json_input_handler<CharT>& handler, + basic_csv_parameters<CharT,Allocator> params) + + : parser_(handler,params), + is_(is), + buffer_length_(default_max_buffer_length), + buffer_position_(0), + eof_(false), + index_(0) + { + buffer_.reserve(buffer_length_); + } + + basic_csv_reader(std::basic_istream<CharT>& is, + basic_json_input_handler<CharT>& handler, + parse_error_handler& err_handler) + : + parser_(handler,err_handler), + is_(is), + buffer_length_(default_max_buffer_length), + buffer_position_(0), + eof_(false), + index_(0) + { + buffer_.reserve(buffer_length_); + } + + basic_csv_reader(std::basic_istream<CharT>& is, + basic_json_input_handler<CharT>& handler, + parse_error_handler& err_handler, + basic_csv_parameters<CharT,Allocator> params) + : + parser_(handler,err_handler,params), + is_(is), + buffer_length_(default_max_buffer_length), + buffer_position_(0), + eof_(false), + index_(0) + { + buffer_.reserve(buffer_length_); + } + + ~basic_csv_reader() + { + } + + void read() + { + parser_.reset(); + while (!eof_ && !parser_.done()) + { + if (!(index_ < buffer_.size())) + { + if (!is_.eof()) + { + buffer_.clear(); + buffer_.resize(buffer_length_); + is_.read(buffer_.data(), buffer_length_); + buffer_.resize(static_cast<size_t>(is_.gcount())); + if (buffer_.size() == 0) + { + eof_ = true; + } + index_ = 0; + } + else + { + eof_ = true; + } + } + if (!eof_) + { + parser_.parse(buffer_.data(),index_,buffer_.size()); + index_ = parser_.index(); + } + } + parser_.end_parse(); + } + + bool eof() const + { + return eof_; + } + + size_t buffer_length() const + { + return buffer_length_; + } + + void buffer_length(size_t length) + { + buffer_length_ = length; + buffer_.reserve(buffer_length_); + } + +#if !defined(JSONCONS_NO_DEPRECATED) + + size_t buffer_capacity() const + { + return buffer_length_; + } + + void buffer_capacity(size_t length) + { + buffer_length_ = length; + buffer_.reserve(buffer_length_); + } +#endif +}; + +template <class Json> +Json decode_csv(typename Json::string_view_type s) +{ + json_decoder<Json> decoder; + + basic_csv_parser<typename Json::char_type> parser(decoder); + parser.reset(); + parser.parse(s.data(), 0, s.size()); + parser.end_parse(); + return decoder.get_result(); +} + +template <class Json,class Allocator> +Json decode_csv(typename Json::string_view_type s, const basic_csv_parameters<typename Json::char_type,Allocator>& params) +{ + json_decoder<Json,Allocator> decoder; + + basic_csv_parser<typename Json::char_type,Allocator> parser(decoder, params); + parser.reset(); + parser.parse(s.data(), 0, s.size()); + parser.end_parse(); + return decoder.get_result(); +} + +template <class Json> +Json decode_csv(std::basic_istream<typename Json::char_type>& is) +{ + json_decoder<Json> decoder; + + basic_csv_reader<typename Json::char_type> reader(is,decoder); + reader.read(); + return decoder.get_result(); +} + +template <class Json,class Allocator> +Json decode_csv(std::basic_istream<typename Json::char_type>& is, const basic_csv_parameters<typename Json::char_type,Allocator>& params) +{ + json_decoder<Json,Allocator> decoder; + + basic_csv_reader<typename Json::char_type,Allocator> reader(is,decoder,params); + reader.read(); + return decoder.get_result(); +} + +typedef basic_csv_reader<char> csv_reader; +typedef basic_csv_reader<wchar_t> wcsv_reader; + +}} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons_ext/csv/csv_serializer.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/csv/csv_serializer.hpp new file mode 100644 index 00000000..54c8035d --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/csv/csv_serializer.hpp @@ -0,0 +1,504 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_CSV_CSV_SERIALIZER_HPP +#define JSONCONS_CSV_CSV_SERIALIZER_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <ostream> +#include <cstdlib> +#include <unordered_map> +#include <memory> +#include <limits> // std::numeric_limits +#include <jsoncons/json_exception.hpp> +#include <jsoncons/serialization_options.hpp> +#include <jsoncons/json_output_handler.hpp> +#include <jsoncons/detail/number_printers.hpp> +#include <jsoncons/detail/obufferedstream.hpp> +#include <jsoncons_ext/csv/csv_parameters.hpp> +#include <jsoncons/detail/writer.hpp> + +namespace jsoncons { namespace csv { + +template<class CharT,class Writer=jsoncons::detail::ostream_buffered_writer<CharT>,class Allocator=std::allocator<CharT>> +class basic_csv_serializer final : public basic_json_output_handler<CharT> +{ +public: + typedef typename Writer::output_type output_type; + + typedef Allocator allocator_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<CharT> char_allocator_type; + typedef std::basic_string<CharT, std::char_traits<CharT>, char_allocator_type> string_type; + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<string_type> string_allocator_type; + + using typename basic_json_output_handler<CharT>::string_view_type ; +private: + struct stack_item + { + stack_item(bool is_object) + : is_object_(is_object), count_(0) + { + } + bool is_object() const + { + return is_object_; + } + + bool is_object_; + size_t count_; + string_type name_; + }; + Writer writer_; + basic_csv_parameters<CharT,Allocator> parameters_; + basic_serialization_options<CharT> options_; + std::vector<stack_item> stack_; + jsoncons::detail::print_double fp_; + std::vector<string_type,string_allocator_type> column_names_; + + typedef typename std::allocator_traits<allocator_type>:: template rebind_alloc<std::pair<const string_type,string_type>> string_string_allocator_type; + std::unordered_map<string_type,string_type, std::hash<string_type>,std::equal_to<string_type>,string_string_allocator_type> buffered_line_; + + // Noncopyable and nonmoveable + basic_csv_serializer(const basic_csv_serializer&) = delete; + basic_csv_serializer& operator=(const basic_csv_serializer&) = delete; +public: + basic_csv_serializer(output_type& os) + : + writer_(os), + options_(), + stack_(), + fp_(options_.precision()), + column_names_(parameters_.column_names()) + { + } + + basic_csv_serializer(output_type& os, + const basic_csv_parameters<CharT,Allocator>& params) + : + writer_(os), + parameters_(params), + options_(), + stack_(), + fp_(options_.precision()), + column_names_(parameters_.column_names()) + { + } + +private: + + template<class AnyWriter> + void escape_string(const CharT* s, + size_t length, + CharT quote_char, CharT quote_escape_char, + AnyWriter& writer) + { + const CharT* begin = s; + const CharT* end = s + length; + for (const CharT* it = begin; it != end; ++it) + { + CharT c = *it; + if (c == quote_char) + { + writer.put(quote_escape_char); + writer.put(quote_char); + } + else + { + writer.put(c); + } + } + } + + void do_begin_json() override + { + } + + void do_end_json() override + { + writer_.flush(); + } + + void do_begin_object() override + { + stack_.push_back(stack_item(true)); + } + + void do_end_object() override + { + if (stack_.size() == 2) + { + if (stack_[0].count_ == 0) + { + for (size_t i = 0; i < column_names_.size(); ++i) + { + if (i > 0) + { + writer_.put(parameters_.field_delimiter()); + } + writer_.write(column_names_[i]); + } + writer_.write(parameters_.line_delimiter()); + } + for (size_t i = 0; i < column_names_.size(); ++i) + { + if (i > 0) + { + writer_.put(parameters_.field_delimiter()); + } + auto it = buffered_line_.find(column_names_[i]); + if (it != buffered_line_.end()) + { + writer_.write(it->second); + it->second.clear(); + } + } + writer_.write(parameters_.line_delimiter()); + } + stack_.pop_back(); + + end_value(); + } + + void do_begin_array() override + { + stack_.push_back(stack_item(false)); + if (stack_.size() == 2) + { + if (stack_[0].count_ == 0) + { + for (size_t i = 0; i < column_names_.size(); ++i) + { + if (i > 0) + { + writer_.put(parameters_.field_delimiter()); + } + writer_.write(column_names_[i]); + } + if (column_names_.size() > 0) + { + writer_.write(parameters_.line_delimiter()); + } + } + } + } + + void do_end_array() override + { + if (stack_.size() == 2) + { + writer_.write(parameters_.line_delimiter()); + } + stack_.pop_back(); + + end_value(); + } + + void do_name(const string_view_type& name) override + { + if (stack_.size() == 2) + { + stack_.back().name_ = string_type(name); + buffered_line_[string_type(name)] = std::basic_string<CharT>(); + if (stack_[0].count_ == 0 && parameters_.column_names().size() == 0) + { + column_names_.push_back(string_type(name)); + } + } + } + + template <class AnyWriter> + void write_string(const CharT* s, size_t length, AnyWriter& writer) + { + bool quote = false; + if (parameters_.quote_style() == quote_style_type::all || parameters_.quote_style() == quote_style_type::nonnumeric || + (parameters_.quote_style() == quote_style_type::minimal && + (std::char_traits<CharT>::find(s, length, parameters_.field_delimiter()) != nullptr || std::char_traits<CharT>::find(s, length, parameters_.quote_char()) != nullptr))) + { + quote = true; + writer.put(parameters_.quote_char()); + } + escape_string(s, length, parameters_.quote_char(), parameters_.quote_escape_char(), writer); + if (quote) + { + writer.put(parameters_.quote_char()); + } + + } + + void do_null_value() override + { + if (stack_.size() == 2) + { + if (stack_.back().is_object()) + { + auto it = buffered_line_.find(stack_.back().name_); + if (it != buffered_line_.end()) + { + std::basic_string<CharT> s; + jsoncons::detail::string_writer<CharT> bo(s); + do_null_value(bo); + bo.flush(); + it->second = s; + } + } + else + { + do_null_value(writer_); + } + } + } + + void do_string_value(const string_view_type& val) override + { + if (stack_.size() == 2) + { + if (stack_.back().is_object()) + { + auto it = buffered_line_.find(stack_.back().name_); + if (it != buffered_line_.end()) + { + std::basic_string<CharT> s; + jsoncons::detail::string_writer<CharT> bo(s); + value(val,bo); + bo.flush(); + it->second = s; + } + } + else + { + value(val,writer_); + } + } + } + + void do_byte_string_value(const uint8_t*, size_t) override + { + + } + + void do_double_value(double val, const number_format&) override + { + if (stack_.size() == 2) + { + if (stack_.back().is_object()) + { + auto it = buffered_line_.find(stack_.back().name_); + if (it != buffered_line_.end()) + { + std::basic_string<CharT> s; + jsoncons::detail::string_writer<CharT> bo(s); + value(val,bo); + bo.flush(); + it->second = s; + } + } + else + { + value(val,writer_); + } + } + } + + void do_integer_value(int64_t val) override + { + if (stack_.size() == 2) + { + if (stack_.back().is_object()) + { + auto it = buffered_line_.find(stack_.back().name_); + if (it != buffered_line_.end()) + { + std::basic_string<CharT> s; + jsoncons::detail::string_writer<CharT> bo(s); + value(val,bo); + bo.flush(); + it->second = s; + } + } + else + { + value(val,writer_); + } + } + } + + void do_uinteger_value(uint64_t val) override + { + if (stack_.size() == 2) + { + if (stack_.back().is_object()) + { + auto it = buffered_line_.find(stack_.back().name_); + if (it != buffered_line_.end()) + { + std::basic_string<CharT> s; + jsoncons::detail::string_writer<CharT> bo(s); + value(val,bo); + bo.flush(); + it->second = s; + } + } + else + { + value(val,writer_); + } + } + } + + void do_bool_value(bool val) override + { + if (stack_.size() == 2) + { + if (stack_.back().is_object()) + { + auto it = buffered_line_.find(stack_.back().name_); + if (it != buffered_line_.end()) + { + std::basic_string<CharT> s; + jsoncons::detail::string_writer<CharT> bo(s); + value(val,bo); + bo.flush(); + it->second = s; + } + } + else + { + value(val,writer_); + } + } + } + + template <class AnyWriter> + void value(const string_view_type& value, AnyWriter& writer) + { + begin_value(writer); + write_string(value.data(),value.length(),writer); + end_value(); + } + + template <class AnyWriter> + void value(double val, AnyWriter& writer) + { + begin_value(writer); + + if ((std::isnan)(val)) + { + writer.write(options_.nan_replacement()); + } + else if (val == std::numeric_limits<double>::infinity()) + { + writer.write(options_.pos_inf_replacement()); + } + else if (!(std::isfinite)(val)) + { + writer.write(options_.neg_inf_replacement()); + } + else + { + fp_(val,options_.precision(),writer); + } + + end_value(); + + } + + template <class AnyWriter> + void value(int64_t val, AnyWriter& writer) + { + begin_value(writer); + + std::basic_ostringstream<CharT> ss; + ss << val; + writer.write(ss.str()); + + end_value(); + } + + template <class AnyWriter> + void value(uint64_t val, AnyWriter& writer) + { + begin_value(writer); + + std::basic_ostringstream<CharT> ss; + ss << val; + writer.write(ss.str()); + + end_value(); + } + + template <class AnyWriter> + void value(bool val, AnyWriter& writer) + { + begin_value(writer); + + if (val) + { + auto buf = jsoncons::detail::true_literal<CharT>(); + writer.write(buf,4); + } + else + { + auto buf = jsoncons::detail::false_literal<CharT>(); + writer.write(buf,5); + } + + end_value(); + } + + template <class AnyWriter> + void do_null_value(AnyWriter& writer) + { + begin_value(writer); + auto buf = jsoncons::detail::null_literal<CharT>(); + writer.write(buf,4); + end_value(); + + } + + template <class AnyWriter> + void begin_value(AnyWriter& writer) + { + if (!stack_.empty()) + { + if (!stack_.back().is_object_ && stack_.back().count_ > 0) + { + writer.put(parameters_.field_delimiter()); + } + } + } + + void end_value() + { + if (!stack_.empty()) + { + ++stack_.back().count_; + } + } +}; + +template <class Json> +void encode_csv(const Json& j, std::basic_ostream<typename Json::char_type>& os) +{ + typedef typename Json::char_type char_type; + basic_csv_serializer<char_type> serializer(os); + j.dump(serializer); +} + +template <class Json,class Allocator> +void encode_csv(const Json& j, std::basic_ostream<typename Json::char_type>& os, const basic_csv_parameters<typename Json::char_type,Allocator>& params) +{ + typedef typename Json::char_type char_type; + basic_csv_serializer<char_type,jsoncons::detail::ostream_buffered_writer<char_type>,Allocator> serializer(os,params); + j.dump(serializer); +} + +typedef basic_csv_serializer<char> csv_serializer; + +}} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpatch/jsonpatch.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpatch/jsonpatch.hpp new file mode 100644 index 00000000..f6997001 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpatch/jsonpatch.hpp @@ -0,0 +1,530 @@ +// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONPOINTER_JSONPATCH_HPP +#define JSONCONS_JSONPOINTER_JSONPATCH_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <memory> +#include <jsoncons/json.hpp> +#include <jsoncons_ext/jsonpointer/jsonpointer.hpp> +#include <jsoncons_ext/jsonpatch/jsonpatch_error_category.hpp> + +namespace jsoncons { namespace jsonpatch { + +class jsonpatch_error : public std::exception, public virtual json_exception +{ +public: + jsonpatch_error(const std::error_code& ec) + : error_code_(ec) + { + } + jsonpatch_error(const jsonpatch_error& other) = default; + + jsonpatch_error(jsonpatch_error&& other) = default; + + const char* what() const JSONCONS_NOEXCEPT override + { + try + { + const_cast<std::string&>(buffer_) = error_code_.message(); + return buffer_.c_str(); + } + catch (...) + { + return ""; + } + } + + const std::error_code code() const + { + return error_code_; + } + + jsonpatch_error& operator=(const jsonpatch_error& e) = default; + jsonpatch_error& operator=(jsonpatch_error&& e) = default; +private: + std::string buffer_; + std::error_code error_code_; +}; + +namespace detail { + + JSONCONS_DEFINE_LITERAL(test_literal,"test") + JSONCONS_DEFINE_LITERAL(add_literal,"add") + JSONCONS_DEFINE_LITERAL(remove_literal,"remove") + JSONCONS_DEFINE_LITERAL(replace_literal,"replace") + JSONCONS_DEFINE_LITERAL(move_literal,"move") + JSONCONS_DEFINE_LITERAL(copy_literal,"copy") + JSONCONS_DEFINE_LITERAL(op_literal,"op") + JSONCONS_DEFINE_LITERAL(path_literal,"path") + JSONCONS_DEFINE_LITERAL(from_literal,"from") + JSONCONS_DEFINE_LITERAL(value_literal,"value") + + enum class op_type {add,remove,replace}; + enum class state_type {begin,abort,commit}; + + template <class Json> + struct operation_unwinder + { + typedef typename Json::string_type string_type; + typedef typename Json::string_view_type string_view_type; + + struct entry + { + op_type op; + string_type path; + Json value; + }; + + Json& target; + state_type state; + std::vector<entry> stack; + + operation_unwinder(Json& j) + : target(j), state(state_type::begin) + { + } + + ~operation_unwinder() + { + std::error_code ec; + //std::cout << "state: " << std::boolalpha << (state == state_type::commit) << ", stack size: " << stack.size() << std::endl; + if (state != state_type::commit) + { + for (auto it = stack.rbegin(); it != stack.rend(); ++it) + { + if (it->op == op_type::add) + { + jsonpointer::insert_or_assign(target,it->path,it->value,ec); + if (ec) + { + //std::cout << "add: " << it->path << std::endl; + break; + } + } + else if (it->op == op_type::remove) + { + jsonpointer::remove(target,it->path,ec); + if (ec) + { + //std::cout << "remove: " << it->path << std::endl; + break; + } + } + else if (it->op == op_type::replace) + { + jsonpointer::replace(target,it->path,it->value,ec); + if (ec) + { + //std::cout << "replace: " << it->path << std::endl; + break; + } + } + } + } + } + }; + + template <class Json> + Json from_diff(const Json& source, const Json& target, const typename Json::string_type& path) + { + typedef typename Json::char_type char_type; + typedef typename Json::string_type string_type; + typedef typename Json::string_view_type string_view_type; + + Json result = typename Json::array(); + + if (source == target) + { + return result; + } + + if (source.is_array() && target.is_array()) + { + size_t common = (std::min)(source.size(),target.size()); + for (size_t i = 0; i < common; ++i) + { + std::basic_ostringstream<char_type> ss; + ss << path << '/' << i; + auto temp_diff = from_diff(source[i],target[i],ss.str()); + result.insert(result.array_range().end(),temp_diff.array_range().begin(),temp_diff.array_range().end()); + } + // Element in source, not in target - remove + for (size_t i = target.size(); i < source.size(); ++i) + { + std::basic_ostringstream<char_type> ss; + ss << path << '/' << i; + Json val = typename Json::object(); + val.insert_or_assign(op_literal<char_type>(), remove_literal<char_type>()); + val.insert_or_assign(path_literal<char_type>(), ss.str()); + result.push_back(std::move(val)); + } + // Element in target, not in source - add, + // Fix contributed by Alexander rog13 + for (size_t i = source.size(); i < target.size(); ++i) + { + const auto& a = target[i]; + std::basic_ostringstream<char_type> ss; + ss << path << '/' << i; + Json val = typename Json::object(); + val.insert_or_assign(op_literal<char_type>(), add_literal<char_type>()); + val.insert_or_assign(path_literal<char_type>(), ss.str()); + val.insert_or_assign(value_literal<char_type>(), a); + result.push_back(std::move(val)); + } + } + else if (source.is_object() && target.is_object()) + { + for (const auto& a : source.object_range()) + { + std::basic_ostringstream<char_type> ss; + ss << path << '/'; + jsonpointer::escape(a.key(),ss); + auto it = target.find(a.key()); + if (it != target.object_range().end()) + { + auto temp_diff = from_diff(a.value(),it->value(),ss.str()); + result.insert(result.array_range().end(),temp_diff.array_range().begin(),temp_diff.array_range().end()); + } + else + { + Json val = typename Json::object(); + val.insert_or_assign(op_literal<char_type>(), remove_literal<char_type>()); + val.insert_or_assign(path_literal<char_type>(), ss.str()); + result.push_back(std::move(val)); + } + } + for (const auto& a : target.object_range()) + { + auto it = source.find(a.key()); + if (it == source.object_range().end()) + { + std::basic_ostringstream<char_type> ss; + ss << path << '/'; + jsonpointer::escape(a.key(),ss); + Json val = typename Json::object(); + val.insert_or_assign(op_literal<char_type>(), add_literal<char_type>()); + val.insert_or_assign(path_literal<char_type>(), ss.str()); + val.insert_or_assign(value_literal<char_type>(), a.value()); + result.push_back(std::move(val)); + } + } + } + else + { + Json val = typename Json::object(); + val.insert_or_assign(op_literal<char_type>(), replace_literal<char_type>()); + val.insert_or_assign(path_literal<char_type>(), path); + val.insert_or_assign(value_literal<char_type>(), target); + result.push_back(std::move(val)); + } + + return result; + } +} + +template <class Json> +void apply_patch(Json& target, const Json& patch, std::error_code& patch_ec) +{ + typedef typename Json::char_type char_type; + typedef typename Json::string_type string_type; + typedef typename Json::string_view_type string_view_type; + + detail::operation_unwinder<Json> unwinder(target); + + // Validate + + string_type bad_path; + for (const auto& operation : patch.array_range()) + { + unwinder.state = detail::state_type::begin; + + if (operation.count(detail::op_literal<char_type>()) != 1 || operation.count(detail::path_literal<char_type>()) != 1) + { + patch_ec = jsonpatch_errc::invalid_patch; + unwinder.state = detail::state_type::abort; + } + else + { + const string_view_type op = operation.at(detail::op_literal<char_type>()).as_string_view(); + const string_view_type path = operation.at(detail::path_literal<char_type>()).as_string_view(); + + if (op == detail::test_literal<char_type>()) + { + std::error_code ec; + Json val = jsonpointer::get(target,path,ec); + if (ec) + { + patch_ec = jsonpatch_errc::test_failed; + unwinder.state = detail::state_type::abort; + } + else if (operation.count(detail::value_literal<char_type>()) != 1) + { + patch_ec = jsonpatch_errc::invalid_patch; + unwinder.state = detail::state_type::abort; + } + else if (val != operation.at(detail::value_literal<char_type>())) + { + patch_ec = jsonpatch_errc::test_failed; + unwinder.state = detail::state_type::abort; + } + } + else if (op == detail::add_literal<char_type>()) + { + if (operation.count(detail::value_literal<char_type>()) != 1) + { + patch_ec = jsonpatch_errc::invalid_patch; + unwinder.state = detail::state_type::abort; + } + else + { + std::error_code insert_ec; + Json val = operation.at(detail::value_literal<char_type>()); + auto npath = jsonpointer::normalized_path(target,path); + jsonpointer::insert(target,npath,val,insert_ec); // try insert without replace + if (insert_ec) // try a replace + { + std::error_code select_ec; + Json orig_val = jsonpointer::get(target,npath,select_ec); + if (select_ec) // shouldn't happen + { + patch_ec = jsonpatch_errc::add_failed; + unwinder.state = detail::state_type::abort; + } + else + { + std::error_code replace_ec; + jsonpointer::replace(target,npath,val,replace_ec); + if (replace_ec) + { + patch_ec = jsonpatch_errc::add_failed; + unwinder.state = detail::state_type::abort; + } + else + { + unwinder.stack.push_back({detail::op_type::replace,npath,orig_val}); + } + } + } + else // insert without replace succeeded + { + unwinder.stack.push_back({detail::op_type::remove,npath,Json::null()}); + } + } + } + else if (op == detail::remove_literal<char_type>()) + { + std::error_code ec; + Json val = jsonpointer::get(target,path,ec); + if (ec) + { + patch_ec = jsonpatch_errc::remove_failed; + unwinder.state = detail::state_type::abort; + } + else + { + jsonpointer::remove(target,path,ec); + if (ec) + { + patch_ec = jsonpatch_errc::remove_failed; + unwinder.state = detail::state_type::abort; + } + else + { + unwinder.stack.push_back({detail::op_type::add,string_type(path),val}); + } + } + } + else if (op == detail::replace_literal<char_type>()) + { + std::error_code ec; + Json val = jsonpointer::get(target,path,ec); + if (ec) + { + patch_ec = jsonpatch_errc::replace_failed; + unwinder.state = detail::state_type::abort; + } + else if (operation.count(detail::value_literal<char_type>()) != 1) + { + patch_ec = jsonpatch_errc::invalid_patch; + unwinder.state = detail::state_type::abort; + } + else + { + jsonpointer::replace(target,path,operation.at(detail::value_literal<char_type>()),ec); + if (ec) + { + patch_ec = jsonpatch_errc::replace_failed; + unwinder.state = detail::state_type::abort; + } + else + { + unwinder.stack.push_back({detail::op_type::replace,string_type(path),val}); + } + } + } + else if (op == detail::move_literal<char_type>()) + { + if (operation.count(detail::from_literal<char_type>()) != 1) + { + patch_ec = jsonpatch_errc::invalid_patch; + unwinder.state = detail::state_type::abort; + } + else + { + string_view_type from = operation.at(detail::from_literal<char_type>()).as_string_view(); + std::error_code ec; + Json val = jsonpointer::get(target,from,ec); + if (ec) + { + patch_ec = jsonpatch_errc::move_failed; + unwinder.state = detail::state_type::abort; + } + else + { + jsonpointer::remove(target,from,ec); + if (ec) + { + patch_ec = jsonpatch_errc::move_failed; + unwinder.state = detail::state_type::abort; + } + else + { + unwinder.stack.push_back({detail::op_type::add,string_type(from),val}); + // add + std::error_code insert_ec; + auto npath = jsonpointer::normalized_path(target,path); + jsonpointer::insert(target,npath,val,insert_ec); // try insert without replace + if (insert_ec) // try a replace + { + std::error_code select_ec; + Json orig_val = jsonpointer::get(target,npath,select_ec); + if (select_ec) // shouldn't happen + { + patch_ec = jsonpatch_errc::copy_failed; + unwinder.state = detail::state_type::abort; + } + else + { + std::error_code replace_ec; + jsonpointer::replace(target, npath, val, replace_ec); + if (replace_ec) + { + patch_ec = jsonpatch_errc::copy_failed; + unwinder.state = detail::state_type::abort; + + } + else + { + unwinder.stack.push_back({ detail::op_type::replace,npath,orig_val }); + } + + } + } + else + { + unwinder.stack.push_back({detail::op_type::remove,npath,Json::null()}); + } + } + } + } + } + else if (op == detail::copy_literal<char_type>()) + { + if (operation.count(detail::from_literal<char_type>()) != 1) + { + patch_ec = jsonpatch_errc::invalid_patch; + unwinder.state = detail::state_type::abort; + } + else + { + std::error_code ec; + string_view_type from = operation.at(detail::from_literal<char_type>()).as_string_view(); + Json val = jsonpointer::get(target,from,ec); + if (ec) + { + patch_ec = jsonpatch_errc::copy_failed; + unwinder.state = detail::state_type::abort; + } + else + { + // add + auto npath = jsonpointer::normalized_path(target,path); + std::error_code insert_ec; + jsonpointer::insert(target,npath,val,insert_ec); // try insert without replace + if (insert_ec) // Failed, try a replace + { + std::error_code select_ec; + Json orig_val = jsonpointer::get(target,npath, select_ec); + if (select_ec) // shouldn't happen + { + patch_ec = jsonpatch_errc::copy_failed; + unwinder.state = detail::state_type::abort; + } + else + { + std::error_code replace_ec; + jsonpointer::replace(target, npath, val,replace_ec); + if (replace_ec) + { + patch_ec = jsonpatch_errc::copy_failed; + unwinder.state = detail::state_type::abort; + } + else + { + unwinder.stack.push_back({ detail::op_type::replace,npath,orig_val }); + } + } + } + else + { + unwinder.stack.push_back({detail::op_type::remove,npath,Json::null()}); + } + } + } + } + if (unwinder.state != detail::state_type::begin) + { + bad_path = string_type(path); + } + } + if (unwinder.state != detail::state_type::begin) + { + break; + } + } + if (unwinder.state == detail::state_type::begin) + { + unwinder.state = detail::state_type::commit; + } +} + +template <class Json> +Json from_diff(const Json& source, const Json& target) +{ + typename Json::string_type path; + return detail::from_diff(source, target, path); +} + +template <class Json> +void apply_patch(Json& target, const Json& patch) +{ + std::error_code ec; + apply_patch(target, patch, ec); + if (ec) + { + JSONCONS_THROW(jsonpatch_error(ec)); + } +} + +}} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpatch/jsonpatch_error_category.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpatch/jsonpatch_error_category.hpp new file mode 100644 index 00000000..6e566fc1 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpatch/jsonpatch_error_category.hpp @@ -0,0 +1,82 @@ +/// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONPATCH_JSONPATCH_ERROR_CATEGORY_HPP +#define JSONCONS_JSONPATCH_JSONPATCH_ERROR_CATEGORY_HPP + +#include <jsoncons/json_exception.hpp> +#include <system_error> + +namespace jsoncons { namespace jsonpatch { + +enum class jsonpatch_errc +{ + ok = 0, + invalid_patch = 1, + test_failed, + add_failed, + remove_failed, + replace_failed, + move_failed, + copy_failed + +}; + +class jsonpatch_error_category_impl + : public std::error_category +{ +public: + virtual const char* name() const JSONCONS_NOEXCEPT + { + return "jsonpatch"; + } + virtual std::string message(int ev) const + { + switch (static_cast<jsonpatch_errc>(ev)) + { + case jsonpatch_errc::invalid_patch: + return "Invalid JSON Patch document"; + case jsonpatch_errc::test_failed: + return "JSON Patch test operation failed"; + case jsonpatch_errc::add_failed: + return "JSON Patch add operation failed"; + case jsonpatch_errc::remove_failed: + return "JSON Patch remove operation failed"; + case jsonpatch_errc::replace_failed: + return "JSON Patch replace operation failed"; + case jsonpatch_errc::move_failed: + return "JSON Patch move operation failed"; + case jsonpatch_errc::copy_failed: + return "JSON Patch copy operation failed"; + default: + return "Unknown JSON Patch error"; + } + } +}; + +inline +const std::error_category& jsonpatch_error_category() +{ + static jsonpatch_error_category_impl instance; + return instance; +} + +inline +std::error_code make_error_code(jsonpatch_errc result) +{ + return std::error_code(static_cast<int>(result),jsonpatch_error_category()); +} + +}} + +namespace std { + template<> + struct is_error_code_enum<jsoncons::jsonpatch::jsonpatch_errc> : public true_type + { + }; +} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpath/json_query.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpath/json_query.hpp new file mode 100644 index 00000000..b042bbbb --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpath/json_query.hpp @@ -0,0 +1,1119 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONPATH_JSONQUERY_HPP +#define JSONCONS_JSONPATH_JSONQUERY_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <memory> +#include <jsoncons/json.hpp> +#include "jsonpath_filter.hpp" +#include "jsonpath_error_category.hpp" + +namespace jsoncons { namespace jsonpath { + +enum class result_type {value,path}; + +template<class Json> +Json json_query(const Json& root, const typename Json::string_view_type& path, result_type result_t = result_type::value) +{ + if (result_t == result_type::value) + { + detail::jsonpath_evaluator<Json,const Json&,detail::VoidPathConstructor<Json>> evaluator; + evaluator.evaluate(root,path.data(),path.length()); + return evaluator.get_values(); + } + else + { + detail::jsonpath_evaluator<Json,const Json&,detail::PathConstructor<Json>> evaluator; + evaluator.evaluate(root,path.data(),path.length()); + return evaluator.get_normalized_paths(); + } +} + +template<class Json, class T> +void json_replace(Json& root, const typename Json::string_view_type& path, T&& new_value) +{ + detail::jsonpath_evaluator<Json,Json&,detail::VoidPathConstructor<Json>> evaluator; + evaluator.evaluate(root,path.data(),path.length()); + evaluator.replace(std::forward<T>(new_value)); +} + +namespace detail { + +template<class CharT> +bool try_string_to_index(const CharT *s, size_t length, size_t* value, bool* positive) +{ + static const size_t max_value = (std::numeric_limits<size_t>::max)(); + static const size_t max_value_div_10 = max_value / 10; + + size_t start = 0; + size_t n = 0; + if (length > 0) + { + if (s[start] == '-') + { + *positive = false; + ++start; + } + else + { + *positive = true; + } + } + if (length > start) + { + for (size_t i = start; i < length; ++i) + { + CharT c = s[i]; + switch (c) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + { + size_t x = c - '0'; + if (n > max_value_div_10) + { + return false; + } + n = n * 10; + if (n > max_value - x) + { + return false; + } + + n += x; + } + break; + default: + return false; + break; + } + } + *value = n; + return true; + } + else + { + return false; + } +} + +enum class path_state +{ + start, + cr, + lf, + expect_dot_or_left_bracket, + expect_unquoted_name_or_left_bracket, + unquoted_name, + left_bracket_single_quoted_string, + left_bracket_double_quoted_string, + left_bracket, + left_bracket_start, + left_bracket_end, + left_bracket_end2, + left_bracket_step, + left_bracket_step2, + expect_comma_or_right_bracket, + dot +}; + +template<class Json, + class JsonReference=const Json&, + class PathCons=PathConstructor<Json>> +class jsonpath_evaluator : private parsing_context +{ +private: + typedef typename Json::char_type char_type; + typedef typename Json::char_traits_type char_traits_type; + typedef std::basic_string<char_type,char_traits_type> string_type; + typedef typename Json::string_view_type string_view_type; + typedef JsonReference reference; + using pointer = typename std::conditional<std::is_const<typename std::remove_reference<JsonReference>::type>::value,typename Json::const_pointer,typename Json::pointer>::type; + struct node_type + { + node_type() = default; + node_type(const string_type& p, const pointer& valp) + : skip_contained_object(false),path(p),val_ptr(valp) + { + } + node_type(string_type&& p, pointer&& valp) + : skip_contained_object(false),path(std::move(p)),val_ptr(valp) + { + } + node_type(const node_type&) = default; + node_type(node_type&&) = default; + + bool skip_contained_object; + string_type path; + pointer val_ptr; + }; + typedef std::vector<node_type> node_set; + + static string_view_type length_literal() + { + static const char_type data[] = {'l','e','n','g','t','h'}; + return string_view_type{data,sizeof(data)/sizeof(char_type)}; + } + + class selector + { + public: + virtual ~selector() + { + } + virtual void select(node_type& node, const string_type& path, reference val, + node_set& nodes, std::vector<std::shared_ptr<Json>>& temp_json_values) = 0; + }; + + class expr_selector final : public selector + { + private: + jsonpath_filter_expr<Json> result_; + public: + expr_selector(const jsonpath_filter_expr<Json>& result) + : result_(result) + { + } + + void select(node_type& node, const string_type& path, reference val, + node_set& nodes, std::vector<std::shared_ptr<Json>>& temp_json_values) override + { + auto index = result_.eval(val); + if (index.template is<size_t>()) + { + size_t start = index. template as<size_t>(); + if (val.is_array() && start < val.size()) + { + nodes.emplace_back(PathCons()(path,start),std::addressof(val[start])); + } + } + else if (index.is_string()) + { + name_selector selector(index.as_string_view(),true); + selector.select(node, path, val, nodes, temp_json_values); + } + } + }; + + class filter_selector final : public selector + { + private: + jsonpath_filter_expr<Json> result_; + public: + filter_selector(const jsonpath_filter_expr<Json>& result) + : result_(result) + { + } + + void select(node_type& node, const string_type& path, reference val, + node_set& nodes, std::vector<std::shared_ptr<Json>>&) override + { + if (val.is_array()) + { + node.skip_contained_object =true; + for (size_t i = 0; i < val.size(); ++i) + { + if (result_.exists(val[i])) + { + nodes.emplace_back(PathCons()(path,i),std::addressof(val[i])); + } + } + } + else if (val.is_object()) + { + if (!node.skip_contained_object) + { + if (result_.exists(val)) + { + nodes.emplace_back(path, std::addressof(val)); + } + } + else + { + node.skip_contained_object = false; + } + } + } + }; + + class name_selector final : public selector + { + private: + string_type name_; + bool positive_start_; + public: + name_selector(const string_view_type& name, bool positive_start) + : name_(name), positive_start_(positive_start) + { + } + + void select(node_type& node, const string_type& path, reference val, + node_set& nodes, + std::vector<std::shared_ptr<Json>>& temp_json_values) override + { + if (val.is_object() && val.count(name_) > 0) + { + nodes.emplace_back(PathCons()(path,name_),std::addressof(val.at(name_))); + } + else if (val.is_array()) + { + size_t pos = 0; + if (try_string_to_index(name_.data(), name_.size(), &pos, &positive_start_)) + { + size_t index = positive_start_ ? pos : val.size() - pos; + if (index < val.size()) + { + nodes.emplace_back(PathCons()(path,index),std::addressof(val[index])); + } + } + else if (name_ == length_literal() && val.size() > 0) + { + auto temp = std::make_shared<Json>(val.size()); + temp_json_values.push_back(temp); + nodes.emplace_back(PathCons()(path,name_),temp.get()); + } + } + else if (val.is_string()) + { + size_t pos = 0; + string_view_type sv = val.as_string_view(); + if (try_string_to_index(name_.data(), name_.size(), &pos, &positive_start_)) + { + size_t index = positive_start_ ? pos : sv.size() - pos; + auto sequence = unicons::sequence_at(sv.data(), sv.data() + sv.size(), index); + if (sequence.length() > 0) + { + auto temp = std::make_shared<Json>(sequence.begin(),sequence.length()); + temp_json_values.push_back(temp); + nodes.emplace_back(PathCons()(path,index),temp.get()); + } + } + else if (name_ == length_literal() && sv.size() > 0) + { + size_t count = unicons::u32_length(sv.begin(),sv.end()); + auto temp = std::make_shared<Json>(count); + temp_json_values.push_back(temp); + nodes.emplace_back(PathCons()(path,name_),temp.get()); + } + } + } + }; + + class array_slice_selector final : public selector + { + private: + size_t start_; + bool positive_start_; + size_t end_; + bool positive_end_; + bool undefined_end_; + size_t step_; + bool positive_step_; + public: + array_slice_selector(size_t start, bool positive_start, + size_t end, bool positive_end, + size_t step, bool positive_step, + bool undefined_end) + : start_(start), positive_start_(positive_start), + end_(end), positive_end_(positive_end),undefined_end_(undefined_end), + step_(step), positive_step_(positive_step) + { + } + + void select(node_type& node, const string_type& path, reference val, + node_set& nodes, + std::vector<std::shared_ptr<Json>>&) override + { + if (positive_step_) + { + end_array_slice1(path, val, nodes); + } + else + { + end_array_slice2(path, val, nodes); + } + } + + void end_array_slice1(const string_type& path, reference val, node_set& nodes) + { + if (val.is_array()) + { + size_t start = positive_start_ ? start_ : val.size() - start_; + size_t end; + if (!undefined_end_) + { + end = positive_end_ ? end_ : val.size() - end_; + } + else + { + end = val.size(); + } + for (size_t j = start; j < end; j += step_) + { + if (j < val.size()) + { + nodes.emplace_back(PathCons()(path,j),std::addressof(val[j])); + } + } + } + } + + void end_array_slice2(const string_type& path, reference val, node_set& nodes) + { + if (val.is_array()) + { + size_t start = positive_start_ ? start_ : val.size() - start_; + size_t end; + if (!undefined_end_) + { + end = positive_end_ ? end_ : val.size() - end_; + } + else + { + end = val.size(); + } + + size_t j = end + step_ - 1; + while (j > (start+step_-1)) + { + j -= step_; + if (j < val.size()) + { + nodes.emplace_back(PathCons()(path,j),std::addressof(val[j])); + } + } + } + } + }; + + default_parse_error_handler default_err_handler_; + parse_error_handler *err_handler_; + path_state state_; + string_type buffer_; + size_t start_; + bool positive_start_; + size_t end_; + bool positive_end_; + bool undefined_end_; + size_t step_; + bool positive_step_; + bool recursive_descent_; + node_set nodes_; + std::vector<node_set> stack_; + std::vector<std::shared_ptr<Json>> temp_json_values_; + size_t line_; + size_t column_; + const char_type* begin_input_; + const char_type* end_input_; + const char_type* p_; + std::vector<std::shared_ptr<selector>> selectors_; + +public: + jsonpath_evaluator() + : err_handler_(&default_err_handler_), + state_(path_state::start), + start_(0), positive_start_(true), + end_(0), positive_end_(true), undefined_end_(false), + step_(0), positive_step_(true), + recursive_descent_(false), + line_(0), column_(0), + begin_input_(nullptr), end_input_(nullptr), + p_(nullptr) + { + } + + Json get_values() const + { + Json result = typename Json::array(); + + if (stack_.size() > 0) + { + result.reserve(stack_.back().size()); + for (const auto& p : stack_.back()) + { + result.push_back(*(p.val_ptr)); + } + } + return result; + } + + Json get_normalized_paths() const + { + Json result = typename Json::array(); + if (stack_.size() > 0) + { + result.reserve(stack_.back().size()); + for (const auto& p : stack_.back()) + { + result.push_back(p.path); + } + } + return result; + } + + template <class T> + void replace(T&& new_value) + { + if (stack_.size() > 0) + { + for (size_t i = 0; i < stack_.back().size(); ++i) + { + *(stack_.back()[i].val_ptr) = new_value; + } + } + } + + void evaluate(reference root, const string_view_type& path) + { + evaluate(root,path.data(),path.length()); + } + void evaluate(reference root, const char_type* path) + { + evaluate(root,path,char_traits_type::length(path)); + } + + void evaluate(reference root, + const char_type* path, + size_t length) + { + std::error_code ec; + evaluate(root, path, length, ec); + if (ec) + { + throw parse_error(ec,line_,column_); + } + } + + void evaluate(reference root, + const char_type* path, + size_t length, + std::error_code& ec) + { + path_state pre_line_break_state = path_state::start; + + begin_input_ = path; + end_input_ = path + length; + p_ = begin_input_; + + line_ = 1; + column_ = 1; + state_ = path_state::start; + + recursive_descent_ = false; + + clear_index(); + + while (p_ < end_input_) + { + switch (state_) + { + case path_state::cr: + ++line_; + column_ = 1; + switch (*p_) + { + case '\n': + state_ = pre_line_break_state; + ++p_; + ++column_; + break; + default: + state_ = pre_line_break_state; + break; + } + break; + case path_state::lf: + ++line_; + column_ = 1; + state_ = pre_line_break_state; + break; + case path_state::start: + switch (*p_) + { + case ' ':case '\t': + break; + case '$': + case '@': + { + string_type s; + s.push_back('$'); + node_set v; + v.emplace_back(std::move(s),std::addressof(root)); + stack_.push_back(v); + + state_ = path_state::expect_dot_or_left_bracket; + } + break; + default: + err_handler_->fatal_error(jsonpath_parser_errc::expected_root, *this); + ec = jsonpath_parser_errc::expected_root; + return; + }; + ++p_; + ++column_; + break; + case path_state::dot: + switch (*p_) + { + case '.': + recursive_descent_ = true; + ++p_; + ++column_; + state_ = path_state::expect_unquoted_name_or_left_bracket; + break; + default: + state_ = path_state::expect_unquoted_name_or_left_bracket; + break; + } + break; + case path_state::expect_unquoted_name_or_left_bracket: + switch (*p_) + { + case '.': + err_handler_->fatal_error(jsonpath_parser_errc::expected_name, *this); + ec = jsonpath_parser_errc::expected_name; + return; + case '*': + end_all(); + transfer_nodes(); + state_ = path_state::expect_dot_or_left_bracket; + ++p_; + ++column_; + break; + case '[': + state_ = path_state::left_bracket; + ++p_; + ++column_; + break; + default: + buffer_.clear(); + state_ = path_state::unquoted_name; + break; + } + break; + case path_state::expect_dot_or_left_bracket: + switch (*p_) + { + case ' ':case '\t': + break; + case '.': + state_ = path_state::dot; + break; + case '[': + state_ = path_state::left_bracket; + break; + default: + err_handler_->fatal_error(jsonpath_parser_errc::expected_separator, *this); + ec = jsonpath_parser_errc::expected_separator; + return; + }; + ++p_; + ++column_; + break; + case path_state::expect_comma_or_right_bracket: + switch (*p_) + { + case ',': + state_ = path_state::left_bracket; + break; + case ']': + apply_selectors(); + state_ = path_state::expect_dot_or_left_bracket; + break; + case ' ':case '\t': + break; + default: + err_handler_->fatal_error(jsonpath_parser_errc::expected_right_bracket, *this); + ec = jsonpath_parser_errc::expected_right_bracket; + return; + } + ++p_; + ++column_; + break; + case path_state::left_bracket: + switch (*p_) + { + case ' ':case '\t': + ++p_; + ++column_; + break; + case '(': + { + jsonpath_filter_parser<Json> parser(line_,column_); + auto result = parser.parse(root, p_,end_input_,&p_); + line_ = parser.line(); + column_ = parser.column(); + selectors_.push_back(std::make_shared<expr_selector>(result)); + state_ = path_state::expect_comma_or_right_bracket; + } + break; + case '?': + { + jsonpath_filter_parser<Json> parser(line_,column_); + auto result = parser.parse(root,p_,end_input_,&p_); + line_ = parser.line(); + column_ = parser.column(); + selectors_.push_back(std::make_shared<filter_selector>(result)); + state_ = path_state::expect_comma_or_right_bracket; + } + break; + case ':': + clear_index(); + state_ = path_state::left_bracket_end; + ++p_; + ++column_; + break; + case '*': + end_all(); + state_ = path_state::expect_comma_or_right_bracket; + ++p_; + ++column_; + break; + case '\'': + state_ = path_state::left_bracket_single_quoted_string; + ++p_; + ++column_; + break; + case '\"': + state_ = path_state::left_bracket_double_quoted_string; + ++p_; + ++column_; + break; + default: + clear_index(); + buffer_.push_back(*p_); + state_ = path_state::left_bracket_start; + ++p_; + ++column_; + break; + } + break; + case path_state::left_bracket_start: + switch (*p_) + { + case ':': + if (!try_string_to_index(buffer_.data(), buffer_.size(), &start_, &positive_start_)) + { + err_handler_->fatal_error(jsonpath_parser_errc::expected_index, *this); + ec = jsonpath_parser_errc::expected_index; + return; + } + state_ = path_state::left_bracket_end; + break; + case ',': + selectors_.push_back(std::make_shared<name_selector>(buffer_,positive_start_)); + buffer_.clear(); + state_ = path_state::left_bracket; + break; + case ']': + selectors_.push_back(std::make_shared<name_selector>(buffer_,positive_start_)); + buffer_.clear(); + apply_selectors(); + state_ = path_state::expect_dot_or_left_bracket; + break; + default: + buffer_.push_back(*p_); + break; + } + ++p_; + ++column_; + break; + case path_state::left_bracket_end: + switch (*p_) + { + case '-': + positive_end_ = false; + state_ = path_state::left_bracket_end2; + break; + case ':': + step_ = 0; + state_ = path_state::left_bracket_step; + break; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + undefined_end_ = false; + end_ = static_cast<size_t>(*p_-'0'); + state_ = path_state::left_bracket_end2; + break; + case ',': + selectors_.push_back(std::make_shared<array_slice_selector>(start_,positive_start_,end_,positive_end_,step_,positive_step_,undefined_end_)); + state_ = path_state::left_bracket; + break; + case ']': + selectors_.push_back(std::make_shared<array_slice_selector>(start_,positive_start_,end_,positive_end_,step_,positive_step_,undefined_end_)); + apply_selectors(); + state_ = path_state::expect_dot_or_left_bracket; + break; + } + ++p_; + ++column_; + break; + case path_state::left_bracket_end2: + switch (*p_) + { + case ':': + step_ = 0; + state_ = path_state::left_bracket_step; + break; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + undefined_end_ = false; + end_ = end_*10 + static_cast<size_t>(*p_-'0'); + break; + case ',': + selectors_.push_back(std::make_shared<array_slice_selector>(start_,positive_start_,end_,positive_end_,step_,positive_step_,undefined_end_)); + state_ = path_state::left_bracket; + break; + case ']': + selectors_.push_back(std::make_shared<array_slice_selector>(start_,positive_start_,end_,positive_end_,step_,positive_step_,undefined_end_)); + apply_selectors(); + state_ = path_state::expect_dot_or_left_bracket; + break; + } + ++p_; + ++column_; + break; + case path_state::left_bracket_step: + switch (*p_) + { + case '-': + positive_step_ = false; + state_ = path_state::left_bracket_step2; + break; + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + step_ = static_cast<size_t>(*p_-'0'); + state_ = path_state::left_bracket_step2; + break; + case ',': + selectors_.push_back(std::make_shared<array_slice_selector>(start_,positive_start_,end_,positive_end_,step_,positive_step_,undefined_end_)); + state_ = path_state::left_bracket; + break; + case ']': + selectors_.push_back(std::make_shared<array_slice_selector>(start_,positive_start_,end_,positive_end_,step_,positive_step_,undefined_end_)); + apply_selectors(); + state_ = path_state::expect_dot_or_left_bracket; + break; + } + ++p_; + ++column_; + break; + case path_state::left_bracket_step2: + switch (*p_) + { + case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': + step_ = step_*10 + static_cast<size_t>(*p_-'0'); + break; + case ',': + selectors_.push_back(std::make_shared<array_slice_selector>(start_,positive_start_,end_,positive_end_,step_,positive_step_,undefined_end_)); + state_ = path_state::left_bracket; + break; + case ']': + selectors_.push_back(std::make_shared<array_slice_selector>(start_,positive_start_,end_,positive_end_,step_,positive_step_,undefined_end_)); + apply_selectors(); + state_ = path_state::expect_dot_or_left_bracket; + break; + } + ++p_; + ++column_; + break; + case path_state::unquoted_name: + switch (*p_) + { + case '[': + apply_unquoted_string(buffer_); + transfer_nodes(); + start_ = 0; + state_ = path_state::left_bracket; + break; + case '.': + apply_unquoted_string(buffer_); + transfer_nodes(); + state_ = path_state::dot; + break; + case ' ':case '\t': + apply_unquoted_string(buffer_); + transfer_nodes(); + state_ = path_state::expect_dot_or_left_bracket; + break; + case '\r': + apply_unquoted_string(buffer_); + transfer_nodes(); + pre_line_break_state = path_state::expect_dot_or_left_bracket; + state_= path_state::cr; + break; + case '\n': + apply_unquoted_string(buffer_); + transfer_nodes(); + pre_line_break_state = path_state::expect_dot_or_left_bracket; + state_= path_state::lf; + break; + default: + buffer_.push_back(*p_); + break; + }; + ++p_; + ++column_; + break; + case path_state::left_bracket_single_quoted_string: + switch (*p_) + { + case '\'': + selectors_.push_back(std::make_shared<name_selector>(buffer_,positive_start_)); + buffer_.clear(); + state_ = path_state::expect_comma_or_right_bracket; + break; + case '\\': + buffer_.push_back(*p_); + if (p_+1 < end_input_) + { + ++p_; + ++column_; + buffer_.push_back(*p_); + } + break; + default: + buffer_.push_back(*p_); + break; + }; + ++p_; + ++column_; + break; + case path_state::left_bracket_double_quoted_string: + switch (*p_) + { + case '\"': + selectors_.push_back(std::make_shared<name_selector>(buffer_,positive_start_)); + buffer_.clear(); + state_ = path_state::expect_comma_or_right_bracket; + break; + case '\\': + buffer_.push_back(*p_); + if (p_+1 < end_input_) + { + ++p_; + ++column_; + buffer_.push_back(*p_); + } + break; + default: + buffer_.push_back(*p_); + break; + }; + ++p_; + ++column_; + break; + default: + ++p_; + ++column_; + break; + } + } + switch (state_) + { + case path_state::unquoted_name: + { + apply_unquoted_string(buffer_); + transfer_nodes(); + } + break; + default: + break; + } + } + + void clear_index() + { + buffer_.clear(); + start_ = 0; + positive_start_ = true; + end_ = 0; + positive_end_ = true; + undefined_end_ = true; + step_ = 1; + positive_step_ = true; + } + + void end_all() + { + for (size_t i = 0; i < stack_.back().size(); ++i) + { + const auto& path = stack_.back()[i].path; + pointer p = stack_.back()[i].val_ptr; + + if (p->is_array()) + { + for (auto it = p->array_range().begin(); it != p->array_range().end(); ++it) + { + nodes_.emplace_back(PathCons()(path,it - p->array_range().begin()),std::addressof(*it)); + } + } + else if (p->is_object()) + { + for (auto it = p->object_range().begin(); it != p->object_range().end(); ++it) + { + nodes_.emplace_back(PathCons()(path,it->key()),std::addressof(it->value())); + } + } + + } + start_ = 0; + } + + void apply_unquoted_string(const string_view_type& name) + { + if (name.length() > 0) + { + for (size_t i = 0; i < stack_.back().size(); ++i) + { + apply_unquoted_string(stack_.back()[i].path, *(stack_.back()[i].val_ptr), name); + } + } + buffer_.clear(); + } + + void apply_unquoted_string(const string_type& path, reference val, const string_view_type& name) + { + if (val.is_object()) + { + if (val.count(name) > 0) + { + nodes_.emplace_back(PathCons()(path,name),std::addressof(val.at(name))); + } + if (recursive_descent_) + { + for (auto it = val.object_range().begin(); it != val.object_range().end(); ++it) + { + if (it->value().is_object() || it->value().is_array()) + { + apply_unquoted_string(path, it->value(), name); + } + } + } + } + else if (val.is_array()) + { + size_t pos = 0; + if (try_string_to_index(name.data(),name.size(),&pos, &positive_start_)) + { + size_t index = positive_start_ ? pos : val.size() - pos; + if (index < val.size()) + { + nodes_.emplace_back(PathCons()(path,index),std::addressof(val[index])); + } + } + else if (name == length_literal() && val.size() > 0) + { + auto temp = std::make_shared<Json>(val.size()); + temp_json_values_.push_back(temp); + nodes_.emplace_back(PathCons()(path,name),temp.get()); + } + if (recursive_descent_) + { + for (auto it = val.array_range().begin(); it != val.array_range().end(); ++it) + { + if (it->is_object() || it->is_array()) + { + apply_unquoted_string(path, *it, name); + } + } + } + } + else if (val.is_string()) + { + string_view_type sv = val.as_string_view(); + size_t pos = 0; + if (try_string_to_index(name.data(),name.size(),&pos, &positive_start_)) + { + auto sequence = unicons::sequence_at(sv.data(), sv.data() + sv.size(), pos); + if (sequence.length() > 0) + { + auto temp = std::make_shared<Json>(sequence.begin(),sequence.length()); + temp_json_values_.push_back(temp); + nodes_.emplace_back(PathCons()(path,pos),temp.get()); + } + } + else if (name == length_literal() && sv.size() > 0) + { + size_t count = unicons::u32_length(sv.begin(),sv.end()); + auto temp = std::make_shared<Json>(count); + temp_json_values_.push_back(temp); + nodes_.emplace_back(PathCons()(path,name),temp.get()); + } + } + } + + void apply_selectors() + { + if (selectors_.size() > 0) + { + for (size_t i = 0; i < stack_.back().size(); ++i) + { + node_type& node = stack_.back()[i]; + apply_selectors(node, node.path, *(node.val_ptr)); + } + selectors_.clear(); + } + transfer_nodes(); + } + + void apply_selectors(node_type& node, const string_type& path, reference val) + { + for (const auto& selector : selectors_) + { + selector->select(node, path, val, nodes_, temp_json_values_); + } + if (recursive_descent_) + { + if (val.is_object()) + { + for (auto& nvp : val.object_range()) + { + if (nvp.value().is_object() || nvp.value().is_array()) + { + apply_selectors(node,PathCons()(path,nvp.key()),nvp.value()); + } + } + } + else if (val.is_array()) + { + for (auto& elem : val.array_range()) + { + if (elem.is_object() || elem.is_array()) + { + apply_selectors(node,path, elem); + } + } + } + } + } + + void transfer_nodes() + { + stack_.push_back(nodes_); + nodes_.clear(); + recursive_descent_ = false; + } + + size_t do_line_number() const override + { + return line_; + } + + size_t do_column_number() const override + { + return column_; + } + +}; + +} + +}} + +#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/jsonpath_error_category.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpath/jsonpath_error_category.hpp index 7f6b6a12..62aa5889 100644 --- a/vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/jsonpath_error_category.hpp +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpath/jsonpath_error_category.hpp @@ -7,24 +7,28 @@ #ifndef JSONCONS_JSONPATH_JSONPATH_ERROR_CATEGORY_HPP #define JSONCONS_JSONPATH_JSONPATH_ERROR_CATEGORY_HPP -#include "jsoncons/jsoncons.hpp" +#include <jsoncons/json_exception.hpp> #include <system_error> namespace jsoncons { namespace jsonpath { -namespace jsonpath_parser_errc +enum class jsonpath_parser_errc { - const int expected_root = 1; - const int expected_right_bracket = 2; - const int expected_name = 3; - const int expected_separator = 4; - const int invalid_filter = 5; - const int invalid_filter_expected_slash = 6; - const int invalid_filter_unbalanced_paren = 7; - const int invalid_filter_unsupported_operator = 8; - const int invalid_filter_expected_right_brace = 9; - const int invalid_filter_expected_primary = 10; -} + ok = 0, + expected_root = 1, + expected_right_bracket = 2, + expected_name = 3, + expected_separator = 4, + invalid_filter = 5, + invalid_filter_expected_slash = 6, + invalid_filter_unbalanced_paren = 7, + invalid_filter_unsupported_operator = 8, + invalid_filter_expected_right_brace = 9, + invalid_filter_expected_primary = 10, + expected_index = 11, + expected_left_bracket_token = 12, + unexpected_operator = 13 +}; class jsonpath_error_category_impl : public std::error_category @@ -36,7 +40,7 @@ public: } virtual std::string message(int ev) const { - switch (ev) + switch (static_cast<jsonpath_parser_errc>(ev)) { case jsonpath_parser_errc::expected_root: return "Expected $"; @@ -44,6 +48,8 @@ public: return "Expected ]"; case jsonpath_parser_errc::expected_name: return "Expected a name following a dot"; + case jsonpath_parser_errc::expected_index: + return "Expected index"; case jsonpath_parser_errc::expected_separator: return "Expected dot or left bracket separator"; case jsonpath_parser_errc::invalid_filter: @@ -58,6 +64,8 @@ public: return "Invalid path filter, expected right brace }"; case jsonpath_parser_errc::invalid_filter_expected_primary: return "Invalid path filter, expected primary expression."; + case jsonpath_parser_errc::expected_left_bracket_token: + return "Expected ?,',\",0-9,*"; default: return "Unknown jsonpath parser error"; } @@ -71,5 +79,19 @@ const std::error_category& jsonpath_error_category() return instance; } +inline +std::error_code make_error_code(jsonpath_parser_errc result) +{ + return std::error_code(static_cast<int>(result),jsonpath_error_category()); +} + }} + +namespace std { + template<> + struct is_error_code_enum<jsoncons::jsonpath::jsonpath_parser_errc> : public true_type + { + }; +} + #endif diff --git a/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpath/jsonpath_filter.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpath/jsonpath_filter.hpp new file mode 100644 index 00000000..c3af2edd --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpath/jsonpath_filter.hpp @@ -0,0 +1,1874 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONPATH_FILTER_HPP +#define JSONCONS_JSONPATH_FILTER_HPP + +#include <string> +#include <map> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <memory> +#include <regex> +#include <functional> +#include <cmath> +#include <jsoncons/json.hpp> +#include "jsonpath_error_category.hpp" + +namespace jsoncons { namespace jsonpath { namespace detail { + +JSONCONS_DEFINE_LITERAL(eqtilde_literal,"=~") +JSONCONS_DEFINE_LITERAL(star_literal,"*") +JSONCONS_DEFINE_LITERAL(forwardslash_literal,"/") +JSONCONS_DEFINE_LITERAL(plus_literal,"+") +JSONCONS_DEFINE_LITERAL(minus_literal,"-") +JSONCONS_DEFINE_LITERAL(lt_literal,"<") +JSONCONS_DEFINE_LITERAL(lte_literal,"<=") +JSONCONS_DEFINE_LITERAL(gt_literal,">") +JSONCONS_DEFINE_LITERAL(gte_literal,">=") +JSONCONS_DEFINE_LITERAL(eq_literal,"==") +JSONCONS_DEFINE_LITERAL(ne_literal,"!=") +JSONCONS_DEFINE_LITERAL(ampamp_literal,"&&") +JSONCONS_DEFINE_LITERAL(pipepipe_literal,"||") +JSONCONS_DEFINE_LITERAL(max_literal,"max") +JSONCONS_DEFINE_LITERAL(min_literal,"min") + +template<class Json> +struct PathConstructor +{ + typedef typename Json::char_type char_type; + typedef typename Json::string_view_type string_view_type; + typedef typename Json::string_type string_type; + + string_type operator()(const string_type& path, size_t index) const + { + char_type buf[255]; + char_type* p = buf; + do + { + *p++ = static_cast<char_type>(48 + index % 10); + } while (index /= 10); + + string_type s; + s.append(path); + s.push_back('['); + while (--p >= buf) + { + s.push_back(*p); + } + s.push_back(']'); + return s; + } + + string_type operator()(const string_type& path, const string_view_type& sv) const + { + string_type s; + s.append(path); + s.push_back('['); + s.push_back('\''); + s.append(sv.data(),sv.length()); + s.push_back('\''); + s.push_back(']'); + return s; + } +}; + +template<class Json> +struct VoidPathConstructor +{ + typedef typename Json::char_type char_type; + typedef typename Json::string_view_type string_view_type; + typedef typename Json::string_type string_type; + + string_type operator()(const string_type&, size_t) const + { + return string_type{}; + } + + string_type operator()(const string_type&, string_view_type) const + { + return string_type{}; + } +}; + +template <class Json, + class JsonReference, + class PathCons> +class jsonpath_evaluator; + +enum class filter_state +{ + start, + cr, + lf, + expect_right_round_bracket, + expect_oper_or_right_round_bracket, + expect_path_or_value_or_unary_op, + expect_regex, + regex, + single_quoted_text, + double_quoted_text, + unquoted_text, + path, + value, + oper, + function_argument, + done +}; + +enum class token_type +{ + operand, + unary_operator, + binary_operator, + lparen, + rparen +}; + +template <class Json> +class term +{ +public: + typedef typename Json::string_type string_type; + typedef typename Json::char_type char_type; + + virtual ~term() {} + + virtual void initialize(const Json&) + { + } + virtual bool accept_single_node() const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual Json evaluate_single_node() const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual bool exclaim() const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual bool eq_term(const term&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual bool eq(const Json&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual bool ne_term(const term&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual bool ne(const Json&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual bool regex_term(const term&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual bool regex2(const string_type&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual bool ampamp_term(const term&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual bool ampamp(const Json&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual bool pipepipe_term(const term&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual bool pipepipe(const Json&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual bool lt_term(const term&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual bool lt(const Json&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual bool gt_term(const term&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual bool gt(const Json&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + + virtual Json minus_term(const term&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual Json minus(const Json&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + + virtual Json left_minus(const Json&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + + virtual Json unary_minus() const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual Json plus_term(const term&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual Json plus(const Json&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual Json mult_term(const term&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual Json mult(const Json&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + + virtual Json div_term(const term&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + virtual Json div(const Json&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } + + virtual Json left_div(const Json&) const + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,1,1); + } +}; + +template <class Json> +struct operator_properties +{ + typedef std::function<Json(const term<Json>&, const term<Json>&)> operator_type; + + size_t precedence_level; + bool is_right_associative; + operator_type op; +}; + +template <class Json> +struct function_properties +{ + typedef std::function<Json(const term<Json>&)> function_type; + + size_t precedence_level; + bool is_right_associative; + bool is_aggregate; + function_type op; +}; + +template <class Json> +class token +{ + token_type type_; + size_t precedence_level_; + bool is_right_associative_; + bool is_aggregate_; + std::shared_ptr<term<Json>> operand_ptr_; + std::function<Json(const term<Json>&)> unary_operator_; + std::function<Json(const term<Json>&, const term<Json>&)> operator_; +public: + typedef std::function<Json(const term<Json>&)> unary_operator_type; + typedef std::function<Json(const term<Json>&, const term<Json>&)> operator_type; + + Json operator()(const term<Json>& a) + { + return unary_operator_(a); + } + + Json operator()(const term<Json>& a, const term<Json>& b) + { + return operator_(a,b); + } + + token(token_type type) + : type_(type),precedence_level_(0),is_right_associative_(false),is_aggregate_(false) + { + } + token(token_type type, std::shared_ptr<term<Json>> term_ptr) + : type_(type),precedence_level_(0),is_right_associative_(false),is_aggregate_(false),operand_ptr_(term_ptr) + { + } + token(size_t precedence_level, + bool is_right_associative, + std::function<Json(const term<Json>&)> unary_operator) + : type_(token_type::unary_operator), + precedence_level_(precedence_level), + is_right_associative_(is_right_associative), + is_aggregate_(false), + unary_operator_(unary_operator) + { + } + token(const operator_properties<Json>& properties) + : type_(token_type::binary_operator), + precedence_level_(properties.precedence_level), + is_right_associative_(properties.is_right_associative), + is_aggregate_(false), + operator_(properties.op) + { + } + token(const function_properties<Json>& properties) + : type_(token_type::unary_operator), + precedence_level_(properties.precedence_level), + is_right_associative_(properties.is_right_associative), + is_aggregate_(properties.is_aggregate), + unary_operator_(properties.op) + { + } + token(const token& t) = default; + //token(token&& t) = default; + + token<Json>& operator=(const token<Json>& val) = default; + //token<Json>& operator=(token<Json>&& val) = default; + + bool is_operator() const + { + return is_unary_operator() || is_binary_operator(); + } + + bool is_unary_operator() const + { + return type_ == token_type::unary_operator; + } + + bool is_binary_operator() const + { + return type_ == token_type::binary_operator; + } + + bool is_operand() const + { + return type_ == token_type::operand; + } + + bool is_lparen() const + { + return type_ == token_type::lparen; + } + + bool is_rparen() const + { + return type_ == token_type::rparen; + } + + size_t precedence_level() const + { + return precedence_level_; + } + + bool is_right_associative() const + { + return is_right_associative_; + } + + bool is_aggregate() const + { + return is_aggregate_; + } + + const term<Json>& operand() + { + JSONCONS_ASSERT(type_ == token_type::operand && operand_ptr_ != nullptr); + return *operand_ptr_; + } + + void initialize(const Json& context_node) + { + if (operand_ptr_.get() != nullptr) + { + operand_ptr_->initialize(context_node); + } + } +}; + +template <class Json> +bool ampamp(const Json& lhs, const Json& rhs) +{ + return lhs.as_bool() && rhs.as_bool(); +} + +template <class Json> +bool pipepipe(const Json& lhs, const Json& rhs) +{ + return lhs.as_bool() || rhs.as_bool(); +} + +template <class Json> +bool lt(const Json& lhs, const Json& rhs) +{ + bool result = false; + if (lhs. template is<unsigned long long>() && rhs. template is<unsigned long long>()) + { + result = lhs. template as<unsigned long long>() < rhs. template as<unsigned long long>(); + } + else if (lhs. template is<long long>() && rhs. template is<long long>()) + { + result = lhs. template as<long long>() < rhs. template as<long long>(); + } + else if ((lhs.is_number() && rhs.is_double()) || (lhs.is_double() && rhs.is_number())) + { + result = lhs.as_double() < rhs.as_double(); + } + else if (lhs.is_string() && rhs.is_string()) + { + result = lhs.as_string_view() < rhs.as_string_view(); + } + return result; +} + +template <class Json> +bool gt(const Json& lhs, const Json& rhs) +{ + return lt(rhs,lhs); +} + +template <class Json> +Json plus(const Json& lhs, const Json& rhs) +{ + Json result = Json(jsoncons::null_type()); + if (lhs.is_integer() && rhs.is_integer()) + { + result = Json(((lhs.as_integer() + rhs.as_integer()))); + } + else if ((lhs.is_number() && rhs.is_double()) || (lhs.is_double() && rhs.is_number())) + { + result = Json((lhs.as_double() + rhs.as_double())); + } + else if (lhs.is_uinteger() && rhs.is_uinteger()) + { + result = Json((lhs.as_uinteger() + rhs.as_uinteger())); + } + return result; +} + +template <class Json> +Json mult(const Json& lhs, const Json& rhs) +{ + Json result = Json(jsoncons::null_type()); + if (lhs.is_integer() && rhs.is_integer()) + { + result = Json(((lhs.as_integer() * rhs.as_integer()))); + } + else if ((lhs.is_number() && rhs.is_double()) || (lhs.is_double() && rhs.is_number())) + { + result = Json((lhs.as_double() * rhs.as_double())); + } + else if (lhs.is_uinteger() && rhs.is_uinteger()) + { + result = Json((lhs.as_uinteger() * rhs.as_uinteger())); + } + return result; +} + +template <class Json> +Json div(const Json& lhs, const Json& rhs) +{ + Json result = Json(jsoncons::null_type()); + if (lhs.is_integer() && rhs.is_integer()) + { + result = Json((double)(lhs.as_integer() / (double)rhs.as_integer())); + } + else if ((lhs.is_number() && rhs.is_double()) || (lhs.is_double() && rhs.is_number())) + { + result = Json((lhs.as_double() / rhs.as_double())); + } + else if (lhs.is_uinteger() && rhs.is_uinteger()) + { + result = Json((double)(lhs.as_uinteger() / (double)rhs.as_uinteger())); + } + return result; +} + +template <class Json> +Json unary_minus(const Json& lhs) +{ + Json result = Json::null(); + if (lhs.is_integer()) + { + result = -lhs.as_integer(); + } + else if (lhs.is_double()) + { + result = -lhs.as_double(); + } + return result; +} + +template <class Json> +Json minus(const Json& lhs, const Json& rhs) +{ + Json result = Json::null(); + if (lhs.is_integer() && rhs.is_integer()) + { + result = ((lhs.as_integer() - rhs.as_integer())); + } + else if ((lhs.is_number() && rhs.is_double()) || (lhs.is_double() && rhs.is_number())) + { + result = (lhs.as_double() - rhs.as_double()); + } + else if (lhs.is_uinteger() && rhs.is_uinteger() && lt(rhs,lhs)) + { + result = (lhs.as_uinteger() - rhs.as_uinteger()); + } + return result; +} + +template <class Json> +class value_term final : public term<Json> +{ + Json value_; +public: + template <class T> + value_term(const T& val) + : value_(val) + { + } + + bool accept_single_node() const override + { + return value_.as_bool(); + } + + Json evaluate_single_node() const override + { + return value_; + } + + bool exclaim() const override + { + return !value_.as_bool(); + } + + bool eq_term(const term<Json>& rhs) const override + { + return rhs.eq(value_); + } + + bool eq(const Json& rhs) const override + { + return value_ == rhs; + } + + bool ne_term(const term<Json>& rhs) const override + { + return rhs.ne(value_); + } + bool ne(const Json& rhs) const override + { + return value_ != rhs; + } + bool regex_term(const term<Json>& rhs) const override + { + return rhs.regex2(value_.as_string()); + } + bool ampamp_term(const term<Json>& rhs) const override + { + return rhs.ampamp(value_); + } + bool ampamp(const Json& rhs) const override + { + return jsoncons::jsonpath::detail::ampamp(value_,rhs); + } + bool pipepipe_term(const term<Json>& rhs) const override + { + return rhs.pipepipe(value_); + } + bool pipepipe(const Json& rhs) const override + { + return jsoncons::jsonpath::detail::pipepipe(value_,rhs); + } + + bool lt_term(const term<Json>& rhs) const override + { + return rhs.gt(value_); + } + bool lt(const Json& rhs) const override + { + return jsoncons::jsonpath::detail::lt(value_,rhs); + } + + bool gt_term(const term<Json>& rhs) const override + { + return rhs.lt(value_); + } + bool gt(const Json& rhs) const override + { + return jsoncons::jsonpath::detail::gt(value_,rhs); + } + + Json minus_term(const term<Json>& rhs) const override + { + return rhs.left_minus(value_); + } + Json minus(const Json& rhs) const override + { + return jsoncons::jsonpath::detail::minus(value_,rhs); + } + + Json left_minus(const Json& lhs) const override + { + return jsoncons::jsonpath::detail::minus(lhs,value_); + } + + Json unary_minus() const override + { + return jsoncons::jsonpath::detail::unary_minus(value_); + } + + Json plus_term(const term<Json>& rhs) const override + { + return rhs.plus(value_); + } + + Json plus(const Json& rhs) const override + { + return jsoncons::jsonpath::detail::plus(value_,rhs); + } + Json mult_term(const term<Json>& rhs) const override + { + return rhs.mult(value_); + } + + Json mult(const Json& rhs) const override + { + return jsoncons::jsonpath::detail::mult(value_,rhs); + } + + Json div_term(const term<Json>& rhs) const override + { + return rhs.left_div(value_); + } + Json div(const Json& rhs) const override + { + return jsoncons::jsonpath::detail::div(value_,rhs); + } + + Json left_div(const Json& lhs) const override + { + return jsoncons::jsonpath::detail::div(lhs,value_); + } +}; + +template <class Json> +class regex_term final : public term<Json> +{ + typedef typename Json::char_type char_type; + typedef typename Json::string_type string_type; + const std::basic_regex<char_type> pattern_; +public: + regex_term(const string_type& pattern, std::regex::flag_type flags) + : pattern_(pattern,flags) + { + } + + bool regex2(const string_type& subject) const override + { + return std::regex_match(subject, pattern_); + } +}; + +template <class Json> +class path_term final : public term<Json> +{ + typedef typename Json::string_type string_type; + + string_type path_; + Json nodes_; +public: + path_term(const string_type& path) + : path_(path) + { + } + + void initialize(const Json& context_node) override + { + jsonpath_evaluator<Json,const Json&,VoidPathConstructor<Json>> evaluator; + evaluator.evaluate(context_node,path_); + nodes_ = evaluator.get_values(); + } + + bool accept_single_node() const override + { + return nodes_.size() != 0; + } + + Json evaluate_single_node() const override + { + return nodes_.size() == 1 ? nodes_[0] : nodes_; + } + + bool exclaim() const override + { + return nodes_.size() == 0; + } + + bool eq_term(const term<Json>& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.eq(nodes_[i]); + } + } + return result; + } + + bool eq(const Json& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = nodes_[i] == rhs; + } + } + return result; + } + + bool ne_term(const term<Json>& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.ne(nodes_[i]); + } + } + return result; + + } + bool ne(const Json& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = nodes_[i] != rhs; + } + } + return result; + } + bool regex_term(const term<Json>& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.regex2(nodes_[i].as_string()); + } + } + return result; + } + bool ampamp_term(const term<Json>& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.ampamp(nodes_[i]); + } + } + return result; + } + bool ampamp(const Json& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = jsoncons::jsonpath::detail::ampamp(nodes_[i],rhs); + } + } + return result; + } + bool pipepipe_term(const term<Json>& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.pipepipe(nodes_[i]); + } + } + return result; + } + bool pipepipe(const Json& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = jsoncons::jsonpath::detail::pipepipe(nodes_[i],rhs); + } + } + return result; + } + + bool lt(const Json& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = jsoncons::jsonpath::detail::lt(nodes_[i],rhs); + } + } + return result; + } + + bool lt_term(const term<Json>& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.gt(nodes_[i]); + } + } + return result; + } + + bool gt(const Json& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = jsoncons::jsonpath::detail::gt(nodes_[i],rhs); + } + } + return result; + } + + bool gt_term(const term<Json>& rhs) const override + { + bool result = false; + if (nodes_.size() > 0) + { + result = true; + for (size_t i = 0; result && i < nodes_.size(); ++i) + { + result = rhs.lt(nodes_[i]); + } + } + return result; + } + + Json minus_term(const term<Json>& rhs) const override + { + static auto a_null = Json(jsoncons::null_type()); + return nodes_.size() == 1 ? rhs.left_minus(nodes_[0]) : a_null; + } + Json minus(const Json& rhs) const override + { + return nodes_.size() == 1 ? jsoncons::jsonpath::detail::minus(nodes_[0],rhs) : Json(jsoncons::null_type()); + } + + Json left_minus(const Json& lhs) const override + { + static auto a_null = Json(jsoncons::null_type()); + return nodes_.size() == 1 ? jsoncons::jsonpath::detail::minus(lhs,nodes_[0]) : a_null; + } + + Json unary_minus() const override + { + return nodes_.size() == 1 ? jsoncons::jsonpath::detail::unary_minus(nodes_[0]) : Json::null(); + } + + Json plus_term(const term<Json>& rhs) const override + { + static auto a_null = Json(jsoncons::null_type()); + return nodes_.size() == 1 ? rhs.plus(nodes_[0]) : a_null; + } + Json plus(const Json& rhs) const override + { + static auto a_null = Json(jsoncons::null_type()); + return nodes_.size() == 1 ? jsoncons::jsonpath::detail::plus(nodes_[0],rhs) : a_null; + } + + Json mult_term(const term<Json>& rhs) const override + { + static auto a_null = Json(jsoncons::null_type()); + return nodes_.size() == 1 ? rhs.mult(nodes_[0]) : a_null; + } + Json mult(const Json& rhs) const override + { + static auto a_null = Json(jsoncons::null_type()); + return nodes_.size() == 1 ? jsoncons::jsonpath::detail::mult(nodes_[0],rhs) : a_null; + } + + Json div_term(const term<Json>& rhs) const override + { + static auto a_null = Json(jsoncons::null_type()); + return nodes_.size() == 1 ? rhs.left_div(nodes_[0]) : a_null; + } + Json div(const Json& rhs) const override + { + static auto a_null = Json(jsoncons::null_type()); + return nodes_.size() == 1 ? jsoncons::jsonpath::detail::div(nodes_[0],rhs) : a_null; + } + + Json left_div(const Json& lhs) const override + { + static auto a_null = Json(jsoncons::null_type()); + return nodes_.size() == 1 ? jsoncons::jsonpath::detail::div(lhs, nodes_[0]) : a_null; + } +}; + +template <class Json> +token<Json> evaluate(const Json& context, std::vector<token<Json>>& tokens) +{ + for (auto it= tokens.begin(); it != tokens.end(); ++it) + { + it->initialize(context); + } + std::vector<token<Json>> stack; + for (auto t : tokens) + { + if (t.is_operand()) + { + stack.push_back(t); + } + else if (t.is_unary_operator()) + { + auto rhs = stack.back(); + stack.pop_back(); + Json val = t(rhs.operand()); + stack.push_back(token<Json>(token_type::operand,std::make_shared<value_term<Json>>(val))); + } + else if (t.is_binary_operator()) + { + auto rhs = stack.back(); + stack.pop_back(); + auto lhs = stack.back(); + stack.pop_back(); + Json val = t(lhs.operand(), rhs.operand()); + stack.push_back(token<Json>(token_type::operand,std::make_shared<value_term<Json>>(val))); + } + } + if (stack.size() != 1) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Invalid state")); + } + + return stack.back(); +} + +template <class Json> +class jsonpath_filter_expr +{ +public: + std::vector<token<Json>> tokens_; + size_t line_; + size_t column_; +public: + + jsonpath_filter_expr(const std::vector<token<Json>>& tokens, size_t line, size_t column) + : tokens_(tokens), line_(line), column_(column) + { + } + + Json eval(const Json& context_node) + { + try + { + auto t = evaluate(context_node,tokens_); + + return t.operand().evaluate_single_node(); + + } + catch (const parse_error& e) + { + throw parse_error(e.code(),line_,column_); + } + } + + bool exists(const Json& context_node) + { + try + { + auto t = evaluate(context_node,tokens_); + return t.operand().accept_single_node(); + } + catch (const parse_error& e) + { + throw parse_error(e.code(),line_,column_); + } + } +}; + +template <class Json> +class jsonpath_filter_parser +{ + typedef typename Json::string_type string_type; + typedef typename Json::string_view_type string_view_type; + typedef typename Json::char_type char_type; + + std::vector<token<Json>> output_stack_; + std::vector<token<Json>> operator_stack_; + std::vector<filter_state> state_stack_; + + size_t line_; + size_t column_; + + static const operator_properties<Json> op_properties_[]; + + class function_table + { + typedef std::map<string_type,function_properties<Json>> function_dictionary; + + const function_dictionary functions_ = + { + { + max_literal<char_type>(),{1,true,true,[](const term<Json>& term) + { + Json a = term.evaluate_single_node(); + + double v = std::numeric_limits<double>::lowest(); + for (const auto& elem : a.array_range()) + { + double x = elem. template as<double>(); + if (x > v) + { + v = x; + } + } + return v; + } + } + }, + { + min_literal<char_type>(),{1,true,true,[](const term<Json>& term) + { + Json a = term.evaluate_single_node(); + + double v = (std::numeric_limits<double>::max)(); + for (const auto& elem : a.array_range()) + { + double x = elem. template as<double>(); + if (x < v) + { + v = x; + } + } + return v; + } + } + } + }; + + public: + + typename function_dictionary::const_iterator find(const string_type& key) const + { + return functions_.find(key); + } + typename function_dictionary::const_iterator end() const + { + return functions_.end(); + } + }; + + class binary_operator_table + { + typedef std::map<string_type,operator_properties<Json>> binary_operator_map; + + const binary_operator_map operators = + { + {eqtilde_literal<char_type>(),{2,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.regex_term(b)); }}}, + {star_literal<char_type>(),{3,false,[](const term<Json>& a, const term<Json>& b) {return a.mult_term(b); }}}, + {forwardslash_literal<char_type>(),{3,false,[](const term<Json>& a, const term<Json>& b) {return a.div_term(b); }}}, + {plus_literal<char_type>(),{4,false,[](const term<Json>& a, const term<Json>& b) {return a.plus_term(b); }}}, + {minus_literal<char_type>(),{4,false,[](const term<Json>& a, const term<Json>& b) {return a.minus_term(b); }}}, + {lt_literal<char_type>(),{5,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.lt_term(b)); }}}, + {lte_literal<char_type>(),{5,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.lt_term(b) || a.eq_term(b)); }}}, + {gt_literal<char_type>(),{5,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.gt_term(b)); }}}, + {gte_literal<char_type>(),{5,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.gt_term(b) || a.eq_term(b)); }}}, + {eq_literal<char_type>(),{6,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.eq_term(b)); }}}, + {ne_literal<char_type>(),{6,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.ne_term(b)); }}}, + {ampamp_literal<char_type>(),{7,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.ampamp_term(b)); }}}, + {pipepipe_literal<char_type>(),{8,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.pipepipe_term(b)); }}} + }; + + public: + typename binary_operator_map::const_iterator find(const string_type& key) const + { + return operators.find(key); + } + typename binary_operator_map::const_iterator end() const + { + return operators.end(); + } + }; + + function_table functions_; + binary_operator_table binary_operators_; + +public: + jsonpath_filter_parser() + : line_(1), column_(1) + { + } + jsonpath_filter_parser(size_t line, size_t column) + : line_(line), column_(column) + { + } + + size_t line() const + { + return line_; + } + + size_t column() const + { + return column_; + } + + jsonpath_filter_expr<Json> parse(const Json& root, const char_type* p, size_t length, const char_type** end_ptr) + { + return parse(root, p,p+length, end_ptr); + } + + void push_state(filter_state state) + { + state_stack_.push_back(state); + } + + filter_state pop_state() + { + if (state_stack_.empty()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Invalid state")); + } + filter_state state = state_stack_.back(); + state_stack_.pop_back(); + return state; + } + + void add_token(token<Json> token) + { + if (token.is_operand()) + { + output_stack_.push_back(token); + } + else if (token.is_lparen()) + { + operator_stack_.push_back(token); + } + else if (token.is_rparen()) + { + auto it = operator_stack_.rbegin(); + while (it != operator_stack_.rend() && !it->is_lparen()) + { + output_stack_.push_back(*it); + ++it; + } + if (it == operator_stack_.rend()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Unbalanced parenthesis")); + } + operator_stack_.erase(it.base(),operator_stack_.end()); + operator_stack_.pop_back(); + } + else if (token.is_operator()) + { + if (operator_stack_.empty() || operator_stack_.back().is_lparen()) + { + operator_stack_.push_back(token); + } + else if (token.precedence_level() < operator_stack_.back().precedence_level() + || (token.precedence_level() == operator_stack_.back().precedence_level() && token.is_right_associative())) + { + operator_stack_.push_back(token); + } + else + { + auto it = operator_stack_.rbegin(); + while (it != operator_stack_.rend() && it->is_operator() + && (token.precedence_level() > it->precedence_level() + || (token.precedence_level() == it->precedence_level() && token.is_right_associative()))) + { + output_stack_.push_back(*it); + ++it; + } + + operator_stack_.erase(it.base(),operator_stack_.end()); + operator_stack_.push_back(token); + } + } + } + + jsonpath_filter_expr<Json> parse(const Json& root, const char_type* p, const char_type* end_expr, const char_type** end_ptr) + { + output_stack_.clear(); + operator_stack_.clear(); + state_stack_.clear(); + + string_type buffer; + + int depth = 0; + filter_state state = filter_state::start; + while (p < end_expr && state != filter_state::done) + { + switch (state) + { + case filter_state::cr: + ++line_; + column_ = 1; + switch (*p) + { + case '\n': + state = pop_state(); + ++p; + ++column_; + break; + default: + state = pop_state(); + break; + } + break; + case filter_state::lf: + ++line_; + column_ = 1; + state = pop_state(); + break; + case filter_state::start: + switch (*p) + { + case '\r': + push_state(state); + state = filter_state::cr; + break; + case '\n': + push_state(state); + state = filter_state::lf; + break; + case '(': + state = filter_state::expect_path_or_value_or_unary_op; + ++depth; + add_token(token<Json>(token_type::lparen)); + break; + case ')': + state = filter_state::expect_path_or_value_or_unary_op; + add_token(token<Json>(token_type::rparen)); + if (--depth == 0) + { + state = filter_state::done; + } + break; + } + ++p; + ++column_; + break; + case filter_state::function_argument: + { + switch (*p) + { + case '\r': + push_state(state); + state = filter_state::cr; + break; + case '\n': + push_state(state); + state = filter_state::lf; + break; + case ' ':case '\t': + break; + case ')': + if (buffer.length() > 0) + { + if (operator_stack_.back().is_aggregate()) + { + try + { + // path, parse against root, get value + jsonpath_evaluator<Json,const Json&,detail::VoidPathConstructor<Json>> evaluator; + evaluator.evaluate(root,buffer.data(),buffer.length()); + auto result = evaluator.get_values(); + add_token(token<Json>(token_type::operand,std::make_shared<value_term<Json>>(result))); + } + catch (const parse_error& e) + { + throw parse_error(e.code(),line_,column_); + } + } + else + { + add_token(token<Json>(token_type::operand,std::make_shared<path_term<Json>>(buffer))); + } + buffer.clear(); + state = filter_state::expect_oper_or_right_round_bracket; + } + break; + default: + buffer.push_back(*p); + break; + } + ++p; + ++column_; + } + break; + case filter_state::oper: + switch (*p) + { + case '~': + { + buffer.push_back(*p); + ++p; + ++column_; + auto it = binary_operators_.find(buffer); + if (it == binary_operators_.end()) + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator, line_, column_); + } + buffer.clear(); + add_token(token<Json>(it->second)); + state = filter_state::expect_regex; + } + break; + case '=': + case '&': + case '|': + { + buffer.push_back(*p); + ++p; + ++column_; + auto it = binary_operators_.find(buffer); + if (it == binary_operators_.end()) + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator, line_, column_); + } + buffer.clear(); + add_token(token<Json>(it->second)); + state = filter_state::expect_path_or_value_or_unary_op; + } + break; + default: + { + auto it = binary_operators_.find(buffer); + if (it == binary_operators_.end()) + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator, line_, column_); + } + buffer.clear(); + add_token(token<Json>(it->second)); + state = filter_state::expect_path_or_value_or_unary_op; + } + break; + } + break; + case filter_state::unquoted_text: + { + switch (*p) + { + case ' ':case '\t': + if (buffer.length() > 0) + { + try + { + auto val = Json::parse(buffer); + add_token(token<Json>(token_type::operand,std::make_shared<value_term<Json>>(val))); + } + catch (const parse_error& e) + { + throw parse_error(e.code(),line_,column_); + } + buffer.clear(); + } + ++p; + ++column_; + break; + case '(': + { + auto it = functions_.find(buffer); + if (it == functions_.end()) + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unsupported_operator,line_,column_); + } + add_token(token<Json>(it->second)); + state = filter_state::function_argument; + buffer.clear(); + ++p; + ++column_; + break; + } + case '<': + case '>': + case '!': + case '=': + case '&': + case '|': + case '+': + case '-': + case '*': + case '/': + { + if (buffer.length() > 0) + { + try + { + auto val = Json::parse(buffer); + add_token(token<Json>(token_type::operand,std::make_shared<value_term<Json>>(val))); + } + catch (const parse_error& e) + { + throw parse_error(e.code(),line_,column_); + } + buffer.clear(); + } + buffer.push_back(*p); + state = filter_state::oper; + ++p; + ++column_; + } + break; + case ')': + if (buffer.length() > 0) + { + try + { + auto val = Json::parse(buffer); + add_token(token<Json>(token_type::operand,std::make_shared<value_term<Json>>(val))); + } + catch (const parse_error& e) + { + throw parse_error(e.code(),line_,column_); + } + buffer.clear(); + } + add_token(token<Json>(token_type::rparen)); + if (--depth == 0) + { + state = filter_state::done; + } + else + { + state = filter_state::expect_path_or_value_or_unary_op; + } + ++p; + ++column_; + break; + default: + buffer.push_back(*p); + ++p; + ++column_; + break; + } + } + break; + case filter_state::single_quoted_text: + { + switch (*p) + { + case '\\': + buffer.push_back(*p); + if (p+1 < end_expr) + { + ++p; + ++column_; + buffer.push_back(*p); + } + break; + case '\'': + buffer.push_back('\"'); + //if (buffer.length() > 0) + { + try + { + auto val = Json::parse(buffer); + add_token(token<Json>(token_type::operand,std::make_shared<value_term<Json>>(val))); + } + catch (const parse_error& e) + { + throw parse_error(e.code(),line_,column_); + } + buffer.clear(); + } + state = filter_state::expect_path_or_value_or_unary_op; + break; + + default: + buffer.push_back(*p); + break; + } + } + ++p; + ++column_; + break; + case filter_state::double_quoted_text: + { + switch (*p) + { + case '\\': + buffer.push_back(*p); + if (p+1 < end_expr) + { + ++p; + ++column_; + buffer.push_back(*p); + } + break; + case '\"': + buffer.push_back(*p); + //if (buffer.length() > 0) + { + try + { + auto val = Json::parse(buffer); + add_token(token<Json>(token_type::operand,std::make_shared<value_term<Json>>(val))); + } + catch (const parse_error& e) + { + throw parse_error(e.code(),line_,column_); + } + buffer.clear(); + } + state = filter_state::expect_path_or_value_or_unary_op; + break; + + default: + buffer.push_back(*p); + break; + } + } + ++p; + ++column_; + break; + case filter_state::expect_path_or_value_or_unary_op: + switch (*p) + { + case '\r': + push_state(state); + state = filter_state::cr; + ++p; + break; + case '\n': + push_state(state); + state = filter_state::lf; + ++p; + break; + case ' ':case '\t': + ++p; + ++column_; + break; + case '!': + { + std::function<Json(const term<Json>&)> f = [](const term<Json>& b) {return Json(b.exclaim());}; + add_token(token<Json>(1, true, f)); + ++p; + ++column_; + break; + } + case '-': + { + std::function<Json(const term<Json>&)> f = [](const term<Json>& b) {return b.unary_minus();}; + add_token(token<Json>(1, true, f)); + ++p; + ++column_; + break; + } + case '@': + buffer.push_back(*p); + state = filter_state::path; + ++p; + ++column_; + break; + case '\'': + buffer.push_back('\"'); + state = filter_state::single_quoted_text; + ++p; + ++column_; + break; + case '\"': + buffer.push_back(*p); + state = filter_state::double_quoted_text; + ++p; + ++column_; + break; + case '(': + ++depth; + add_token(token<Json>(token_type::lparen)); + ++p; + ++column_; + break; + case ')': + add_token(token<Json>(token_type::rparen)); + if (--depth == 0) + { + state = filter_state::done; + } + ++p; + ++column_; + break; + default: + // don't increment + state = filter_state::unquoted_text; + break; + }; + break; + case filter_state::expect_oper_or_right_round_bracket: + switch (*p) + { + case '\r': + push_state(state); + state = filter_state::cr; + ++p; + break; + case '\n': + push_state(state); + state = filter_state::lf; + ++p; + break; + case ' ':case '\t': + ++p; + ++column_; + break; + case ')': + add_token(token<Json>(token_type::rparen)); + if (--depth == 0) + { + state = filter_state::done; + ++p; // fix + } + break; + case '<': + case '>': + case '!': + case '=': + case '&': + case '|': + case '+': + case '-': + case '*': + case '/': + { + buffer.push_back(*p); + state = filter_state::oper; + ++p; + ++column_; + } + break; + default: + throw parse_error(jsonpath_parser_errc::invalid_filter,line_,column_); + break; + }; + break; + case filter_state::expect_right_round_bracket: + switch (*p) + { + case '\r': + push_state(state); + state = filter_state::cr; + break; + case '\n': + push_state(state); + state = filter_state::lf; + break; + case ' ':case '\t': + break; + case ')': + add_token(token<Json>(token_type::rparen)); + if (--depth == 0) + { + state = filter_state::done; + } + else + { + state = filter_state::expect_oper_or_right_round_bracket; + } + break; + default: + throw parse_error(jsonpath_parser_errc::invalid_filter,line_,column_); + break; + }; + ++p; + ++column_; + break; + case filter_state::path: + switch (*p) + { + case '<': + case '>': + case '!': + case '=': + case '&': + case '|': + case '+': + case '-': + case '*': + case '/': + { + if (buffer.length() > 0) + { + add_token(token<Json>(token_type::operand,std::make_shared<path_term<Json>>(buffer))); + buffer.clear(); + } + buffer.push_back(*p); + ++p; + ++column_; + state = filter_state::oper; + } + break; + case ')': + if (buffer.length() > 0) + { + add_token(token<Json>(token_type::operand,std::make_shared<path_term<Json>>(buffer))); + add_token(token<Json>(token_type::rparen)); + buffer.clear(); + } + if (--depth == 0) + { + state = filter_state::done; + } + else + { + state = filter_state::expect_path_or_value_or_unary_op; + } + ++p; + ++column_; + break; + default: + buffer.push_back(*p); + ++p; + ++column_; + break; + }; + break; + case filter_state::expect_regex: + switch (*p) + { + case '\r': + push_state(state); + state = filter_state::cr; + break; + case '\n': + push_state(state); + state = filter_state::lf; + break; + case ' ':case '\t': + break; + case '/': + state = filter_state::regex; + break; + default: + throw parse_error(jsonpath_parser_errc::invalid_filter_expected_slash,line_,column_); + break; + }; + ++p; + ++column_; + break; + case filter_state::regex: + { + switch (*p) + { + case '/': + //if (buffer.length() > 0) + { + std::regex::flag_type flags = std::regex_constants::ECMAScript; + if (p+1 < end_expr && *(p+1) == 'i') + { + ++p; + ++column_; + flags |= std::regex_constants::icase; + } + add_token(token<Json>(token_type::operand,std::make_shared<regex_term<Json>>(buffer,flags))); + buffer.clear(); + } + state = filter_state::expect_path_or_value_or_unary_op; + break; + + default: + buffer.push_back(*p); + break; + } + } + ++p; + ++column_; + break; + default: + ++p; + ++column_; + break; + } + } + if (depth != 0) + { + throw parse_error(jsonpath_parser_errc::invalid_filter_unbalanced_paren,line_,column_); + } + *end_ptr = p; + + return jsonpath_filter_expr<Json>(output_stack_,line_,column_); + } +}; + +template <class Json> +const operator_properties<Json> jsonpath_filter_parser<Json>::op_properties_[] = +{ + {2,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.regex_term(b));}}, + {3,false,[](const term<Json>& a, const term<Json>& b) {return a.mult_term(b);}}, + {3,false,[](const term<Json>& a, const term<Json>& b) {return a.div_term(b);}}, + {4,false,[](const term<Json>& a, const term<Json>& b) {return a.plus_term(b);}}, + {4,false,[](const term<Json>& a, const term<Json>& b) {return a.minus_term(b);}}, + {5,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.lt_term(b));}}, + {5,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.lt_term(b) || a.eq_term(b));}}, + {5,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.gt_term(b));}}, + {5,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.gt_term(b) || a.eq_term(b));}}, + {6,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.eq_term(b)); }}, + {6,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.ne_term(b)); }}, + {7,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.ampamp_term(b));}}, + {8,false,[](const term<Json>& a, const term<Json>& b) {return Json(a.pipepipe_term(b));}} +}; + +}}} + +#endif
\ No newline at end of file diff --git a/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpointer/jsonpointer.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpointer/jsonpointer.hpp new file mode 100644 index 00000000..56b4efa2 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpointer/jsonpointer.hpp @@ -0,0 +1,810 @@ +// Copyright 2017 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONPOINTER_JSONPOINTER_HPP +#define JSONCONS_JSONPOINTER_JSONPOINTER_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <memory> +#include <jsoncons/json.hpp> +#include <jsoncons_ext/jsonpointer/jsonpointer_error_category.hpp> + +namespace jsoncons { namespace jsonpointer { + +class jsonpointer_error : public std::exception, public virtual json_exception +{ +public: + jsonpointer_error(const std::error_code& ec) + : error_code_(ec) + { + } + jsonpointer_error(const jsonpointer_error& other) = default; + + jsonpointer_error(jsonpointer_error&& other) = default; + + const char* what() const JSONCONS_NOEXCEPT override + { + try + { + const_cast<std::string&>(buffer_) = error_code_.message(); + return buffer_.c_str(); + } + catch (...) + { + return ""; + } + } + + const std::error_code code() const + { + return error_code_; + } + + jsonpointer_error& operator=(const jsonpointer_error& e) = default; + jsonpointer_error& operator=(jsonpointer_error&& e) = default; +private: + std::string buffer_; + std::error_code error_code_; +}; + +namespace detail { + +enum class pointer_state +{ + start, + array_reference_token, + zero_array_reference_token, + nonzero_array_reference_token, + after_last_array_reference_token, + object_reference_token, + escaped +}; +template <class Json,class JsonReference, class Enable = void> +class json_wrapper +{ +}; + +template <class Json,class JsonReference> +class json_wrapper<Json,JsonReference,typename std::enable_if<std::is_reference<decltype(std::declval<Json>().at(typename Json::string_view_type()))>::value>::type> +{ +public: + using reference = JsonReference; + using pointer = typename std::conditional<std::is_const<typename std::remove_reference<JsonReference>::type>::value,typename Json::const_pointer,typename Json::pointer>::type; + + json_wrapper(reference ref) JSONCONS_NOEXCEPT + : ptr_(std::addressof(ref)) + { + } + + json_wrapper(const json_wrapper&) JSONCONS_NOEXCEPT = default; + + json_wrapper& operator=(const json_wrapper&) JSONCONS_NOEXCEPT = default; + + reference get() const JSONCONS_NOEXCEPT + { + return *ptr_; + } +private: + pointer ptr_; +}; + +template <class Json,class JsonReference> +class json_wrapper<Json,JsonReference,typename std::enable_if<!std::is_reference<decltype(std::declval<Json>().at(typename Json::string_view_type()))>::value>::type> +{ +public: + using value_type = typename Json::value_type; + using reference = JsonReference; + using pointer = typename std::conditional<std::is_const<typename std::remove_reference<JsonReference>::type>::value,typename Json::const_pointer,typename Json::pointer>::type; + + json_wrapper(reference ref) JSONCONS_NOEXCEPT + : val_(ref) + { + } + + json_wrapper(const json_wrapper& w) JSONCONS_NOEXCEPT + : val_(w.val_) + { + } + + json_wrapper& operator=(const json_wrapper&) JSONCONS_NOEXCEPT = default; + + value_type get() const JSONCONS_NOEXCEPT + { + return val_; + } +private: + value_type val_; +}; + +template<class Json,class JsonReference> +struct path_resolver +{ + typedef typename Json::string_type string_type; + typedef typename Json::string_view_type string_view_type; + using reference = JsonReference; + using pointer = typename std::conditional<std::is_const<typename std::remove_reference<JsonReference>::type>::value,typename Json::const_pointer,typename Json::pointer>::type; + + jsonpointer_errc operator()(std::vector<json_wrapper<Json,JsonReference>>& current, + size_t index) const + { + if (index >= current.back().get().size()) + { + return jsonpointer_errc::index_exceeds_array_size; + } + current.push_back(current.back().get().at(index)); + return jsonpointer_errc(); + } + + jsonpointer_errc operator()(std::vector<json_wrapper<Json,JsonReference>>& current, + const string_view_type& name) const + { + if (!current.back().get().has_key(name)) + { + return jsonpointer_errc::name_not_found; + } + current.push_back(current.back().get().at(name)); + return jsonpointer_errc(); + } +}; + +template<class Json, class JsonReference> +struct path_setter +{ + typedef typename Json::string_type string_type; + typedef typename Json::string_view_type string_view_type; + using reference = JsonReference; + using pointer = typename std::conditional<std::is_const<typename std::remove_reference<JsonReference>::type>::value,typename Json::const_pointer,typename Json::pointer>::type; + + jsonpointer_errc operator()(std::vector<json_wrapper<Json,JsonReference>>& current, + size_t index) const + { + if (index >= current.back().get().size()) + { + return jsonpointer_errc::index_exceeds_array_size; + } + current.push_back(current.back().get().at(index)); + return jsonpointer_errc(); + } + + jsonpointer_errc operator()(std::vector<json_wrapper<Json,JsonReference>>& current, + const string_view_type& name) const + { + jsonpointer_errc ec = jsonpointer_errc(); + if (!current.back().get().has_key(name)) + { + return jsonpointer_errc::name_not_found; + } + current.push_back(current.back().get().at(name)); + return ec; + } +}; + +template<class Json,class JsonReference> +class jsonpointer_evaluator : private parsing_context +{ + typedef typename Json::string_type string_type; + typedef typename string_type::value_type char_type; + typedef typename Json::string_view_type string_view_type; + using reference = JsonReference; + using pointer = typename std::conditional<std::is_const<typename std::remove_reference<JsonReference>::type>::value,typename Json::const_pointer,typename Json::pointer>::type; + + jsonpointer::detail::pointer_state state_; + size_t line_; + size_t column_; + const char_type* begin_input_; + const char_type* end_input_; + const char_type* p_; + string_type buffer_; + size_t index_; + std::vector<json_wrapper<Json,JsonReference>> current_; +public: + Json get_result() + { + return std::move(current_.back().get()); + } + + size_t line_number() const + { + return line_; + } + + size_t column_number() const + { + return column_; + } + + jsonpointer_errc get(reference root, const string_view_type& path) + { + path_resolver<Json,reference> op; + jsonpointer_errc ec = evaluate(root,op,path); + if (ec != jsonpointer_errc()) + { + return ec; + } + + switch (state_) + { + case pointer_state::start: + break; + case pointer_state::zero_array_reference_token: + case pointer_state::nonzero_array_reference_token: + ec = op(current_,index_); + break; + case pointer_state::object_reference_token: + ec = op(current_,buffer_); + break; + default: + return jsonpointer_errc::end_of_input; + } + return ec; + } + + string_type normalized_path(reference root, const string_view_type& path) + { + jsonpointer_errc ec = evaluate(root,path_setter<Json,reference>(),path); + if (ec != jsonpointer_errc()) + { + return string_type(path); + } + if (state_ == jsonpointer::detail::pointer_state::after_last_array_reference_token) + { + string_type p = string_type(path.substr(0,path.length()-1)); + std::string s = std::to_string(current_.back().get().size()); + for (auto c : s) + { + p.push_back(c); + } + return p; + } + else + { + return string_type(path); + } + } + + jsonpointer_errc insert_or_assign(reference root, const string_view_type& path, const Json& value) + { + jsonpointer_errc ec = evaluate(root,path_setter<Json,reference>(),path); + if (ec != jsonpointer_errc()) + { + return ec; + } + + switch (state_) + { + case jsonpointer::detail::pointer_state::start: + break; + case jsonpointer::detail::pointer_state::zero_array_reference_token: + case jsonpointer::detail::pointer_state::nonzero_array_reference_token: + if (index_ > current_.back().get().size()) + { + return jsonpointer_errc::index_exceeds_array_size; + } + if (index_ == current_.back().get().size()) + { + current_.back().get().push_back(value); + } + else + { + current_.back().get().insert(current_.back().get().array_range().begin()+index_,value); + } + break; + case jsonpointer::detail::pointer_state::after_last_array_reference_token: + current_.back().get().push_back(value); + break; + case jsonpointer::detail::pointer_state::object_reference_token: + current_.back().get().insert_or_assign(buffer_,value); + break; + default: + return jsonpointer_errc::end_of_input; + } + return ec; + } + + jsonpointer_errc insert(reference root, const string_view_type& path, const Json& value) + { + jsonpointer_errc ec = evaluate(root,path_setter<Json,reference>(),path); + if (ec != jsonpointer_errc()) + { + return ec; + } + + switch (state_) + { + case jsonpointer::detail::pointer_state::start: + break; + case jsonpointer::detail::pointer_state::zero_array_reference_token: + case jsonpointer::detail::pointer_state::nonzero_array_reference_token: + if (index_ > current_.back().get().size()) + { + return jsonpointer_errc::index_exceeds_array_size; + } + if (index_ == current_.back().get().size()) + { + current_.back().get().push_back(value); + } + else + { + current_.back().get().insert(current_.back().get().array_range().begin()+index_,value); + } + break; + case jsonpointer::detail::pointer_state::after_last_array_reference_token: + current_.back().get().push_back(value); + break; + case jsonpointer::detail::pointer_state::object_reference_token: + if (current_.back().get().has_key(buffer_)) + { + ec = jsonpointer_errc::key_already_exists; + } + else + { + current_.back().get().insert_or_assign(buffer_,value); + } + break; + default: + return jsonpointer_errc::end_of_input; + } + return ec; + } + + jsonpointer_errc remove(reference root, const string_view_type& path) + { + jsonpointer_errc ec = evaluate(root,path_resolver<Json,reference>(),path); + if (ec != jsonpointer_errc()) + { + return ec; + } + + switch (state_) + { + case jsonpointer::detail::pointer_state::start: + break; + case jsonpointer::detail::pointer_state::zero_array_reference_token: + case jsonpointer::detail::pointer_state::nonzero_array_reference_token: + if (index_ >= current_.back().get().size()) + { + return jsonpointer_errc::index_exceeds_array_size; + } + current_.back().get().erase(current_.back().get().array_range().begin()+index_); + break; + case jsonpointer::detail::pointer_state::after_last_array_reference_token: + return jsonpointer_errc::index_exceeds_array_size; + case jsonpointer::detail::pointer_state::object_reference_token: + if (!current_.back().get().has_key(buffer_)) + { + return jsonpointer_errc::name_not_found; + } + current_.back().get().erase(buffer_); + break; + default: + return jsonpointer_errc::end_of_input; + } + return ec; + } + + jsonpointer_errc replace(reference root, const string_view_type& path, const Json& value) + { + jsonpointer_errc ec = evaluate(root,path_resolver<Json,reference>(),path); + if (ec != jsonpointer_errc()) + { + return ec; + } + + switch (state_) + { + case jsonpointer::detail::pointer_state::start: + break; + case jsonpointer::detail::pointer_state::zero_array_reference_token: + case jsonpointer::detail::pointer_state::nonzero_array_reference_token: + if (index_ >= current_.back().get().size()) + { + return jsonpointer_errc::index_exceeds_array_size; + } + (current_.back().get())[index_] = value; + break; + case jsonpointer::detail::pointer_state::after_last_array_reference_token: + return jsonpointer_errc::index_exceeds_array_size; + case jsonpointer::detail::pointer_state::object_reference_token: + if (!current_.back().get().has_key(buffer_)) + { + return jsonpointer_errc::name_not_found; + } + current_.back().get().insert_or_assign(buffer_,value); + break; + default: + return jsonpointer_errc::end_of_input; + } + return jsonpointer_errc(); + } + + template <class Op> + jsonpointer_errc evaluate(reference root, Op op, const string_view_type& path) + { + jsonpointer_errc ec = jsonpointer_errc(); + + line_ = 1; + column_ = 1; + state_ = jsonpointer::detail::pointer_state::start; + begin_input_ = path.data(); + end_input_ = path.data() + path.length(); + p_ = begin_input_; + + index_ = 0; + + current_.push_back(root); + + while (p_ < end_input_) + { + switch (state_) + { + case jsonpointer::detail::pointer_state::start: + switch (*p_) + { + case '/': + if (current_.back().get().is_array()) + { + state_ = jsonpointer::detail::pointer_state::array_reference_token; + index_ = 0; + } + else if (current_.back().get().is_object()) + { + state_ = jsonpointer::detail::pointer_state::object_reference_token; + buffer_.clear(); + } + else + { + return jsonpointer_errc::expected_object_or_array; + } + break; + default: + return jsonpointer_errc::expected_slash; + }; + ++p_; + ++column_; + break; + case jsonpointer::detail::pointer_state::array_reference_token: + switch (*p_) + { + case '0': + index_ = 0; + state_ = jsonpointer::detail::pointer_state::zero_array_reference_token; + break; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + index_ = (*p_ - '0'); + state_ = jsonpointer::detail::pointer_state::nonzero_array_reference_token; + break; + case '-': + state_ = jsonpointer::detail::pointer_state::after_last_array_reference_token; + break; + default: + return jsonpointer_errc::expected_digit_or_dash; + }; + ++p_; + ++column_; + break; + case jsonpointer::detail::pointer_state::zero_array_reference_token: + switch (*p_) + { + case '/': + ec = op(current_,index_); + if (ec != jsonpointer_errc()) + { + return ec; + } + if (current_.back().get().is_array()) + { + state_ = jsonpointer::detail::pointer_state::array_reference_token; + index_ = 0; + } + else if (current_.back().get().is_object()) + { + state_ = jsonpointer::detail::pointer_state::object_reference_token; + buffer_.clear(); + } + else + { + return jsonpointer_errc::expected_object_or_array; + } + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return jsonpointer_errc::unexpected_leading_zero; + case '-': + return jsonpointer_errc::index_exceeds_array_size; + default: + return jsonpointer_errc::expected_digit_or_dash; + }; + ++p_; + ++column_; + break; + case jsonpointer::detail::pointer_state::after_last_array_reference_token: + switch (*p_) + { + case '/': + return jsonpointer_errc::index_exceeds_array_size; + default: + return jsonpointer_errc::expected_slash; + }; + ++p_; + ++column_; + break; + case jsonpointer::detail::pointer_state::nonzero_array_reference_token: + switch (*p_) + { + case '/': + ec = op(current_,index_); + if (ec != jsonpointer_errc()) + { + return ec; + } + if (current_.back().get().is_array()) + { + state_ = jsonpointer::detail::pointer_state::array_reference_token; + index_ = 0; + } + else if (current_.back().get().is_object()) + { + state_ = jsonpointer::detail::pointer_state::object_reference_token; + buffer_.clear(); + } + else + { + return jsonpointer_errc::expected_object_or_array; + } + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + index_ = index_ * 10 + (*p_ - '0'); + break; + case '-': + return jsonpointer_errc::index_exceeds_array_size; + default: + return jsonpointer_errc::expected_digit_or_dash; + }; + ++p_; + ++column_; + break; + case jsonpointer::detail::pointer_state::object_reference_token: + switch (*p_) + { + case '/': + ec = op(current_,buffer_); + if (ec != jsonpointer_errc()) + { + return ec; + } + if (current_.back().get().is_array()) + { + state_ = jsonpointer::detail::pointer_state::array_reference_token; + index_ = 0; + } + else if (current_.back().get().is_object()) + { + state_ = jsonpointer::detail::pointer_state::object_reference_token; + buffer_.clear(); + } + else + { + return jsonpointer_errc::expected_object_or_array; + } + break; + case '~': + state_ = jsonpointer::detail::pointer_state::escaped; + break; + default: + buffer_.push_back(*p_); + break; + }; + ++p_; + ++column_; + break; + case jsonpointer::detail::pointer_state::escaped: + switch (*p_) + { + case '0': + buffer_.push_back('~'); + state_ = jsonpointer::detail::pointer_state::object_reference_token; + break; + case '1': + buffer_.push_back('/'); + state_ = jsonpointer::detail::pointer_state::object_reference_token; + break; + default: + return jsonpointer_errc::expected_0_or_1; + }; + ++p_; + ++column_; + break; + } + } + return ec; + } + +private: + + // parsing_context + + size_t do_line_number() const override + { + return line_; + } + + size_t do_column_number() const override + { + return column_; + } +}; + +} + +template<class Json> +typename Json::string_type normalized_path(const Json& root, const typename Json::string_view_type& path) +{ + detail::jsonpointer_evaluator<Json,const Json&> evaluator; + return evaluator.normalized_path(root,path); +} + +template<class Json> +Json get(const Json& root, const typename Json::string_view_type& path) +{ + detail::jsonpointer_evaluator<Json,const Json&> evaluator; + jsonpointer_errc ec = evaluator.get(root,path); + if (ec != jsonpointer_errc()) + { + JSONCONS_THROW(jsonpointer_error(ec)); + } + return evaluator.get_result(); +} + +template<class Json> +Json get(const Json& root, const typename Json::string_view_type& path, std::error_code& ec) +{ + detail::jsonpointer_evaluator<Json,const Json&> evaluator; + ec = evaluator.get(root,path); + return evaluator.get_result(); +} + +template<class Json> +bool contains(const Json& root, const typename Json::string_view_type& path) +{ + detail::jsonpointer_evaluator<Json,const Json&> evaluator; + jsonpointer_errc ec = evaluator.get(root,path); + return ec == jsonpointer_errc() ? true : false; +} + +template<class Json> +void insert_or_assign(Json& root, const typename Json::string_view_type& path, const Json& value) +{ + detail::jsonpointer_evaluator<Json,Json&> evaluator; + + jsonpointer_errc ec = evaluator.insert_or_assign(root,path,value); + if (ec != jsonpointer_errc()) + { + JSONCONS_THROW(jsonpointer_error(ec)); + } +} + +template<class Json> +void insert_or_assign(Json& root, const typename Json::string_view_type& path, const Json& value, std::error_code& ec) +{ + detail::jsonpointer_evaluator<Json,Json&> evaluator; + + ec = evaluator.insert_or_assign(root,path,value); +} + +template<class Json> +void insert(Json& root, const typename Json::string_view_type& path, const Json& value) +{ + detail::jsonpointer_evaluator<Json,Json&> evaluator; + + jsonpointer_errc ec = evaluator.insert(root,path,value); + if (ec != jsonpointer_errc()) + { + JSONCONS_THROW(jsonpointer_error(ec)); + } +} + +template<class Json> +void insert(Json& root, const typename Json::string_view_type& path, const Json& value, std::error_code& ec) +{ + detail::jsonpointer_evaluator<Json,Json&> evaluator; + + ec = evaluator.insert(root,path,value); +} + +template<class Json> +void remove(Json& root, const typename Json::string_view_type& path) +{ + detail::jsonpointer_evaluator<Json,Json&> evaluator; + + jsonpointer_errc ec = evaluator.remove(root,path); + if (ec != jsonpointer_errc()) + { + JSONCONS_THROW(jsonpointer_error(ec)); + } +} + +template<class Json> +void remove(Json& root, const typename Json::string_view_type& path, std::error_code& ec) +{ + detail::jsonpointer_evaluator<Json,Json&> evaluator; + + ec = evaluator.remove(root,path); +} + +template<class Json> +void replace(Json& root, const typename Json::string_view_type& path, const Json& value) +{ + detail::jsonpointer_evaluator<Json,Json&> evaluator; + + jsonpointer_errc ec = evaluator.replace(root,path,value); + if (ec != jsonpointer_errc()) + { + JSONCONS_THROW(jsonpointer_error(ec)); + } +} + +template<class Json> +void replace(Json& root, const typename Json::string_view_type& path, const Json& value, std::error_code& ec) +{ + detail::jsonpointer_evaluator<Json,Json&> evaluator; + + ec = evaluator.replace(root,path,value); +} + +template <class String> +void escape(const String& s, std::basic_ostringstream<typename String::value_type>& os) +{ + for (auto c : s) + { + if (c == '~') + { + os.put('~'); + os.put('0'); + } + else if (c == '/') + { + os.put('~'); + os.put('1'); + } + else + { + os.put(c); + } + } +} + +}} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpointer/jsonpointer_error_category.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpointer/jsonpointer_error_category.hpp new file mode 100644 index 00000000..01ddc9dc --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/jsonpointer/jsonpointer_error_category.hpp @@ -0,0 +1,87 @@ +/// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_JSONPOINTER_JSONPOINTER_ERROR_CATEGORY_HPP +#define JSONCONS_JSONPOINTER_JSONPOINTER_ERROR_CATEGORY_HPP + +#include <jsoncons/json_exception.hpp> +#include <system_error> + +namespace jsoncons { namespace jsonpointer { + +enum class jsonpointer_errc +{ + ok = 0, + expected_slash = 1, + expected_digit_or_dash, + unexpected_leading_zero, + index_exceeds_array_size, + expected_0_or_1, + name_not_found, + key_already_exists, + expected_object_or_array, + end_of_input +}; + +class jsonpointer_error_category_impl + : public std::error_category +{ +public: + virtual const char* name() const JSONCONS_NOEXCEPT + { + return "jsoncons.jsonpointer"; + } + virtual std::string message(int ev) const + { + switch (static_cast<jsonpointer_errc>(ev)) + { + case jsonpointer_errc::expected_slash: + return "Expected /"; + case jsonpointer_errc::expected_digit_or_dash: + return "Expected digit or '-'"; + case jsonpointer_errc::unexpected_leading_zero: + return "Unexpected leading zero"; + case jsonpointer_errc::index_exceeds_array_size: + return "Index exceeds array size"; + case jsonpointer_errc::expected_0_or_1: + return "Expected '0' or '1' after escape character '~'"; + case jsonpointer_errc::name_not_found: + return "Name not found"; + case jsonpointer_errc::key_already_exists: + return "Key already exists"; + case jsonpointer_errc::expected_object_or_array: + return "Expected object or array"; + case jsonpointer_errc::end_of_input: + return "Unexpected end of input"; + default: + return "Unknown jsonpointer error"; + } + } +}; + +inline +const std::error_category& jsonpointer_error_category() +{ + static jsonpointer_error_category_impl instance; + return instance; +} + +inline +std::error_code make_error_code(jsonpointer_errc result) +{ + return std::error_code(static_cast<int>(result),jsonpointer_error_category()); +} + +}} + +namespace std { + template<> + struct is_error_code_enum<jsoncons::jsonpointer::jsonpointer_errc> : public true_type + { + }; +} + +#endif diff --git a/vendor/jsoncons-0.104.0/jsoncons_ext/msgpack/msgpack.hpp b/vendor/jsoncons-0.104.0/jsoncons_ext/msgpack/msgpack.hpp new file mode 100644 index 00000000..fd35dfe6 --- /dev/null +++ b/vendor/jsoncons-0.104.0/jsoncons_ext/msgpack/msgpack.hpp @@ -0,0 +1,795 @@ +// Copyright 2013 Daniel Parker +// Distributed under the Boost license, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See https://github.com/danielaparker/jsoncons for latest version + +#ifndef JSONCONS_MSGPACK_MSGPACK_HPP +#define JSONCONS_MSGPACK_MSGPACK_HPP + +#include <string> +#include <sstream> +#include <vector> +#include <istream> +#include <cstdlib> +#include <memory> +#include <limits> +#include <cassert> +#include <jsoncons/json.hpp> +#include <jsoncons_ext/binary/binary_utilities.hpp> + +namespace jsoncons { namespace msgpack { + +class msgpack_decode_error : public std::invalid_argument, public virtual json_exception +{ +public: + explicit msgpack_decode_error(size_t pos) JSONCONS_NOEXCEPT + : std::invalid_argument("") + { + buffer_.append("Error decoding a message pack at position "); + buffer_.append(std::to_string(pos)); + } + ~msgpack_decode_error() JSONCONS_NOEXCEPT + { + } + const char* what() const JSONCONS_NOEXCEPT override + { + return buffer_.c_str(); + } +private: + std::string buffer_; +}; + +namespace msgpack_format +{ + const uint8_t nil_cd = 0xc0; + const uint8_t false_cd = 0xc2; + const uint8_t true_cd = 0xc3; + const uint8_t float32_cd = 0xca; + const uint8_t float64_cd = 0xcb; + const uint8_t uint8_cd = 0xcc; + const uint8_t uint16_cd = 0xcd; + const uint8_t uint32_cd = 0xce; + const uint8_t uint64_cd = 0xcf; + const uint8_t int8_cd = 0xd0; + const uint8_t int16_cd = 0xd1; + const uint8_t int32_cd = 0xd2; + const uint8_t int64_cd = 0xd3; + const uint8_t str8_cd = 0xd9; + const uint8_t str16_cd = 0xda; + const uint8_t str32_cd = 0xdb; + const uint8_t array16_cd = 0xdc; + const uint8_t array32_cd = 0xdd; + const uint8_t map16_cd = 0xde; + const uint8_t map32_cd = 0xdf; +} + +struct Encode_msgpack_ +{ + template <typename T> + void operator()(T val, std::vector<uint8_t>& v) + { + binary::to_big_endian(val,v); + } +}; + +struct Calculate_size_ +{ + template <typename T> + void operator()(T, size_t& size) + { + size += sizeof(T); + } +}; + +template<class Json> +class msgpack_Encoder_ +{ +public: + typedef typename Json::string_view_type string_view_type; + + static size_t calculate_size(const Json& j) + { + size_t n = 0; + msgpack_Encoder_<Json>::encode(j,Calculate_size_(),n); + return n; + } + + template <class Action, class Result> + static void encode(const Json& jval, Action action, Result& v) + { + switch (jval.type_id()) + { + case json_type_tag::null_t: + { + // nil + action(static_cast<uint8_t>(msgpack_format::nil_cd), v); + break; + } + + case json_type_tag::bool_t: + { + // true and false + action(static_cast<uint8_t>(jval.as_bool() ? msgpack_format::true_cd : msgpack_format::false_cd),v); + break; + } + + case json_type_tag::integer_t: + { + int64_t val = jval.as_integer(); + if (val >= 0) + { + if (val <= (std::numeric_limits<int8_t>::max)()) + { + // positive fixnum stores 7-bit positive integer + action(static_cast<int8_t>(val),v); + } + else if (val <= (std::numeric_limits<uint8_t>::max)()) + { + // uint 8 stores a 8-bit unsigned integer + action(static_cast<uint8_t>(msgpack_format::uint8_cd), v); + action(static_cast<uint8_t>(val),v); + } + else if (val <= (std::numeric_limits<uint16_t>::max)()) + { + // uint 16 stores a 16-bit big-endian unsigned integer + action(static_cast<uint8_t>(msgpack_format::uint16_cd), v); + action(static_cast<uint16_t>(val),v); + } + else if (val <= (std::numeric_limits<uint32_t>::max)()) + { + // uint 32 stores a 32-bit big-endian unsigned integer + action(static_cast<uint8_t>(msgpack_format::uint32_cd), v); + action(static_cast<uint32_t>(val),v); + } + else if (val <= (std::numeric_limits<int64_t>::max)()) + { + // int 64 stores a 64-bit big-endian signed integer + action(static_cast<uint8_t>(msgpack_format::int64_cd), v); + action(static_cast<int64_t>(val),v); + } + } + else + { + if (val >= -32) + { + // negative fixnum stores 5-bit negative integer + action(static_cast<int8_t>(val), v); + } + else if (val >= (std::numeric_limits<int8_t>::min)()) + { + // int 8 stores a 8-bit signed integer + action(static_cast<uint8_t>(msgpack_format::int8_cd), v); + action(static_cast<int8_t>(val),v); + } + else if (val >= (std::numeric_limits<int16_t>::min)()) + { + // int 16 stores a 16-bit big-endian signed integer + action(static_cast<uint8_t>(msgpack_format::int16_cd), v); + action(static_cast<int16_t>(val),v); + } + else if (val >= (std::numeric_limits<int32_t>::min)()) + { + // int 32 stores a 32-bit big-endian signed integer + action(static_cast<uint8_t>(msgpack_format::int32_cd), v); + action(static_cast<int32_t>(val),v); + } + else if (val >= (std::numeric_limits<int64_t>::min)()) + { + // int 64 stores a 64-bit big-endian signed integer + action(static_cast<uint8_t>(msgpack_format::int64_cd), v); + action(static_cast<int64_t>(val),v); + } + } + break; + } + + case json_type_tag::uinteger_t: + { + uint64_t val = jval.as_uinteger(); + if (val <= (std::numeric_limits<int8_t>::max)()) + { + // positive fixnum stores 7-bit positive integer + action(static_cast<uint8_t>(val), v); + } + else if (val <= (std::numeric_limits<uint8_t>::max)()) + { + // uint 8 stores a 8-bit unsigned integer + action(static_cast<uint8_t>(msgpack_format::uint8_cd), v); + action(static_cast<uint8_t>(val), v); + } + else if (val <= (std::numeric_limits<uint16_t>::max)()) + { + // uint 16 stores a 16-bit big-endian unsigned integer + action(static_cast<uint8_t>(msgpack_format::uint16_cd), v); + action(static_cast<uint16_t>(val),v); + } + else if (val <= (std::numeric_limits<uint32_t>::max)()) + { + // uint 32 stores a 32-bit big-endian unsigned integer + action(static_cast<uint8_t>(msgpack_format::uint32_cd), v); + action(static_cast<uint32_t>(val),v); + } + else if (val <= (std::numeric_limits<uint64_t>::max)()) + { + // uint 64 stores a 64-bit big-endian unsigned integer + action(static_cast<uint8_t>(msgpack_format::uint64_cd), v); + action(static_cast<uint64_t>(val),v); + } + break; + } + + case json_type_tag::double_t: + { + // float 64 + action(static_cast<uint8_t>(msgpack_format::float64_cd), v); + action(jval.as_double(),v); + break; + } + + case json_type_tag::small_string_t: + case json_type_tag::string_t: + { + encode_string(jval.as_string_view(), action, v); + break; + } + + case json_type_tag::array_t: + { + const auto length = jval.array_value().size(); + if (length <= 15) + { + // fixarray + action(static_cast<uint8_t>(0x90 | length), v); + } + else if (length <= (std::numeric_limits<uint16_t>::max)()) + { + // array 16 + action(static_cast<uint8_t>(msgpack_format::array16_cd), v); + action(static_cast<uint16_t>(length),v); + } + else if (length <= (std::numeric_limits<uint32_t>::max)()) + { + // array 32 + action(static_cast<uint8_t>(msgpack_format::array32_cd), v); + action(static_cast<uint32_t>(length),v); + } + + // append each element + for (const auto& el : jval.array_range()) + { + encode(el, action, v); + } + break; + } + + case json_type_tag::object_t: + { + const auto length = jval.object_value().size(); + if (length <= 15) + { + // fixmap + action(static_cast<uint8_t>(0x80 | (length & 0xf)), v); + } + else if (length <= 65535) + { + // map 16 + action(static_cast<uint8_t>(msgpack_format::map16_cd), v); + action(static_cast<uint16_t>(length), v); + } + else if (length <= 4294967295) + { + // map 32 + action(static_cast<uint8_t>(msgpack_format::map32_cd), v); + action(static_cast<uint32_t>(length),v); + } + + // append each element + for (const auto& kv: jval.object_range()) + { + encode_string(kv.key(), action, v); + encode(kv.value(), action, v); + } + break; + } + + default: + { + break; + } + } + } + + template <class Action, class Result> + static void encode_string(const string_view_type& sv, Action action, Result& v) + { + std::basic_string<uint8_t> target; + auto result = unicons::convert( + sv.begin(), sv.end(), std::back_inserter(target), + unicons::conv_flags::strict); + if (result.ec != unicons::conv_errc()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Illegal unicode")); + } + + const size_t length = target.length(); + if (length <= 31) + { + // fixstr stores a byte array whose length is upto 31 bytes + action(static_cast<uint8_t>(0xa0 | length), v); + } + else if (length <= (std::numeric_limits<uint8_t>::max)()) + { + // str 8 stores a byte array whose length is upto (2^8)-1 bytes + action(static_cast<uint8_t>(msgpack_format::str8_cd), v); + action(static_cast<uint8_t>(length), v); + } + else if (length <= (std::numeric_limits<uint16_t>::max)()) + { + // str 16 stores a byte array whose length is upto (2^16)-1 bytes + action(static_cast<uint8_t>(msgpack_format::str16_cd), v); + action(static_cast<uint16_t>(length), v); + } + else if (length <= (std::numeric_limits<uint32_t>::max)()) + { + // str 32 stores a byte array whose length is upto (2^32)-1 bytes + action(static_cast<uint8_t>(msgpack_format::str32_cd), v); + action(static_cast<uint32_t>(length),v); + } + + for (size_t i = 0; i < length; ++i) + { + action(static_cast<uint8_t>(target.data()[i]), v); + } + } +}; + +// decode_msgpack + +template<class Json> +class Decode_msgpack_ +{ + const uint8_t* begin_; + const uint8_t* end_; + const uint8_t* it_; +public: + typedef typename Json::char_type char_type; + + Decode_msgpack_(const uint8_t* begin, const uint8_t* end) + : begin_(begin), end_(end), it_(begin) + { + } + + Json decode() + { + // store && increment index + const uint8_t* pos = it_++; + + if (*pos <= 0xbf) + { + if (*pos <= 0x7f) + { + // positive fixint + return Json(*pos); + } + else if (*pos <= 0x8f) + { + // fixmap + Json result; + const size_t len = *pos & 0x0f; + result.reserve(len); + for (size_t i = 0; i < len; ++i) + { + auto j = decode(); + result.set(j.as_string_view(),decode()); + } + return result; + } + else if (*pos <= 0x9f) + { + // fixarray + Json result = typename Json::array(); + const size_t len = *pos & 0x0f; + result.reserve(len); + for (size_t i = 0; i < len; ++i) + { + result.push_back(decode()); + } + return result; + } + else + { + // fixstr + const size_t len = *pos & 0x1f; + const uint8_t* first = &(*it_); + const uint8_t* last = first + len; + it_ += len; + + std::basic_string<char_type> target; + auto result = unicons::convert( + first, last,std::back_inserter(target),unicons::conv_flags::strict); + if (result.ec != unicons::conv_errc()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Illegal unicode")); + } + return Json(target); + } + } + else if (*pos >= 0xe0) + { + // negative fixint + return static_cast<int8_t>(*pos); + } + else + { + switch (*pos) + { + case msgpack_format::nil_cd: + { + return Json(null_type()); + } + case msgpack_format::true_cd: + { + return Json(true); + } + case msgpack_format::false_cd: + { + return Json(false); + } + case msgpack_format::float32_cd: + { + const uint8_t* endp; + float res = binary::from_big_endian<float>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return res; + } + + case msgpack_format::float64_cd: + { + const uint8_t* endp; + double res = binary::from_big_endian<double>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return res; + } + + case msgpack_format::uint8_cd: + { + const uint8_t* endp; + auto x = binary::from_big_endian<uint8_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return Json(x); + } + + case msgpack_format::uint16_cd: + { + const uint8_t* endp; + auto x = binary::from_big_endian<uint16_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return x; + } + + case msgpack_format::uint32_cd: + { + const uint8_t* endp; + auto x = binary::from_big_endian<uint32_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return x; + } + + case msgpack_format::uint64_cd: + { + const uint8_t* endp; + auto x = binary::from_big_endian<uint64_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return x; + } + + case msgpack_format::int8_cd: + { + const uint8_t* endp; + auto x = binary::from_big_endian<int8_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return Json(x); + } + + case msgpack_format::int16_cd: + { + const uint8_t* endp; + auto x = binary::from_big_endian<int16_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return x; + } + + case msgpack_format::int32_cd: + { + const uint8_t* endp; + auto x = binary::from_big_endian<int32_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return x; + } + + case msgpack_format::int64_cd: + { + const uint8_t* endp; + auto x = binary::from_big_endian<int64_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + return x; + } + + case msgpack_format::str8_cd: + { + const uint8_t* endp; + const auto len = binary::from_big_endian<int8_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + + const uint8_t* first = &(*(pos + 2)); + const uint8_t* last = first + len; + it_ += len; + + std::basic_string<char_type> target; + auto result = unicons::convert( + first, last,std::back_inserter(target),unicons::conv_flags::strict); + if (result.ec != unicons::conv_errc()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Illegal unicode")); + } + return target; + } + + case msgpack_format::str16_cd: + { + const uint8_t* endp; + const auto len = binary::from_big_endian<int16_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + + const uint8_t* first = &(*(pos + 3)); + const uint8_t* last = first + len; + it_ += len; + + std::basic_string<char_type> target; + auto result = unicons::convert( + first, last,std::back_inserter(target),unicons::conv_flags::strict); + if (result.ec != unicons::conv_errc()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Illegal unicode")); + } + return target; + } + + case msgpack_format::str32_cd: + { + const uint8_t* endp; + const auto len = binary::from_big_endian<int32_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + + const uint8_t* first = &(*(pos + 5)); + const uint8_t* last = first + len; + it_ += len; + + std::basic_string<char_type> target; + auto result = unicons::convert( + first, last,std::back_inserter(target),unicons::conv_flags::strict); + if (result.ec != unicons::conv_errc()) + { + JSONCONS_THROW(json_exception_impl<std::runtime_error>("Illegal unicode")); + } + return target; + } + + case msgpack_format::array16_cd: + { + Json result = typename Json::array(); + const uint8_t* endp; + const auto len = binary::from_big_endian<uint16_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + result.reserve(len); + for (size_t i = 0; i < len; ++i) + { + result.push_back(decode()); + } + return result; + } + + case msgpack_format::array32_cd: + { + Json result = typename Json::array(); + const uint8_t* endp; + const auto len = binary::from_big_endian<uint32_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + result.reserve(len); + for (size_t i = 0; i < len; ++i) + { + result.push_back(decode()); + } + return result; + } + + case msgpack_format::map16_cd : + { + const uint8_t* endp; + const auto len = binary::from_big_endian<uint16_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + Json result = typename Json::object(); + result.reserve(len); + for (size_t i = 0; i < len; ++i) + { + auto j = decode(); + result.set(j.as_string_view(),decode()); + } + return result; + } + + case msgpack_format::map32_cd : + { + Json result = typename Json::object(); + const uint8_t* endp; + const auto len = binary::from_big_endian<uint32_t>(it_,end_,&endp); + if (endp == it_) + { + JSONCONS_THROW(msgpack_decode_error(end_-it_)); + } + else + { + it_ = endp; + } + result.reserve(len); + for (size_t i = 0; i < len; ++i) + { + auto key = decode().as_string_view(); + result.set(key,decode()); + } + return result; + } + + default: + { + JSONCONS_THROW(msgpack_decode_error(end_-pos)); + } + } + } + } +}; + +template<class Json> +void encode_msgpack(const Json& j, std::vector<uint8_t>& v) +{ + size_t n = 0; + msgpack_Encoder_<Json>::encode(j,Calculate_size_(),n); + v.reserve(n); + //v.reserve(msgpack_Encoder_<Json>::calculate_size(j)); + + msgpack_Encoder_<Json>::encode(j,Encode_msgpack_(),v); +} + +template<class Json> +Json decode_msgpack(const std::vector<uint8_t>& v) +{ + Decode_msgpack_<Json> decoder(v.data(),v.data()+v.size()); + return decoder.decode(); +} + +#if !defined(JSONCONS_NO_DEPRECATED) +template<class Json> +std::vector<uint8_t> encode_msgpack(const Json& j) +{ + std::vector<uint8_t> v; + encode_msgpack(j, v); + return v; +} +#endif + +}} + +#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons/json.hpp b/vendor/jsoncons-0.99.2/jsoncons/json.hpp deleted file mode 100644 index b9058b59..00000000 --- a/vendor/jsoncons-0.99.2/jsoncons/json.hpp +++ /dev/null @@ -1,3574 +0,0 @@ -// Copyright 2013 Daniel Parker -// Distributed under the Boost license, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -// See https://github.com/danielaparker/jsoncons for latest version - -#ifndef JSONCONS_JSON_HPP -#define JSONCONS_JSON_HPP - -#include <limits> -#include <string> -#include <vector> -#include <exception> -#include <cstdlib> -#include <cstring> -#include <ostream> -#include <memory> -#include <typeinfo> -#include "jsoncons/json_structures.hpp" -#include "jsoncons/jsoncons.hpp" -#include "jsoncons/json_output_handler.hpp" -#include "jsoncons/output_format.hpp" -#include "jsoncons/json_serializer.hpp" -#include "jsoncons/json_deserializer.hpp" -#include "jsoncons/json_reader.hpp" -#include "jsoncons/json_type_traits.hpp" - -#if defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wswitch" -#endif - -namespace jsoncons { - -template <class T, class Alloc, typename... Args> -T* create_impl(const Alloc& allocator, Args&& ... args) -{ - typename std::allocator_traits<Alloc>:: template rebind_alloc<T> alloc(allocator); - T* storage = alloc.allocate(1); - try - { - std::allocator_traits<Alloc>:: template rebind_traits<T>::construct(alloc, storage, std::forward<Args>(args)...); - } - catch (...) - { - alloc.deallocate(storage,1); - throw; - } - return storage; -} - -template <class T, class Alloc> -void destroy_impl(const Alloc& allocator, T* p) -{ - typename std::allocator_traits<Alloc>:: template rebind_alloc<T> alloc(allocator); - std::allocator_traits<Alloc>:: template rebind_traits<T>::destroy(alloc, p); - alloc.deallocate(p,1); -} - -template <typename CharT, class Alloc> -class serializable_any -{ -public: - typedef Alloc allocator_type; - - serializable_any(const Alloc& allocator = Alloc()) - : impl_(nullptr) - { - (void)allocator; - } - serializable_any(const serializable_any& val) - : allocator_(std::allocator_traits<allocator_type>::select_on_container_copy_construction(val.get_allocator())) - { - impl_ = val.impl_ != nullptr ? val.impl_->clone(allocator_) : nullptr; - } - serializable_any(const serializable_any& val, const Alloc& allocator) - { - (void)allocator; - impl_ = val.impl_ != nullptr ? val.impl_->clone(Alloc()) : nullptr; - } - - serializable_any(serializable_any&& val) - : impl_(std::move(val.impl_)) - { - val.impl_ = nullptr; - } - serializable_any(serializable_any&& val, const Alloc& allocator) - : impl_(std::move(val.impl_)) - { - (void)allocator; - val.impl_ = nullptr; - } - ~serializable_any() - { - if (impl_ != nullptr) - { - destroy_impl(allocator_,impl_); - } - } - - template<typename T> - explicit serializable_any(T val) - { - impl_ = create_impl<any_handle_impl<typename type_wrapper<T>::value_type>>(allocator_,val); - } - - Alloc get_allocator() const - { - return allocator_; - } - - template <typename T> - typename type_wrapper<T>::reference cast() - { - if (typeid(*impl_) != typeid(any_handle_impl<typename type_wrapper<T>::value_type>)) - { - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Bad serializable_any cast"); - } - return static_cast<any_handle_impl<typename type_wrapper<T>::value_type>&>(*impl_).value_; - } - - template <typename T> - typename type_wrapper<T>::const_reference cast() const - { - if (typeid(*impl_) != typeid(any_handle_impl<typename type_wrapper<T>::value_type>)) - { - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Bad serializable_any cast"); - } - return static_cast<any_handle_impl<typename type_wrapper<T>::value_type>&>(*impl_).value_; - } - - serializable_any& operator=(serializable_any rhs) - { - std::swap(impl_,rhs.impl_); - return *this; - } - - void to_stream(basic_json_output_handler<CharT>& os) const - { - impl_->to_stream(os); - } - - class any_handle - { - public: - virtual ~any_handle() - { - } - - virtual any_handle* clone(const Alloc& allocator) const = 0; - - virtual void to_stream(basic_json_output_handler<CharT>& os) const = 0; - }; - - template <class T> - class any_handle_impl : public any_handle - { - public: - any_handle_impl(T value, const Alloc& allocator = Alloc()) - : value_(value) - { - (void)allocator; - } - - virtual any_handle* clone(const Alloc& allocator) const - { - return create_impl<any_handle_impl<T>>(allocator, value_); - } - - virtual void to_stream(basic_json_output_handler<CharT>& os) const - { - serialize(os,value_); - } - - T value_; - }; - - Alloc allocator_; - any_handle* impl_; -}; - -template <typename CharT,class T> inline -void serialize(basic_json_output_handler<CharT>& os, const T&) -{ - os.value(null_type()); -} - -template <typename CharT> -class basic_parse_error_handler; - -enum class value_types : uint8_t -{ - // Simple types - empty_object_t, - small_string_t, - double_t, - integer_t, - uinteger_t, - bool_t, - null_t, - // Non simple types - string_t, - object_t, - array_t, - any_t -}; - -inline -bool is_simple(value_types type) -{ - return type < value_types::string_t; -} - -template <typename CharT, typename Alloc = std::allocator<CharT>> -class basic_json -{ -public: - - typedef Alloc allocator_type; - - typedef CharT char_type; - typedef typename std::char_traits<CharT> char_traits_type; - - typedef typename std::allocator_traits<Alloc>:: template rebind_alloc<CharT> string_allocator; - typedef std::basic_string<CharT,char_traits_type,string_allocator> string_type; - typedef basic_json<CharT,Alloc> value_type; - typedef name_value_pair<string_type,value_type> member_type; - - typedef typename std::allocator_traits<Alloc>:: template rebind_alloc<basic_json<CharT,Alloc>> array_allocator; - - typedef typename std::allocator_traits<Alloc>:: template rebind_alloc<member_type> object_allocator; - - typedef json_array<basic_json<CharT,Alloc>,array_allocator> array; - typedef json_object<string_type,basic_json<CharT,Alloc>,object_allocator> object; - typedef serializable_any<char_type,Alloc> any; - - typedef jsoncons::null_type null_type; - - typedef typename object::iterator object_iterator; - typedef typename object::const_iterator const_object_iterator; - typedef typename array::iterator array_iterator; - typedef typename array::const_iterator const_array_iterator; - - template <typename IteratorT> - class range - { - IteratorT first_; - IteratorT last_; - public: - range(const IteratorT& first, const IteratorT& last) - : first_(first), last_(last) - { - } - - public: - friend class basic_json<CharT, Alloc>; - - IteratorT begin() - { - return first_; - } - IteratorT end() - { - return last_; - } - }; - - typedef range<object_iterator> object_range; - typedef range<const_object_iterator> const_object_range; - typedef range<array_iterator> array_range; - typedef range<const_array_iterator> const_array_range; - - struct variant - { - struct string_data : public string_allocator - { - const char_type* c_str() const { return p_; } - const char_type* data() const { return p_; } - size_t length() const { return length_; } - string_allocator get_allocator() const - { - return *this; - } - - bool operator==(const string_data& rhs) const - { - return length() == rhs.length() ? std::char_traits<char_type>::compare(data(), rhs.data(), length()) == 0 : false; - } - - string_data(const string_allocator& allocator) - : string_allocator(allocator), p_(nullptr), length_(0) - { - } - - char_type* p_; - size_t length_; - private: - string_data(const string_data&); - string_data& operator=(const string_data&); - }; - - struct string_dataA - { - string_data data; - char_type c[1]; - }; - typedef typename std::aligned_storage<sizeof(string_dataA), JSONCONS_ALIGNOF(string_dataA)>::type storage_type; - - static size_t aligned_size(size_t n) - { - return sizeof(storage_type) + n; - } - - string_data* create_string_data(const char_type* s, size_t length, const string_allocator& allocator) - { - size_t mem_size = aligned_size(length*sizeof(char_type)); - - typename std::allocator_traits<string_allocator>:: template rebind_alloc<char> alloc(allocator); - - char* storage = alloc.allocate(mem_size); - string_data* ps = new(storage)string_data(allocator); - auto psa = reinterpret_cast<string_dataA*>(storage); - - ps->p_ = new(&psa->c)char_type[length + 1]; - memcpy(ps->p_, s, length*sizeof(char_type)); - ps->p_[length] = 0; - ps->length_ = length; - return ps; - } - - void destroy_string_data(const string_allocator& allocator, string_data* p) - { - size_t mem_size = aligned_size(p->length_*sizeof(char_type)); - typename std::allocator_traits<string_allocator>:: template rebind_alloc<char> alloc(allocator); - alloc.deallocate(reinterpret_cast<char*>(p),mem_size); - } - - static const size_t small_string_capacity = (sizeof(int64_t)/sizeof(char_type)) - 1; - - variant() - : type_(value_types::empty_object_t) - { - } - - variant(const Alloc& a) - : type_(value_types::object_t) - { - value_.object_val_ = create_impl<object>(a, object_allocator(a)); - } - - variant(std::initializer_list<value_type> init, - const Alloc& a) - : type_(value_types::array_t) - { - value_.array_val_ = create_impl<array>(a, std::move(init), array_allocator(a)); - } - - explicit variant(variant&& var) - : type_(value_types::null_t) - { - swap(var); - } - - explicit variant(variant&& var, const Alloc& a) - : type_(value_types::null_t) - { - swap(var); - } - - explicit variant(const variant& var) - { - init_variant(var); - } - explicit variant(const variant& var, const Alloc& a) - : type_(var.type_) - { - init_variant(var); - } - - variant(const object & val) - : type_(value_types::object_t) - { - value_.object_val_ = create_impl<object>(val.get_allocator(), val) ; - } - - variant(const object & val, const Alloc& a) - : type_(value_types::object_t) - { - value_.object_val_ = create_impl<object>(a, val, object_allocator(a)) ; - } - - variant(object&& val) - : type_(value_types::object_t) - { - value_.object_val_ = create_impl<object>(val.get_allocator(), std::move(val)); - } - - variant(object&& val, const Alloc& a) - : type_(value_types::object_t) - { - value_.object_val_ = create_impl<object>(a, std::move(val), object_allocator(a)); - } - - variant(const array& val) - : type_(value_types::array_t) - { - value_.array_val_ = create_impl<array>(val.get_allocator(), val); - } - - variant(const array& val, const Alloc& a) - : type_(value_types::array_t) - { - value_.array_val_ = create_impl<array>(a, val, array_allocator(a)); - } - - variant(array&& val) - : type_(value_types::array_t) - { - value_.array_val_ = create_impl<array>(val.get_allocator(), std::move(val)); - } - - variant(array&& val, const Alloc& a) - : type_(value_types::array_t) - { - value_.array_val_ = create_impl<array>(a, std::move(val), array_allocator(a)); - } - - explicit variant(const any& val, const Alloc& a) - : type_(value_types::any_t) - { - value_.any_val_ = create_impl<any>(a, val); - } - - explicit variant(null_type) - : type_(value_types::null_t) - { - } - - explicit variant(bool val) - : type_(value_types::bool_t) - { - value_.bool_val_ = val; - } - - explicit variant(double val, uint8_t precision) - : type_(value_types::double_t), length_or_precision_(precision) - { - value_.double_val_ = val; - } - - explicit variant(int64_t val) - : type_(value_types::integer_t) - { - value_.integer_val_ = val; - } - - explicit variant(uint64_t val) - : type_(value_types::uinteger_t) - { - value_.uinteger_val_ = val; - } - - explicit variant(const string_type& s, const Alloc& a) - { - if (s.length() > variant::small_string_capacity) - { - type_ = value_types::string_t; - //value_.string_val_ = create_impl<string_type>(a, s, string_allocator(a)); - value_.string_val_ = create_string_data(s.data(), s.length(), string_allocator(a)); - } - else - { - type_ = value_types::small_string_t; - length_or_precision_ = static_cast<uint8_t>(s.length()); - std::memcpy(value_.small_string_val_,s.data(),s.length()*sizeof(char_type)); - value_.small_string_val_[length_or_precision_] = 0; - } - } - - explicit variant(const char_type* s, const Alloc& a) - { - size_t length = std::char_traits<char_type>::length(s); - if (length > variant::small_string_capacity) - { - type_ = value_types::string_t; - //value_.string_val_ = create_impl<string_type>(a, s, string_allocator(a)); - value_.string_val_ = create_string_data(s, length, string_allocator(a)); - } - else - { - type_ = value_types::small_string_t; - length_or_precision_ = static_cast<uint8_t>(length); - std::memcpy(value_.small_string_val_,s,length*sizeof(char_type)); - value_.small_string_val_[length_or_precision_] = 0; - } - } - - explicit variant(const char_type* s, size_t length, const Alloc& a) - { - if (length > variant::small_string_capacity) - { - type_ = value_types::string_t; - //value_.string_val_ = create_impl<string_type>(a, s, length, string_allocator(a)); - value_.string_val_ = create_string_data(s, length, string_allocator(a)); - } - else - { - type_ = value_types::small_string_t; - length_or_precision_ = static_cast<uint8_t>(length); - std::memcpy(value_.small_string_val_,s,length*sizeof(char_type)); - value_.small_string_val_[length_or_precision_] = 0; - } - } - - template<class InputIterator> - variant(InputIterator first, InputIterator last, const Alloc& a) - : type_(value_types::array_t) - { - value_.array_val_ = create_impl<array>(a, first, last, array_allocator(a)); - } - - void init_variant(const variant& var) - { - type_ = var.type_; - switch (type_) - { - case value_types::null_t: - case value_types::empty_object_t: - break; - case value_types::double_t: - length_or_precision_ = 0; - value_.double_val_ = var.value_.double_val_; - break; - case value_types::integer_t: - value_.integer_val_ = var.value_.integer_val_; - break; - case value_types::uinteger_t: - value_.uinteger_val_ = var.value_.uinteger_val_; - break; - case value_types::bool_t: - value_.bool_val_ = var.value_.bool_val_; - break; - case value_types::small_string_t: - length_or_precision_ = var.length_or_precision_; - std::memcpy(value_.small_string_val_,var.value_.small_string_val_,var.length_or_precision_*sizeof(char_type)); - value_.small_string_val_[length_or_precision_] = 0; - break; - case value_types::string_t: - //value_.string_val_ = create_impl<string_type>(var.value_.string_val_->get_allocator(), *(var.value_.string_val_), string_allocator(var.value_.string_val_->get_allocator())); - value_.string_val_ = create_string_data(var.value_.string_val_->data(), var.value_.string_val_->length(), string_allocator(var.value_.string_val_->get_allocator())); - break; - case value_types::array_t: - value_.array_val_ = create_impl<array>(var.value_.array_val_->get_allocator(), *(var.value_.array_val_), array_allocator(var.value_.array_val_->get_allocator())); - break; - case value_types::object_t: - value_.object_val_ = create_impl<object>(var.value_.object_val_->get_allocator(), *(var.value_.object_val_), object_allocator(var.value_.object_val_->get_allocator())); - break; - case value_types::any_t: - value_.any_val_ = create_impl<any>(var.value_.any_val_->get_allocator(), *(var.value_.any_val_)); - break; - default: - break; - } - } - - ~variant() - { - destroy_variant(); - } - - void destroy_variant() - { - switch (type_) - { - case value_types::string_t: - //destroy_impl(value_.string_val_->get_allocator(), value_.string_val_); - destroy_string_data(value_.string_val_->get_allocator(), value_.string_val_); - break; - case value_types::array_t: - destroy_impl(value_.array_val_->get_allocator(), value_.array_val_); - break; - case value_types::object_t: - destroy_impl(value_.object_val_->get_allocator(), value_.object_val_); - break; - case value_types::any_t: - destroy_impl(value_.any_val_->get_allocator(), value_.any_val_); - break; - default: - break; - } - } - - variant& operator=(const variant& val) - { - if (this != &val) - { - if (is_simple(type_)) - { - if (is_simple(val.type_)) - { - type_ = val.type_; - length_or_precision_ = val.length_or_precision_; - value_ = val.value_; - } - else - { - init_variant(val); - } - } - else - { - destroy_variant(); - init_variant(val); - } - } - return *this; - } - - variant& operator=(variant&& val) - { - if (this != &val) - { - val.swap(*this); - } - return *this; - } - - void assign(const object & val) - { - destroy_variant(); - type_ = value_types::object_t; - value_.object_val_ = create_impl<object>(val.get_allocator(), val, object_allocator(val.get_allocator())); - } - - void assign(object && val) - { - switch (type_) - { - case value_types::object_t: - value_.object_val_->swap(val); - break; - default: - destroy_variant(); - type_ = value_types::object_t; - value_.object_val_ = create_impl<object>(val.get_allocator(), std::move(val), object_allocator(val.get_allocator())); - break; - } - } - - void assign(const array& val) - { - destroy_variant(); - type_ = value_types::array_t; - value_.array_val_ = create_impl<array>(val.get_allocator(), val, array_allocator(val.get_allocator())) ; - } - - void assign(array&& val) - { - switch (type_) - { - case value_types::array_t: - value_.array_val_->swap(val); - break; - default: - destroy_variant(); - type_ = value_types::array_t; - value_.array_val_ = create_impl<array>(val.get_allocator(), std::move(val), array_allocator(val.get_allocator())); - break; - } - } - - void assign(const string_type& s) - { - destroy_variant(); - if (s.length() > variant::small_string_capacity) - { - type_ = value_types::string_t; - //value_.string_val_ = create_impl<string_type>(s.get_allocator(), s, string_allocator(s.get_allocator())); - value_.string_val_ = create_string_data(s.data(), s.length(), string_allocator(s.get_allocator())); - } - else - { - type_ = value_types::small_string_t; - length_or_precision_ = static_cast<uint8_t>(s.length()); - std::memcpy(value_.small_string_val_,s.data(),s.length()*sizeof(char_type)); - value_.small_string_val_[length_or_precision_] = 0; - } - } - - void assign_string(const char_type* s, size_t length, const Alloc& allocator = Alloc()) - { - destroy_variant(); - if (length > variant::small_string_capacity) - { - type_ = value_types::string_t; - //value_.string_val_ = create_impl<string_type>(allocator, s, length, string_allocator(allocator)); - value_.string_val_ = create_string_data(s, length, string_allocator(allocator)); - } - else - { - type_ = value_types::small_string_t; - length_or_precision_ = static_cast<uint8_t>(length); - std::memcpy(value_.small_string_val_,s,length*sizeof(char_type)); - value_.small_string_val_[length_or_precision_] = 0; - } - } - - void assign(int64_t val) - { - destroy_variant(); - type_ = value_types::integer_t; - value_.integer_val_ = val; - } - - void assign(uint64_t val) - { - destroy_variant(); - type_ = value_types::uinteger_t; - value_.uinteger_val_ = val; - } - - void assign(double val, uint8_t precision = 0) - { - destroy_variant(); - type_ = value_types::double_t; - length_or_precision_ = precision; - value_.double_val_ = val; - } - - void assign(bool val) - { - destroy_variant(); - type_ = value_types::bool_t; - value_.bool_val_ = val; - } - - void assign(null_type) - { - destroy_variant(); - type_ = value_types::null_t; - } - - void assign(const any& rhs) - { - destroy_variant(); - type_ = value_types::any_t; - value_.any_val_ = create_impl<any>(rhs.get_allocator(), rhs); - } - - bool operator!=(const variant& rhs) const - { - return !(*this == rhs); - } - - bool operator==(const variant& rhs) const - { - if (is_number() & rhs.is_number()) - { - switch (type_) - { - case value_types::integer_t: - switch (rhs.type_) - { - case value_types::integer_t: - return value_.integer_val_ == rhs.value_.integer_val_; - case value_types::uinteger_t: - return value_.integer_val_ == rhs.value_.uinteger_val_; - case value_types::double_t: - return value_.integer_val_ == rhs.value_.double_val_; - default: - break; - } - break; - case value_types::uinteger_t: - switch (rhs.type_) - { - case value_types::integer_t: - return value_.uinteger_val_ == rhs.value_.integer_val_; - case value_types::uinteger_t: - return value_.uinteger_val_ == rhs.value_.uinteger_val_; - case value_types::double_t: - return value_.uinteger_val_ == rhs.value_.double_val_; - default: - break; - } - break; - case value_types::double_t: - switch (rhs.type_) - { - case value_types::integer_t: - return value_.double_val_ == rhs.value_.integer_val_; - case value_types::uinteger_t: - return value_.double_val_ == rhs.value_.uinteger_val_; - case value_types::double_t: - return value_.double_val_ == rhs.value_.double_val_; - default: - break; - } - break; - default: - break; - } - } - - switch (type_) - { - case value_types::bool_t: - return type_ == rhs.type_ && value_.bool_val_ == rhs.value_.bool_val_; - case value_types::null_t: - return type_ == rhs.type_; - case value_types::empty_object_t: - return type_ == rhs.type_ || (rhs.type_ == value_types::object_t && rhs.empty()); - case value_types::small_string_t: - return type_ == rhs.type_ && length_or_precision_ == rhs.length_or_precision_ ? std::char_traits<char_type>::compare(value_.small_string_val_,rhs.value_.small_string_val_,length_or_precision_) == 0 : false; - case value_types::string_t: - return type_ == rhs.type_ && *(value_.string_val_) == *(rhs.value_.string_val_); - case value_types::array_t: - return type_ == rhs.type_ && *(value_.array_val_) == *(rhs.value_.array_val_); - break; - case value_types::object_t: - return (type_ == rhs.type_ && *(value_.object_val_) == *(rhs.value_.object_val_)) || (rhs.type_ == value_types::empty_object_t && empty()); - break; - case value_types::any_t: - return type_ == rhs.type_; - default: - // throw - break; - } - return false; - } - - bool is_null() const JSONCONS_NOEXCEPT - { - return type_ == value_types::null_t; - } - - bool is_bool() const JSONCONS_NOEXCEPT - { - return type_ == value_types::bool_t; - } - - bool empty() const JSONCONS_NOEXCEPT - { - switch (type_) - { - case value_types::small_string_t: - return length_or_precision_ == 0; - case value_types::string_t: - return value_.string_val_->length() == 0; - case value_types::array_t: - return value_.array_val_->size() == 0; - case value_types::empty_object_t: - return true; - case value_types::object_t: - return value_.object_val_->size() == 0; - default: - return false; - } - } - - bool is_string() const JSONCONS_NOEXCEPT - { - return (type_ == value_types::string_t) | (type_ == value_types::small_string_t); - } - - bool is_number() const JSONCONS_NOEXCEPT - { - return type_ == value_types::double_t || type_ == value_types::integer_t || type_ == value_types::uinteger_t; - } - - void swap(variant& rhs) - { - using std::swap; - if (this == &rhs) - { - // same object, do nothing - } - else - { - swap(type_, rhs.type_); - swap(length_or_precision_, rhs.length_or_precision_); - swap(value_, rhs.value_); - } - } - - value_types type_; - uint8_t length_or_precision_; - union - { - double double_val_; - int64_t integer_val_; - uint64_t uinteger_val_; - bool bool_val_; - object* object_val_; - array* array_val_; - any* any_val_; - string_data* string_val_; - char_type small_string_val_[sizeof(int64_t)/sizeof(char_type)]; - } value_; - }; - - template <class ParentT> - class json_proxy - { - private: - typedef json_proxy<ParentT> proxy_type; - - ParentT& parent_; - const string_type& name_; - - json_proxy() = delete; - json_proxy& operator = (const json_proxy& other) = delete; - - json_proxy(ParentT& parent, const string_type& name) - : parent_(parent), name_(name) - { - } - - basic_json<CharT,Alloc>& evaluate() - { - return parent_.evaluate(name_); - } - - const basic_json<CharT,Alloc>& evaluate() const - { - return parent_.evaluate(name_); - } - - basic_json<CharT,Alloc>& evaluate_with_default() - { - basic_json<CharT,Alloc>& val = parent_.evaluate_with_default(); - auto it = val.find(name_.data(),name_.length()); - if (it == val.members().end()) - { - it = val.set(val.members().begin(),name_,object(val.object_value().get_allocator())); - } - return it->value(); - } - - basic_json<CharT,Alloc>& evaluate(size_t index) - { - return parent_.evaluate(name_).at(index); - } - - const basic_json<CharT,Alloc>& evaluate(size_t index) const - { - return parent_.evaluate(name_).at(index); - } - - basic_json<CharT,Alloc>& evaluate(const string_type& index) - { - return parent_.evaluate(name_).at(index); - } - - const basic_json<CharT,Alloc>& evaluate(const string_type& index) const - { - return parent_.evaluate(name_).at(index); - } - public: - - friend class basic_json<CharT,Alloc>; - - object_range members() - { - return evaluate().members(); - } - - const_object_range members() const - { - return evaluate().members(); - } - - array_range elements() - { - return evaluate().elements(); - } - - const_array_range elements() const - { - return evaluate().elements(); - } - - size_t size() const JSONCONS_NOEXCEPT - { - return evaluate().size(); - } - - value_types type() const - { - return evaluate().type(); - } - - size_t count(const string_type& name) const - { - return evaluate().count(name); - } - - bool is_null() const JSONCONS_NOEXCEPT - { - return evaluate().is_null(); - } - - bool empty() const - { - return evaluate().empty(); - } - - size_t capacity() const - { - return evaluate().capacity(); - } - - void reserve(size_t n) - { - evaluate().reserve(n); - } - - void resize(size_t n) - { - evaluate().resize(n); - } - - template <typename T> - void resize(size_t n, T val) - { - evaluate().resize(n,val); - } - - template<typename T> - bool is() const - { - return evaluate().template is<T>(); - } - - bool is_string() const JSONCONS_NOEXCEPT - { - return evaluate().is_string(); - } - - bool is_number() const JSONCONS_NOEXCEPT - { - return evaluate().is_number(); - } - bool is_bool() const JSONCONS_NOEXCEPT - { - return evaluate().is_bool(); - } - - bool is_object() const JSONCONS_NOEXCEPT - { - return evaluate().is_object(); - } - - bool is_array() const JSONCONS_NOEXCEPT - { - return evaluate().is_array(); - } - - bool is_any() const JSONCONS_NOEXCEPT - { - return evaluate().is_any(); - } - - bool is_integer() const JSONCONS_NOEXCEPT - { - return evaluate().is_integer(); - } - - bool is_uinteger() const JSONCONS_NOEXCEPT - { - return evaluate().is_uinteger(); - } - - bool is_double() const JSONCONS_NOEXCEPT - { - return evaluate().is_double(); - } - - string_type as_string() const JSONCONS_NOEXCEPT - { - return evaluate().as_string(); - } - - string_type as_string(const string_allocator& allocator) const JSONCONS_NOEXCEPT - { - return evaluate().as_string(allocator); - } - - string_type as_string(const basic_output_format<char_type>& format) const - { - return evaluate().as_string(format); - } - - string_type as_string(const basic_output_format<char_type>& format, - const string_allocator& allocator) const - { - return evaluate().as_string(format,allocator); - } - - template<typename T> - T as() const - { - return evaluate().template as<T>(); - } - - template<typename T> - typename std::enable_if<std::is_same<string_type,T>::value>::type as(const string_allocator& allocator) const - { - return evaluate().template as<T>(allocator); - } - - any& any_value() - { - return evaluate().any_value(); - } - - const any& any_value() const - { - return evaluate().any_value(); - } - - bool as_bool() const JSONCONS_NOEXCEPT - { - return evaluate().as_bool(); - } - - template <class T> - std::vector<T> as_vector() const - { - return evaluate().template as_vector<T>(); - } - - double as_double() const - { - return evaluate().as_double(); - } - - int64_t as_integer() const - { - return evaluate().as_integer(); - } - - unsigned long long as_ulonglong() const - { - return evaluate().as_ulonglong(); - } - - uint64_t as_uinteger() const - { - return evaluate().as_uinteger(); - } - - template <class T> - const T& any_cast() const - { - return evaluate().template any_cast<T>(); - } - // Returns a const reference to the custom data associated with name - - template <class T> - T& any_cast() - { - return evaluate().template any_cast<T>(); - } - // Returns a reference to the custom data associated with name - - operator basic_json&() - { - return evaluate(); - } - - operator const basic_json&() const - { - return evaluate(); - } - - template <typename T> - json_proxy& operator=(T val) - { - parent_.evaluate_with_default().set(name_, val); - return *this; - } - - json_proxy& operator=(const basic_json& val) - { - parent_.evaluate_with_default().set(name_, val); - return *this; - } - - json_proxy& operator=(basic_json&& val) - { - parent_.evaluate_with_default().set(name_, std::move(val)); - return *this; - } - - bool operator==(const basic_json& val) const - { - return evaluate() == val; - } - - bool operator!=(const basic_json& val) const - { - return evaluate() != val; - } - - basic_json<CharT,Alloc>& operator[](size_t i) - { - return evaluate_with_default().at(i); - } - - const basic_json<CharT,Alloc>& operator[](size_t i) const - { - return evaluate().at(i); - } - - json_proxy<proxy_type> operator[](const string_type& name) - { - return json_proxy<proxy_type>(*this,name); - } - - const json_proxy<proxy_type> operator[](const string_type& name) const - { - return json_proxy<proxy_type>(*this,name); - } - - basic_json<CharT,Alloc>& at(const string_type& name) - { - return evaluate().at(name); - } - - const basic_json<CharT,Alloc>& at(const string_type& name) const - { - return evaluate().at(name); - } - - const basic_json<CharT,Alloc>& at(size_t index) - { - return evaluate().at(index); - } - - const basic_json<CharT,Alloc>& at(size_t index) const - { - return evaluate().at(index); - } - - object_iterator find(const string_type& name) - { - return evaluate().find(name); - } - - const_object_iterator find(const string_type& name) const - { - return evaluate().find(name); - } - - object_iterator find(const char_type* name) - { - return evaluate().find(name); - } - - const_object_iterator find(const char_type* name) const - { - return evaluate().find(name); - } - - object_iterator find(const char_type* name, size_t length) - { - return evaluate().find(name,length); - } - - const_object_iterator find(const char_type* name, size_t length) const - { - return evaluate().find(name,length); - } - - template <typename T> - basic_json<CharT,Alloc> get(const string_type& name, T&& default_val) const - { - return evaluate().get(name,std::forward<T>(default_val)); - } - - void shrink_to_fit() - { - evaluate_with_default().shrink_to_fit(); - } - - void clear() - { - evaluate().clear(); - } - // Remove all elements from an array or object - - void erase(object_iterator first, object_iterator last) - { - evaluate().erase(first, last); - } - // Remove a range of elements from an object - - void erase(array_iterator first, array_iterator last) - { - evaluate().erase(first, last); - } - - void erase(const string_type& name) - { - evaluate().erase(name); - } - - // Remove a member from an object - - void set(const string_type& name, const basic_json<CharT,Alloc>& value) - { - evaluate().set(name,value); - } - - void set(string_type&& name, const basic_json<CharT,Alloc>& value) - - { - evaluate().set(std::move(name),value); - } - - void set(const string_type& name, basic_json<CharT,Alloc>&& value) - - { - evaluate().set(name,std::move(value)); - } - - void set(string_type&& name, basic_json<CharT,Alloc>&& value) - - { - evaluate().set(std::move(name),std::move(value)); - } - - object_iterator set(object_iterator hint, const string_type& name, const basic_json<CharT,Alloc>& value) - { - return evaluate().set(hint, name,value); - } - - object_iterator set(object_iterator hint, string_type&& name, const basic_json<CharT,Alloc>& value) - - { - return evaluate().set(hint, std::move(name),value); - } - - object_iterator set(object_iterator hint, const string_type& name, basic_json<CharT,Alloc>&& value) - - { - return evaluate().set(hint, name,std::move(value)); - } - - object_iterator set(object_iterator hint, string_type&& name, basic_json<CharT,Alloc>&& value) - - { - return evaluate().set(hint, std::move(name),std::move(value)); - } - - void add(basic_json<CharT,Alloc>&& value) - { - evaluate_with_default().add(std::move(value)); - } - - void add(const basic_json<CharT,Alloc>& value) - { - evaluate_with_default().add(value); - } - - array_iterator add(const_array_iterator pos, const basic_json<CharT,Alloc>& value) - { - return evaluate_with_default().add(pos, value); - } - - array_iterator add(const_array_iterator pos, basic_json<CharT,Alloc>&& value) - { - return evaluate_with_default().add(pos, std::move(value)); - } - - string_type to_string(const string_allocator& allocator = string_allocator()) const JSONCONS_NOEXCEPT - { - return evaluate().to_string(allocator); - } - - string_type to_string(const basic_output_format<char_type>& format, string_allocator& allocator = string_allocator()) const - { - return evaluate().to_string(format,allocator); - } - - void to_stream(std::basic_ostream<char_type>& os) const - { - evaluate().to_stream(os); - } - - void to_stream(std::basic_ostream<char_type>& os, const basic_output_format<char_type>& format) const - { - evaluate().to_stream(os,format); - } - - void to_stream(std::basic_ostream<char_type>& os, const basic_output_format<char_type>& format, bool indenting) const - { - evaluate().to_stream(os,format,indenting); - } - - void swap(basic_json<CharT,Alloc>& val) - { - evaluate_with_default().swap(val); - } - - friend std::basic_ostream<char_type>& operator<<(std::basic_ostream<char_type>& os, const json_proxy& o) - { - o.to_stream(os); - return os; - } - -#if !defined(JSONCONS_NO_DEPRECATED) - - void resize_array(size_t n) - { - evaluate().resize_array(n); - } - - template <typename T> - void resize_array(size_t n, T val) - { - evaluate().resize_array(n,val); - } - - object_iterator begin_members() - { - return evaluate().begin_members(); - } - - const_object_iterator begin_members() const - { - return evaluate().begin_members(); - } - - object_iterator end_members() - { - return evaluate().end_members(); - } - - const_object_iterator end_members() const - { - return evaluate().end_members(); - } - - array_iterator begin_elements() - { - return evaluate().begin_elements(); - } - - const_array_iterator begin_elements() const - { - return evaluate().begin_elements(); - } - - array_iterator end_elements() - { - return evaluate().end_elements(); - } - - const_array_iterator end_elements() const - { - return evaluate().end_elements(); - } - - const basic_json<CharT,Alloc>& get(const string_type& name) const - { - return evaluate().get(name); - } - - bool is_ulonglong() const JSONCONS_NOEXCEPT - { - return evaluate().is_ulonglong(); - } - - bool is_longlong() const JSONCONS_NOEXCEPT - { - return evaluate().is_longlong(); - } - - int as_int() const - { - return evaluate().as_int(); - } - - unsigned int as_uint() const - { - return evaluate().as_uint(); - } - - long as_long() const - { - return evaluate().as_long(); - } - - unsigned long as_ulong() const - { - return evaluate().as_ulong(); - } - - long long as_longlong() const - { - return evaluate().as_longlong(); - } - - void add(size_t index, const basic_json<CharT,Alloc>& value) - { - evaluate_with_default().add(index, value); - } - - void add(size_t index, basic_json<CharT,Alloc>&& value) - { - evaluate_with_default().add(index, std::move(value)); - } - - bool has_member(const string_type& name) const - { - return evaluate().has_member(name); - } - - // Remove a range of elements from an array - void remove_range(size_t from_index, size_t to_index) - { - evaluate().remove_range(from_index, to_index); - } - // Remove a range of elements from an array - void remove(const string_type& name) - { - evaluate().remove(name); - } - void remove_member(const string_type& name) - { - evaluate().remove(name); - } - bool is_empty() const JSONCONS_NOEXCEPT - { - return empty(); - } - bool is_numeric() const JSONCONS_NOEXCEPT - { - return is_number(); - } -#endif - }; - - static basic_json parse_stream(std::basic_istream<char_type>& is); - static basic_json parse_stream(std::basic_istream<char_type>& is, basic_parse_error_handler<char_type>& err_handler); - - static basic_json parse(const string_type& s) - { - basic_json_deserializer<basic_json<CharT, Alloc>> handler; - basic_json_parser<char_type> parser(handler); - parser.begin_parse(); - parser.parse(s.data(),0,s.length()); - parser.end_parse(); - parser.check_done(s.data(),parser.index(),s.length()); - if (!handler.is_valid()) - { - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Failed to parse json string"); - } - return handler.get_result(); - } - - static basic_json parse(const string_type& s, basic_parse_error_handler<char_type>& err_handler) - { - basic_json_deserializer<basic_json<CharT, Alloc>> handler; - basic_json_parser<char_type> parser(handler,err_handler); - parser.begin_parse(); - parser.parse(s.data(),0,s.length()); - parser.end_parse(); - parser.check_done(s.data(),parser.index(),s.length()); - if (!handler.is_valid()) - { - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Failed to parse json string"); - } - return handler.get_result(); - } - - static basic_json parse_file(const std::string& s); - - static basic_json parse_file(const std::string& s, basic_parse_error_handler<char_type>& err_handler); - - static basic_json make_array() - { - return basic_json::array(); - } - - static basic_json make_array(size_t n, const array_allocator& allocator = array_allocator()) - { - return basic_json::array(n,allocator); - } - - template <class T> - static basic_json make_array(size_t n, const T& val, const array_allocator& allocator = array_allocator()) - { - return basic_json::array(n, val,allocator); - } - - template <size_t dim> - static typename std::enable_if<dim==1,basic_json>::type make_array(size_t n) - { - return array(n); - } - - template <size_t dim, class T> - static typename std::enable_if<dim==1,basic_json>::type make_array(size_t n, const T& val, const Alloc& allocator = Alloc()) - { - return array(n,val,allocator); - } - - template <size_t dim, typename... Args> - static typename std::enable_if<(dim>1),basic_json>::type make_array(size_t n, Args... args) - { - const size_t dim1 = dim - 1; - - basic_json val = make_array<dim1>(args...); - val.resize(n); - for (size_t i = 0; i < n; ++i) - { - val[i] = make_array<dim1>(args...); - } - return val; - } - - variant var_; - - basic_json() - : var_() - { - } - - basic_json(const Alloc& allocator) - : var_(allocator) - { - } - - basic_json(std::initializer_list<value_type> init, - const Alloc& allocator = Alloc()) - : var_(std::move(init), allocator) - { - } - - basic_json(const basic_json<CharT, Alloc>& val) - : var_(val.var_) - { - } - - basic_json(const basic_json<CharT, Alloc>& val, const Alloc& allocator) - : var_(val.var_,allocator) - { - } - - basic_json(basic_json<CharT,Alloc>&& other) - : var_(std::move(other.var_)) - { - } - - basic_json(basic_json<CharT,Alloc>&& other, const Alloc& allocator) - : var_(std::move(other.var_),allocator) - { - } - - basic_json(const array& val) - : var_(val) - { - } - - basic_json(array&& other) - : var_(std::move(other)) - { - } - - basic_json(const object& other) - : var_(other) - { - } - - basic_json(object&& other) - : var_(std::move(other)) - { - } - - template <class ParentT> - basic_json(const json_proxy<ParentT>& proxy, const Alloc& allocator = Alloc()) - : var_(proxy.evaluate().var_,allocator) - { - } - - template <typename T> - basic_json(T val) - : var_(null_type()) - { - json_type_traits<value_type,T>::assign(*this,val); - } - - basic_json(double val, uint8_t precision) - : var_(val,precision) - { - } - - template <typename T> - basic_json(T val, const Alloc& allocator) - : var_(allocator) - { - json_type_traits<value_type,T>::assign(*this,val); - } - - basic_json(const char_type *s, size_t length, const Alloc& allocator = Alloc()) - : var_(s, length, allocator) - { - } - template<class InputIterator> - basic_json(InputIterator first, InputIterator last, const Alloc& allocator = Alloc()) - : var_(first,last,allocator) - { - } - - ~basic_json() - { - } - - basic_json& operator=(const basic_json<CharT,Alloc>& rhs) - { - var_ = rhs.var_; - return *this; - } - - basic_json& operator=(basic_json<CharT,Alloc>&& rhs) - { - if (this != &rhs) - { - var_ = std::move(rhs.var_); - } - return *this; - } - - basic_json& operator=(std::initializer_list<value_type> init) - { - basic_json<CharT,Alloc> val(init); - swap(val); - return *this; - } - - template <class T> - basic_json<CharT, Alloc>& operator=(T val) - { - json_type_traits<value_type,T>::assign(*this,val); - return *this; - } - - bool operator!=(const basic_json<CharT,Alloc>& rhs) const; - - bool operator==(const basic_json<CharT,Alloc>& rhs) const; - - size_t size() const JSONCONS_NOEXCEPT - { - switch (var_.type_) - { - case value_types::empty_object_t: - return 0; - case value_types::object_t: - return var_.value_.object_val_->size(); - case value_types::array_t: - return var_.value_.array_val_->size(); - default: - return 0; - } - } - - basic_json<CharT,Alloc>& operator[](size_t i) - { - return at(i); - } - - const basic_json<CharT,Alloc>& operator[](size_t i) const - { - return at(i); - } - - json_proxy<basic_json<CharT, Alloc>> operator[](const string_type& name) - { - switch (var_.type_) - { - case value_types::empty_object_t: - create_object_implicitly(); - case value_types::object_t: - return json_proxy<basic_json<CharT,Alloc>>(*this, name); - break; - default: - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an object"); - break; - } - } - - const basic_json<CharT,Alloc>& operator[](const string_type& name) const - { - return at(name); - } - - string_type to_string(const string_allocator& allocator=string_allocator()) const JSONCONS_NOEXCEPT - { - string_type s(allocator); - std::basic_ostringstream<char_type,char_traits_type,string_allocator> os(s); - { - basic_json_serializer<char_type> serializer(os); - to_stream(serializer); - } - return os.str(); - } - - string_type to_string(const basic_output_format<char_type>& format, - const string_allocator& allocator=string_allocator()) const - { - string_type s(allocator); - std::basic_ostringstream<char_type> os(s); - { - basic_json_serializer<char_type> serializer(os, format); - to_stream(serializer); - } - return os.str(); - } - - void to_stream(basic_json_output_handler<char_type>& handler) const - { - switch (var_.type_) - { - case value_types::small_string_t: - handler.value(var_.value_.small_string_val_,var_.length_or_precision_); - break; - case value_types::string_t: - handler.value(var_.value_.string_val_->data(),var_.value_.string_val_->length()); - break; - case value_types::double_t: - handler.value(var_.value_.double_val_, var_.length_or_precision_); - break; - case value_types::integer_t: - handler.value(var_.value_.integer_val_); - break; - case value_types::uinteger_t: - handler.value(var_.value_.uinteger_val_); - break; - case value_types::bool_t: - handler.value(var_.value_.bool_val_); - break; - case value_types::null_t: - handler.value(null_type()); - break; - case value_types::empty_object_t: - handler.begin_object(); - handler.end_object(); - break; - case value_types::object_t: - { - handler.begin_object(); - object* o = var_.value_.object_val_; - for (const_object_iterator it = o->begin(); it != o->end(); ++it) - { - handler.name((it->name()).data(),it->name().length()); - it->value().to_stream(handler); - } - handler.end_object(); - } - break; - case value_types::array_t: - { - handler.begin_array(); - array *o = var_.value_.array_val_; - for (const_array_iterator it = o->begin(); it != o->end(); ++it) - { - it->to_stream(handler); - } - handler.end_array(); - } - break; - case value_types::any_t: - var_.value_.any_val_->to_stream(handler); - break; - default: - break; - } - } - - void to_stream(std::basic_ostream<char_type>& os) const - { - basic_json_serializer<char_type> serializer(os); - to_stream(serializer); - } - - void to_stream(std::basic_ostream<char_type>& os, const basic_output_format<char_type>& format) const - { - basic_json_serializer<char_type> serializer(os, format); - to_stream(serializer); - } - - void to_stream(std::basic_ostream<char_type>& os, const basic_output_format<char_type>& format, bool indenting) const - { - basic_json_serializer<char_type> serializer(os, format, indenting); - to_stream(serializer); - } - - bool is_null() const JSONCONS_NOEXCEPT - { - return var_.is_null(); - } - - size_t count(const string_type& name) const - { - switch (var_.type_) - { - case value_types::object_t: - { - auto it = var_.value_.object_val_->find(name.data(),name.length()); - if (it == members().end()) - { - return 0; - } - size_t count = 0; - while (it != members().end() && it->name() == name) - { - ++count; - ++it; - } - return count; - } - break; - default: - return 0; - } - } - - template<typename T> - bool is() const - { - return json_type_traits<value_type,T>::is(*this); - } - - bool is_string() const JSONCONS_NOEXCEPT - { - return var_.is_string(); - } - - - bool is_bool() const JSONCONS_NOEXCEPT - { - return var_.is_bool(); - } - - bool is_object() const JSONCONS_NOEXCEPT - { - return var_.type_ == value_types::object_t || var_.type_ == value_types::empty_object_t; - } - - bool is_array() const JSONCONS_NOEXCEPT - { - return var_.type_ == value_types::array_t; - } - - bool is_any() const JSONCONS_NOEXCEPT - { - return var_.type_ == value_types::any_t; - } - - bool is_integer() const JSONCONS_NOEXCEPT - { - return var_.type_ == value_types::integer_t || (var_.type_ == value_types::uinteger_t && (as_uinteger() <= static_cast<unsigned long long>(std::numeric_limits<long long>::max JSONCONS_NO_MACRO_EXP()))); - } - - bool is_uinteger() const JSONCONS_NOEXCEPT - { - return var_.type_ == value_types::uinteger_t || (var_.type_ == value_types::integer_t && as_integer() >= 0); - } - - bool is_double() const JSONCONS_NOEXCEPT - { - return var_.type_ == value_types::double_t; - } - - bool is_number() const JSONCONS_NOEXCEPT - { - return var_.is_number(); - } - - bool empty() const JSONCONS_NOEXCEPT - { - return var_.empty(); - } - - size_t capacity() const - { - switch (var_.type_) - { - case value_types::array_t: - return var_.value_.array_val_->capacity(); - case value_types::object_t: - return var_.value_.object_val_->capacity(); - default: - return 0; - } - } - - template<class U=Alloc, - typename std::enable_if<std::is_default_constructible<U>::value - >::type* = nullptr> - void create_object_implicitly() - { - var_.type_ = value_types::object_t; - var_.value_.object_val_ = create_impl<object>(Alloc(),object_allocator(Alloc())); - } - - template<class U=Alloc, - typename std::enable_if<!std::is_default_constructible<U>::value - >::type* = nullptr> - void create_object_implicitly() const - { - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Cannot create_impl object implicitly - allocator is not default constructible."); - } - - void reserve(size_t n) - { - switch (var_.type_) - { - case value_types::array_t: - var_.value_.array_val_->reserve(n); - break; - case value_types::empty_object_t: - { - create_object_implicitly(); - var_.value_.object_val_->reserve(n); - } - break; - case value_types::object_t: - { - var_.value_.object_val_->reserve(n); - } - break; - default: - break; - } - } - - void resize(size_t n) - { - switch (var_.type_) - { - case value_types::array_t: - var_.value_.array_val_->resize(n); - break; - default: - break; - } - } - - template <typename T> - void resize(size_t n, T val) - { - switch (var_.type_) - { - case value_types::array_t: - var_.value_.array_val_->resize(n, val); - break; - default: - break; - } - } - - template<typename T> - T as() const - { - return json_type_traits<value_type,T>::as(*this); - } - - template<typename T> - typename std::enable_if<std::is_same<string_type,T>::value>::type as(const string_allocator& allocator) const - { - return json_type_traits<value_type,T>::as(*this,allocator); - } - - bool as_bool() const JSONCONS_NOEXCEPT - { - switch (var_.type_) - { - case value_types::null_t: - case value_types::empty_object_t: - return false; - case value_types::bool_t: - return var_.value_.bool_val_; - case value_types::double_t: - return var_.value_.double_val_ != 0.0; - case value_types::integer_t: - return var_.value_.integer_val_ != 0; - case value_types::uinteger_t: - return var_.value_.uinteger_val_ != 0; - case value_types::small_string_t: - return var_.length_or_precision_ != 0; - case value_types::string_t: - return var_.value_.string_val_->length() != 0; - case value_types::array_t: - return var_.value_.array_val_->size() != 0; - case value_types::object_t: - return var_.value_.object_val_->size() != 0; - case value_types::any_t: - return true; - default: - return false; - } - } - - int64_t as_integer() const - { - switch (var_.type_) - { - case value_types::double_t: - return static_cast<int64_t>(var_.value_.double_val_); - case value_types::integer_t: - return static_cast<int64_t>(var_.value_.integer_val_); - case value_types::uinteger_t: - return static_cast<int64_t>(var_.value_.uinteger_val_); - case value_types::bool_t: - return var_.value_.bool_val_ ? 1 : 0; - default: - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an integer"); - } - } - - uint64_t as_uinteger() const - { - switch (var_.type_) - { - case value_types::double_t: - return static_cast<uint64_t>(var_.value_.double_val_); - case value_types::integer_t: - return static_cast<uint64_t>(var_.value_.integer_val_); - case value_types::uinteger_t: - return static_cast<uint64_t>(var_.value_.uinteger_val_); - case value_types::bool_t: - return var_.value_.bool_val_ ? 1 : 0; - default: - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an unsigned integer"); - } - } - - double as_double() const - { - switch (var_.type_) - { - case value_types::double_t: - return var_.value_.double_val_; - case value_types::integer_t: - return static_cast<double>(var_.value_.integer_val_); - case value_types::uinteger_t: - return static_cast<double>(var_.value_.uinteger_val_); - case value_types::null_t: - return std::numeric_limits<double>::quiet_NaN(); - default: - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not a double"); - } - } - - string_type as_string() const JSONCONS_NOEXCEPT - { - switch (var_.type_) - { - case value_types::small_string_t: - return string_type(var_.value_.small_string_val_,var_.length_or_precision_); - case value_types::string_t: - return string_type(var_.value_.string_val_->data(),var_.value_.string_val_->length(),var_.value_.string_val_->get_allocator()); - default: - return to_string(); - } - } - - string_type as_string(const string_allocator& allocator) const JSONCONS_NOEXCEPT - { - switch (var_.type_) - { - case value_types::small_string_t: - return string_type(var_.value_.small_string_val_,var_.length_or_precision_,allocator); - case value_types::string_t: - return string_type(var_.value_.string_val_->data(),var_.value_.string_val_->length(),allocator); - default: - return to_string(allocator); - } - } - - string_type as_string(const basic_output_format<char_type>& format) const - { - switch (var_.type_) - { - case value_types::small_string_t: - return string_type(var_.value_.small_string_val_,var_.length_or_precision_); - case value_types::string_t: - return string_type(var_.value_.string_val_->data(),var_.value_.string_val_->length(),var_.value_.string_val_->get_allocator()); - default: - return to_string(format); - } - } - - string_type as_string(const basic_output_format<char_type>& format, - const string_allocator& allocator) const - { - switch (var_.type_) - { - case value_types::small_string_t: - return string_type(var_.value_.small_string_val_,var_.length_or_precision_,allocator); - case value_types::string_t: - return string_type(var_.value_.string_val_->data(),var_.value_.string_val_->length(),allocator); - default: - return to_string(format,allocator); - } - } - - const char_type* as_cstring() const - { - switch (var_.type_) - { - case value_types::small_string_t: - return var_.value_.small_string_val_; - case value_types::string_t: - return var_.value_.string_val_->c_str(); - default: - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not a cstring"); - } - } - - any& any_value(); - - const any& any_value() const; - - basic_json<CharT, Alloc>& at(const string_type& name) - { - switch (var_.type_) - { - case value_types::empty_object_t: - JSONCONS_THROW_EXCEPTION_1(std::out_of_range,"%s not found", name); - case value_types::object_t: - { - auto it = var_.value_.object_val_->find(name.data(),name.length()); - if (it == members().end()) - { - JSONCONS_THROW_EXCEPTION_1(std::out_of_range, "%s not found", name); - } - return it->value(); - } - break; - default: - { - JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to get %s from a value that is not an object", name); - } - } - } - - basic_json<CharT, Alloc>& evaluate() - { - return *this; - } - - basic_json<CharT, Alloc>& evaluate_with_default() - { - return *this; - } - - const basic_json<CharT, Alloc>& evaluate() const - { - return *this; - } - - basic_json<CharT, Alloc>& evaluate(size_t i) - { - return at(i); - } - - const basic_json<CharT, Alloc>& evaluate(size_t i) const - { - return at(i); - } - - basic_json<CharT, Alloc>& evaluate(const string_type& name) - { - return at(name); - } - - const basic_json<CharT, Alloc>& evaluate(const string_type& name) const - { - return at(name); - } - - const basic_json<CharT, Alloc>& at(const string_type& name) const - { - switch (var_.type_) - { - case value_types::empty_object_t: - JSONCONS_THROW_EXCEPTION_1(std::out_of_range,"%s not found", name); - case value_types::object_t: - { - auto it = var_.value_.object_val_->find(name.data(),name.length()); - if (it == members().end()) - { - JSONCONS_THROW_EXCEPTION_1(std::out_of_range, "%s not found", name); - } - return it->value(); - } - break; - default: - { - JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to get %s from a value that is not an object", name); - } - } - } - - basic_json<CharT, Alloc>& at(size_t i) - { - switch (var_.type_) - { - case value_types::array_t: - if (i >= var_.value_.array_val_->size()) - { - JSONCONS_THROW_EXCEPTION(std::out_of_range,"Invalid array subscript"); - } - return var_.value_.array_val_->operator[](i); - default: - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Index on non-array value not supported"); - } - } - - const basic_json<CharT, Alloc>& at(size_t i) const - { - switch (var_.type_) - { - case value_types::array_t: - if (i >= var_.value_.array_val_->size()) - { - JSONCONS_THROW_EXCEPTION(std::out_of_range,"Invalid array subscript"); - } - return var_.value_.array_val_->operator[](i); - default: - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Index on non-array value not supported"); - } - } - - object_iterator find(const string_type& name) - { - switch (var_.type_) - { - case value_types::empty_object_t: - return members().end(); - case value_types::object_t: - return var_.value_.object_val_->find(name.data(),name.length()); - default: - { - JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to get %s from a value that is not an object", name); - } - } - } - - const_object_iterator find(const string_type& name) const - { - switch (var_.type_) - { - case value_types::empty_object_t: - return members().end(); - case value_types::object_t: - return var_.value_.object_val_->find(name.data(),name.length()); - default: - { - JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to get %s from a value that is not an object", name); - } - } - } - - object_iterator find(const char_type* name) - { - switch (var_.type_) - { - case value_types::empty_object_t: - return members().end(); - case value_types::object_t: - return var_.value_.object_val_->find(name, std::char_traits<char_type>::length(name)); - default: - { - JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to get %s from a value that is not an object", name); - } - } - } - - const_object_iterator find(const char_type* name) const - { - switch (var_.type_) - { - case value_types::empty_object_t: - return members().end(); - case value_types::object_t: - return var_.value_.object_val_->find(name, std::char_traits<char_type>::length(name)); - default: - { - JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to get %s from a value that is not an object", name); - } - } - } - - object_iterator find(const char_type* name, size_t length) - { - switch (var_.type_) - { - case value_types::empty_object_t: - return members().end(); - case value_types::object_t: - return var_.value_.object_val_->find(name, length); - default: - { - JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to get %s from a value that is not an object", name); - } - } - } - - const_object_iterator find(const char_type* name, size_t length) const - { - switch (var_.type_) - { - case value_types::empty_object_t: - return members().end(); - case value_types::object_t: - return var_.value_.object_val_->find(name, length); - default: - { - JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to get %s from a value that is not an object", name); - } - } - } - - template<typename T> - basic_json<CharT, Alloc> get(const string_type& name, T&& default_val) const - { - switch (var_.type_) - { - case value_types::empty_object_t: - { - return basic_json<CharT,Alloc>(std::forward<T>(default_val)); - } - case value_types::object_t: - { - const_object_iterator it = var_.value_.object_val_->find(name.data(),name.length()); - if (it != members().end()) - { - return it->value(); - } - else - { - return basic_json<CharT,Alloc>(std::forward<T>(default_val)); - } - } - default: - { - JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to get %s from a value that is not an object", name); - } - } - } - - // Modifiers - - void shrink_to_fit() - { - switch (var_.type_) - { - case value_types::array_t: - var_.value_.array_val_->shrink_to_fit(); - break; - case value_types::object_t: - var_.value_.object_val_->shrink_to_fit(); - break; - default: - break; - } - } - - void clear() - { - switch (var_.type_) - { - case value_types::array_t: - var_.value_.array_val_->clear(); - break; - case value_types::object_t: - var_.value_.object_val_->clear(); - break; - default: - break; - } - } - - void erase(object_iterator first, object_iterator last) - { - switch (var_.type_) - { - case value_types::empty_object_t: - break; - case value_types::object_t: - var_.value_.object_val_->erase(first, last); - break; - default: - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an object"); - break; - } - } - - void erase(array_iterator first, array_iterator last) - { - switch (var_.type_) - { - case value_types::array_t: - var_.value_.array_val_->erase(first, last); - break; - default: - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an array"); - break; - } - } - - // Removes all elements from an array value whose index is between from_index, inclusive, and to_index, exclusive. - - void erase(const string_type& name) - { - switch (var_.type_) - { - case value_types::empty_object_t: - break; - case value_types::object_t: - var_.value_.object_val_->erase(name.data(),name.length()); - break; - default: - JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to set %s on a value that is not an object", name); - break; - } - } - - void set(const string_type& name, const basic_json<CharT, Alloc>& value) - { - switch (var_.type_) - { - case value_types::empty_object_t: - create_object_implicitly(); - case value_types::object_t: - var_.value_.object_val_->set(name, value); - break; - default: - { - JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to set %s on a value that is not an object", name); - } - } - } - - void set(string_type&& name, const basic_json<CharT, Alloc>& value){ - switch (var_.type_){ - case value_types::empty_object_t: - create_object_implicitly(); - case value_types::object_t: - var_.value_.object_val_->set(std::move(name),value); - break; - default: - { - JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to set %s on a value that is not an object",name); - } - } - } - - void set(const string_type& name, basic_json<CharT, Alloc>&& value){ - switch (var_.type_){ - case value_types::empty_object_t: - create_object_implicitly(); - case value_types::object_t: - var_.value_.object_val_->set(name,std::move(value)); - break; - default: - { - JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to set %s on a value that is not an object",name); - } - } - } - - void set(string_type&& name, basic_json<CharT, Alloc>&& value) - { - switch (var_.type_) - { - case value_types::empty_object_t: - create_object_implicitly(); - case value_types::object_t: - var_.value_.object_val_->set(std::move(name),std::move(value)); - break; - default: - { - JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to set %s on a value that is not an object",name); - } - } - } - - object_iterator set(object_iterator hint, const string_type& name, const basic_json<CharT, Alloc>& value) - { - switch (var_.type_) - { - case value_types::empty_object_t: - create_object_implicitly(); - case value_types::object_t: - return var_.value_.object_val_->set(hint, name, value); - break; - default: - { - JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to set %s on a value that is not an object", name); - } - } - } - - object_iterator set(object_iterator hint, string_type&& name, const basic_json<CharT, Alloc>& value){ - switch (var_.type_){ - case value_types::empty_object_t: - create_object_implicitly(); - case value_types::object_t: - return var_.value_.object_val_->set(hint, std::move(name),value); - break; - default: - { - JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to set %s on a value that is not an object",name); - } - } - } - - object_iterator set(object_iterator hint, const string_type& name, basic_json<CharT, Alloc>&& value){ - switch (var_.type_){ - case value_types::empty_object_t: - create_object_implicitly(); - case value_types::object_t: - return var_.value_.object_val_->set(hint, name,std::move(value)); - break; - default: - { - JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to set %s on a value that is not an object",name); - } - } - } - - object_iterator set(object_iterator hint, string_type&& name, basic_json<CharT, Alloc>&& value){ - switch (var_.type_){ - case value_types::empty_object_t: - create_object_implicitly(); - case value_types::object_t: - return var_.value_.object_val_->set(hint, std::move(name),std::move(value)); - break; - default: - { - JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to set %s on a value that is not an object",name); - } - } - } - - void add(const basic_json<CharT, Alloc>& value) - { - switch (var_.type_) - { - case value_types::array_t: - var_.value_.array_val_->push_back(value); - break; - default: - { - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Attempting to insert into a value that is not an array"); - } - } - } - - void add(basic_json<CharT, Alloc>&& value){ - switch (var_.type_){ - case value_types::array_t: - var_.value_.array_val_->push_back(std::move(value)); - break; - default: - { - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Attempting to insert into a value that is not an array"); - } - } - } - - array_iterator add(const_array_iterator pos, const basic_json<CharT, Alloc>& value) - { - switch (var_.type_) - { - case value_types::array_t: - return var_.value_.array_val_->add(pos, value); - break; - default: - { - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Attempting to insert into a value that is not an array"); - } - } - } - - array_iterator add(const_array_iterator pos, basic_json<CharT, Alloc>&& value){ - switch (var_.type_){ - case value_types::array_t: - return var_.value_.array_val_->add(pos, std::move(value)); - break; - default: - { - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Attempting to insert into a value that is not an array"); - } - } - } - - value_types type() const - { - return var_.type_; - } - - uint8_t length_or_precision() const - { - return var_.length_or_precision_; - } - - void swap(basic_json<CharT,Alloc>& b) - { - var_.swap(b.var_); - } - - template <class T> - std::vector<T> as_vector() const - { - std::vector<T> v(size()); - for (size_t i = 0; i < v.size(); ++i) - { - v[i] = json_type_traits<value_type,T>::as(at(i)); - } - return v; - } - - friend void swap(basic_json<CharT,Alloc>& a, basic_json<CharT,Alloc>& b) - { - a.swap(b); - } - - void assign_any(const typename basic_json<CharT,Alloc>::any& rhs) - { - var_.assign(rhs); - } - - void assign_string(const string_type& rhs) - { - var_.assign(rhs); - } - - void assign_string(const char_type* rhs, size_t length) - { - var_.assign_string(rhs,length); - } - - void assign_bool(bool rhs) - { - var_.assign(rhs); - } - - void assign_object(const object & rhs) - { - var_.assign(rhs); - } - - void assign_array(const array& rhs) - { - var_.assign(rhs); - } - - void assign_null() - { - var_.assign(null_type()); - } - - template <typename T> - const T& any_cast() const - { - if (var_.type_ != value_types::any_t) - { - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Bad any cast"); - } - return var_.value_.any_val_->template cast<T>(); - } - template <typename T> - T& any_cast() - { - if (var_.type_ != value_types::any_t) - { - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Bad any cast"); - } - return var_.value_.any_val_->template cast<T>(); - } - - void assign_integer(int64_t rhs) - { - var_.assign(rhs); - } - - void assign_uinteger(uint64_t rhs) - { - var_.assign(rhs); - } - - void assign_double(double rhs, uint8_t precision = 0) - { - var_.assign(rhs,precision); - } - - static basic_json make_2d_array(size_t m, size_t n); - - template <typename T> - static basic_json make_2d_array(size_t m, size_t n, T val); - - static basic_json make_3d_array(size_t m, size_t n, size_t k); - - template <typename T> - static basic_json make_3d_array(size_t m, size_t n, size_t k, T val); - -#if !defined(JSONCONS_NO_DEPRECATED) - typedef any json_any_type; - - static basic_json parse(std::basic_istream<char_type>& is) - { - return parse_stream(is); - } - static basic_json parse(std::basic_istream<char_type>& is, basic_parse_error_handler<char_type>& err_handler) - { - return parse_stream(is,err_handler); - } - - static basic_json parse_string(const string_type& s) - { - return parse(s); - } - - static basic_json parse_string(const string_type& s, basic_parse_error_handler<char_type>& err_handler) - { - return parse(s,err_handler); - } - - void resize_array(size_t n) - { - resize(n); - } - - template <typename T> - void resize_array(size_t n, T val) - { - resize(n,val); - } - - object_iterator begin_members() - { - return members().begin(); - } - - const_object_iterator begin_members() const - { - return members().begin(); - } - - object_iterator end_members() - { - return members().end(); - } - - const_object_iterator end_members() const - { - return members().end(); - } - - array_iterator begin_elements() - { - return elements().begin(); - } - - const_array_iterator begin_elements() const - { - return elements().begin(); - } - - array_iterator end_elements() - { - return elements().end(); - } - - const_array_iterator end_elements() const - { - return elements().end(); - } - - const basic_json<CharT,Alloc>& get(const string_type& name) const - { - static const basic_json<CharT, Alloc> a_null = null_type(); - - switch (var_.type_) - { - case value_types::empty_object_t: - return a_null; - case value_types::object_t: - { - const_object_iterator it = var_.value_.object_val_->find(name.data(),name.length()); - return it != members().end() ? it->value() : a_null; - } - default: - { - JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Attempting to get %s from a value that is not an object", name); - } - } - } - - bool is_longlong() const JSONCONS_NOEXCEPT - { - return var_.type_ == value_types::integer_t; - } - - bool is_ulonglong() const JSONCONS_NOEXCEPT - { - return var_.type_ == value_types::uinteger_t; - } - - long long as_longlong() const - { - return as_integer(); - } - - unsigned long long as_ulonglong() const - { - return as_uinteger(); - } - - int as_int() const - { - switch (var_.type_) - { - case value_types::double_t: - return static_cast<int>(var_.value_.double_val_); - case value_types::integer_t: - return static_cast<int>(var_.value_.integer_val_); - case value_types::uinteger_t: - return static_cast<int>(var_.value_.uinteger_val_); - case value_types::bool_t: - return var_.value_.bool_val_ ? 1 : 0; - default: - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an int"); - } - } - - unsigned int as_uint() const - { - switch (var_.type_) - { - case value_types::double_t: - return static_cast<unsigned int>(var_.value_.double_val_); - case value_types::integer_t: - return static_cast<unsigned int>(var_.value_.integer_val_); - case value_types::uinteger_t: - return static_cast<unsigned int>(var_.value_.uinteger_val_); - case value_types::bool_t: - return var_.value_.bool_val_ ? 1 : 0; - default: - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an unsigned int"); - } - } - - long as_long() const - { - switch (var_.type_) - { - case value_types::double_t: - return static_cast<long>(var_.value_.double_val_); - case value_types::integer_t: - return static_cast<long>(var_.value_.integer_val_); - case value_types::uinteger_t: - return static_cast<long>(var_.value_.uinteger_val_); - case value_types::bool_t: - return var_.value_.bool_val_ ? 1 : 0; - default: - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not a long"); - } - } - - unsigned long as_ulong() const - { - switch (var_.type_) - { - case value_types::double_t: - return static_cast<unsigned long>(var_.value_.double_val_); - case value_types::integer_t: - return static_cast<unsigned long>(var_.value_.integer_val_); - case value_types::uinteger_t: - return static_cast<unsigned long>(var_.value_.uinteger_val_); - case value_types::bool_t: - return var_.value_.bool_val_ ? 1 : 0; - default: - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an unsigned long"); - } - } - - void add(size_t index, const basic_json<CharT, Alloc>& value) - { - switch (var_.type_) - { - case value_types::array_t: - var_.value_.array_val_->add(index, value); - break; - default: - { - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Attempting to insert into a value that is not an array"); - } - } - } - - void add(size_t index, basic_json<CharT, Alloc>&& value){ - switch (var_.type_){ - case value_types::array_t: - var_.value_.array_val_->add(index, std::move(value)); - break; - default: - { - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Attempting to insert into a value that is not an array"); - } - } - } - - bool has_member(const string_type& name) const - { - switch (var_.type_) - { - case value_types::object_t: - { - const_object_iterator it = var_.value_.object_val_->find(name.data(),name.length()); - return it != members().end(); - } - break; - default: - return false; - } - } - - void remove_range(size_t from_index, size_t to_index) - { - switch (var_.type_) - { - case value_types::array_t: - var_.value_.array_val_->remove_range(from_index, to_index); - break; - default: - break; - } - } - // Removes all elements from an array value whose index is between from_index, inclusive, and to_index, exclusive. - - void remove(const string_type& name) - { - erase(name.data(),name.length()); - } - void remove_member(const string_type& name) - { - erase(name.data(),name.length()); - } - // Removes a member from an object value - - bool is_empty() const JSONCONS_NOEXCEPT - { - return empty(); - } - bool is_numeric() const JSONCONS_NOEXCEPT - { - return is_number(); - } - - void assign_longlong(long long rhs) - { - var_.assign(rhs); - } - void assign_ulonglong(unsigned long long rhs) - { - var_.assign(rhs); - } - - template<int size> - static typename std::enable_if<size==1,basic_json>::type make_multi_array() - { - return make_array(); - } - template<size_t size> - static typename std::enable_if<size==1,basic_json>::type make_multi_array(size_t n) - { - return make_array(n); - } - template<size_t size,typename T> - static typename std::enable_if<size==1,basic_json>::type make_multi_array(size_t n, T val) - { - return make_array(n,val); - } - template<size_t size> - static typename std::enable_if<size==2,basic_json>::type make_multi_array(size_t m, size_t n) - { - return make_array<2>(m, n); - } - template<size_t size,typename T> - static typename std::enable_if<size==2,basic_json>::type make_multi_array(size_t m, size_t n, T val) - { - return make_array<2>(m, n, val); - } - template<size_t size> - static typename std::enable_if<size==3,basic_json>::type make_multi_array(size_t m, size_t n, size_t k) - { - return make_array<3>(m, n, k); - } - template<size_t size,typename T> - static typename std::enable_if<size==3,basic_json>::type make_multi_array(size_t m, size_t n, size_t k, T val) - { - return make_array<3>(m, n, k, val); - } -#endif - - object_range members() - { - switch (var_.type_) - { - case value_types::empty_object_t: - return object_range(object_iterator(true),object_iterator(true)); - case value_types::object_t: - return object_range(object_value().begin(),object_value().end()); - default: - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an object"); - } - } - - const_object_range members() const - { - switch (var_.type_) - { - case value_types::empty_object_t: - return const_object_range(const_object_iterator(true),const_object_iterator(true)); - case value_types::object_t: - return const_object_range(object_value().begin(),object_value().end()); - default: - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an object"); - } - } - - array_range elements() - { - switch (var_.type_) - { - case value_types::array_t: - return array_range(array_value().begin(),array_value().end()); - default: - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an array"); - } - } - - const_array_range elements() const - { - switch (var_.type_) - { - case value_types::array_t: - return const_array_range(array_value().begin(),array_value().end()); - default: - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an array"); - } - } - - array& array_value() - { - switch (var_.type_) - { - case value_types::array_t: - return *(var_.value_.array_val_); - default: - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Bad array cast"); - break; - } - } - - const array& array_value() const - { - switch (var_.type_) - { - case value_types::array_t: - return *(var_.value_.array_val_); - default: - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Bad array cast"); - break; - } - } - - object& object_value() - { - switch (var_.type_) - { - case value_types::empty_object_t: - create_object_implicitly(); - case value_types::object_t: - return *(var_.value_.object_val_); - default: - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Bad object cast"); - break; - } - } - - const object& object_value() const - { - switch (var_.type_) - { - case value_types::empty_object_t: - const_cast<value_type*>(this)->create_object_implicitly(); // HERE - case value_types::object_t: - return *(var_.value_.object_val_); - default: - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Bad object cast"); - break; - } - } - -private: - - friend std::basic_ostream<typename string_type::value_type>& operator<<(std::basic_ostream<typename string_type::value_type>& os, const basic_json<CharT, Alloc>& o) - { - o.to_stream(os); - return os; - } - - friend std::basic_istream<typename string_type::value_type>& operator<<(std::basic_istream<typename string_type::value_type>& is, basic_json<CharT, Alloc>& o) - { - basic_json_deserializer<basic_json<CharT, Alloc>> handler; - basic_json_reader<typename string_type::value_type> reader(is, handler); - reader.read_next(); - reader.check_done(); - if (!handler.is_valid()) - { - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Failed to parse json stream"); - } - o = handler.get_result(); - return is; - } -}; - -template <class JsonT> -void swap(typename JsonT::member_type& a, typename JsonT::member_type& b) -{ - a.swap(b); -} - -template<typename CharT, typename Alloc> -bool basic_json<CharT, Alloc>::operator!=(const basic_json<CharT, Alloc>& rhs) const -{ - return !(*this == rhs); -} - -template<typename CharT, typename Alloc> -bool basic_json<CharT, Alloc>::operator==(const basic_json<CharT, Alloc>& rhs) const -{ - return var_ == rhs.var_; -} - -template<typename CharT, typename Alloc> -basic_json<CharT, Alloc> basic_json<CharT, Alloc>::make_2d_array(size_t m, size_t n) -{ - basic_json<CharT, Alloc> a = basic_json<CharT, Alloc>::array(); - a.resize(m); - for (size_t i = 0; i < a.size(); ++i) - { - a[i] = basic_json<CharT, Alloc>::make_array(n); - } - return a; -} - -template<typename CharT, typename Alloc> -template<typename T> -basic_json<CharT, Alloc> basic_json<CharT, Alloc>::make_2d_array(size_t m, size_t n, T val) -{ - basic_json<CharT, Alloc> v; - v = val; - basic_json<CharT, Alloc> a = make_array(m); - for (size_t i = 0; i < a.size(); ++i) - { - a[i] = basic_json<CharT, Alloc>::make_array(n, v); - } - return a; -} - -template<typename CharT, typename Alloc> -basic_json<CharT, Alloc> basic_json<CharT, Alloc>::make_3d_array(size_t m, size_t n, size_t k) -{ - basic_json<CharT, Alloc> a = basic_json<CharT, Alloc>::array(); - a.resize(m); - for (size_t i = 0; i < a.size(); ++i) - { - a[i] = basic_json<CharT, Alloc>::make_2d_array(n, k); - } - return a; -} - -template<typename CharT, typename Alloc> -template<typename T> -basic_json<CharT, Alloc> basic_json<CharT, Alloc>::make_3d_array(size_t m, size_t n, size_t k, T val) -{ - basic_json<CharT, Alloc> v; - v = val; - basic_json<CharT, Alloc> a = make_array(m); - for (size_t i = 0; i < a.size(); ++i) - { - a[i] = basic_json<CharT, Alloc>::make_2d_array(n, k, v); - } - return a; -} - -template<typename CharT, typename Alloc> -basic_json<CharT, Alloc> basic_json<CharT, Alloc>::parse_stream(std::basic_istream<char_type>& is) -{ - basic_json_deserializer<basic_json<CharT, Alloc>> handler; - basic_json_reader<char_type> reader(is, handler); - reader.read_next(); - reader.check_done(); - if (!handler.is_valid()) - { - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Failed to parse json stream"); - } - return handler.get_result(); -} - -template<typename CharT, typename Alloc> -basic_json<CharT, Alloc> basic_json<CharT, Alloc>::parse_stream(std::basic_istream<char_type>& is, - basic_parse_error_handler<char_type>& err_handler) -{ - basic_json_deserializer<basic_json<CharT, Alloc>> handler; - basic_json_reader<char_type> reader(is, handler, err_handler); - reader.read_next(); - reader.check_done(); - if (!handler.is_valid()) - { - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Failed to parse json stream"); - } - return handler.get_result(); -} - -template<typename CharT, typename Alloc> -basic_json<CharT, Alloc> basic_json<CharT, Alloc>::parse_file(const std::string& filename) -{ - FILE* fp; - -#if defined(JSONCONS_HAS_FOPEN_S) - errno_t err = fopen_s(&fp, filename.c_str(), "rb"); - if (err != 0) - { - JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Cannot open file %s", filename); - } -#else - fp = std::fopen(filename.c_str(), "rb"); - if (fp == nullptr) - { - JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Cannot open file %s", filename); - } -#endif - basic_json_deserializer<basic_json<CharT, Alloc>> handler; - try - { - // obtain file size: - std::fseek (fp , 0 , SEEK_END); - long size = std::ftell (fp); - std::rewind(fp); - - if (size > 0) - { - std::vector<char_type> buffer(size); - - // copy the file into the buffer: - size_t result = std::fread (buffer.data(),1,size,fp); - if (result != static_cast<unsigned long long>(size)) - { - JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Error reading file %s", filename); - } - - basic_json_parser<char_type> parser(handler); - parser.begin_parse(); - parser.parse(buffer.data(),0,buffer.size()); - parser.end_parse(); - parser.check_done(buffer.data(),parser.index(),buffer.size()); - } - - std::fclose (fp); - } - catch (...) - { - std::fclose (fp); - throw; - } - if (!handler.is_valid()) - { - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Failed to parse json file"); - } - return handler.get_result(); -} - -template<typename CharT, typename Alloc> -basic_json<CharT, Alloc> basic_json<CharT, Alloc>::parse_file(const std::string& filename, - basic_parse_error_handler<char_type>& err_handler) -{ - FILE* fp; - -#if !defined(JSONCONS_HAS_FOPEN_S) - fp = std::fopen(filename.c_str(), "rb"); - if (fp == nullptr) - { - JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Cannot open file %s", filename); - } -#else - errno_t err = fopen_s(&fp, filename.c_str(), "rb"); - if (err != 0) - { - JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Cannot open file %s", filename); - } -#endif - - basic_json_deserializer<basic_json<CharT, Alloc>> handler; - try - { - // obtain file size: - std::fseek (fp , 0 , SEEK_END); - long size = std::ftell (fp); - std::rewind(fp); - - if (size > 0) - { - std::vector<char_type> buffer(size); - - // copy the file into the buffer: - size_t result = std::fread (buffer.data(),1,size,fp); - if (result != static_cast<unsigned long long>(size)) - { - JSONCONS_THROW_EXCEPTION_1(std::runtime_error,"Error reading file %s", filename); - } - - basic_json_parser<char_type> parser(handler,err_handler); - parser.begin_parse(); - parser.parse(buffer.data(),0,buffer.size()); - parser.end_parse(); - parser.check_done(buffer.data(),parser.index(),buffer.size()); - } - - std::fclose (fp); - } - catch (...) - { - std::fclose (fp); - throw; - } - if (!handler.is_valid()) - { - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Failed to parse json file"); - } - return handler.get_result(); -} - -template<typename CharT, typename Alloc> -typename basic_json<CharT, Alloc>::any& basic_json<CharT, Alloc>::any_value() -{ - switch (var_.type_) - { - case value_types::any_t: - { - return *var_.value_.any_val_; - } - default: - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an any value"); - } -} - -template<typename CharT, typename Alloc> -const typename basic_json<CharT, Alloc>::any& basic_json<CharT, Alloc>::any_value() const -{ - switch (var_.type_) - { - case value_types::any_t: - { - return *var_.value_.any_val_; - } - default: - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Not an any value"); - } -} - -template <typename JsonT> -std::basic_istream<typename JsonT::char_type>& operator>>(std::basic_istream<typename JsonT::char_type>& is, JsonT& o) -{ - basic_json_deserializer<JsonT> handler; - basic_json_reader<typename JsonT::char_type> reader(is, handler); - reader.read_next(); - reader.check_done(); - if (!handler.is_valid()) - { - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Failed to parse json stream"); - } - o = handler.get_result(); - return is; -} - -template<typename JsonT> -class json_printable -{ -public: - typedef typename JsonT::char_type char_type; - - json_printable(const JsonT& o, - bool is_pretty_print) - : o_(&o), is_pretty_print_(is_pretty_print) - { - } - - json_printable(const JsonT& o, - bool is_pretty_print, - const basic_output_format<char_type>& format) - : o_(&o), is_pretty_print_(is_pretty_print), format_(format) - { - ; - } - - void to_stream(std::basic_ostream<char_type>& os) const - { - o_->to_stream(os, format_, is_pretty_print_); - } - - friend std::basic_ostream<char_type>& operator<<(std::basic_ostream<char_type>& os, const json_printable<JsonT>& o) - { - o.to_stream(os); - return os; - } - - const JsonT *o_; - bool is_pretty_print_; - basic_output_format<char_type> format_; -private: - json_printable(); -}; - -template<typename JsonT> -json_printable<JsonT> print(const JsonT& val) -{ - return json_printable<JsonT>(val,false); -} - -template<class JsonT> -json_printable<JsonT> print(const JsonT& val, - const basic_output_format<typename JsonT::char_type>& format) -{ - return json_printable<JsonT>(val, false, format); -} - -template<class JsonT> -json_printable<JsonT> pretty_print(const JsonT& val) -{ - return json_printable<JsonT>(val,true); -} - -template<typename JsonT> -json_printable<JsonT> pretty_print(const JsonT& val, - const basic_output_format<typename JsonT::char_type>& format) -{ - return json_printable<JsonT>(val, true, format); -} - -typedef basic_json<char,std::allocator<char>> json; -typedef basic_json<wchar_t,std::allocator<wchar_t>> wjson; - -typedef basic_json_deserializer<json> json_deserializer; -typedef basic_json_deserializer<wjson> wjson_deserializer; - -} - -#if defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - -#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons/json_deserializer.hpp b/vendor/jsoncons-0.99.2/jsoncons/json_deserializer.hpp deleted file mode 100644 index 31cd0db9..00000000 --- a/vendor/jsoncons-0.99.2/jsoncons/json_deserializer.hpp +++ /dev/null @@ -1,267 +0,0 @@ -// Copyright 2013-2016 Daniel Parker -// Distributed under the Boost license, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -// See https://github.com/danielaparker/jsoncons for latest version - -#ifndef JSONCONS_JSON_DESERIALIZER_HPP -#define JSONCONS_JSON_DESERIALIZER_HPP - -#include <string> -#include <sstream> -#include <vector> -#include <istream> -#include <cstdlib> -#include <memory> -#include "jsoncons/jsoncons.hpp" -#include "jsoncons/json_input_handler.hpp" - -namespace jsoncons { - -template <class JsonT> -class basic_json_deserializer : public basic_json_input_handler<typename JsonT::char_type> -{ - static const int default_stack_size = 1000; - - typedef typename JsonT::char_type char_type; - typedef typename JsonT::member_type member_type; - typedef typename JsonT::string_type string_type; - typedef typename string_type::allocator_type string_allocator; - typedef typename JsonT::allocator_type allocator_type; - typedef typename JsonT::array array; - typedef typename array::allocator_type array_allocator; - typedef typename JsonT::object object; - typedef typename object::allocator_type object_allocator; - typedef typename JsonT::value_type value_type; - - string_allocator sa_; - object_allocator oa_; - array_allocator aa_; - - JsonT result_; - size_t top_; - - struct stack_item - { - string_type name_; - value_type value_; - }; - std::vector<stack_item> stack_; - std::vector<size_t> stack2_; - bool is_valid_; - -public: - basic_json_deserializer(const string_allocator& sa = string_allocator(), - const allocator_type& allocator = allocator_type()) - : sa_(sa), - oa_(allocator), - aa_(allocator), - top_(0), - stack_(default_stack_size), - stack2_(), - is_valid_(true) // initial json value is an empty object - - { - stack2_.reserve(100); - } - - bool is_valid() const - { - return is_valid_; - } - - JsonT get_result() - { - is_valid_ = false; - return std::move(result_); - } - -#if !defined(JSONCONS_NO_DEPRECATED) - JsonT& root() - { - return result_; - } -#endif - -private: - - void push_initial() - { - top_ = 0; - if (top_ >= stack_.size()) - { - stack_.resize(top_*2); - } - } - - void pop_initial() - { - JSONCONS_ASSERT(top_ == 1); - result_.swap(stack_[0].value_); - --top_; - } - - void push_object() - { - stack2_.push_back(top_); - stack_[top_].value_ = object(oa_); - if (++top_ >= stack_.size()) - { - stack_.resize(top_*2); - } - } - - void pop_object() - { - stack2_.pop_back(); - JSONCONS_ASSERT(top_ > 0); - } - - void push_array() - { - stack2_.push_back(top_); - stack_[top_].value_ = array(aa_); - if (++top_ >= stack_.size()) - { - stack_.resize(top_*2); - } - } - - void pop_array() - { - stack2_.pop_back(); - JSONCONS_ASSERT(top_ > 0); - } - - void do_begin_json() override - { - is_valid_ = false; - push_initial(); - } - - void do_end_json() override - { - is_valid_ = true; - pop_initial(); - } - - void do_begin_object(const basic_parsing_context<char_type>&) override - { - push_object(); - } - - void do_end_object(const basic_parsing_context<char_type>&) override - { - end_structure(); - pop_object(); - } - - void do_begin_array(const basic_parsing_context<char_type>&) override - { - push_array(); - } - - void do_end_array(const basic_parsing_context<char_type>&) override - { - end_structure(); - pop_array(); - } - - static member_type move_pair(stack_item&& val) - { - return member_type(std::move(val.name_),std::move(val.value_)); - } - - void end_structure() - { - JSONCONS_ASSERT(stack2_.size() > 0); - if (stack_[stack2_.back()].value_.is_object()) - { - size_t count = top_ - (stack2_.back() + 1); - auto s = stack_.begin() + (stack2_.back()+1); - auto send = s + count; - stack_[stack2_.back()].value_.object_value().insert( - std::make_move_iterator(s), - std::make_move_iterator(send), - move_pair); - top_ -= count; - } - else - { - size_t count = top_ - (stack2_.back() + 1); - stack_[stack2_.back()].value_.resize(count); - - auto s = stack_.begin() + (stack2_.back()+1); - auto dend = stack_[stack2_.back()].value_.elements().end(); - for (auto it = stack_[stack2_.back()].value_.elements().begin(); - it != dend; ++it, ++s) - { - *it = std::move(s->value_); - } - top_ -= count; - } - } - - void do_name(const char_type* p, size_t length, const basic_parsing_context<char_type>&) override - { - stack_[top_].name_ = string_type(p,length,sa_); - } - - void do_string_value(const char_type* p, size_t length, const basic_parsing_context<char_type>&) override - { - stack_[top_].value_ = JsonT(p,length,sa_); - if (++top_ >= stack_.size()) - { - stack_.resize(top_*2); - } - } - - void do_integer_value(int64_t value, const basic_parsing_context<char_type>&) override - { - stack_[top_].value_ = value; - if (++top_ >= stack_.size()) - { - stack_.resize(top_*2); - } - } - - void do_uinteger_value(uint64_t value, const basic_parsing_context<char_type>&) override - { - stack_[top_].value_ = value; - if (++top_ >= stack_.size()) - { - stack_.resize(top_*2); - } - } - - void do_double_value(double value, uint8_t precision, const basic_parsing_context<char_type>&) override - { - stack_[top_].value_ = value_type(value,precision); - if (++top_ >= stack_.size()) - { - stack_.resize(top_*2); - } - } - - void do_bool_value(bool value, const basic_parsing_context<char_type>&) override - { - stack_[top_].value_ = value; - if (++top_ >= stack_.size()) - { - stack_.resize(top_*2); - } - } - - void do_null_value(const basic_parsing_context<char_type>&) override - { - stack_[top_].value_ = null_type(); - if (++top_ >= stack_.size()) - { - stack_.resize(top_*2); - } - } -}; - -} - -#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons/json_filter.hpp b/vendor/jsoncons-0.99.2/jsoncons/json_filter.hpp deleted file mode 100644 index 2019c01d..00000000 --- a/vendor/jsoncons-0.99.2/jsoncons/json_filter.hpp +++ /dev/null @@ -1,324 +0,0 @@ -// Copyright 2013 Daniel Parker -// Distributed under the Boost license, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -// See https://github.com/danielaparker/jsoncons for latest version - -#ifndef JSONCONS_JSON_FILTER_HPP -#define JSONCONS_JSON_FILTER_HPP - -#include <string> - -#include "jsoncons/json_input_handler.hpp" -#include "jsoncons/json_output_handler.hpp" -#include "jsoncons/parse_error_handler.hpp" - -namespace jsoncons { - -template <typename CharT> -class basic_json_input_output_adapter : public basic_json_input_handler<CharT> -{ -public: - basic_json_input_output_adapter() - : writer_(std::addressof(null_json_output_handler<CharT>())) - { - } - - basic_json_input_output_adapter(basic_json_output_handler<CharT>& handler) - : writer_(std::addressof(handler)) - { - } - -private: - - void do_begin_json() override - { - writer_->begin_json(); - } - - void do_end_json() override - { - writer_->end_json(); - } - - void do_begin_object(const basic_parsing_context<CharT>& context) override - { - writer_->begin_object(); - } - - void do_end_object(const basic_parsing_context<CharT>& context) override - { - writer_->end_object(); - } - - void do_begin_array(const basic_parsing_context<CharT>& context) override - { - writer_->begin_array(); - } - - void do_end_array(const basic_parsing_context<CharT>& context) override - { - writer_->end_array(); - } - - void do_name(const CharT* name, size_t length, - const basic_parsing_context<CharT>& context) override - { - writer_->name(name, length); - } - - void do_string_value(const CharT* value, size_t length, - const basic_parsing_context<CharT>& context) override - { - writer_->value(value, length); - } - - void do_integer_value(int64_t value, const basic_parsing_context<CharT>& context) override - { - writer_->value(value); - } - - void do_uinteger_value(uint64_t value, - const basic_parsing_context<CharT>& context) override - { - writer_->value(value); - } - - void do_double_value(double value, uint8_t precision, const basic_parsing_context<CharT>& context) override - { - writer_->value(value, precision); - } - - void do_bool_value(bool value, const basic_parsing_context<CharT>& context) override - { - writer_->value(value); - } - - void do_null_value(const basic_parsing_context<CharT>& context) override - { - writer_->value(null_type()); - } - - basic_json_output_handler<CharT>* writer_; -}; - -template <typename CharT> -class basic_json_filter : public basic_json_input_handler<CharT> -{ -public: - basic_json_filter(basic_json_input_handler<CharT>& handler) - : handler_(std::addressof(handler)), - err_handler_(std::addressof(basic_default_parse_error_handler<CharT>::instance())) - { - } - - basic_json_filter(basic_json_input_handler<CharT>& handler, - basic_parse_error_handler<CharT>& err_handler) - : handler_(std::addressof(handler)), - err_handler_(std::addressof(err_handler)) - { - } - - basic_json_filter(basic_json_output_handler<CharT>& output_handler) - : input_output_adapter_(output_handler), handler_(std::addressof(input_output_adapter_)), - err_handler_(std::addressof(basic_default_parse_error_handler<CharT>::instance())) - { - } - - basic_json_filter(basic_json_output_handler<CharT>& output_handler, - basic_parse_error_handler<CharT>& err_handler) - : input_output_adapter_(output_handler), handler_(std::addressof(input_output_adapter_)), - err_handler_(std::addressof(err_handler)) - { - } - - basic_json_input_handler<CharT>& input_handler() - { - return *handler_; - } - -#if !defined(JSONCONS_NO_DEPRECATED) - basic_json_input_handler<CharT>& parent() - { - return *handler_; - } -#endif - -private: - void do_begin_json() override - { - handler_->begin_json(); - } - - void do_end_json() override - { - handler_->end_json(); - } - - void do_begin_object(const basic_parsing_context<CharT>& context) override - { - handler_->begin_object(context); - } - - void do_end_object(const basic_parsing_context<CharT>& context) override - { - handler_->end_object(context); - } - - void do_begin_array(const basic_parsing_context<CharT>& context) override - { - handler_->begin_array(context); - } - - void do_end_array(const basic_parsing_context<CharT>& context) override - { - handler_->end_array(context); - } - - void do_name(const CharT* name, size_t length, const basic_parsing_context<CharT>& context) override - { - handler_->name(name, length, context); - } - - void do_string_value(const CharT* value, size_t length, const basic_parsing_context<CharT>& context) override - { - handler_->value(value,length,context); - } - - void do_double_value(double value, uint8_t precision, const basic_parsing_context<CharT>& context) override - { - handler_->value(value,precision,context); - } - - void do_integer_value(int64_t value, const basic_parsing_context<CharT>& context) override - { - handler_->value(value,context); - } - - void do_uinteger_value(uint64_t value, const basic_parsing_context<CharT>& context) override - { - handler_->value(value,context); - } - - void do_bool_value(bool value, const basic_parsing_context<CharT>& context) override - { - handler_->value(value,context); - } - - void do_null_value(const basic_parsing_context<CharT>& context) override - { - handler_->value(null_type(),context); - } - - basic_json_input_output_adapter<CharT> input_output_adapter_; - basic_json_input_handler<CharT>* handler_; - basic_parse_error_handler<CharT>* err_handler_; -}; - -// Filters out begin_json and end_json events -template <typename CharT> -class basic_begin_end_json_filter : public basic_json_filter<CharT> -{ -public: - basic_begin_end_json_filter(basic_json_input_handler<CharT>& handler) - : basic_json_filter<CharT>(handler) - { - } -private: - void do_begin_json() override - { - } - - void do_end_json() override - { - } -}; - -template <typename CharT> -class basic_json_output_input_adapter : public basic_json_output_handler<CharT> -{ -public: - basic_json_output_input_adapter(basic_json_input_handler<CharT>& input_handler, - const basic_parsing_context<CharT>& context) - : input_handler_(std::addressof(input_handler)), - context_(std::addressof(context)) - { - } - -private: - - void do_begin_json() override - { - input_handler_->begin_json(); - } - - void do_end_json() override - { - input_handler_->end_json(); - } - - void do_begin_object() override - { - input_handler_->begin_object(*context_); - } - - void do_end_object() override - { - input_handler_->end_object(*context_); - } - - void do_begin_array() override - { - input_handler_->begin_array(*context_); - } - - void do_end_array() override - { - input_handler_->end_array(*context_); - } - - void do_name(const CharT* name, size_t length) override - { - input_handler_->name(name, length, *context_); - } - - void do_string_value(const CharT* value, size_t length) override - { - input_handler_->value(value, length, *context_); - } - - void do_integer_value(int64_t value) override - { - input_handler_->value(value, *context_); - } - - void do_uinteger_value(uint64_t value) override - { - input_handler_->value(value, *context_); - } - - void do_double_value(double value, uint8_t precision) override - { - input_handler_->value(value, precision, *context_); - } - - void do_bool_value(bool value) override - { - input_handler_->value(value, *context_); - } - - void do_null_value() override - { - input_handler_->value(null_type(), *context_); - } - - basic_json_input_handler<CharT>* input_handler_; - const basic_parsing_context<CharT>* context_; -}; - -typedef basic_json_filter<char> json_filter; -typedef basic_json_filter<wchar_t> wjson_filter; - -} - -#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons/json_input_handler.hpp b/vendor/jsoncons-0.99.2/jsoncons/json_input_handler.hpp deleted file mode 100644 index 566209e5..00000000 --- a/vendor/jsoncons-0.99.2/jsoncons/json_input_handler.hpp +++ /dev/null @@ -1,282 +0,0 @@ -// Copyright 2013 Daniel Parker -// Distributed under the Boost license, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -// See https://github.com/danielaparker/jsoncons for latest version - -#ifndef JSONCONS_JSON_INPUT_HANDLER_HPP -#define JSONCONS_JSON_INPUT_HANDLER_HPP - -#include <string> -#include "jsoncons/jsoncons.hpp" - -namespace jsoncons { - -template<typename CharT> -uint64_t string_to_uinteger(const CharT *s, size_t length) throw(std::overflow_error) -{ - static const uint64_t max_value = std::numeric_limits<uint64_t>::max JSONCONS_NO_MACRO_EXP(); - static const uint64_t max_value_div_10 = max_value / 10; - uint64_t n = 0; - for (size_t i = 0; i < length; ++i) - { - uint64_t x = s[i] - '0'; - if (n > max_value_div_10) - { - throw std::overflow_error("Unsigned overflow"); - } - n = n * 10; - if (n > max_value - x) - { - throw std::overflow_error("Unsigned overflow"); - } - - n += x; - } - return n; -} - -template<typename CharT> -int64_t string_to_integer(bool has_neg, const CharT *s, size_t length) throw(std::overflow_error) -{ - const long long max_value = std::numeric_limits<int64_t>::max JSONCONS_NO_MACRO_EXP(); - const long long max_value_div_10 = max_value / 10; - - long long n = 0; - for (size_t i = 0; i < length; ++i) - { - long long x = s[i] - '0'; - if (n > max_value_div_10) - { - throw std::overflow_error("Integer overflow"); - } - n = n * 10; - if (n > max_value - x) - { - throw std::overflow_error("Integer overflow"); - } - - n += x; - } - return has_neg ? -n : n; -} - -template <typename CharT> -class basic_parsing_context; - -template <typename CharT> -class basic_json_input_handler -{ -public: - virtual ~basic_json_input_handler() {} - - void begin_json() - { - do_begin_json(); - } - - void end_json() - { - do_end_json(); - } - - void begin_object(const basic_parsing_context<CharT>& context) - { - do_begin_object(context); - } - - void end_object(const basic_parsing_context<CharT>& context) - { - do_end_object(context); - } - - void begin_array(const basic_parsing_context<CharT>& context) - { - do_begin_array(context); - } - - void end_array(const basic_parsing_context<CharT>& context) - { - do_end_array(context); - } - - void name(const std::basic_string<CharT>& name, const basic_parsing_context<CharT>& context) - { - do_name(name.data(), name.length(), context); - } - - void name(const CharT* p, size_t length, const basic_parsing_context<CharT>& context) - { - do_name(p, length, context); - } - - void value(const std::basic_string<CharT>& value, const basic_parsing_context<CharT>& context) - { - do_string_value(value.data(), value.length(), context); - } - - void value(const CharT* p, size_t length, const basic_parsing_context<CharT>& context) - { - do_string_value(p, length, context); - } - - void value(const CharT* p, const basic_parsing_context<CharT>& context) - { - do_string_value(p, std::char_traits<CharT>::length(p), context); - } - - void value(int value, const basic_parsing_context<CharT>& context) - { - do_integer_value(value,context); - } - - void value(long value, const basic_parsing_context<CharT>& context) - { - do_integer_value(value,context); - } - - void value(long long value, const basic_parsing_context<CharT>& context) - { - do_integer_value(value,context); - } - - void value(unsigned int value, const basic_parsing_context<CharT>& context) - { - do_uinteger_value(value,context); - } - - void value(unsigned long value, const basic_parsing_context<CharT>& context) - { - do_uinteger_value(value,context); - } - - void value(unsigned long long value, const basic_parsing_context<CharT>& context) - { - do_uinteger_value(value,context); - } - - void value(float value, uint8_t precision, const basic_parsing_context<CharT>& context) - { - do_double_value(value, precision, context); - } - - void value(double value, uint8_t precision, const basic_parsing_context<CharT>& context) - { - do_double_value(value, precision, context); - } - - void value(bool value, const basic_parsing_context<CharT>& context) - { - do_bool_value(value,context); - } - - void value(null_type, const basic_parsing_context<CharT>& context) - { - do_null_value(context); - } - -private: - virtual void do_begin_json() = 0; - - virtual void do_end_json() = 0; - - virtual void do_begin_object(const basic_parsing_context<CharT>& context) = 0; - - virtual void do_end_object(const basic_parsing_context<CharT>& context) = 0; - - virtual void do_begin_array(const basic_parsing_context<CharT>& context) = 0; - - virtual void do_end_array(const basic_parsing_context<CharT>& context) = 0; - - virtual void do_name(const CharT* name, size_t length, const basic_parsing_context<CharT>& context) = 0; - - virtual void do_null_value(const basic_parsing_context<CharT>& context) = 0; - - virtual void do_string_value(const CharT* value, size_t length, const basic_parsing_context<CharT>& context) = 0; - - virtual void do_double_value(double value, uint8_t precision, const basic_parsing_context<CharT>& context) = 0; - - virtual void do_integer_value(int64_t value, const basic_parsing_context<CharT>& context) = 0; - - virtual void do_uinteger_value(uint64_t value, const basic_parsing_context<CharT>& context) = 0; - - virtual void do_bool_value(bool value, const basic_parsing_context<CharT>& context) = 0; -}; - - -template <typename CharT> -class basic_empty_json_input_handler : public basic_json_input_handler<CharT> -{ -public: - static basic_json_input_handler<CharT>& instance() - { - static basic_empty_json_input_handler<CharT> instance; - return instance; - } -private: - void do_begin_json() override - { - } - - void do_end_json() override - { - } - - void do_begin_object(const basic_parsing_context<CharT>&) override - { - } - - void do_end_object(const basic_parsing_context<CharT>&) override - { - } - - void do_begin_array(const basic_parsing_context<CharT>&) override - { - } - - void do_end_array(const basic_parsing_context<CharT>&) override - { - } - - void do_name(const CharT* p, size_t length, const basic_parsing_context<CharT>&) override - { - (void)p; - (void)length; - } - - void do_null_value(const basic_parsing_context<CharT>&) override - { - } - - void do_string_value(const CharT* p, size_t length, const basic_parsing_context<CharT>&) override - { - (void)p; - (void)length; - } - - void do_double_value(double, uint8_t, const basic_parsing_context<CharT>&) override - { - } - - void do_integer_value(int64_t, const basic_parsing_context<CharT>&) override - { - } - - void do_uinteger_value(uint64_t, const basic_parsing_context<CharT>&) override - { - } - - void do_bool_value(bool, const basic_parsing_context<CharT>&) override - { - } -}; - -typedef basic_json_input_handler<char> json_input_handler; -typedef basic_json_input_handler<wchar_t> wjson_input_handler; - -typedef basic_empty_json_input_handler<char> empty_json_input_handler; -typedef basic_empty_json_input_handler<wchar_t> wempty_json_input_handler; - -} - -#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons/json_parser.hpp b/vendor/jsoncons-0.99.2/jsoncons/json_parser.hpp deleted file mode 100644 index 8a06c2e7..00000000 --- a/vendor/jsoncons-0.99.2/jsoncons/json_parser.hpp +++ /dev/null @@ -1,1587 +0,0 @@ -// Copyright 2015 Daniel Parker -// Distributed under the Boost license, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -// See https://github.com/danielaparker/jsoncons for latest version - -#ifndef JSONCONS_JSON_PARSER_HPP -#define JSONCONS_JSON_PARSER_HPP - -#include <memory> -#include <string> -#include <sstream> -#include <vector> -#include <istream> -#include <cstdlib> -#include <stdexcept> -#include <system_error> -#include "jsoncons/jsoncons.hpp" -#include "jsoncons/json_input_handler.hpp" -#include "jsoncons/parse_error_handler.hpp" -#include "jsoncons/json_error_category.hpp" - -namespace jsoncons { - -enum class states -{ - root, - start, - slash, - slash_slash, - slash_star, - slash_star_star, - expect_comma_or_end, - object, - expect_member_name_or_end, - expect_member_name, - expect_colon, - expect_value_or_end, - expect_value, - array, - string, - member_name, - escape, - u1, - u2, - u3, - u4, - expect_surrogate_pair1, - expect_surrogate_pair2, - u6, - u7, - u8, - u9, - minus, - zero, - integer, - fraction, - exp1, - exp2, - exp3, - n, - t, - f, - cr, - lf, - done -}; - -template<typename CharT> -class basic_json_parser : private basic_parsing_context<CharT> -{ - static const int default_initial_stack_capacity_ = 100; - - std::vector<states> stack_; - basic_json_input_handler<CharT> *handler_; - basic_parse_error_handler<CharT> *err_handler_; - size_t column_; - size_t line_; - uint32_t cp_; - uint32_t cp2_; - std::basic_string<CharT> string_buffer_; - std::basic_string<char> number_buffer_; - bool is_negative_; - size_t index_; - int initial_stack_capacity_; - int nesting_depth_; - int max_depth_; - float_reader float_reader_; - const CharT* begin_input_; - const CharT* end_input_; - const CharT* p_; - uint8_t precision_; - std::pair<const CharT*,size_t> literal_; - size_t literal_index_; - -public: - basic_json_parser(basic_json_input_handler<CharT>& handler) - : handler_(std::addressof(handler)), - err_handler_(std::addressof(basic_default_parse_error_handler<CharT>::instance())), - column_(0), - line_(0), - cp_(0), - is_negative_(false), - index_(0), - initial_stack_capacity_(default_initial_stack_capacity_) - { - max_depth_ = std::numeric_limits<int>::max JSONCONS_NO_MACRO_EXP(); - } - - basic_json_parser(basic_json_input_handler<CharT>& handler, - basic_parse_error_handler<CharT>& err_handler) - : handler_(std::addressof(handler)), - err_handler_(std::addressof(err_handler)), - column_(0), - line_(0), - cp_(0), - is_negative_(false), - index_(0), - initial_stack_capacity_(default_initial_stack_capacity_) - - { - max_depth_ = std::numeric_limits<int>::max JSONCONS_NO_MACRO_EXP(); - } - - const basic_parsing_context<CharT>& parsing_context() const - { - return *this; - } - - ~basic_json_parser() - { - } - - size_t max_nesting_depth() const - { - return static_cast<size_t>(max_depth_); - } - - void max_nesting_depth(size_t max_nesting_depth) - { - max_depth_ = static_cast<int>(std::min(max_nesting_depth,static_cast<size_t>(std::numeric_limits<int>::max JSONCONS_NO_MACRO_EXP()))); - } - - states parent() const - { - return stack_[stack_.size()-2]; - } - - bool done() const - { - return stack_.back() == states::done; - } - - void do_space() - { - while ((p_ + 1) < end_input_ && (*(p_ + 1) == ' ' || *(p_ + 1) == '\t')) - { - ++p_; - ++column_; - } - } - - void do_begin_object() - { - if (++nesting_depth_ >= max_depth_) - { - err_handler_->error(std::error_code(json_parser_errc::max_depth_exceeded, json_error_category()), *this); - } - stack_.back() = states::object; - stack_.push_back(states::expect_member_name_or_end); - handler_->begin_object(*this); - } - - void do_end_object() - { - --nesting_depth_; - JSONCONS_ASSERT(!stack_.empty()) - stack_.pop_back(); - if (stack_.back() == states::object) - { - handler_->end_object(*this); - } - else if (stack_.back() == states::array) - { - err_handler_->fatal_error(std::error_code(json_parser_errc::expected_comma_or_right_bracket, json_error_category()), *this); - } - else - { - err_handler_->fatal_error(std::error_code(json_parser_errc::unexpected_right_brace, json_error_category()), *this); - } - - JSONCONS_ASSERT(stack_.size() >= 2); - if (parent() == states::root) - { - stack_.back() = states::done; - handler_->end_json(); - } - else - { - stack_.back() = states::expect_comma_or_end; - } - } - - void do_begin_array() - { - if (++nesting_depth_ >= max_depth_) - { - err_handler_->error(std::error_code(json_parser_errc::max_depth_exceeded, json_error_category()), *this); - } - stack_.back() = states::array; - stack_.push_back(states::expect_value_or_end); - handler_->begin_array(*this); - } - - void do_end_array() - { - --nesting_depth_; - JSONCONS_ASSERT(!stack_.empty()) - stack_.pop_back(); - if (stack_.back() == states::array) - { - handler_->end_array(*this); - } - else if (stack_.back() == states::object) - { - err_handler_->fatal_error(std::error_code(json_parser_errc::expected_comma_or_right_brace, json_error_category()), *this); - } - else - { - err_handler_->fatal_error(std::error_code(json_parser_errc::unexpected_right_bracket, json_error_category()), *this); - } - JSONCONS_ASSERT(stack_.size() >= 2); - if (parent() == states::root) - { - stack_.back() = states::done; - handler_->end_json(); - } - else - { - stack_.back() = states::expect_comma_or_end; - } - } - - void begin_parse() - { - stack_.clear(); - stack_.reserve(initial_stack_capacity_); - stack_.push_back(states::root); - stack_.push_back(states::start); - line_ = 1; - column_ = 1; - nesting_depth_ = 0; - } - - void check_done(const CharT* input, size_t start, size_t length) - { - index_ = start; - for (; index_ < length; ++index_) - { - CharT curr_char_ = input[index_]; - switch (curr_char_) - { - case '\n': - case '\r': - case '\t': - case ' ': - break; - default: - err_handler_->error(std::error_code(json_parser_errc::extra_character, json_error_category()), *this); - break; - } - } - } - - void parse_string() - { - const CharT* sb = p_; - bool done = false; - while (!done && p_ < end_input_) - { - switch (*p_) - { - case 0x00:case 0x01:case 0x02:case 0x03:case 0x04:case 0x05:case 0x06:case 0x07:case 0x08:case 0x0b: - case 0x0c:case 0x0e:case 0x0f:case 0x10:case 0x11:case 0x12:case 0x13:case 0x14:case 0x15:case 0x16: - case 0x17:case 0x18:case 0x19:case 0x1a:case 0x1b:case 0x1c:case 0x1d:case 0x1e:case 0x1f: - string_buffer_.append(sb,p_-sb); - column_ += (p_ - sb + 1); - err_handler_->error(std::error_code(json_parser_errc::illegal_control_character, json_error_category()), *this); - // recovery - skip - done = true; - ++p_; - break; - case '\r': - { - column_ += (p_ - sb + 1); - err_handler_->error(std::error_code(json_parser_errc::illegal_character_in_string, json_error_category()), *this); - // recovery - keep - string_buffer_.append(sb, p_ - sb + 1); - stack_.push_back(states::cr); - done = true; - ++p_; - } - break; - case '\n': - { - column_ += (p_ - sb + 1); - err_handler_->error(std::error_code(json_parser_errc::illegal_character_in_string, json_error_category()), *this); - // recovery - keep - string_buffer_.append(sb, p_ - sb + 1); - stack_.push_back(states::lf); - done = true; - ++p_; - } - break; - case '\t': - { - column_ += (p_ - sb + 1); - err_handler_->error(std::error_code(json_parser_errc::illegal_character_in_string, json_error_category()), *this); - // recovery - keep - string_buffer_.append(sb, p_ - sb + 1); - done = true; - ++p_; - } - break; - case '\\': - string_buffer_.append(sb,p_-sb); - column_ += (p_ - sb + 1); - stack_.back() = states::escape; - done = true; - ++p_; - break; - case '\"': - if (string_buffer_.length() == 0) - { - end_string_value(sb,p_-sb); - } - else - { - string_buffer_.append(sb,p_-sb); - end_string_value(string_buffer_.data(),string_buffer_.length()); - string_buffer_.clear(); - } - column_ += (p_ - sb + 1); - done = true; - ++p_; - break; - default: - ++p_; - break; - } - } - if (!done) - { - string_buffer_.append(sb,p_-sb); - column_ += (p_ - sb + 1); - } - } - - void parse(const CharT* const input, size_t start, size_t length) - { - begin_input_ = input + start; - end_input_ = input + length; - p_ = begin_input_; - - index_ = start; - while ((p_ < end_input_) && (stack_.back() != states::done)) - { - switch (*p_) - { - case 0x00:case 0x01:case 0x02:case 0x03:case 0x04:case 0x05:case 0x06:case 0x07:case 0x08:case 0x0b: - case 0x0c:case 0x0e:case 0x0f:case 0x10:case 0x11:case 0x12:case 0x13:case 0x14:case 0x15:case 0x16: - case 0x17:case 0x18:case 0x19:case 0x1a:case 0x1b:case 0x1c:case 0x1d:case 0x1e:case 0x1f: - err_handler_->error(std::error_code(json_parser_errc::illegal_control_character, json_error_category()), *this); - break; - default: - break; - } - - switch (stack_.back()) - { - case states::cr: - ++line_; - column_ = 1; - switch (*p_) - { - case '\n': - JSONCONS_ASSERT(!stack_.empty()) - stack_.pop_back(); - ++p_; - break; - default: - JSONCONS_ASSERT(!stack_.empty()) - stack_.pop_back(); - break; - } - break; - case states::lf: - ++line_; - column_ = 1; - JSONCONS_ASSERT(!stack_.empty()) - stack_.pop_back(); - break; - case states::start: - { - switch (*p_) - { - case '\r': - stack_.push_back(states::cr); - break; - case '\n': - stack_.push_back(states::lf); - break; - case ' ':case '\t': - do_space(); - break; - case '/': - stack_.push_back(states::slash); - break; - case '{': - handler_->begin_json(); - do_begin_object(); - break; - case '[': - handler_->begin_json(); - do_begin_array(); - break; - case '\"': - handler_->begin_json(); - stack_.back() = states::string; - break; - case '-': - handler_->begin_json(); - is_negative_ = true; - stack_.back() = states::minus; - break; - case '0': - handler_->begin_json(); - number_buffer_.push_back(static_cast<char>(*p_)); - stack_.back() = states::zero; - break; - case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': - handler_->begin_json(); - number_buffer_.push_back(static_cast<char>(*p_)); - stack_.back() = states::integer; - break; - case 'f': - handler_->begin_json(); - stack_.back() = states::f; - literal_ = json_literals<CharT>::false_literal(); - literal_index_ = 1; - break; - case 'n': - handler_->begin_json(); - stack_.back() = states::n; - literal_ = json_literals<CharT>::null_literal(); - literal_index_ = 1; - break; - case 't': - handler_->begin_json(); - stack_.back() = states::t; - literal_ = json_literals<CharT>::true_literal(); - literal_index_ = 1; - break; - case '}': - err_handler_->fatal_error(std::error_code(json_parser_errc::unexpected_right_brace, json_error_category()), *this); - break; - case ']': - err_handler_->fatal_error(std::error_code(json_parser_errc::unexpected_right_bracket, json_error_category()), *this); - break; - default: - err_handler_->fatal_error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - - case states::expect_comma_or_end: - { - switch (*p_) - { - case '\r': - stack_.push_back(states::cr); - break; - case '\n': - stack_.push_back(states::lf); - break; - case ' ':case '\t': - do_space(); - break; - case '/': - stack_.push_back(states::slash); - break; - case '}': - do_end_object(); - break; - case ']': - do_end_array(); - break; - case ',': - begin_member_or_element(); - break; - default: - JSONCONS_ASSERT(stack_.size() >= 2); - if (parent() == states::array) - { - err_handler_->error(std::error_code(json_parser_errc::expected_comma_or_right_bracket, json_error_category()), *this); - } - else if (parent() == states::object) - { - err_handler_->error(std::error_code(json_parser_errc::expected_comma_or_right_brace, json_error_category()), *this); - } - break; - } - } - ++p_; - ++column_; - break; - case states::expect_member_name_or_end: - { - switch (*p_) - { - case '\r': - stack_.push_back(states::cr); - break; - case '\n': - stack_.push_back(states::lf); - break; - case ' ':case '\t': - do_space(); - break; - case '/': - stack_.push_back(states::slash); - break; - case '}': - do_end_object(); - break; - case '\"': - stack_.back() = states::member_name; - stack_.push_back(states::string); - break; - case '\'': - err_handler_->error(std::error_code(json_parser_errc::single_quote, json_error_category()), *this); - break; - default: - err_handler_->error(std::error_code(json_parser_errc::expected_name, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - case states::expect_member_name: - { - switch (*p_) - { - case '\r': - stack_.push_back(states::cr); - break; - case '\n': - stack_.push_back(states::lf); - break; - case ' ':case '\t': - do_space(); - break; - case '/': - stack_.push_back(states::slash); - break; - case '\"': - //stack_.back() = states::string; - stack_.back() = states::member_name; - stack_.push_back(states::string); - break; - case '}': - --nesting_depth_; - err_handler_->error(std::error_code(json_parser_errc::extra_comma, json_error_category()), *this); - break; - case '\'': - err_handler_->error(std::error_code(json_parser_errc::single_quote, json_error_category()), *this); - break; - default: - err_handler_->error(std::error_code(json_parser_errc::expected_name, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - case states::expect_colon: - { - switch (*p_) - { - case '\r': - stack_.push_back(states::cr); - break; - case '\n': - stack_.push_back(states::lf); - break; - case ' ':case '\t': - do_space(); - break; - case '/': - stack_.push_back(states::slash); - break; - case ':': - stack_.back() = states::expect_value; - break; - default: - err_handler_->error(std::error_code(json_parser_errc::expected_colon, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - case states::expect_value: - { - switch (*p_) - { - case '\r': - stack_.push_back(states::cr); - break; - case '\n': - stack_.push_back(states::lf); - break; - case ' ':case '\t': - do_space(); - break; - case '/': - stack_.push_back(states::slash); - break; - case '{': - do_begin_object(); - break; - case '[': - do_begin_array(); - break; - case '\"': - stack_.back() = states::string; - break; - case '-': - is_negative_ = true; - stack_.back() = states::minus; - break; - case '0': - number_buffer_.push_back(static_cast<char>(*p_)); - stack_.back() = states::zero; - break; - case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': - number_buffer_.push_back(static_cast<char>(*p_)); - stack_.back() = states::integer; - break; - case 'f': - stack_.back() = states::f; - literal_ = json_literals<CharT>::false_literal(); - literal_index_ = 1; - break; - case 'n': - stack_.back() = states::n; - literal_ = json_literals<CharT>::null_literal(); - literal_index_ = 1; - break; - case 't': - stack_.back() = states::t; - literal_ = json_literals<CharT>::true_literal(); - literal_index_ = 1; - break; - case ']': - JSONCONS_ASSERT(stack_.size() >= 2); - if (parent() == states::array) - { - err_handler_->error(std::error_code(json_parser_errc::extra_comma, json_error_category()), *this); - } - else - { - err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); - } - break; - case '\'': - err_handler_->error(std::error_code(json_parser_errc::single_quote, json_error_category()), *this); - break; - default: - err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - case states::expect_value_or_end: - { - switch (*p_) - { - case '\r': - stack_.push_back(states::cr); - break; - case '\n': - stack_.push_back(states::lf); - break; - case ' ':case '\t': - do_space(); - break; - case '/': - stack_.push_back(states::slash); - break; - case '{': - do_begin_object(); - break; - case '[': - do_begin_array(); - break; - case ']': - do_end_array(); - break; - case '\"': - stack_.back() = states::string; - break; - case '-': - is_negative_ = true; - stack_.back() = states::minus; - break; - case '0': - number_buffer_.push_back(static_cast<char>(*p_)); - stack_.back() = states::zero; - break; - case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': - number_buffer_.push_back(static_cast<char>(*p_)); - stack_.back() = states::integer; - break; - case 'f': - stack_.back() = states::f; - literal_ = json_literals<CharT>::false_literal(); - literal_index_ = 1; - break; - case 'n': - stack_.back() = states::n; - literal_ = json_literals<CharT>::null_literal(); - literal_index_ = 1; - break; - case 't': - stack_.back() = states::t; - literal_ = json_literals<CharT>::true_literal(); - literal_index_ = 1; - break; - case '\'': - err_handler_->error(std::error_code(json_parser_errc::single_quote, json_error_category()), *this); - break; - default: - err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - case states::string: - parse_string(); - break; - case states::escape: - { - escape_next_char(*p_); - } - ++p_; - ++column_; - break; - case states::u1: - { - append_codepoint(*p_); - stack_.back() = states::u2; - } - ++p_; - ++column_; - break; - case states::u2: - { - append_codepoint(*p_); - stack_.back() = states::u3; - } - ++p_; - ++column_; - break; - case states::u3: - { - append_codepoint(*p_); - stack_.back() = states::u4; - } - ++p_; - ++column_; - break; - case states::u4: - { - append_codepoint(*p_); - if (cp_ >= min_lead_surrogate && cp_ <= max_lead_surrogate) - { - stack_.back() = states::expect_surrogate_pair1; - } - else - { - json_char_traits<CharT, sizeof(CharT)>::append_codepoint_to_string(cp_, string_buffer_); - stack_.back() = states::string; - } - } - ++p_; - ++column_; - break; - case states::expect_surrogate_pair1: - { - switch (*p_) - { - case '\\': - cp2_ = 0; - stack_.back() = states::expect_surrogate_pair2; - break; - default: - err_handler_->error(std::error_code(json_parser_errc::expected_codepoint_surrogate_pair, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - case states::expect_surrogate_pair2: - { - switch (*p_) - { - case 'u': - stack_.back() = states::u6; - break; - default: - err_handler_->error(std::error_code(json_parser_errc::expected_codepoint_surrogate_pair, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - case states::u6: - { - append_second_codepoint(*p_); - stack_.back() = states::u7; - } - ++p_; - ++column_; - break; - case states::u7: - { - append_second_codepoint(*p_); - stack_.back() = states::u8; - } - ++p_; - ++column_; - break; - case states::u8: - { - append_second_codepoint(*p_); - stack_.back() = states::u9; - } - ++p_; - ++column_; - break; - case states::u9: - { - append_second_codepoint(*p_); - uint32_t cp = 0x10000 + ((cp_ & 0x3FF) << 10) + (cp2_ & 0x3FF); - json_char_traits<CharT, sizeof(CharT)>::append_codepoint_to_string(cp, string_buffer_); - stack_.back() = states::string; - } - ++p_; - ++column_; - break; - case states::minus: - { - switch (*p_) - { - case '0': - number_buffer_.push_back(static_cast<char>(*p_)); - stack_.back() = states::zero; - break; - case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': - number_buffer_.push_back(static_cast<char>(*p_)); - stack_.back() = states::integer; - break; - default: - err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - case states::zero: - { - switch (*p_) - { - case '\r': - end_integer_value(); - stack_.push_back(states::cr); - break; - case '\n': - end_integer_value(); - stack_.push_back(states::lf); - break; - case ' ':case '\t': - end_integer_value(); - do_space(); - break; - case '/': - end_integer_value(); - stack_.push_back(states::slash); - break; - case '}': - end_integer_value(); - do_end_object(); - break; - case ']': - end_integer_value(); - do_end_array(); - break; - case '.': - precision_ = static_cast<uint8_t>(number_buffer_.length()); - number_buffer_.push_back(static_cast<char>(*p_)); - stack_.back() = states::fraction; - break; - case ',': - end_integer_value(); - begin_member_or_element(); - break; - case '0': case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': - err_handler_->error(std::error_code(json_parser_errc::leading_zero, json_error_category()), *this); - break; - default: - err_handler_->error(std::error_code(json_parser_errc::invalid_number, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - case states::integer: - { - switch (*p_) - { - case '\r': - end_integer_value(); - stack_.push_back(states::cr); - break; - case '\n': - end_integer_value(); - stack_.push_back(states::lf); - break; - case ' ':case '\t': - end_integer_value(); - do_space(); - break; - case '/': - end_integer_value(); - stack_.push_back(states::slash); - break; - case '}': - end_integer_value(); - do_end_object(); - break; - case ']': - end_integer_value(); - do_end_array(); - break; - case '0': - case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': - number_buffer_.push_back(static_cast<char>(*p_)); - stack_.back() = states::integer; - break; - case '.': - precision_ = static_cast<uint8_t>(number_buffer_.length()); - number_buffer_.push_back(static_cast<char>(*p_)); - stack_.back() = states::fraction; - break; - case ',': - end_integer_value(); - begin_member_or_element(); - break; - case 'e':case 'E': - number_buffer_.push_back(static_cast<char>(*p_)); - stack_.back() = states::exp1; - break; - default: - err_handler_->error(std::error_code(json_parser_errc::invalid_number, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - case states::fraction: - { - switch (*p_) - { - case '\r': - end_fraction_value(); - stack_.push_back(states::cr); - break; - case '\n': - end_fraction_value(); - stack_.push_back(states::lf); - break; - case ' ':case '\t': - end_fraction_value(); - do_space(); - break; - case '/': - end_fraction_value(); - stack_.push_back(states::slash); - break; - case '}': - end_fraction_value(); - do_end_object(); - break; - case ']': - end_fraction_value(); - do_end_array(); - break; - case '0': - case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': - ++precision_; - number_buffer_.push_back(static_cast<char>(*p_)); - stack_.back() = states::fraction; - break; - case ',': - end_fraction_value(); - begin_member_or_element(); - break; - case 'e':case 'E': - number_buffer_.push_back(static_cast<char>(*p_)); - stack_.back() = states::exp1; - break; - default: - err_handler_->error(std::error_code(json_parser_errc::invalid_number, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - case states::exp1: - { - switch (*p_) - { - case '+': - stack_.back() = states::exp2; - break; - case '-': - number_buffer_.push_back(static_cast<char>(*p_)); - stack_.back() = states::exp2; - break; - case '0': - case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': - number_buffer_.push_back(static_cast<char>(*p_)); - stack_.back() = states::exp3; - break; - default: - err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - case states::exp2: - { - switch (*p_) - { - case '0': - case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': - number_buffer_.push_back(static_cast<char>(*p_)); - stack_.back() = states::exp3; - break; - default: - err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - case states::exp3: - { - switch (*p_) - { - case '\r': - end_fraction_value(); - stack_.push_back(states::cr); - break; - case '\n': - end_fraction_value(); - stack_.push_back(states::lf); - break; - case ' ':case '\t': - end_fraction_value(); - do_space(); - break; - case '/': - end_fraction_value(); - stack_.push_back(states::slash); - break; - case '}': - end_fraction_value(); - do_end_object(); - break; - case ']': - end_fraction_value(); - do_end_array(); - break; - case ',': - end_fraction_value(); - begin_member_or_element(); - break; - case '0': - case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': - number_buffer_.push_back(static_cast<char>(*p_)); - stack_.back() = states::exp3; - break; - default: - err_handler_->error(std::error_code(json_parser_errc::invalid_number, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - case states::t: - while (p_ < end_input_ && literal_index_ < literal_.second) - { - if (*p_ != literal_.first[literal_index_]) - { - err_handler_->error(std::error_code(json_parser_errc::invalid_value, json_error_category()), *this); - } - ++p_; - ++literal_index_; - ++column_; - } - if (literal_index_ == literal_.second) - { - handler_->value(true, *this); - JSONCONS_ASSERT(stack_.size() >= 2); - if (parent() == states::root) - { - stack_.back() = states::done; - handler_->end_json(); - } - else - { - stack_.back() = states::expect_comma_or_end; - } - } - break; - case states::f: - while (p_ < end_input_ && literal_index_ < literal_.second) - { - if (*p_ != literal_.first[literal_index_]) - { - err_handler_->error(std::error_code(json_parser_errc::invalid_value, json_error_category()), *this); - } - ++p_; - ++literal_index_; - ++column_; - } - if (literal_index_ == literal_.second) - { - handler_->value(false, *this); - JSONCONS_ASSERT(stack_.size() >= 2); - if (parent() == states::root) - { - stack_.back() = states::done; - handler_->end_json(); - } - else - { - stack_.back() = states::expect_comma_or_end; - } - } - break; - case states::n: - while (p_ < end_input_ && literal_index_ < literal_.second) - { - if (*p_ != literal_.first[literal_index_]) - { - err_handler_->error(std::error_code(json_parser_errc::invalid_value, json_error_category()), *this); - } - ++p_; - ++literal_index_; - ++column_; - } - if (literal_index_ == literal_.second) - { - handler_->value(null_type(), *this); - JSONCONS_ASSERT(stack_.size() >= 2); - if (parent() == states::root) - { - stack_.back() = states::done; - handler_->end_json(); - } - else - { - stack_.back() = states::expect_comma_or_end; - } - } - break; - case states::slash: - { - switch (*p_) - { - case '*': - stack_.back() = states::slash_star; - break; - case '/': - stack_.back() = states::slash_slash; - break; - default: - err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - case states::slash_star: - { - switch (*p_) - { - case '\r': - stack_.push_back(states::cr); - break; - case '\n': - stack_.push_back(states::lf); - break; - case '*': - stack_.back() = states::slash_star_star; - break; - } - } - ++p_; - ++column_; - break; - case states::slash_slash: - { - switch (*p_) - { - case '\r': - stack_.pop_back(); - break; - case '\n': - stack_.pop_back(); - break; - default: - ++p_; - ++column_; - } - } - break; - case states::slash_star_star: - { - switch (*p_) - { - case '/': - JSONCONS_ASSERT(!stack_.empty()) - stack_.pop_back(); - break; - default: - stack_.back() = states::slash_star; - break; - } - } - ++p_; - ++column_; - break; - default: - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Bad parser state"); - break; - } - } - index_ += (p_-begin_input_); - } - - void end_parse() - { - JSONCONS_ASSERT(stack_.size() >= 2); - if (parent() == states::root) - { - switch (stack_.back()) - { - case states::zero: - case states::integer: - end_integer_value(); - break; - case states::fraction: - case states::exp3: - end_fraction_value(); - break; - default: - break; - } - } - if (stack_.back() == states::lf || stack_.back() == states::cr) - { - stack_.pop_back(); - } - if (!(stack_.back() == states::done || stack_.back() == states::start)) - { - err_handler_->error(std::error_code(json_parser_errc::unexpected_eof, json_error_category()), *this); - } - } - - states state() const - { - return stack_.back(); - } - - size_t index() const - { - return index_; - } -private: - void end_fraction_value() - { - try - { - double d = float_reader_.read(number_buffer_.data(), precision_); - if (is_negative_) - d = -d; - handler_->value(d, static_cast<uint8_t>(precision_), *this); - } - catch (...) - { - err_handler_->error(std::error_code(json_parser_errc::invalid_number, json_error_category()), *this); - handler_->value(null_type(), *this); // recovery - } - number_buffer_.clear(); - is_negative_ = false; - - JSONCONS_ASSERT(stack_.size() >= 2); - switch (parent()) - { - case states::array: - case states::object: - stack_.back() = states::expect_comma_or_end; - break; - case states::root: - stack_.back() = states::done; - handler_->end_json(); - break; - default: - err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); - break; - } - } - - void end_integer_value() - { - if (is_negative_) - { - try - { - int64_t d = string_to_integer(is_negative_, number_buffer_.data(), number_buffer_.length()); - handler_->value(d, *this); - } - catch (const std::exception&) - { - try - { - double d = float_reader_.read(number_buffer_.data(), number_buffer_.length()); - handler_->value(-d, static_cast<uint8_t>(number_buffer_.length()), *this); - } - catch (...) - { - err_handler_->error(std::error_code(json_parser_errc::invalid_number, json_error_category()), *this); - handler_->value(null_type(), *this); - } - } - } - else - { - try - { - uint64_t d = string_to_uinteger(number_buffer_.data(), number_buffer_.length()); - handler_->value(d, *this); - } - catch (const std::exception&) - { - try - { - double d = float_reader_.read(number_buffer_.data(),number_buffer_.length()); - handler_->value(d, static_cast<uint8_t>(number_buffer_.length()), *this); - } - catch (...) - { - err_handler_->error(std::error_code(json_parser_errc::invalid_number, json_error_category()), *this); - handler_->value(null_type(), *this); - } - } - } - - JSONCONS_ASSERT(stack_.size() >= 2); - switch (parent()) - { - case states::array: - case states::object: - stack_.back() = states::expect_comma_or_end; - break; - case states::root: - stack_.back() = states::done; - handler_->end_json(); - break; - default: - err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); - break; - } - number_buffer_.clear(); - is_negative_ = false; - } - - void append_codepoint(int c) - { - switch (c) - { - case '0': case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': - case 'a':case 'b':case 'c':case 'd':case 'e':case 'f': - case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': - cp_ = append_to_codepoint(cp_, c); - break; - default: - err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); - break; - } - } - - void append_second_codepoint(int c) - { - switch (c) - { - case '0': - case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': - case 'a':case 'b':case 'c':case 'd':case 'e':case 'f': - case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': - cp2_ = append_to_codepoint(cp2_, c); - break; - default: - err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); - break; - } - } - - void escape_next_char(int next_input) - { - switch (next_input) - { - case '\"': - string_buffer_.push_back('\"'); - stack_.back() = states::string; - break; - case '\\': - string_buffer_.push_back('\\'); - stack_.back() = states::string; - break; - case '/': - string_buffer_.push_back('/'); - stack_.back() = states::string; - break; - case 'b': - string_buffer_.push_back('\b'); - stack_.back() = states::string; - break; - case 'f': - string_buffer_.push_back('\f'); - stack_.back() = states::string; - break; - case 'n': - string_buffer_.push_back('\n'); - stack_.back() = states::string; - break; - case 'r': - string_buffer_.push_back('\r'); - stack_.back() = states::string; - break; - case 't': - string_buffer_.push_back('\t'); - stack_.back() = states::string; - break; - case 'u': - cp_ = 0; - stack_.back() = states::u1; - break; - default: - err_handler_->error(std::error_code(json_parser_errc::illegal_escaped_character, json_error_category()), *this); - break; - } - } - - void end_string_value(const CharT* s, size_t length) - { - JSONCONS_ASSERT(stack_.size() >= 2); - switch (parent()) - { - case states::member_name: - handler_->name(s, length, *this); - stack_.pop_back(); - stack_.back() = states::expect_colon; - break; - case states::object: - case states::array: - handler_->value(s, length, *this); - stack_.back() = states::expect_comma_or_end; - break; - case states::root: - handler_->value(s, length, *this); - stack_.back() = states::done; - handler_->end_json(); - break; - default: - err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); - break; - } - } - - void begin_member_or_element() - { - JSONCONS_ASSERT(stack_.size() >= 2); - switch (parent()) - { - case states::object: - stack_.back() = states::expect_member_name; - break; - case states::array: - stack_.back() = states::expect_value; - break; - case states::root: - break; - default: - err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); - break; - } - } - - uint32_t append_to_codepoint(uint32_t cp, int c) - { - cp *= 16; - if (c >= '0' && c <= '9') - { - cp += c - '0'; - } - else if (c >= 'a' && c <= 'f') - { - cp += c - 'a' + 10; - } - else if (c >= 'A' && c <= 'F') - { - cp += c - 'A' + 10; - } - else - { - err_handler_->error(std::error_code(json_parser_errc::invalid_hex_escape_sequence, json_error_category()), *this); - } - return cp; - } - - size_t do_line_number() const override - { - return line_; - } - - size_t do_column_number() const override - { - return column_; - } - - CharT do_current_char() const override - { - return p_ < end_input_? *p_ : 0; - } -}; - -typedef basic_json_parser<char> json_parser; -typedef basic_json_parser<wchar_t> wjson_parser; - -} - -#endif - diff --git a/vendor/jsoncons-0.99.2/jsoncons/json_parser.hpp.orig b/vendor/jsoncons-0.99.2/jsoncons/json_parser.hpp.orig deleted file mode 100644 index e4769d5c..00000000 --- a/vendor/jsoncons-0.99.2/jsoncons/json_parser.hpp.orig +++ /dev/null @@ -1,2157 +0,0 @@ -// Copyright 2015 Daniel Parker -// Distributed under the Boost license, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -// See https://github.com/danielaparker/jsoncons for latest version - -#ifndef JSONCONS_JSON_PARSER_HPP -#define JSONCONS_JSON_PARSER_HPP - -#include <memory> -#include <string> -#include <sstream> -#include <vector> -#include <istream> -#include <cstdlib> -#include <stdexcept> -#include <system_error> -#include "jsoncons/jsoncons.hpp" -#include "jsoncons/json_input_handler.hpp" -#include "jsoncons/parse_error_handler.hpp" -#include "jsoncons/json_error_category.hpp" - -namespace jsoncons { - -enum class modes -{ - done, - start, - array_element, - object_member_name, - object_member_value -}; - -enum class states -{ - start, - slash, - slash_slash, - slash_star, - slash_star_star, - expect_comma_or_end, - object, - expect_member_name, - expect_colon, - expect_value, - array, - string, - escape, - u1, - u2, - u3, - u4, - expect_surrogate_pair1, - expect_surrogate_pair2, - u6, - u7, - u8, - u9, - minus, - zero, - integer, - fraction, - exp1, - exp2, - exp3, - n, - t, - f, - cr, - lf, - done, - scalar -}; - -template<typename CharT> -class basic_json_parser : private basic_parsing_context<CharT> -{ - static const int default_depth = 100; - - std::vector<states> state_stack_; - int top_; - std::vector<modes> stack_; - basic_json_input_handler<CharT> *handler_; - basic_parse_error_handler<CharT> *err_handler_; - size_t column_; - size_t line_; - uint32_t cp_; - uint32_t cp2_; - std::basic_string<CharT> string_buffer_; - std::basic_string<char> number_buffer_; - bool is_negative_; - states saved_state_; - states pre_line_break_state_; - size_t index_; - int depth_; - int max_depth_; - float_reader float_reader_; - const CharT* begin_input_; - const CharT* end_input_; - const CharT* p_; - uint8_t precision_; - std::pair<const CharT*,size_t> literal_; - size_t literal_index_; - - std::vector<states> stack2_; - -public: - basic_json_parser(basic_json_input_handler<CharT>& handler) - : top_(-1), - stack_(default_depth), - handler_(std::addressof(handler)), - err_handler_(std::addressof(basic_default_parse_error_handler<CharT>::instance())), - column_(0), - line_(0), - cp_(0), - is_negative_(false), - index_(0), - depth_(default_depth) - { - max_depth_ = std::numeric_limits<int>::max JSONCONS_NO_MACRO_EXP(); - } - - basic_json_parser(basic_json_input_handler<CharT>& handler, - basic_parse_error_handler<CharT>& err_handler) - : top_(-1), - stack_(default_depth), - handler_(std::addressof(handler)), - err_handler_(std::addressof(err_handler)), - column_(0), - line_(0), - cp_(0), - is_negative_(false), - index_(0), - depth_(default_depth) - - { - max_depth_ = std::numeric_limits<int>::max JSONCONS_NO_MACRO_EXP(); - } - - const basic_parsing_context<CharT>& parsing_context() const - { - return *this; - } - - ~basic_json_parser() - { - } - - size_t max_nesting_depth() const - { - return static_cast<size_t>(max_depth_); - } - - void max_nesting_depth(size_t max_nesting_depth) - { - max_depth_ = static_cast<int>(std::min(max_nesting_depth,static_cast<size_t>(std::numeric_limits<int>::max JSONCONS_NO_MACRO_EXP()))); - if (depth_ > max_depth_) - { - depth_ = max_depth_; - stack_.resize(depth_); - } - } - - bool done() const - { - return state_stack_.back() == states::done; - } - - void begin_parse() - { - if (!push(modes::done)) - { - err_handler_->error(std::error_code(json_parser_errc::max_depth_exceeded, json_error_category()), *this); - } - state_stack_.clear(); - state_stack_.push_back(states::start); - line_ = 1; - column_ = 1; - stack2_.push_back(states::start); - stack2_.push_back(states::scalar); - } - - void check_done(const CharT* input, size_t start, size_t length) - { - index_ = start; - for (; index_ < length; ++index_) - { - CharT curr_char_ = input[index_]; - switch (curr_char_) - { - case '\n': - case '\r': - case '\t': - case ' ': - break; - default: - err_handler_->error(std::error_code(json_parser_errc::extra_character, json_error_category()), *this); - break; - } - } - } - - bool parse_string(const CharT** first, const CharT** last) - { - const CharT* sb = p_; - bool done = false; - bool complete = false; - while (!done && p_ < end_input_) - { - switch (*p_) - { - case 0x00:case 0x01:case 0x02:case 0x03:case 0x04:case 0x05:case 0x06:case 0x07:case 0x08:case 0x0b: - case 0x0c:case 0x0e:case 0x0f:case 0x10:case 0x11:case 0x12:case 0x13:case 0x14:case 0x15:case 0x16: - case 0x17:case 0x18:case 0x19:case 0x1a:case 0x1b:case 0x1c:case 0x1d:case 0x1e:case 0x1f: - string_buffer_.append(sb,p_-sb); - column_ += (p_ - sb + 1); - err_handler_->error(std::error_code(json_parser_errc::illegal_control_character, json_error_category()), *this); - // recovery - skip - done = true; - ++p_; - break; - case '\r': - { - column_ += (p_ - sb + 1); - err_handler_->error(std::error_code(json_parser_errc::illegal_character_in_string, json_error_category()), *this); - // recovery - keep - string_buffer_.append(sb, p_ - sb + 1); -<<<<<<< HEAD - pre_line_break_state_ = state_stack_.back(); - state_stack_.back() = states::cr; -======= - pre_line_break_state_ = state_; - state_ = states::cr; - ->>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 - done = true; - ++p_; - - stack2_.push_back(states::cr); - } - break; - case '\n': - { - column_ += (p_ - sb + 1); - err_handler_->error(std::error_code(json_parser_errc::illegal_character_in_string, json_error_category()), *this); - // recovery - keep - string_buffer_.append(sb, p_ - sb + 1); - pre_line_break_state_ = state_stack_.back(); - state_stack_.back() = states::lf; - done = true; - ++p_; - - stack2_.push_back(states::lf); - } - break; - case '\t': - { - column_ += (p_ - sb + 1); - err_handler_->error(std::error_code(json_parser_errc::illegal_character_in_string, json_error_category()), *this); - // recovery - keep - string_buffer_.append(sb, p_ - sb + 1); - done = true; - ++p_; - } - break; - case '\\': - string_buffer_.append(sb,p_-sb); - column_ += (p_ - sb + 1); -<<<<<<< HEAD - state_stack_.back() = states::escape; -======= - state_ = states::escape; - stack2_.front() = states::escape; ->>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 - done = true; - ++p_; - break; - case '\"': - if (string_buffer_.length() == 0) - { - *first = sb; - *last = p_; - //end_string_value(sb,p_-sb); - } - else - { - string_buffer_.append(sb,p_-sb); - *first = string_buffer_.data(); - *last = string_buffer_.data() + string_buffer_.length(); - //end_string_value(string_buffer_.data(),string_buffer_.length()); - //string_buffer_.clear(); - } - column_ += (p_ - sb + 1); - done = true; - complete = true; - ++p_; - break; - default: - ++p_; - break; - } - } - if (!done) - { - string_buffer_.append(sb,p_-sb); - column_ += (p_ - sb + 1); - } - - return complete; - } - - void parse(const CharT* const input, size_t start, size_t length) - { - begin_input_ = input + start; - end_input_ = input + length; - p_ = begin_input_; - - index_ = start; - while ((p_ < end_input_) && (state_stack_.back() != states::done)) - { - switch (*p_) - { - case 0x00:case 0x01:case 0x02:case 0x03:case 0x04:case 0x05:case 0x06:case 0x07:case 0x08:case 0x0b: - case 0x0c:case 0x0e:case 0x0f:case 0x10:case 0x11:case 0x12:case 0x13:case 0x14:case 0x15:case 0x16: - case 0x17:case 0x18:case 0x19:case 0x1a:case 0x1b:case 0x1c:case 0x1d:case 0x1e:case 0x1f: - err_handler_->error(std::error_code(json_parser_errc::illegal_control_character, json_error_category()), *this); - break; - default: - break; - } - - switch (state_stack_.back()) - { - case states::cr: - ++line_; - column_ = 1; - switch (*p_) - { - case '\n': - state_stack_.back() = pre_line_break_state_; - ++p_; - break; - default: - state_stack_.back() = pre_line_break_state_; - break; - } - JSONCONS_ASSERT(stack2_.size() > 0); - stack2_.pop_back(); - break; - case states::lf: - ++line_; - column_ = 1; -<<<<<<< HEAD - state_stack_.back() = pre_line_break_state_; -======= - state_ = pre_line_break_state_; - JSONCONS_ASSERT(stack2_.size() > 0); - stack2_.pop_back(); ->>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 - break; - case states::start: - { - switch (*p_) - { - case '\r': -<<<<<<< HEAD - pre_line_break_state_ = state_stack_.back(); - state_stack_.back() = states::cr; - break; - case '\n': - pre_line_break_state_ = state_stack_.back(); - state_stack_.back() = states::lf; -======= - pre_line_break_state_ = state_; - state_ = states::cr; - stack2_.push_back(states::cr); - break; - case '\n': - pre_line_break_state_ = state_; - state_ = states::lf; - stack2_.push_back(states::lf); ->>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 - break; - case ' ':case '\t': - { - bool done = false; - while (!done && (p_ + 1) < end_input_) - { - switch (*(p_ + 1)) - { - case ' ':case '\t': - ++p_; - ++column_; - break; - default: - done = true; - break; - } - } - } - break; - case '{': - handler_->begin_json(); - if (!push(modes::object_member_name)) - { - err_handler_->error(std::error_code(json_parser_errc::max_depth_exceeded, json_error_category()), *this); - } -<<<<<<< HEAD - state_stack_.back() = states::object; -======= - state_ = states::object; - ->>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 - handler_->begin_object(*this); - break; - case '[': - handler_->begin_json(); - if (!push(modes::array_element)) - { - err_handler_->error(std::error_code(json_parser_errc::max_depth_exceeded, json_error_category()), *this); - } - state_stack_.back() = states::array; - handler_->begin_array(*this); - break; - case '\"': - handler_->begin_json(); - flip(modes::done, modes::start); - state_stack_.back() = states::string; - break; - case '-': - handler_->begin_json(); - flip(modes::done, modes::start); - is_negative_ = true; - state_stack_.back() = states::minus; - break; - case '0': - handler_->begin_json(); - flip(modes::done, modes::start); - number_buffer_.push_back(static_cast<char>(*p_)); - state_stack_.back() = states::zero; - break; - case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': - handler_->begin_json(); - flip(modes::done, modes::start); - number_buffer_.push_back(static_cast<char>(*p_)); - state_stack_.back() = states::integer; - break; - case 'f': - handler_->begin_json(); - flip(modes::done, modes::start); - state_stack_.back() = states::f; - literal_ = json_literals<CharT>::false_literal(); - literal_index_ = 1; - break; - case 'n': - handler_->begin_json(); - flip(modes::done, modes::start); - state_stack_.back() = states::n; - literal_ = json_literals<CharT>::null_literal(); - literal_index_ = 1; - break; - case 't': - handler_->begin_json(); - flip(modes::done, modes::start); - state_stack_.back() = states::t; - literal_ = json_literals<CharT>::true_literal(); - literal_index_ = 1; - break; - case '/': - saved_state_ = state_stack_.back(); - state_stack_.back() = states::slash; - break; - case '}': - err_handler_->fatal_error(std::error_code(json_parser_errc::unexpected_right_brace, json_error_category()), *this); - break; - case ']': - err_handler_->fatal_error(std::error_code(json_parser_errc::unexpected_right_bracket, json_error_category()), *this); - break; - default: - err_handler_->fatal_error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - - case states::expect_comma_or_end: - { - switch (*p_) - { - case '\r': -<<<<<<< HEAD - pre_line_break_state_ = state_stack_.back(); - state_stack_.back() = states::cr; - break; - case '\n': - pre_line_break_state_ = state_stack_.back(); - state_stack_.back() = states::lf; -======= - pre_line_break_state_ = state_; - state_ = states::cr; - stack2_.push_back(states::cr); - break; - case '\n': - pre_line_break_state_ = state_; - state_ = states::lf; - stack2_.push_back(states::lf); ->>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 - break; - case ' ':case '\t': - { - bool done = false; - while (!done && (p_ + 1) < end_input_) - { - switch (*(p_ + 1)) - { - case ' ':case '\t': - ++p_; - ++column_; - break; - default: - done = true; - break; - } - } - } - break; - case '}': - if (peek() == modes::object_member_value) - { - pop(modes::object_member_value); - handler_->end_object(*this); - if (peek() == modes::done) - { - state_stack_.back() = states::done; - handler_->end_json(); - } - else - { - state_stack_.back() = states::expect_comma_or_end; - } - } - else if (peek() == modes::array_element) - { - err_handler_->fatal_error(std::error_code(json_parser_errc::expected_comma_or_right_bracket, json_error_category()), *this); - } - else - { - err_handler_->fatal_error(std::error_code(json_parser_errc::unexpected_right_brace, json_error_category()), *this); - } - break; - case ']': - if (peek() == modes::array_element) - { - pop(modes::array_element); - handler_->end_array(*this); - if (peek() == modes::done) - { - state_stack_.back() = states::done; - handler_->end_json(); - } - else - { - state_stack_.back() = states::expect_comma_or_end; - } - } - else if (peek() == modes::object_member_value) - { - err_handler_->fatal_error(std::error_code(json_parser_errc::expected_comma_or_right_brace, json_error_category()), *this); - } - else - { - err_handler_->fatal_error(std::error_code(json_parser_errc::unexpected_right_bracket, json_error_category()), *this); - } - break; - case ',': - begin_member_or_element(); - break; - case '/': - saved_state_ = state_stack_.back(); - state_stack_.back() = states::slash; - break; - default: - if (peek() == modes::array_element) - { - err_handler_->error(std::error_code(json_parser_errc::expected_comma_or_right_bracket, json_error_category()), *this); - } - else if (peek() == modes::object_member_value) - { - err_handler_->error(std::error_code(json_parser_errc::expected_comma_or_right_brace, json_error_category()), *this); - } - break; - } - } - ++p_; - ++column_; - break; - case states::object: - { - switch (*p_) - { - case '\r': -<<<<<<< HEAD - pre_line_break_state_ = state_stack_.back(); - state_stack_.back() = states::cr; - break; - case '\n': - pre_line_break_state_ = state_stack_.back(); - state_stack_.back() = states::lf; -======= - pre_line_break_state_ = state_; - state_ = states::cr; - stack2_.push_back(states::cr); - break; - case '\n': - pre_line_break_state_ = state_; - state_ = states::lf; - stack2_.push_back(states::lf); ->>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 - break; - case ' ':case '\t': - { - bool done = false; - while (!done && (p_ + 1) < end_input_) - { - switch (*(p_ + 1)) - { - case ' ':case '\t': - ++p_; - ++column_; - break; - default: - done = true; - break; - } - } - } - break; - case '}': - if (!pop(modes::object_member_name)) - { - err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); - } - handler_->end_object(*this); - if (peek() == modes::done) - { - state_stack_.back() = states::done; - handler_->end_json(); - } - else - { - state_stack_.back() = states::expect_comma_or_end; - } - break; - case '\"': - state_stack_.back() = states::string; - break; - case '/': - saved_state_ = state_stack_.back(); - state_stack_.back() = states::slash; - break; - case '\'': - err_handler_->error(std::error_code(json_parser_errc::single_quote, json_error_category()), *this); - break; - default: - err_handler_->error(std::error_code(json_parser_errc::expected_name, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - case states::expect_member_name: - { - switch (*p_) - { - case '\r': -<<<<<<< HEAD - pre_line_break_state_ = state_stack_.back(); - state_stack_.back() = states::cr; - break; - case '\n': - pre_line_break_state_ = state_stack_.back(); - state_stack_.back() = states::lf; -======= - pre_line_break_state_ = state_; - state_ = states::cr; - stack2_.push_back(states::cr); - break; - case '\n': - pre_line_break_state_ = state_; - state_ = states::lf; - stack2_.push_back(states::lf); ->>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 - break; - case ' ':case '\t': - { - bool done = false; - while (!done && (p_ + 1) < end_input_) - { - switch (*(p_ + 1)) - { - case ' ':case '\t': - ++p_; - ++column_; - break; - default: - done = true; - break; - } - } - } - break; - case '\"': - state_stack_.back() = states::string; - break; - case '/': - saved_state_ = state_stack_.back(); - state_stack_.back() = states::slash; - break; - case '}': - err_handler_->error(std::error_code(json_parser_errc::extra_comma, json_error_category()), *this); - break; - case '\'': - err_handler_->error(std::error_code(json_parser_errc::single_quote, json_error_category()), *this); - break; - default: - err_handler_->error(std::error_code(json_parser_errc::expected_name, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - case states::expect_colon: - { - switch (*p_) - { - case '\r': -<<<<<<< HEAD - pre_line_break_state_ = state_stack_.back(); - state_stack_.back() = states::cr; - break; - case '\n': - pre_line_break_state_ = state_stack_.back(); - state_stack_.back() = states::lf; -======= - pre_line_break_state_ = state_; - state_ = states::cr; - stack2_.push_back(states::cr); - break; - case '\n': - pre_line_break_state_ = state_; - state_ = states::lf; - stack2_.push_back(states::lf); ->>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 - break; - case ' ':case '\t': - { - bool done = false; - while (!done && (p_ + 1) < end_input_) - { - switch (*(p_ + 1)) - { - case ' ':case '\t': - ++p_; - ++column_; - break; - default: - done = true; - break; - } - } - } - break; - case ':': - begin_member_value(); - state_stack_.back() = states::expect_value; - break; - case '/': - saved_state_ = state_stack_.back(); - state_stack_.back() = states::slash; - break; - default: - err_handler_->error(std::error_code(json_parser_errc::expected_colon, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - case states::expect_value: - { - switch (*p_) - { - case '\r': -<<<<<<< HEAD - pre_line_break_state_ = state_stack_.back(); - state_stack_.back() = states::cr; - break; - case '\n': - pre_line_break_state_ = state_stack_.back(); - state_stack_.back() = states::lf; -======= - pre_line_break_state_ = state_; - state_ = states::cr; - stack2_.push_back(states::cr); - break; - case '\n': - pre_line_break_state_ = state_; - state_ = states::lf; - stack2_.push_back(states::lf); ->>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 - break; - case ' ':case '\t': - { - bool done = false; - while (!done && (p_ + 1) < end_input_) - { - switch (*(p_ + 1)) - { - case ' ':case '\t': - ++p_; - ++column_; - break; - default: - done = true; - break; - } - } - } - break; - case '{': - if (!push(modes::object_member_name)) - { - err_handler_->error(std::error_code(json_parser_errc::max_depth_exceeded, json_error_category()), *this); - } - state_stack_.back() = states::object; - handler_->begin_object(*this); - break; - case '[': - if (!push(modes::array_element)) - { - err_handler_->error(std::error_code(json_parser_errc::max_depth_exceeded, json_error_category()), *this); - } - state_stack_.back() = states::array; - handler_->begin_array(*this); - break; - case '/': - saved_state_ = state_stack_.back(); - state_stack_.back() = states::slash; - break; - - case '\"': - state_stack_.back() = states::string; - break; - case '-': - is_negative_ = true; - state_stack_.back() = states::minus; - break; - case '0': - number_buffer_.push_back(static_cast<char>(*p_)); - state_stack_.back() = states::zero; - break; - case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': - number_buffer_.push_back(static_cast<char>(*p_)); - state_stack_.back() = states::integer; - break; - case 'f': - state_stack_.back() = states::f; - literal_ = json_literals<CharT>::false_literal(); - literal_index_ = 1; - /*if ((p_+4) < end_input_) - { - if ((*(p_+1) == 'a') & (*(p_+2) == 'l') & (*(p_+3) == 's') & (*(p_+4) == 'e')) - { - p_ += 4; - column_ += 4; - handler_->value(false, *this); - if (peek() == modes::start) - { - flip(modes::start,modes::done); - state_stack_.back() = states::done; - handler_->end_json(); - } - else - { - state_stack_.back() = states::expect_comma_or_end; - } - } - }*/ - break; - case 'n': - state_stack_.back() = states::n; - literal_ = json_literals<CharT>::null_literal(); - literal_index_ = 1; - break; - case 't': - state_stack_.back() = states::t; - literal_ = json_literals<CharT>::true_literal(); - literal_index_ = 1; - break; - case ']': - if (peek() == modes::array_element) - { - err_handler_->error(std::error_code(json_parser_errc::extra_comma, json_error_category()), *this); - } - else - { - err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); - } - break; - case '\'': - err_handler_->error(std::error_code(json_parser_errc::single_quote, json_error_category()), *this); - break; - default: - err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - case states::array: - { - switch (*p_) - { - case '\r': -<<<<<<< HEAD - pre_line_break_state_ = state_stack_.back(); - state_stack_.back() = states::cr; - break; - case '\n': - pre_line_break_state_ = state_stack_.back(); - state_stack_.back() = states::lf; -======= - pre_line_break_state_ = state_; - state_ = states::cr; - stack2_.push_back(states::cr); - break; - case '\n': - pre_line_break_state_ = state_; - state_ = states::lf; - stack2_.push_back(states::lf); ->>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 - break; - case ' ':case '\t': - { - bool done = false; - while (!done && (p_ + 1) < end_input_) - { - switch (*(p_ + 1)) - { - case ' ':case '\t': - ++p_; - ++column_; - break; - default: - done = true; - break; - } - } - } - break; - case '{': - if (!push(modes::object_member_name)) - { - err_handler_->error(std::error_code(json_parser_errc::max_depth_exceeded, json_error_category()), *this); - } - state_stack_.back() = states::object; - handler_->begin_object(*this); - break; - case '[': - if (!push(modes::array_element)) - { - err_handler_->error(std::error_code(json_parser_errc::max_depth_exceeded, json_error_category()), *this); - } - state_stack_.back() = states::array; - handler_->begin_array(*this); - break; - case ']': - if (!pop(modes::array_element)) - { - err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); - } - handler_->end_array(*this); - if (peek() == modes::done) - { - state_stack_.back() = states::done; - handler_->end_json(); - } - else - { - state_stack_.back() = states::expect_comma_or_end; - } - break; - case '\"': - state_stack_.back() = states::string; - break; - case '/': - saved_state_ = state_stack_.back(); - state_stack_.back() = states::slash; - break; - case '-': - is_negative_ = true; - state_stack_.back() = states::minus; - break; - case '0': - number_buffer_.push_back(static_cast<char>(*p_)); - state_stack_.back() = states::zero; - break; - case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': - number_buffer_.push_back(static_cast<char>(*p_)); - state_stack_.back() = states::integer; - break; - case 'f': - state_stack_.back() = states::f; - literal_ = json_literals<CharT>::false_literal(); - literal_index_ = 1; - /*if ((p_+4) < end_input_) - { - if ((*(p_+1) == 'a') & (*(p_+2) == 'l') & (*(p_+3) == 's') & (*(p_+4) == 'e')) - { - p_ += 4; - column_ += 4; - handler_->value(false, *this); - if (peek() == modes::start) - { - flip(modes::start,modes::done); - state_stack_.back() = states::done; - handler_->end_json(); - } - else - { - state_stack_.back() = states::expect_comma_or_end; - } - } - }*/ - break; - case 'n': - state_stack_.back() = states::n; - literal_ = json_literals<CharT>::null_literal(); - literal_index_ = 1; - break; - case 't': - state_stack_.back() = states::t; - literal_ = json_literals<CharT>::true_literal(); - literal_index_ = 1; - break; - case '\'': - err_handler_->error(std::error_code(json_parser_errc::single_quote, json_error_category()), *this); - break; - default: - err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - case states::string: - { - const CharT* first; - const CharT* last; - if (parse_string(&first,&last)) - { - end_string_value(first,last-first); - string_buffer_.clear(); - } - } - break; - case states::escape: - { - escape_next_char(*p_); - } - ++p_; - ++column_; - break; - case states::u1: - { - append_codepoint(*p_); - state_stack_.back() = states::u2; - } - ++p_; - ++column_; - break; - case states::u2: - { - append_codepoint(*p_); - state_stack_.back() = states::u3; - } - ++p_; - ++column_; - break; - case states::u3: - { - append_codepoint(*p_); - state_stack_.back() = states::u4; - } - ++p_; - ++column_; - break; - case states::u4: - { - append_codepoint(*p_); - if (cp_ >= min_lead_surrogate && cp_ <= max_lead_surrogate) - { - state_stack_.back() = states::expect_surrogate_pair1; - } - else - { - json_char_traits<CharT, sizeof(CharT)>::append_codepoint_to_string(cp_, string_buffer_); - state_stack_.back() = states::string; - } - } - ++p_; - ++column_; - break; - case states::expect_surrogate_pair1: - { - switch (*p_) - { - case '\\': - cp2_ = 0; - state_stack_.back() = states::expect_surrogate_pair2; - break; - default: - err_handler_->error(std::error_code(json_parser_errc::expected_codepoint_surrogate_pair, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - case states::expect_surrogate_pair2: - { - switch (*p_) - { - case 'u': - state_stack_.back() = states::u6; - break; - default: - err_handler_->error(std::error_code(json_parser_errc::expected_codepoint_surrogate_pair, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - case states::u6: - { - append_second_codepoint(*p_); - state_stack_.back() = states::u7; - } - ++p_; - ++column_; - break; - case states::u7: - { - append_second_codepoint(*p_); - state_stack_.back() = states::u8; - } - ++p_; - ++column_; - break; - case states::u8: - { - append_second_codepoint(*p_); - state_stack_.back() = states::u9; - } - ++p_; - ++column_; - break; - case states::u9: - { - append_second_codepoint(*p_); - uint32_t cp = 0x10000 + ((cp_ & 0x3FF) << 10) + (cp2_ & 0x3FF); - json_char_traits<CharT, sizeof(CharT)>::append_codepoint_to_string(cp, string_buffer_); - state_stack_.back() = states::string; - } - ++p_; - ++column_; - break; - case states::minus: - { - switch (*p_) - { - case '0': - number_buffer_.push_back(static_cast<char>(*p_)); - state_stack_.back() = states::zero; - break; - case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': - number_buffer_.push_back(static_cast<char>(*p_)); - state_stack_.back() = states::integer; - break; - default: - err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - case states::zero: - { - switch (*p_) - { - case '\r': -<<<<<<< HEAD - pre_line_break_state_ = state_stack_.back(); - state_stack_.back() = states::cr; - break; - case '\n': - pre_line_break_state_ = state_stack_.back(); - state_stack_.back() = states::lf; -======= - pre_line_break_state_ = state_; - state_ = states::cr; - stack2_.push_back(states::cr); - break; - case '\n': - pre_line_break_state_ = state_; - state_ = states::lf; - stack2_.push_back(states::lf); ->>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 - break; - case ' ':case '\t': - { - bool done = false; - while (!done && (p_ + 1) < end_input_) - { - switch (*(p_ + 1)) - { - case ' ':case '\t': - ++p_; - ++column_; - break; - default: - done = true; - break; - } - } - } - end_integer_value(); - break; // No change - case '}': - end_integer_value(); - if (!pop(modes::object_member_value)) - { - err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); - } - handler_->end_object(*this); - if (peek() == modes::done) - { - state_stack_.back() = states::done; - handler_->end_json(); - } - else - { - state_stack_.back() = states::expect_comma_or_end; - } - break; - case ']': - end_integer_value(); - if (!pop(modes::array_element)) - { - err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); - } - handler_->end_array(*this); - if (peek() == modes::done) - { - state_stack_.back() = states::done; - handler_->end_json(); - } - else - { - state_stack_.back() = states::expect_comma_or_end; - } - break; - case '.': - precision_ = static_cast<uint8_t>(number_buffer_.length()); - number_buffer_.push_back(static_cast<char>(*p_)); - state_stack_.back() = states::fraction; - break; - case ',': - end_integer_value(); - begin_member_or_element(); - break; - case '0': case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': - err_handler_->error(std::error_code(json_parser_errc::leading_zero, json_error_category()), *this); - break; - default: - err_handler_->error(std::error_code(json_parser_errc::invalid_number, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - case states::integer: - { - switch (*p_) - { - case '\r': -<<<<<<< HEAD - pre_line_break_state_ = state_stack_.back(); - state_stack_.back() = states::cr; - break; - case '\n': - pre_line_break_state_ = state_stack_.back(); - state_stack_.back() = states::lf; -======= - pre_line_break_state_ = state_; - state_ = states::cr; - stack2_.push_back(states::cr); - break; - case '\n': - pre_line_break_state_ = state_; - state_ = states::lf; - stack2_.push_back(states::lf); ->>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 - break; - case ' ':case '\t': - { - bool done = false; - while (!done && (p_ + 1) < end_input_) - { - switch (*(p_ + 1)) - { - case ' ':case '\t': - ++p_; - ++column_; - break; - default: - done = true; - break; - } - } - } - end_integer_value(); - break; - case '}': - end_integer_value(); - if (!pop(modes::object_member_value)) - { - err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); - } - handler_->end_object(*this); - if (peek() == modes::done) - { - state_stack_.back() = states::done; - handler_->end_json(); - } - else - { - state_stack_.back() = states::expect_comma_or_end; - } - break; - case ']': - end_integer_value(); - if (!pop(modes::array_element)) - { - err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); - } - handler_->end_array(*this); - if (peek() == modes::done) - { - state_stack_.back() = states::done; - handler_->end_json(); - } - else - { - state_stack_.back() = states::expect_comma_or_end; - } - break; - case '0': - case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': - number_buffer_.push_back(static_cast<char>(*p_)); - state_stack_.back() = states::integer; - break; - case '.': - precision_ = static_cast<uint8_t>(number_buffer_.length()); - number_buffer_.push_back(static_cast<char>(*p_)); - state_stack_.back() = states::fraction; - break; - case ',': - end_integer_value(); - begin_member_or_element(); - break; - case 'e':case 'E': - number_buffer_.push_back(static_cast<char>(*p_)); - state_stack_.back() = states::exp1; - break; - default: - err_handler_->error(std::error_code(json_parser_errc::invalid_number, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - case states::fraction: - { - switch (*p_) - { - case '\r': -<<<<<<< HEAD - pre_line_break_state_ = state_stack_.back(); - state_stack_.back() = states::cr; - break; - case '\n': - pre_line_break_state_ = state_stack_.back(); - state_stack_.back() = states::lf; -======= - pre_line_break_state_ = state_; - state_ = states::cr; - stack2_.push_back(states::cr); - break; - case '\n': - pre_line_break_state_ = state_; - state_ = states::lf; - stack2_.push_back(states::lf); ->>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 - break; - case ' ':case '\t': - { - bool done = false; - while (!done && (p_ + 1) < end_input_) - { - switch (*(p_ + 1)) - { - case ' ':case '\t': - ++p_; - ++column_; - break; - default: - done = true; - break; - } - } - } - end_fraction_value(); - break; - case '}': - end_fraction_value(); - if (!pop(modes::object_member_value)) - { - err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); - } - handler_->end_object(*this); - if (peek() == modes::done) - { - state_stack_.back() = states::done; - handler_->end_json(); - } - else - { - state_stack_.back() = states::expect_comma_or_end; - } - break; - case ']': - end_fraction_value(); - if (!pop(modes::array_element)) - { - err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); - } - handler_->end_array(*this); - if (peek() == modes::done) - { - state_stack_.back() = states::done; - handler_->end_json(); - } - else - { - state_stack_.back() = states::expect_comma_or_end; - } - break; - case '0': - case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': - ++precision_; - number_buffer_.push_back(static_cast<char>(*p_)); - state_stack_.back() = states::fraction; - break; - case ',': - end_fraction_value(); - begin_member_or_element(); - break; - case 'e':case 'E': - number_buffer_.push_back(static_cast<char>(*p_)); - state_stack_.back() = states::exp1; - break; - default: - err_handler_->error(std::error_code(json_parser_errc::invalid_number, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - case states::exp1: - { - switch (*p_) - { - case '+': - state_stack_.back() = states::exp2; - break; - case '-': - number_buffer_.push_back(static_cast<char>(*p_)); - state_stack_.back() = states::exp2; - break; - case '0': - case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': - number_buffer_.push_back(static_cast<char>(*p_)); - state_stack_.back() = states::exp3; - break; - default: - err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - case states::exp2: - { - switch (*p_) - { - case '0': - case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': - number_buffer_.push_back(static_cast<char>(*p_)); - state_stack_.back() = states::exp3; - break; - default: - err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - case states::exp3: - { - switch (*p_) - { - case '\r': -<<<<<<< HEAD - pre_line_break_state_ = state_stack_.back(); - state_stack_.back() = states::cr; - break; - case '\n': - pre_line_break_state_ = state_stack_.back(); - state_stack_.back() = states::lf; -======= - pre_line_break_state_ = state_; - state_ = states::cr; - stack2_.push_back(states::cr); - break; - case '\n': - pre_line_break_state_ = state_; - state_ = states::lf; - stack2_.push_back(states::lf); ->>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 - break; - case ' ':case '\t': - { - bool done = false; - while (!done && (p_ + 1) < end_input_) - { - switch (*(p_ + 1)) - { - case ' ':case '\t': - ++p_; - ++column_; - break; - default: - done = true; - break; - } - } - } - end_fraction_value(); - break; - case '}': - end_fraction_value(); - if (!pop(modes::object_member_value)) - { - err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); - } - handler_->end_object(*this); - if (peek() == modes::done) - { - state_stack_.back() = states::done; - handler_->end_json(); - } - else - { - state_stack_.back() = states::expect_comma_or_end; - } - break; - case ']': - end_fraction_value(); - if (!pop(modes::array_element)) - { - err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); - } - handler_->end_array(*this); - if (peek() == modes::done) - { - state_stack_.back() = states::done; - handler_->end_json(); - } - else - { - state_stack_.back() = states::expect_comma_or_end; - } - break; - case ',': - end_fraction_value(); - begin_member_or_element(); - break; - case '0': - case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': - number_buffer_.push_back(static_cast<char>(*p_)); - state_stack_.back() = states::exp3; - break; - default: - err_handler_->error(std::error_code(json_parser_errc::invalid_number, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - case states::t: - while (p_ < end_input_ && literal_index_ < literal_.second) - { - if (*p_ != literal_.first[literal_index_]) - { - err_handler_->error(std::error_code(json_parser_errc::invalid_value, json_error_category()), *this); - } - ++p_; - ++literal_index_; - ++column_; - } - if (literal_index_ == literal_.second) - { - handler_->value(true, *this); - if (peek() == modes::start) - { - flip(modes::start,modes::done); - state_stack_.back() = states::done; - handler_->end_json(); - } - else - { - state_stack_.back() = states::expect_comma_or_end; - } - } - break; - case states::f: - while (p_ < end_input_ && literal_index_ < literal_.second) - { - if (*p_ != literal_.first[literal_index_]) - { - err_handler_->error(std::error_code(json_parser_errc::invalid_value, json_error_category()), *this); - } - ++p_; - ++literal_index_; - ++column_; - } - if (literal_index_ == literal_.second) - { - handler_->value(false, *this); - if (peek() == modes::start) - { - flip(modes::start,modes::done); - state_stack_.back() = states::done; - handler_->end_json(); - } - else - { - state_stack_.back() = states::expect_comma_or_end; - } - } - break; - case states::n: - while (p_ < end_input_ && literal_index_ < literal_.second) - { - if (*p_ != literal_.first[literal_index_]) - { - err_handler_->error(std::error_code(json_parser_errc::invalid_value, json_error_category()), *this); - } - ++p_; - ++literal_index_; - ++column_; - } - if (literal_index_ == literal_.second) - { - handler_->value(null_type(), *this); - if (peek() == modes::start) - { - flip(modes::start,modes::done); - state_stack_.back() = states::done; - handler_->end_json(); - } - else - { - state_stack_.back() = states::expect_comma_or_end; - } - } - break; - case states::slash: - { - switch (*p_) - { - case '*': - state_stack_.back() = states::slash_star; - break; - case '/': - state_stack_.back() = states::slash_slash; - break; - default: - err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); - break; - } - } - ++p_; - ++column_; - break; - case states::slash_star: - { - switch (*p_) - { - case '\r': -<<<<<<< HEAD - pre_line_break_state_ = state_stack_.back(); - state_stack_.back() = states::cr; - break; - case '\n': - pre_line_break_state_ = state_stack_.back(); - state_stack_.back() = states::lf; -======= - pre_line_break_state_ = state_; - state_ = states::cr; - stack2_.push_back(states::cr); - break; - case '\n': - pre_line_break_state_ = state_; - state_ = states::lf; - stack2_.push_back(states::lf); ->>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 - break; - case '*': - state_stack_.back() = states::slash_star_star; - break; - } - } - ++p_; - ++column_; - break; - case states::slash_slash: - { - switch (*p_) - { - case '\r': - pre_line_break_state_ = saved_state_; -<<<<<<< HEAD - state_stack_.back() = states::cr; - break; - case '\n': - pre_line_break_state_ = saved_state_; - state_stack_.back() = states::lf; -======= - state_ = states::cr; - stack2_.push_back(states::cr); - break; - case '\n': - pre_line_break_state_ = saved_state_; - state_ = states::lf; - stack2_.push_back(states::lf); ->>>>>>> 8522df40eb2e2c14a4b40274eedf44dd9d631bb8 - break; - } - } - ++p_; - ++column_; - break; - case states::slash_star_star: - { - switch (*p_) - { - case '/': - state_stack_.back() = saved_state_; - break; - default: - state_stack_.back() = states::slash_star; - break; - } - } - ++p_; - ++column_; - break; - default: - JSONCONS_THROW_EXCEPTION(std::runtime_error,"Bad parser state"); - break; - } - } - index_ += (p_-begin_input_); - } - - void end_parse() - { - if (peek() == modes::start) - { - switch (state_stack_.back()) - { - case states::zero: - case states::integer: - end_integer_value(); - break; - case states::fraction: - case states::exp3: - end_fraction_value(); - break; - default: - break; - } - } - if (!pop(modes::done)) - { - err_handler_->error(std::error_code(json_parser_errc::unexpected_eof, json_error_category()), *this); - } - } - - states state() const - { - return state_stack_.back(); - } - - size_t index() const - { - return index_; - } -private: - void end_fraction_value() - { - try - { - double d = float_reader_.read(number_buffer_.data(), precision_); - if (is_negative_) - d = -d; - handler_->value(d, static_cast<uint8_t>(precision_), *this); - } - catch (...) - { - err_handler_->error(std::error_code(json_parser_errc::invalid_number, json_error_category()), *this); - handler_->value(null_type(), *this); // recovery - } - number_buffer_.clear(); - is_negative_ = false; - switch (stack_[top_]) - { - case modes::array_element: - case modes::object_member_value: - state_stack_.back() = states::expect_comma_or_end; - break; - case modes::start: - flip(modes::start,modes::done); - state_stack_.back() = states::done; - handler_->end_json(); - break; - default: - err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); - break; - } - } - - void end_integer_value() - { - if (is_negative_) - { - try - { - int64_t d = string_to_integer(is_negative_, number_buffer_.data(), number_buffer_.length()); - handler_->value(d, *this); - } - catch (const std::exception&) - { - try - { - double d = float_reader_.read(number_buffer_.data(), number_buffer_.length()); - handler_->value(-d, static_cast<uint8_t>(number_buffer_.length()), *this); - } - catch (...) - { - err_handler_->error(std::error_code(json_parser_errc::invalid_number, json_error_category()), *this); - handler_->value(null_type(), *this); - } - } - } - else - { - try - { - uint64_t d = string_to_uinteger(number_buffer_.data(), number_buffer_.length()); - handler_->value(d, *this); - } - catch (const std::exception&) - { - try - { - double d = float_reader_.read(number_buffer_.data(),number_buffer_.length()); - handler_->value(d, static_cast<uint8_t>(number_buffer_.length()), *this); - } - catch (...) - { - err_handler_->error(std::error_code(json_parser_errc::invalid_number, json_error_category()), *this); - handler_->value(null_type(), *this); - } - } - } - - switch (stack_[top_]) - { - case modes::array_element: - case modes::object_member_value: - state_stack_.back() = states::expect_comma_or_end; - break; - case modes::start: - flip(modes::start,modes::done); - state_stack_.back() = states::done; - handler_->end_json(); - break; - default: - err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); - break; - } - number_buffer_.clear(); - is_negative_ = false; - } - - void append_codepoint(int c) - { - switch (c) - { - case '0': case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': - case 'a':case 'b':case 'c':case 'd':case 'e':case 'f': - case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': - cp_ = append_to_codepoint(cp_, c); - break; - default: - err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); - break; - } - } - - void append_second_codepoint(int c) - { - switch (c) - { - case '0': - case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8': case '9': - case 'a':case 'b':case 'c':case 'd':case 'e':case 'f': - case 'A':case 'B':case 'C':case 'D':case 'E':case 'F': - cp2_ = append_to_codepoint(cp2_, c); - break; - default: - err_handler_->error(std::error_code(json_parser_errc::expected_value, json_error_category()), *this); - break; - } - } - - void escape_next_char(int next_input) - { - switch (next_input) - { - case '\"': - string_buffer_.push_back('\"'); - state_stack_.back() = states::string; - break; - case '\\': - string_buffer_.push_back('\\'); - state_stack_.back() = states::string; - break; - case '/': - string_buffer_.push_back('/'); - state_stack_.back() = states::string; - break; - case 'b': - string_buffer_.push_back('\b'); - state_stack_.back() = states::string; - break; - case 'f': - string_buffer_.push_back('\f'); - state_stack_.back() = states::string; - break; - case 'n': - string_buffer_.push_back('\n'); - state_stack_.back() = states::string; - break; - case 'r': - string_buffer_.push_back('\r'); - state_stack_.back() = states::string; - break; - case 't': - string_buffer_.push_back('\t'); - state_stack_.back() = states::string; - break; - case 'u': - cp_ = 0; - state_stack_.back() = states::u1; - break; - default: - err_handler_->error(std::error_code(json_parser_errc::illegal_escaped_character, json_error_category()), *this); - break; - } - } - - void end_string_value(const CharT* s, size_t length) - { - switch (stack_[top_]) - { - case modes::object_member_name: - handler_->name(s, length, *this); - state_stack_.back() = states::expect_colon; - break; - case modes::array_element: - case modes::object_member_value: - handler_->value(s, length, *this); - state_stack_.back() = states::expect_comma_or_end; - break; - case modes::start: - handler_->value(s, length, *this); - flip(modes::start,modes::done); - state_stack_.back() = states::done; - handler_->end_json(); - break; - default: - err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); - break; - } - } - - void begin_member_or_element() - { - switch (stack_[top_]) - { - case modes::object_member_value: - // A comma causes a flip from object_member_value modes to object_member_name modes. - flip(modes::object_member_value, modes::object_member_name); - state_stack_.back() = states::expect_member_name; - break; - case modes::array_element: - state_stack_.back() = states::expect_value; - break; - case modes::done: - break; - default: - err_handler_->error(std::error_code(json_parser_errc::invalid_json_text, json_error_category()), *this); - break; - } - } - - void begin_member_value() - { - flip(modes::object_member_name, modes::object_member_value); - state_stack_.back() = states::expect_value; - } - - uint32_t append_to_codepoint(uint32_t cp, int c) - { - cp *= 16; - if (c >= '0' && c <= '9') - { - cp += c - '0'; - } - else if (c >= 'a' && c <= 'f') - { - cp += c - 'a' + 10; - } - else if (c >= 'A' && c <= 'F') - { - cp += c - 'A' + 10; - } - else - { - err_handler_->error(std::error_code(json_parser_errc::invalid_hex_escape_sequence, json_error_category()), *this); - } - return cp; - } - - size_t do_line_number() const override - { - return line_; - } - - size_t do_column_number() const override - { - return column_; - } - - CharT do_current_char() const override - { - return p_ < end_input_? *p_ : 0; - } - - bool push(modes mode) - { - ++top_; - if (top_ >= depth_) - { - if (top_ >= max_depth_) - { - return false; - } - depth_ *= 2; - stack_.resize(depth_); - } - stack_[top_] = mode; - return true; - } - - modes peek() - { - return stack_[top_]; - } - - bool peek(modes mode) - { - return stack_[top_] == mode; - } - - void flip(modes mode1, modes mode2) - { - JSONCONS_ASSERT((top_ >= 0) && (stack_[top_] == mode1)) - stack_[top_] = mode2; - } - - bool pop(modes mode) - { - if (top_ < 0 || stack_[top_] != mode) - { - return false; - } - --top_; - return true; - } -}; - -typedef basic_json_parser<char> json_parser; -typedef basic_json_parser<wchar_t> wjson_parser; - -} - -#endif - diff --git a/vendor/jsoncons-0.99.2/jsoncons/json_reader.hpp b/vendor/jsoncons-0.99.2/jsoncons/json_reader.hpp deleted file mode 100644 index a0dd4641..00000000 --- a/vendor/jsoncons-0.99.2/jsoncons/json_reader.hpp +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright 2015 Daniel Parker -// Distributed under the Boost license, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -// See https://github.com/danielaparker/jsoncons for latest version - -#ifndef JSONCONS_JSON_READER_HPP -#define JSONCONS_JSON_READER_HPP - -#include <memory> -#include <string> -#include <sstream> -#include <vector> -#include <istream> -#include <cstdlib> -#include <stdexcept> -#include <system_error> -#include "jsoncons/jsoncons.hpp" -#include "jsoncons/json_input_handler.hpp" -#include "jsoncons/parse_error_handler.hpp" -#include "jsoncons/json_parser.hpp" - -namespace jsoncons { - -template<typename CharT> -class basic_json_reader -{ - static const size_t default_max_buffer_length = 16384; - - basic_json_parser<CharT> parser_; - std::basic_istream<CharT> *is_; - basic_parse_error_handler<CharT> *err_handler_; - bool eof_; - std::vector<CharT> buffer_; - size_t buffer_length_; - size_t buffer_capacity_; - size_t index_; -public: - basic_json_reader(std::basic_istream<CharT>& is, - basic_json_input_handler<CharT>& handler) - : parser_(handler), - is_(std::addressof(is)), - err_handler_(std::addressof(basic_default_parse_error_handler<CharT>::instance())), - eof_(false), - buffer_length_(0), - buffer_capacity_(default_max_buffer_length), - index_(0) - { - buffer_.resize(buffer_capacity_); - } - - basic_json_reader(std::basic_istream<CharT>& is, - basic_json_input_handler<CharT>& handler, - basic_parse_error_handler<CharT>& err_handler) - : parser_(handler,err_handler), - is_(std::addressof(is)), - err_handler_(std::addressof(err_handler)), - eof_(false), - buffer_length_(0), - buffer_capacity_(default_max_buffer_length), - index_(0) - { - buffer_.resize(buffer_capacity_); - } - - size_t buffer_capacity() const - { - return buffer_capacity_; - } - - void buffer_capacity(size_t capacity) - { - buffer_capacity_ = capacity; - buffer_.resize(buffer_capacity_); - } - - size_t max_nesting_depth() const - { - return parser_.max_nesting_depth(); - } - - void max_nesting_depth(size_t depth) - { - parser_.max_nesting_depth(depth); - } - - void read_next() - { - parser_.begin_parse(); - while (!eof_ && !parser_.done()) - { - if (!(index_ < buffer_length_)) - { - if (!is_->eof()) - { - is_->read(buffer_.data(), buffer_capacity_); - buffer_length_ = static_cast<size_t>(is_->gcount()); - if (buffer_length_ == 0) - { - eof_ = true; - } - index_ = 0; - } - else - { - eof_ = true; - } - } - if (!eof_) - { - parser_.parse(buffer_.data(),index_,buffer_length_); - index_ = parser_.index(); - } - } - parser_.end_parse(); - } - - void check_done() - { - while (!eof_) - { - if (!(index_ < buffer_length_)) - { - if (!is_->eof()) - { - is_->read(buffer_.data(), buffer_capacity_); - buffer_length_ = static_cast<size_t>(is_->gcount()); - if (buffer_length_ == 0) - { - eof_ = true; - } - index_ = 0; - } - else - { - eof_ = true; - } - } - if (!eof_) - { - parser_.check_done(buffer_.data(),index_,buffer_length_); - index_ = parser_.index(); - } - } - } - - bool eof() const - { - return eof_; - } - -#if !defined(JSONCONS_NO_DEPRECATED) - void read() - { - read_next(); - } - - size_t max_depth() const - { - return parser_.max_nesting_depth(); - } - - void max_depth(size_t depth) - { - parser_.max_nesting_depth(depth); - } -#endif -}; - -typedef basic_json_reader<char> json_reader; -typedef basic_json_reader<wchar_t> wjson_reader; - -} - -#endif - diff --git a/vendor/jsoncons-0.99.2/jsoncons/json_serializer.hpp b/vendor/jsoncons-0.99.2/jsoncons/json_serializer.hpp deleted file mode 100644 index d9f3bf4f..00000000 --- a/vendor/jsoncons-0.99.2/jsoncons/json_serializer.hpp +++ /dev/null @@ -1,435 +0,0 @@ -// Copyright 2013 Daniel Parker -// Distributed under the Boost license, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -// See https://github.com/danielaparker/jsoncons for latest version - -#ifndef JSONCONS_JSON_SERIALIZER_HPP -#define JSONCONS_JSON_SERIALIZER_HPP - -#include <string> -#include <sstream> -#include <vector> -#include <istream> -#include <ostream> -#include <cstdlib> -#include <limits> // std::numeric_limits -#include <fstream> -#include "jsoncons/jsoncons.hpp" -#include "jsoncons/output_format.hpp" -#include "jsoncons/json_output_handler.hpp" - -namespace jsoncons { - -template<typename CharT> -class basic_json_serializer : public basic_json_output_handler<CharT> -{ - static const size_t default_buffer_length = 16384; - - struct stack_item - { - stack_item(bool is_object) - : is_object_(is_object), count_(0), option_(block_options::next_line), multiline_(false) - { - scalar_option_ = is_object ? block_options::next_line : block_options::same_line; - } - stack_item(bool is_object, block_options option) - : is_object_(is_object), count_(0), option_(option), multiline_(false) - { - scalar_option_ = is_object ? block_options::next_line : block_options::same_line; - } - bool is_multiline() const - { - return multiline_; - } - - bool is_object() const - { - return is_object_; - } - - bool is_same_line() const - { - return option_ = block_options::same_line; - } - - bool is_next_line() const - { - return option_ == block_options::next_line; - } - - bool scalar_next_line() const - { - return scalar_option_ == block_options::next_line; - } - - bool is_object_; - size_t count_; - block_options option_; - block_options scalar_option_; - bool multiline_; - }; - basic_output_format<CharT> format_; - std::vector<stack_item> stack_; - int indent_; - std::streamsize original_precision_; - std::ios_base::fmtflags original_format_flags_; - bool indenting_; - float_printer<CharT> fp_; - buffered_ostream<CharT> bos_; -public: - basic_json_serializer(std::basic_ostream<CharT>& os) - : indent_(0), - indenting_(false), - fp_(format_.precision()), - bos_(os) - { - } - - basic_json_serializer(std::basic_ostream<CharT>& os, bool indenting) - : indent_(0), - indenting_(indenting), - fp_(format_.precision()), - bos_(os) - { - } - - basic_json_serializer(std::basic_ostream<CharT>& os, const basic_output_format<CharT>& format) - : format_(format), - indent_(0), - indenting_(false), - fp_(format_.precision()), - bos_(os) - { - } - basic_json_serializer(std::basic_ostream<CharT>& os, const basic_output_format<CharT>& format, bool indenting) - : format_(format), - indent_(0), - indenting_(indenting), - fp_(format_.precision()), - bos_(os) - { - } - - ~basic_json_serializer() - { - } - -private: - // Implementing methods - void do_begin_json() override - { - } - - void do_end_json() override - { - bos_.flush(); - } - - void do_begin_object() override - { - if (!stack_.empty() && !stack_.back().is_object()) - { - if (!stack_.empty()) - { - if (stack_.back().count_ > 0) - { - bos_. put(','); - } - } - } - - if (indenting_) - { - if (!stack_.empty() && stack_.back().is_object()) - { - if (format_.object_object_block_option() == block_options::next_line) - { - write_indent(); - } - stack_.push_back(stack_item(true,format_.object_object_block_option())); - } - else if (!stack_.empty()) - { - if (format_.array_object_block_option() == block_options::next_line) - { - write_indent(); - } - stack_.push_back(stack_item(true,format_.array_object_block_option())); - } - else - { - stack_.push_back(stack_item(true)); - } - indent(); - } - else - { - stack_.push_back(stack_item(true)); - } - bos_.put('{'); - } - - void do_end_object() override - { - JSONCONS_ASSERT(!stack_.empty()); - if (indenting_) - { - unindent(); - write_indent(); - } - stack_.pop_back(); - bos_.put('}'); - - end_value(); - } - - - void do_begin_array() override - { - if (!stack_.empty() && !stack_.back().is_object()) - { - if (!stack_.empty()) - { - if (stack_.back().count_ > 0) - { - bos_. put(','); - } - } - } - if (indenting_) - { - if (!stack_.empty() && stack_.back().is_object()) - { - if (format_.object_array_block_option() == block_options::next_line) - { - write_indent(); - } - stack_.push_back(stack_item(false,format_.object_array_block_option())); - } - else if (!stack_.empty()) - { - if (format_.array_array_block_option() == block_options::next_line) - { - write_indent(); - } - stack_.push_back(stack_item(false,format_.array_array_block_option())); - } - else - { - stack_.push_back(stack_item(false)); - } - indent(); - } - else - { - stack_.push_back(stack_item(false)); - } - bos_.put('['); - } - - void do_end_array() override - { - JSONCONS_ASSERT(!stack_.empty()); - if (indenting_) - { - unindent(); - if (stack_.back().is_multiline()) - { - write_indent(); - } - } - stack_.pop_back(); - bos_.put(']'); - end_value(); - } - - void do_name(const CharT* name, size_t length) override - { - if (!stack_.empty()) - { - if (stack_.back().count_ > 0) - { - bos_. put(','); - } - if (indenting_) - { - if (stack_.back().scalar_next_line()) - { - write_indent(); - } - } - } - - bos_.put('\"'); - escape_string<CharT>(name, length, format_, bos_); - bos_.put('\"'); - bos_.put(':'); - bos_.put(' '); - } - - void do_null_value() override - { - if (!stack_.empty() && !stack_.back().is_object()) - { - begin_scalar_value(); - } - - auto buf = json_literals<CharT>::null_literal(); - bos_.write(buf.first,buf.second); - - end_value(); - } - - void do_string_value(const CharT* value, size_t length) override - { - if (!stack_.empty() && !stack_.back().is_object()) - { - begin_scalar_value(); - } - - bos_. put('\"'); - escape_string<CharT>(value, length, format_, bos_); - bos_. put('\"'); - - end_value(); - } - - void do_double_value(double value, uint8_t precision) override - { - if (!stack_.empty() && !stack_.back().is_object()) - { - begin_scalar_value(); - } - - if (is_nan(value) && format_.replace_nan()) - { - bos_.write(format_.nan_replacement()); - } - else if (is_pos_inf(value) && format_.replace_pos_inf()) - { - bos_.write(format_.pos_inf_replacement()); - } - else if (is_neg_inf(value) && format_.replace_neg_inf()) - { - bos_.write(format_.neg_inf_replacement()); - } - else - { - fp_.print(value,precision,bos_); - } - - end_value(); - } - - void do_integer_value(int64_t value) override - { - if (!stack_.empty() && !stack_.back().is_object()) - { - begin_scalar_value(); - } - print_integer(value,bos_); - end_value(); - } - - void do_uinteger_value(uint64_t value) override - { - if (!stack_.empty() && !stack_.back().is_object()) - { - begin_scalar_value(); - } - print_uinteger(value,bos_); - end_value(); - } - - void do_bool_value(bool value) override - { - if (!stack_.empty() && !stack_.back().is_object()) - { - begin_scalar_value(); - } - - if (value) - { - auto buf = json_literals<CharT>::true_literal(); - bos_.write(buf.first,buf.second); - } - else - { - auto buf = json_literals<CharT>::false_literal(); - bos_.write(buf.first,buf.second); - } - - end_value(); - } - - void begin_scalar_value() - { - if (!stack_.empty()) - { - if (stack_.back().count_ > 0) - { - bos_. put(','); - } - if (indenting_) - { - if (stack_.back().scalar_next_line()) - { - write_indent(); - } - } - } - } - - void begin_value() - { - if (!stack_.empty()) - { - if (stack_.back().count_ > 0) - { - bos_. put(','); - } - if (indenting_ && stack_.back().is_next_line()) - { - write_indent(); - } - } - } - - void end_value() - { - if (!stack_.empty()) - { - ++stack_.back().count_; - } - } - - void indent() - { - indent_ += static_cast<int>(format_.indent()); - } - - void unindent() - { - indent_ -= static_cast<int>(format_.indent()); - } - - void write_indent() - { - if (!stack_.empty()) - { - stack_.back().multiline_ = true; - } - bos_. put('\n'); - for (int i = 0; i < indent_; ++i) - { - bos_. put(' '); - } - } -}; - -typedef basic_json_serializer<char> json_serializer; -typedef basic_json_serializer<wchar_t> wjson_serializer; - -} -#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons/json_structures.hpp b/vendor/jsoncons-0.99.2/jsoncons/json_structures.hpp deleted file mode 100644 index ee8f75af..00000000 --- a/vendor/jsoncons-0.99.2/jsoncons/json_structures.hpp +++ /dev/null @@ -1,860 +0,0 @@ -// Copyright 2013 Daniel Parker -// Distributed under the Boost license, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -// See https://github.com/danielaparker/jsoncons for latest version - -#ifndef JSONCONS_JSON_STRUCTURES_HPP -#define JSONCONS_JSON_STRUCTURES_HPP - -#include <string> -#include <vector> -#include <exception> -#include <cstdlib> -#include <cstring> -#include <iostream> -#include <algorithm> -#include <sstream> -#include <iomanip> -#include <utility> -#include <initializer_list> -#include "jsoncons/jsoncons.hpp" - -namespace jsoncons { - -template <class JsonT, class Alloc> -class json_array -{ -public: - typedef Alloc allocator_type; - typedef JsonT value_type; - typedef typename std::allocator_traits<Alloc>:: template rebind_alloc<JsonT> vector_allocator_type; - typedef typename std::vector<JsonT,Alloc>::reference reference; - typedef typename std::vector<JsonT,Alloc>::const_reference const_reference; - typedef typename std::vector<JsonT,Alloc>::iterator iterator; - typedef typename std::vector<JsonT,Alloc>::const_iterator const_iterator; - - json_array() - : elements_() - { - } - - explicit json_array(const Alloc& allocator) - : elements_(allocator) - { - } - - explicit json_array(size_t n, const Alloc& allocator = Alloc()) - : elements_(n,JsonT(),allocator) - { - } - - explicit json_array(size_t n, const JsonT& value, const Alloc& allocator = Alloc()) - : elements_(n,value,allocator) - { - } - - template <class InputIterator> - json_array(InputIterator begin, InputIterator end, const Alloc& allocator = Alloc()) - : elements_(begin,end,allocator) - { - } - - json_array(const json_array& val) - : elements_(val.elements_) - { - } - - json_array(const json_array& val, const Alloc& allocator) - : elements_(val.elements_,allocator) - { - } - json_array(json_array&& val) - : elements_(std::move(val.elements_)) - { - } - json_array(json_array&& val, const Alloc& allocator) - : elements_(std::move(val.elements_),allocator) - { - } - - json_array(std::initializer_list<JsonT> init, - const Alloc& allocator = Alloc()) - : elements_(std::move(init),allocator) - { - } - - Alloc get_allocator() const - { - return elements_.get_allocator(); - } - - void swap(json_array<JsonT,Alloc>& val) - { - elements_.swap(val.elements_); - } - - size_t size() const {return elements_.size();} - - size_t capacity() const {return elements_.capacity();} - - void clear() {elements_.clear();} - - void shrink_to_fit() - { - for (size_t i = 0; i < elements_.size(); ++i) - { - elements_[i].shrink_to_fit(); - } - elements_.shrink_to_fit(); - } - - void reserve(size_t n) {elements_.reserve(n);} - - void resize(size_t n) {elements_.resize(n);} - - void resize(size_t n, const JsonT& val) {elements_.resize(n,val);} - - void remove_range(size_t from_index, size_t to_index) - { - JSONCONS_ASSERT(from_index <= to_index); - JSONCONS_ASSERT(to_index <= elements_.size()); - elements_.erase(elements_.begin()+from_index,elements_.begin()+to_index); - } - - void erase(iterator first, iterator last) - { - elements_.erase(first,last); - } - - JsonT& operator[](size_t i) {return elements_[i];} - - const JsonT& operator[](size_t i) const {return elements_[i];} - - void push_back(const JsonT& value) - { - elements_.push_back(value); - } - - void push_back(JsonT&& value) - { - elements_.push_back(std::move(value)); - } - - void add(size_t index, const JsonT& value) - { - auto position = index < elements_.size() ? elements_.begin() + index : elements_.end(); - elements_.insert(position, value); - } - - void add(size_t index, JsonT&& value) - { - auto it = index < elements_.size() ? elements_.begin() + index : elements_.end(); - elements_.insert(it, std::move(value)); - } - -#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ < 9 - // work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54577 - iterator add(const_iterator pos, const JsonT& value) - { - iterator it = elements_.begin() + (pos - elements_.begin()); - return elements_.insert(it, value); - } - - iterator add(const_iterator pos, JsonT&& value) - { - iterator it = elements_.begin() + (pos - elements_.begin()); - return elements_.insert(it, std::move(value)); - } -#else - iterator add(const_iterator pos, const JsonT& value) - { - return elements_.insert(pos, value); - } - - iterator add(const_iterator pos, JsonT&& value) - { - return elements_.insert(pos, std::move(value)); - } -#endif - - iterator begin() {return elements_.begin();} - - iterator end() {return elements_.end();} - - const_iterator begin() const {return elements_.begin();} - - const_iterator end() const {return elements_.end();} - - bool operator==(const json_array<JsonT,Alloc>& rhs) const - { - if (size() != rhs.size()) - { - return false; - } - for (size_t i = 0; i < size(); ++i) - { - if (elements_[i] != rhs.elements_[i]) - { - return false; - } - } - return true; - } -private: - json_array& operator=(const json_array<JsonT,Alloc>&); - std::vector<JsonT,Alloc> elements_; -}; - -template <class ValueT,typename CharT> -class member_lt_string -{ - size_t length_; -public: - member_lt_string(size_t length) - : length_(length) - { - } - - bool operator()(const ValueT& a, const CharT* b) const - { - size_t len = std::min JSONCONS_NO_MACRO_EXP(a.name().length(),length_); - int result = std::char_traits<CharT>::compare(a.name().data(),b,len); - if (result != 0) - { - return result < 0; - } - - return a.name().length() < length_; - } -}; - -template <class StringT,typename CharT> -bool name_le_string(const StringT& a, const CharT* b, size_t length) -{ - size_t min_len = std::min JSONCONS_NO_MACRO_EXP(a.length(),length); - int result = std::char_traits<CharT>::compare(a.data(),b, min_len); - if (result != 0) - { - return result < 0; - } - - return a.length() <= length; -} - -template <class StringT,typename CharT> -bool name_eq_string(const StringT& a, const CharT* b, size_t length) -{ - return a.length() == length && std::char_traits<CharT>::compare(a.data(),b,length) == 0; -} - -template <class ValueT> -class member_lt_member -{ - typedef typename ValueT::char_type char_type; -public: - bool operator()(const ValueT& a, const ValueT& b) const - { - if (a.name().length() == b.name().length()) - { - return std::char_traits<char_type>::compare(a.name().data(),b.name().data(),a.name().length()) < 0; - } - - size_t len = std::min JSONCONS_NO_MACRO_EXP(a.name().length(),b.name().length()); - int result = std::char_traits<char_type>::compare(a.name().data(),b.name().data(),len); - if (result != 0) - { - return result < 0; - } - - return a.name().length() < b.name().length(); - } -}; - -template <class StringT, class ValueT> -class name_value_pair -{ -public: - typedef StringT string_type; - typedef typename StringT::value_type char_type; - - name_value_pair() - { - } - name_value_pair(const string_type& name) - : name_(name) - { - } - name_value_pair(string_type&& name) - : name_(std::move(name)) - { - } - - name_value_pair(const string_type& name, const ValueT& val) - : name_(name), value_(val) - { - } - name_value_pair(string_type&& name, const ValueT& val) - : name_(std::move(name)), value_(val) - { - } - name_value_pair(const string_type& name, ValueT&& val) - : name_(name), value_(std::move(val)) - { - } - name_value_pair(string_type&& name, ValueT&& val) - : name_(std::move(name)), value_(std::move(val)) - { - } - name_value_pair(const name_value_pair& member) - : name_(member.name_), value_(member.value_) - { - } - name_value_pair(name_value_pair&& member) - : name_(std::move(member.name_)), value_(std::move(member.value_)) - { - } - - const string_type& name() const - { - return name_; - } - - ValueT& value() - { - return value_; - } - - const ValueT& value() const - { - return value_; - } - - void value(const ValueT& value) - { - value_ = value; - } - - void value(ValueT&& value) - { - value_ = std::move(value); - } - - void swap(name_value_pair& member) - { - name_.swap(member.name_); - value_.swap(member.value_); - } - - name_value_pair& operator=(const name_value_pair& member) - { - if (this != & member) - { - name_ = member.name_; - value_ = member.value_; - } - return *this; - } - - name_value_pair& operator=(name_value_pair&& member) - { - if (this != &member) - { - name_.swap(member.name_); - value_.swap(member.value_); - } - return *this; - } - - void shrink_to_fit() - { - name_.shrink_to_fit(); - value_.shrink_to_fit(); - } -private: - string_type name_; - ValueT value_; -}; - -template <class IteratorT,class NonConstIteratorT> -class json_object_iterator -{ -public: - typedef IteratorT iterator; - typedef typename std::iterator_traits<IteratorT>::value_type value_type; - typedef typename std::iterator_traits<IteratorT>::difference_type difference_type; - typedef typename std::iterator_traits<IteratorT>::pointer pointer; - typedef typename std::iterator_traits<IteratorT>::reference reference; - typedef std::bidirectional_iterator_tag iterator_category; - - json_object_iterator(bool empty = false) - : empty_(empty) - { - } - - json_object_iterator(iterator it) - : empty_(false), it_(it) - { - } - - json_object_iterator(const json_object_iterator<NonConstIteratorT,NonConstIteratorT>& it) - : empty_(it.empty_), it_(it.it_) - { - } - - json_object_iterator& operator=(json_object_iterator rhs) - { - swap(*this,rhs); - return *this; - } - - json_object_iterator& operator++() - { - ++it_; - return *this; - } - - json_object_iterator operator++(int) // postfix increment - { - json_object_iterator temp(*this); - ++it_; - return temp; - } - - json_object_iterator& operator--() - { - --it_; - return *this; - } - - json_object_iterator operator--(int) - { - json_object_iterator temp(*this); - --it_; - return temp; - } - - reference operator*() const - { - return *it_; - } - - pointer operator->() const - { - return &(*it_); - } - - bool empty() const - { - return empty_; - } - - friend bool operator==(const json_object_iterator& it1, const json_object_iterator& it2) - { - return (it1.empty() && it2.empty()) || (it1.it_ == it2.it_); - } - friend bool operator!=(const json_object_iterator& it1, const json_object_iterator& it2) - { - return !(it1.it_ == it2.it_); - } - friend void swap(json_object_iterator& lhs, json_object_iterator& rhs) - { - using std::swap; - swap(lhs.it_,rhs.it_); - swap(lhs.empty_,rhs.empty_); - } - - iterator get() - { - return it_; - } - -//private: - bool empty_; - IteratorT it_; -}; - -template <class StringT,class JsonT,class Alloc> -class json_object -{ -public: - typedef Alloc allocator_type; - typedef typename JsonT::char_type char_type; - typedef StringT string_type; - typedef name_value_pair<StringT,JsonT> value_type; - typedef typename std::vector<value_type, allocator_type>::iterator base_iterator; - typedef typename std::vector<value_type, allocator_type>::const_iterator const_base_iterator; - - typedef json_object_iterator<base_iterator,base_iterator> iterator; - typedef json_object_iterator<const_base_iterator,base_iterator> const_iterator; -private: - std::vector<value_type,allocator_type> members_; -public: - json_object(const allocator_type& allocator = allocator_type()) - : members_(allocator) - { - } - - json_object(const json_object<StringT,JsonT,Alloc>& val) - : members_(val.members_) - { - } - - json_object(json_object&& val) - : members_(std::move(val.members_)) - { - } - - json_object(const json_object<StringT,JsonT,Alloc>& val, const allocator_type& allocator) : - members_(val.members_,allocator) - { - } - - json_object(json_object&& val,const allocator_type& allocator) : - members_(std::move(val.members_),allocator) - { - } - - Alloc get_allocator() const - { - return members_.get_allocator(); - } - - iterator begin() - { - //return members_.begin(); - return iterator(members_.begin()); - } - - iterator end() - { - //return members_.end(); - return iterator(members_.end()); - } - - const_iterator begin() const - { - //return iterator(members.data()); - return const_iterator(members_.begin()); - } - - const_iterator end() const - { - //return members_.end(); - return const_iterator(members_.end()); - } -/* - const_iterator cbegin() const - { - return members_.begin(); - } - - const_iterator cend() const - { - return members_.end(); - } -*/ - void swap(json_object& val) - { - members_.swap(val.members_); - } - - size_t size() const {return members_.size();} - - size_t capacity() const {return members_.capacity();} - - void clear() {members_.clear();} - - void shrink_to_fit() - { - for (size_t i = 0; i < members_.size(); ++i) - { - members_[i].shrink_to_fit(); - } - members_.shrink_to_fit(); - } - - void reserve(size_t n) {members_.reserve(n);} - - iterator find(const char_type* name, size_t length) - { - member_lt_string<value_type,char_type> comp(length); - auto it = std::lower_bound(members_.begin(),members_.end(), name, comp); - auto result = (it != members_.end() && name_eq_string(it->name(),name,length)) ? it : members_.end(); - return iterator(result); - } - - const_iterator find(const char_type* name, size_t length) const - { - member_lt_string<value_type,char_type> comp(length); - auto it = std::lower_bound(members_.begin(),members_.end(), name, comp); - auto result = (it != members_.end() && name_eq_string(it->name(),name,length)) ? it : members_.end(); - return const_iterator(result); - } - - void erase(iterator first, iterator last) - { - members_.erase(first.get(),last.get()); - } - - void erase(const char_type* name, size_t length) - { - member_lt_string<value_type,char_type> comp(length); - auto it = std::lower_bound(members_.begin(),members_.end(), name, comp); - if (it != members_.end() && name_eq_string(it->name(),name,length)) - { - members_.erase(it); - } - } - - template<class InputIt, class UnaryPredicate> - void insert(InputIt first, InputIt last, UnaryPredicate pred) - { - size_t count = std::distance(first,last); - size_t pos = members_.size(); - members_.resize(pos+count); - auto d = members_.begin()+pos; - for (auto s = first; s != last; ++s, ++d) - { - *d = pred(*s); - } - std::sort(members_.begin(),members_.end(),member_lt_member<value_type>()); - } - - void set(const char_type* s, size_t length, const JsonT& value) - { - auto it = std::lower_bound(members_.begin(),members_.end(),s,member_lt_string<value_type,char_type>(length)); - if (it == members_.end()) - { - members_.push_back(value_type(string_type(s,length),value)); - } - else if (name_eq_string(it->name(),s,length)) - { - it->value(value); - } - else - { - members_.insert(it,value_type(string_type(s,length),value)); - } - } - - void set(const char_type* s, size_t length, JsonT&& value) - { - auto it = std::lower_bound(members_.begin(),members_.end(),s,member_lt_string<value_type,char_type>(length)); - if (it == members_.end()) - { - members_.push_back(value_type(string_type(s,length),std::move(value))); - } - else if (name_eq_string(it->name(),s,length)) - { - it->value(std::move(value)); - } - else - { - members_.insert(it,value_type(string_type(s,length),std::move(value))); - } - } - - void set(string_type&& name, const JsonT& value) - { - auto it = std::lower_bound(members_.begin(),members_.end(),name.data() ,member_lt_string<value_type,char_type>(name.length())); - if (it == members_.end()) - { - members_.push_back(value_type(std::move(name), value)); - } - else if (it->name() == name) - { - it->value(value); - } - else - { - members_.insert(it,value_type(std::move(name),value)); - } - } - - void set(const string_type& name, const JsonT& value) - { - set(name.data(),name.length(),value); - } - - void set(const string_type& name, JsonT&& value) - { - set(name.data(),name.length(),std::move(value)); - } - - void set(string_type&& name, JsonT&& value) - { - auto it = std::lower_bound(members_.begin(),members_.end(),name.data() ,member_lt_string<value_type,char_type>(name.length())); - if (it == members_.end()) - { - members_.push_back(value_type(std::move(name), std::move(value))); - } - else if (it->name() == name) - { - it->value(std::move(value)); - } - else - { - members_.insert(it,value_type(std::move(name),std::move(value))); - } - } - - iterator set(iterator hint, const char_type* name, const JsonT& value) - { - return set(hint, name, std::char_traits<char_type>::length(name), value); - } - - iterator set(iterator hint, const char_type* name, JsonT&& value) - { - return set(hint, name, std::char_traits<char_type>::length(name), std::move(value)); - } - - iterator set(iterator hint, const char_type* s, size_t length, const JsonT& value) - { - base_iterator it; - if (hint.get() != members_.end() && name_le_string(hint.get()->name(), s, length)) - { - it = std::lower_bound(hint.get(),members_.end(),s,member_lt_string<value_type,char_type>(length)); - } - else - { - it = std::lower_bound(members_.begin(),members_.end(),s, member_lt_string<value_type,char_type>(length)); - } - - if (it == members_.end()) - { - members_.push_back(value_type(string_type(s, length), value)); - it = members_.begin() + (members_.size() - 1); - } - else if (name_eq_string(it->name(),s,length)) - { - it->value(value); - } - else - { - it = members_.insert(it,value_type(string_type(s,length),value)); - } - return iterator(it); - } - - iterator set(iterator hint, const char_type* s, size_t length, JsonT&& value) - { - base_iterator it; - if (hint.get() != members_.end() && name_le_string(hint.get()->name(), s, length)) - { - it = std::lower_bound(hint.get(),members_.end(),s,member_lt_string<value_type,char_type>(length)); - } - else - { - it = std::lower_bound(members_.begin(),members_.end(),s, member_lt_string<value_type,char_type>(length)); - } - - if (it == members_.end()) - { - members_.push_back(value_type(string_type(s, length), std::move(value))); - it = members_.begin() + (members_.size() - 1); - } - else if (name_eq_string(it->name(),s,length)) - { - it->value(std::move(value)); - } - else - { - it = members_.insert(it,value_type(string_type(s,length),std::move(value))); - } - return iterator(it); - } - - iterator set(iterator hint, const string_type& name, const JsonT& value) - { - return set(hint,name.data(),name.length(),value); - } - - iterator set(iterator hint, string_type&& name, const JsonT& value) - { - base_iterator it; - if (hint.get() != members_.end() && hint.get()->name() <= name) - { - it = std::lower_bound(hint.get(),members_.end(),name.data() ,member_lt_string<value_type,char_type>(name.length())); - } - else - { - it = std::lower_bound(members_.begin(),members_.end(),name.data() ,member_lt_string<value_type,char_type>(name.length())); - } - - if (it == members_.end()) - { - members_.push_back(value_type(std::move(name), value)); - it = members_.begin() + (members_.size() - 1); - } - else if (it->name() == name) - { - it->value(value); - } - else - { - it = members_.insert(it,value_type(std::move(name),value)); - } - return iterator(it); - } - - iterator set(iterator hint, const string_type& name, JsonT&& value) - { - return set(hint,name.data(),name.length(),std::move(value)); - } - - iterator set(iterator hint, string_type&& name, JsonT&& value) - { - typename std::vector<value_type,allocator_type>::iterator it; - if (hint.get() != members_.end() && hint.get()->name() <= name) - { - it = std::lower_bound(hint.get(),members_.end(),name.data() ,member_lt_string<value_type,char_type>(name.length())); - } - else - { - it = std::lower_bound(members_.begin(),members_.end(),name.data() ,member_lt_string<value_type,char_type>(name.length())); - } - - if (it == members_.end()) - { - members_.push_back(value_type(std::move(name), std::move(value))); - it = members_.begin() + (members_.size() - 1); - } - else if (it->name() == name) - { - it->value(std::move(value)); - } - else - { - it = members_.insert(it,value_type(std::move(name),std::move(value))); - } - return iterator(it); - } - - bool operator==(const json_object<StringT,JsonT,Alloc>& rhs) const - { - if (size() != rhs.size()) - { - return false; - } - for (auto it = members_.begin(); it != members_.end(); ++it) - { - - auto rhs_it = std::lower_bound(rhs.members_.begin(), rhs.members_.end(), *it, member_lt_member<value_type>()); - // member_lt_member actually only compares keys, so we need to check the value separately - if (rhs_it == rhs.members_.end() || rhs_it->name() != it->name() || rhs_it->value() != it->value()) - { - return false; - } - } - return true; - } -private: - json_object<StringT,JsonT,Alloc>& operator=(const json_object<StringT,JsonT,Alloc>&); -}; - - - -} - -#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons/json_type_traits.hpp b/vendor/jsoncons-0.99.2/jsoncons/json_type_traits.hpp deleted file mode 100644 index aeda7a0b..00000000 --- a/vendor/jsoncons-0.99.2/jsoncons/json_type_traits.hpp +++ /dev/null @@ -1,594 +0,0 @@ -// Copyright 2013 Daniel Parker -// Distributed under the Boost license, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -// See https://github.com/danielaparker/jsoncons for latest version - -#ifndef JSONCONS_JSON_TYPE_TRAITS_HPP -#define JSONCONS_JSON_TYPE_TRAITS_HPP - -#include <string> -#include <vector> -#include <exception> -#include <cstdlib> -#include <cstring> -#include <utility> -#include <algorithm> -#include <fstream> -#include <limits> -#include "jsoncons/jsoncons.hpp" - -#if defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wswitch" -#endif - -namespace jsoncons { - -template <class JsonT, typename T> -class json_type_traits -{ -public: - static bool is(const JsonT&) - { - return false; - } -}; - -template<class JsonT> -class json_type_traits<JsonT, typename JsonT::string_type> -{ -public: - typedef typename JsonT::string_type string_type; - typedef typename string_type::allocator_type string_allocator; - - static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT - { - return rhs.is_string(); - } - static string_type as(const JsonT& rhs) JSONCONS_NOEXCEPT - { - return rhs.as_string(); - } - static string_type as(const JsonT& rhs, const string_allocator& allocator) JSONCONS_NOEXCEPT - { - return rhs.as_string(allocator); - } - static void assign(JsonT& lhs, const string_type& rhs) - { - lhs.assign_string(rhs); - } -}; - -template<class JsonT> -class json_type_traits<JsonT, typename JsonT::any> -{ -public: - static bool is(const JsonT& lhs) JSONCONS_NOEXCEPT - { - return lhs.is_any(); - } - static typename JsonT::any as(const JsonT& rhs) - { - return rhs.any_value(); - } - static void assign(JsonT& lhs, typename JsonT::any rhs) - { - lhs.assign_any(rhs); - } -}; - -template<class JsonT> -class json_type_traits<JsonT, typename type_wrapper<typename JsonT::char_type>::const_pointer_type> -{ -public: - typedef typename JsonT::char_type char_type; - - static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT - { - return rhs.is_string(); - } - static const char_type* as(const JsonT& rhs) - { - return rhs.as_cstring(); - } - static void assign(JsonT& lhs, const char_type *rhs) - { - size_t length = std::char_traits<char_type>::length(rhs); - lhs.assign_string(rhs,length); - } -}; - -template<class JsonT> -class json_type_traits<JsonT, typename type_wrapper<typename JsonT::char_type>::pointer_type> -{ -public: - typedef typename JsonT::char_type char_type; - - static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT - { - return rhs.is_string(); - } - static const char_type* as(const JsonT& rhs) - { - return rhs.as_cstring(); - } - static void assign(JsonT& lhs, const char_type *rhs) - { - size_t length = std::char_traits<char_type>::length(rhs); - lhs.assign_string(rhs,length); - } -}; - -template<class JsonT> -class json_type_traits<JsonT, char> -{ -public: - static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT - { - if (rhs.is_integer()) - { - return rhs.as_integer() >= std::numeric_limits<char>::min JSONCONS_NO_MACRO_EXP() && rhs.as_integer() <= std::numeric_limits<char>::max JSONCONS_NO_MACRO_EXP(); - } - else - { - return false; - } - } - static char as(const JsonT& rhs) - { - return static_cast<char>(rhs.as_integer()); - } - static void assign(JsonT& lhs, char ch) - { - lhs.assign_integer(ch); - } -}; - -template<class JsonT> -class json_type_traits<JsonT, unsigned char> -{ -public: - static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT - { - if (rhs.is_integer()) - { - return rhs.as_integer() >= 0 && static_cast<unsigned long long>(rhs.as_integer()) <= std::numeric_limits<unsigned char>::max JSONCONS_NO_MACRO_EXP(); - } - else if (rhs.is_uinteger()) - { - return rhs.as_uinteger() <= std::numeric_limits<unsigned char>::max JSONCONS_NO_MACRO_EXP(); - } - else - { - return false; - } - } - static unsigned char as(const JsonT& rhs) - { - return static_cast<unsigned char>(rhs.as_uinteger()); - } - static void assign(JsonT& lhs, unsigned char ch) - { - lhs.assign_uinteger(ch); - } -}; - -template<class JsonT> -class json_type_traits<JsonT, signed char> -{ -public: - static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT - { - if (rhs.is_integer()) - { - return rhs.as_integer() >= std::numeric_limits<char>::min JSONCONS_NO_MACRO_EXP() && rhs.as_integer() <= std::numeric_limits<char>::max JSONCONS_NO_MACRO_EXP(); - } - else if (rhs.is_uinteger()) - { - return rhs.as_uinteger() <= static_cast<unsigned long long>(std::numeric_limits<char>::max JSONCONS_NO_MACRO_EXP()); - } - else - { - return false; - } - } - static signed char as(const JsonT& rhs) - { - return static_cast<signed char>(rhs.as_integer()); - } - static void assign(JsonT& lhs, signed char ch) - { - lhs.assign_integer(ch); - } -}; - -template<class JsonT> -class json_type_traits<JsonT, wchar_t> -{ -public: - static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT - { - if (rhs.is_integer()) - { - return rhs.as_integer() >= std::numeric_limits<wchar_t>::min JSONCONS_NO_MACRO_EXP() && rhs.as_integer() <= std::numeric_limits<wchar_t>::max JSONCONS_NO_MACRO_EXP(); - } - else if (rhs.is_uinteger()) - { - return rhs.as_uinteger() <= static_cast<unsigned long long>(std::numeric_limits<wchar_t>::max JSONCONS_NO_MACRO_EXP()); - } - else - { - return false; - } - } - static wchar_t as(const JsonT& rhs) - { - return static_cast<wchar_t>(rhs.as_integer()); - } - static void assign(JsonT& lhs, wchar_t ch) - { - lhs.assign_integer(ch); - } -}; - -template<class JsonT> -class json_type_traits<JsonT, typename JsonT::object> -{ -public: - static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT - { - return rhs.is_object(); - } - static typename JsonT::object as(JsonT rhs) - { - JSONCONS_ASSERT(rhs.is_object()); - return rhs.object_value(); - } - static void assign(JsonT& lhs, typename JsonT::object rhs) - { - lhs.assign_object(rhs); - } -}; - -template<class JsonT> -class json_type_traits<JsonT, typename JsonT::array> -{ -public: - static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT - { - return rhs.is_array(); - } - static typename JsonT::array as(const JsonT& rhs) - { - JSONCONS_ASSERT(rhs.is_array()); - return rhs.array_value(); - } - static void assign(JsonT& lhs, typename JsonT::array rhs) - { - lhs.assign_array(rhs); - } -}; - -template<class JsonT> -class json_type_traits<JsonT, jsoncons::null_type> -{ -public: - static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT - { - return rhs.is_null(); - } - static typename jsoncons::null_type as(const JsonT& rhs) - { - JSONCONS_ASSERT(rhs.is_null()); - return jsoncons::null_type(); - } - static void assign(JsonT& lhs, null_type) - { - lhs.assign_null(); - } -}; - -template<class JsonT> -class json_type_traits<JsonT, bool> -{ -public: - static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT - { - return rhs.is_bool(); - } - static bool as(const JsonT& rhs) - { - return rhs.as_bool(); - } - static void assign(JsonT& lhs, bool rhs) - { - lhs.assign_bool(rhs); - } -}; - -template<class JsonT> -class json_type_traits<JsonT, short> -{ -public: - static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT - { - if (rhs.is_integer()) - { - return rhs.as_integer() >= std::numeric_limits<short>::min JSONCONS_NO_MACRO_EXP() && rhs.as_integer() <= std::numeric_limits<short>::max JSONCONS_NO_MACRO_EXP(); - } - else if (rhs.is_uinteger()) - { - return rhs.as_uinteger() <= static_cast<unsigned long long>(std::numeric_limits<short>::max JSONCONS_NO_MACRO_EXP()); - } - else - { - return false; - } - } - static short as(const JsonT& rhs) - { - return static_cast<short>(rhs.as_integer()); - } - static void assign(JsonT& lhs, short rhs) - { - lhs.assign_integer(rhs); - } -}; - -template<class JsonT> -class json_type_traits<JsonT, unsigned short> -{ -public: - static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT - { - if (rhs.is_integer()) - { - return rhs.as_integer() >= 0 && static_cast<unsigned long long>(rhs.as_integer()) <= std::numeric_limits<unsigned short>::max JSONCONS_NO_MACRO_EXP(); - } - else if (rhs.is_uinteger()) - { - return rhs.as_uinteger() <= std::numeric_limits<unsigned short>::max JSONCONS_NO_MACRO_EXP(); - } - else - { - return false; - } - } - static unsigned short as(const JsonT& rhs) - { - return (unsigned short)rhs.as_uinteger(); - } - static void assign(JsonT& lhs, unsigned short rhs) - { - lhs.assign_uinteger(rhs); - } -}; - -template<class JsonT> -class json_type_traits<JsonT, int> -{ -public: - static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT - { - if (rhs.is_integer()) - { - return rhs.as_integer() >= std::numeric_limits<int>::min JSONCONS_NO_MACRO_EXP() && rhs.as_integer() <= std::numeric_limits<int>::max JSONCONS_NO_MACRO_EXP(); - } - else if (rhs.is_uinteger()) - { - return rhs.as_uinteger() <= static_cast<unsigned long long>(std::numeric_limits<int>::max JSONCONS_NO_MACRO_EXP()); - } - else - { - return false; - } - } - static int as(const JsonT& rhs) - { - return static_cast<int>(rhs.as_integer()); - } - static void assign(JsonT& lhs, int rhs) - { - lhs.assign_integer(rhs); - } -}; - -template<class JsonT> -class json_type_traits<JsonT, unsigned int> -{ -public: - static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT - { - if (rhs.is_integer()) - { - return rhs.as_integer() >= 0 && static_cast<unsigned long long>(rhs.as_integer()) <= std::numeric_limits<unsigned int>::max JSONCONS_NO_MACRO_EXP(); - } - else if (rhs.is_uinteger()) - { - return rhs.as_uinteger() <= std::numeric_limits<unsigned int>::max JSONCONS_NO_MACRO_EXP(); - } - else - { - return false; - } - } - static unsigned int as(const JsonT& rhs) - { - return static_cast<unsigned int>(rhs.as_uinteger()); - } - static void assign(JsonT& lhs, unsigned int rhs) - { - lhs.assign_uinteger(rhs); - } -}; - -template<class JsonT> -class json_type_traits<JsonT, long> -{ -public: - static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT - { - if (rhs.is_integer()) - { - return rhs.as_integer() >= std::numeric_limits<long>::min JSONCONS_NO_MACRO_EXP() && rhs.as_integer() <= std::numeric_limits<long>::max JSONCONS_NO_MACRO_EXP(); - } - else if (rhs.is_uinteger()) - { - return rhs.as_uinteger() <= static_cast<unsigned long long>(std::numeric_limits<long>::max JSONCONS_NO_MACRO_EXP()); - } - else - { - return false; - } - } - static long as(const JsonT& rhs) - { - return static_cast<long>(rhs.as_integer()); - } - static void assign(JsonT& lhs, long rhs) - { - lhs.assign_integer(rhs); - } -}; - -template<class JsonT> -class json_type_traits<JsonT, unsigned long> -{ -public: - static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT - { - if (rhs.is_integer()) - { - return rhs.as_integer() >= 0 && static_cast<unsigned long long>(rhs.as_integer()) <= std::numeric_limits<unsigned long>::max JSONCONS_NO_MACRO_EXP(); - } - else if (rhs.is_uinteger()) - { - return rhs.as_uinteger() <= std::numeric_limits<unsigned long>::max JSONCONS_NO_MACRO_EXP(); - } - else - { - return false; - } - } - static unsigned long as(const JsonT& rhs) - { - return static_cast<unsigned long>(rhs.as_uinteger()); - } - static void assign(JsonT& lhs, unsigned long rhs) - { - lhs.assign_uinteger(rhs); - } -}; - -template<class JsonT> -class json_type_traits<JsonT, long long> -{ -public: - static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT - { - return rhs.is_integer(); - } - static long long as(const JsonT& rhs) - { - return rhs.as_integer(); - } - static void assign(JsonT& lhs, long long rhs) - { - lhs.assign_integer(rhs); - } -}; - -template<class JsonT> -class json_type_traits<JsonT, unsigned long long> -{ -public: - static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT - { - return rhs.is_uinteger(); - } - static unsigned long long as(const JsonT& rhs) - { - return rhs.as_uinteger(); - } - static void assign(JsonT& lhs, unsigned long long rhs) - { - lhs.assign_uinteger(rhs); - } -}; - -template<class JsonT> -class json_type_traits<JsonT, double> -{ -public: - static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT - { - return rhs.is_double(); - } - - static double as(const JsonT& rhs) - { - return rhs.as_double(); - } - static void assign(JsonT& lhs, double rhs) - { - lhs.assign_double(rhs); - } -}; - -template<class JsonT> -class json_type_traits<JsonT, float> -{ -public: - static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT - { - return rhs.is_double(); - } - static double as(const JsonT& rhs) - { - return static_cast<float>(rhs.as_double()); - } - static void assign(JsonT& lhs, float rhs) - { - lhs.assign_double(static_cast<double>(rhs)); - } -}; - -template<class JsonT, typename T> -class json_type_traits<JsonT, std::vector<T>> -{ -public: - static bool is(const JsonT& rhs) JSONCONS_NOEXCEPT - { - bool result = rhs.is_array(); - for (size_t i = 0; result && i < rhs.size(); ++i) - { - if (!rhs[i].template is<T>()) - { - result = false; - } - } - return result; - } - static std::vector<T> as(const JsonT& rhs) - { - std::vector<T> v(rhs.size()); - for (size_t i = 0; i < v.size(); ++i) - { - v[i] = rhs[i].template as<T>(); - } - return v; - } - static void assign(JsonT& lhs, const std::vector<T>& rhs) - { - lhs = JsonT(rhs.begin(), rhs.end()); - } -}; - -} - -#if defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - -#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons/jsoncons.hpp b/vendor/jsoncons-0.99.2/jsoncons/jsoncons.hpp deleted file mode 100644 index a45e4f8c..00000000 --- a/vendor/jsoncons-0.99.2/jsoncons/jsoncons.hpp +++ /dev/null @@ -1,347 +0,0 @@ -// Copyright 2013 Daniel Parker -// Distributed under the Boost license, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -// See https://github.com/danielaparker/jsoncons for latest version - -#ifndef JSONCONS_JSONCONS_HPP -#define JSONCONS_JSONCONS_HPP - -#include <locale> -#include <string> -#include <vector> -#include <cstdlib> -#include <cwchar> -#include <cstdint> -#include <iostream> -#include <vector> -#include "jsoncons/jsoncons_config.hpp" -#include "jsoncons/jsoncons_io.hpp" - -namespace jsoncons { - -// null_type - -struct null_type -{ -}; - -// json_exception - -class json_exception -{ -public: - virtual const char* what() const JSONCONS_NOEXCEPT = 0; -}; - -template <typename Base> -class json_exception_0 : public Base, public virtual json_exception -{ -public: - json_exception_0(std::string s) JSONCONS_NOEXCEPT - : Base(""), message_(s) - { - } - ~json_exception_0() JSONCONS_NOEXCEPT - { - } - const char* what() const JSONCONS_NOEXCEPT - { - return message_.c_str(); - } -private: - std::string message_; -}; - -template <typename Base> -class json_exception_1 : public Base, public virtual json_exception -{ -public: - json_exception_1(const std::string& format, const std::string& arg1) JSONCONS_NOEXCEPT - : Base(""), format_(format), arg1_(arg1) - { - } - json_exception_1(const std::string& format, const std::wstring& arg1) JSONCONS_NOEXCEPT - : Base(""), format_(format) - { - char buf[255]; - size_t retval; -#if defined(JSONCONS_HAS_WCSTOMBS_S) - wcstombs_s(&retval, buf, sizeof(buf), arg1.c_str(), arg1.size()); -#else - retval = wcstombs(buf, arg1.c_str(), sizeof(buf)); -#endif - if (retval != static_cast<std::size_t>(-1)) - { - arg1_ = buf; - } - } - ~json_exception_1() JSONCONS_NOEXCEPT - { - } - const char* what() const JSONCONS_NOEXCEPT - { - c99_snprintf(const_cast<char*>(message_),255, format_.c_str(),arg1_.c_str()); - return message_; - } -private: - std::string format_; - std::string arg1_; - char message_[255]; -}; - -#define JSONCONS_STR2(x) #x -#define JSONCONS_STR(x) JSONCONS_STR2(x) - -#define JSONCONS_THROW_EXCEPTION(Base,x) throw jsoncons::json_exception_0<Base>((x)) -#define JSONCONS_THROW_EXCEPTION_1(Base,fmt,arg1) throw jsoncons::json_exception_1<Base>((fmt),(arg1)) -#define JSONCONS_ASSERT(x) if (!(x)) { \ - throw jsoncons::json_exception_0<std::runtime_error>("assertion '" #x "' failed at " __FILE__ ":" \ - JSONCONS_STR(__LINE__)); } - -// json_char_traits - -const uint16_t min_lead_surrogate = 0xD800; -const uint16_t max_lead_surrogate = 0xDBFF; -const uint16_t min_trail_surrogate = 0xDC00; -const uint16_t max_trail_surrogate = 0xDFFF; - -template <typename CharT> -struct json_literals -{ -}; - -template <> -struct json_literals<char> -{ - static std::pair<const char*,size_t> null_literal() - { - static const char* value = "null"; - return std::pair<const char*,size_t>(value,4); - } - - static std::pair<const char*,size_t> true_literal() - { - static const char* value = "true"; - return std::pair<const char*,size_t>(value,4); - } - - static std::pair<const char*,size_t> false_literal() - { - static const char* value = "false"; - return std::pair<const char*,size_t>(value,5); - } -}; - -template <> -struct json_literals<wchar_t> -{ - static std::pair<const wchar_t*,size_t> null_literal() - { - static const wchar_t* value = L"null"; - return std::pair<const wchar_t*,size_t>(value,4); - } - - static std::pair<const wchar_t*,size_t> true_literal() - { - static const wchar_t* value = L"true"; - return std::pair<const wchar_t*,size_t>(value,4); - } - - static std::pair<const wchar_t*,size_t> false_literal() - { - static const wchar_t* value = L"false"; - return std::pair<const wchar_t*,size_t>(value,5); - } -}; - -template <typename CharT,size_t Size> -struct json_char_traits -{ -}; - -template <> -struct json_char_traits<char,1> -{ - static uint32_t convert_char_to_codepoint(const char*& it, - const char*) - { - char c = *it; - uint32_t u(c >= 0 ? c : 256 + c ); - uint32_t cp = u; - if (u < 0x80) - { - } - else if ((u >> 5) == 0x6) - { - c = *(++it); - u = (c >= 0 ? c : 256 + c ); - cp = ((cp << 6) & 0x7ff) + (u & 0x3f); - } - else if ((u >> 4) == 0xe) - { - c = *(++it); - u = (c >= 0 ? c : 256 + c ); - cp = ((cp << 12) & 0xffff) + ((static_cast<uint32_t>(0xff & u) << 6) & 0xfff); - c = *(++it); - u = (c >= 0 ? c : 256 + c ); - cp += (u) & 0x3f; - } - else if ((u >> 3) == 0x1e) - { - c = *(++it); - u = (c >= 0 ? c : 256 + c ); - cp = ((cp << 18) & 0x1fffff) + ((static_cast<uint32_t>(0xff & u) << 12) & 0x3ffff); - c = *(++it); - u = (c >= 0 ? c : 256 + c ); - cp += (static_cast<uint32_t>(0xff & u) << 6) & 0xfff; - c = *(++it); - u = (c >= 0 ? c : 256 + c ); - cp += (u) & 0x3f; - } - else - { - } - return cp; - } - - static void append_codepoint_to_string(uint32_t cp, std::string& s) - { - if (cp <= 0x7f) - { - s.push_back(static_cast<char>(cp)); - } - else if (cp <= 0x7FF) - { - s.push_back(static_cast<char>(0xC0 | (0x1f & (cp >> 6)))); - s.push_back(static_cast<char>(0x80 | (0x3f & cp))); - } - else if (cp <= 0xFFFF) - { - s.push_back(0xE0 | static_cast<char>((0xf & (cp >> 12)))); - s.push_back(0x80 | static_cast<char>((0x3f & (cp >> 6)))); - s.push_back(static_cast<char>(0x80 | (0x3f & cp))); - } - else if (cp <= 0x10FFFF) - { - s.push_back(static_cast<char>(0xF0 | (0x7 & (cp >> 18)))); - s.push_back(static_cast<char>(0x80 | (0x3f & (cp >> 12)))); - s.push_back(static_cast<char>(0x80 | (0x3f & (cp >> 6)))); - s.push_back(static_cast<char>(0x80 | (0x3f & cp))); - } - } - -}; - -template <> -struct json_char_traits<wchar_t,2> // assume utf16 -{ - static void append_codepoint_to_string(uint32_t cp, std::wstring& s) - { - if (cp <= 0xFFFF) - { - s.push_back(static_cast<wchar_t>(cp)); - } - else if (cp <= 0x10FFFF) - { - s.push_back(static_cast<wchar_t>((cp >> 10) + min_lead_surrogate - (0x10000 >> 10))); - s.push_back(static_cast<wchar_t>((cp & 0x3ff) + min_trail_surrogate)); - } - } - - static uint32_t convert_char_to_codepoint(const wchar_t*& it, const wchar_t*) - { - uint32_t cp = (0xffff & *it); - if ((cp >= min_lead_surrogate && cp <= max_lead_surrogate)) // surrogate pair - { - uint32_t trail_surrogate = 0xffff & *(++it); - cp = (cp << 10) + trail_surrogate + 0x10000u - (min_lead_surrogate << 10) - min_trail_surrogate; - } - return cp; - } -}; - -template <> -struct json_char_traits<wchar_t,4> // assume utf32 -{ - static void append_codepoint_to_string(uint32_t cp, std::wstring& s) - { - if (cp <= 0xFFFF) - { - s.push_back(static_cast<wchar_t>(cp)); - } - else if (cp <= 0x10FFFF) - { - s.push_back(static_cast<wchar_t>(cp)); - } - } - - static uint32_t convert_char_to_codepoint(const wchar_t*& it, const wchar_t*) - { - uint32_t cp = static_cast<uint32_t>(*it); - return cp; - } -}; - -inline -bool is_control_character(uint32_t c) -{ - return c <= 0x1F || c == 0x7f; -} - -inline -char to_hex_character(unsigned char c) -{ - JSONCONS_ASSERT(c <= 0xF); - - return (c < 10) ? ('0' + c) : ('A' - 10 + c); -} - -inline -bool is_non_ascii_character(uint32_t c) -{ - return c >= 0x80; -} - -template <typename T> -struct type_wrapper -{ - typedef T* pointer_type; - typedef const T* const_pointer_type; - typedef T value_type; - typedef T& reference; - typedef const T& const_reference; -}; - -template <typename T> -struct type_wrapper<const T> -{ - typedef T* pointer_type; - typedef const T* const_pointer_type; - typedef T value_type; - typedef T& reference; - typedef const T& const_reference; -}; - -template <typename T> -struct type_wrapper<T&> -{ - typedef T* pointer_type; - typedef const T* const_pointer_type; - typedef T value_type; - typedef T& reference; - typedef const T& const_reference; -}; - -template <typename T> -struct type_wrapper<const T&> -{ - typedef T* pointer_type; - typedef const T* const_pointer_type; - typedef T value_type; - typedef T& reference; - typedef const T& const_reference; -}; - -} -#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons/jsoncons_config.hpp b/vendor/jsoncons-0.99.2/jsoncons/jsoncons_config.hpp deleted file mode 100644 index 7d261ec0..00000000 --- a/vendor/jsoncons-0.99.2/jsoncons/jsoncons_config.hpp +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright 2013 Daniel Parker -// Distributed under the Boost license, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -// See https://github.com/danielaparker/jsoncons for latest version - -#ifndef JSONCONS_JSONCONS_CONFIG_HPP -#define JSONCONS_JSONCONS_CONFIG_HPP - -#include <stdexcept> -#include <string> -#include <sstream> -#include <vector> -#include <istream> -#include <ostream> -#include <iomanip> -#include <cstdlib> -#include <cmath> -#include <cstdarg> -#include <limits> // std::numeric_limits - -// Uncomment the following line to suppress deprecated names (recommended for new code) -// #define JSONCONS_NO_DEPRECATED - -#define JSONCONS_NO_MACRO_EXP - -namespace jsoncons -{ - -// Follow boost - -#if defined (__clang__) -#if defined(_GLIBCXX_USE_NOEXCEPT) -#define JSONCONS_NOEXCEPT _GLIBCXX_USE_NOEXCEPT -#else -#define JSONCONS_NOEXCEPT noexcept -#endif -#elif defined(__GNUC__) -#define JSONCONS_NOEXCEPT _GLIBCXX_USE_NOEXCEPT -#elif defined(_MSC_VER) -#if _MSC_VER >= 1900 -#define JSONCONS_NOEXCEPT noexcept -#else -#define JSONCONS_NOEXCEPT -#endif -#else -#define JSONCONS_NOEXCEPT -#endif - -#if defined(_MSC_VER) -#define JSONCONS_HAS_FOPEN_S -#define JSONCONS_HAS_WCSTOMBS_S -#if _MSC_VER < 1800 // VS2013 -#define JSONCONS_NO_RAW_STRING_LITERALS -#define JSONCONS_NO_FOR_RANGE -#endif -#if _MSC_VER >= 1900 -#define JSONCONS_ALIGNOF alignof -#else -#define JSONCONS_ALIGNOF __alignof -#endif -#else -#define JSONCONS_ALIGNOF alignof -#endif - -#ifdef _MSC_VER -#pragma warning( disable : 4290 ) -inline bool is_nan(double x) { return _isnan(x) != 0; } -inline bool is_inf(double x) -{ - return !_finite(x) && !_isnan(x); -} -inline bool is_pos_inf(double x) -{ - return is_inf(x) && x > 0; -} -inline bool is_neg_inf(double x) -{ - return is_inf(x) && x < 0; -} - -inline -int c99_vsnprintf(char *str, size_t size, const char *format, va_list ap) -{ - int count = -1; - - if (size != 0) count = _vsnprintf_s(str, size, _TRUNCATE, format, ap); - if (count == -1) count = _vscprintf(format, ap); - - return count; -} - -inline -int c99_snprintf(char *str, size_t size, const char *format, ...) -{ - int count; - va_list ap; - - va_start(ap, format); - count = c99_vsnprintf(str, size, format, ap); - va_end(ap); - - return count; -} -#else -inline bool is_nan(double x) -{ return std::isnan( x ); } -inline bool is_pos_inf(double x) -{return std::isinf(x) && x > 0;} -inline bool is_neg_inf(double x) -{return std::isinf(x) && x > 0;} - -#if __cplusplus >= 201103L -#define c99_snprintf snprintf -#else -#define c99_snprintf std::snprintf -#endif - -#endif - -} - -#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons/jsoncons_io.hpp b/vendor/jsoncons-0.99.2/jsoncons/jsoncons_io.hpp deleted file mode 100644 index 27c90fa1..00000000 --- a/vendor/jsoncons-0.99.2/jsoncons/jsoncons_io.hpp +++ /dev/null @@ -1,358 +0,0 @@ -// Copyright 2013 Daniel Parker -// Distributed under the Boost license, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -// See https://github.com/danielaparker/jsoncons for latest version - -#ifndef JSONCONS_JSONCONS_IO_HPP -#define JSONCONS_JSONCONS_IO_HPP - -#include <stdexcept> -#include <string> -#include <sstream> -#include <vector> -#include <istream> -#include <ostream> -#include <iomanip> -#include <cstdlib> -#include <cmath> -#include <cstdarg> -#include <limits> // std::numeric_limits -#include "jsoncons_config.hpp" -#include "ovectorstream.hpp" - -namespace jsoncons -{ - -template <typename CharT> -class buffered_ostream -{ - static const size_t default_buffer_length = 16384; - - std::basic_ostream<CharT>* os_; - std::vector<CharT> buffer_; - CharT * const begin_buffer_; - const CharT* const end_buffer_; - CharT* p_; -public: - buffered_ostream(std::basic_ostream<CharT>& os) - : os_(std::addressof(os)), buffer_(default_buffer_length), begin_buffer_(buffer_.data()), end_buffer_(buffer_.data()+default_buffer_length), p_(buffer_.data()) - { - } - ~buffered_ostream() - { - os_->write(begin_buffer_, (p_ - begin_buffer_)); - os_->flush(); - } - - void flush() - { - os_->write(begin_buffer_, (p_ - begin_buffer_)); - p_ = begin_buffer_; - os_->flush(); - } - - void write(const CharT* s, size_t length) - { - size_t diff = end_buffer_ - p_; - if (diff >= length) - { - std::memcpy(p_, s, length*sizeof(CharT)); - p_ += length; - } - else - { - os_->write(begin_buffer_, (p_ - begin_buffer_)); - os_->write(s, length); - p_ = begin_buffer_; - } - } - - void write(const std::basic_string<CharT>& s) - { - write(s.data(),s.length()); - } - - void put(CharT c) - { - if (p_ < end_buffer_) - { - *p_++ = c; - } - else - { - os_->write(begin_buffer_, (p_-begin_buffer_)); - p_ = begin_buffer_; - *p_++ = c; - } - } - -}; - -#ifdef _MSC_VER - -template <typename CharT> -class float_printer -{ - uint8_t precision_; -public: - float_printer(int precision) - : precision_(precision) - { - } - - void print(double val, uint8_t precision, buffered_ostream<CharT>& os) - { - char buf[_CVTBUFSIZE]; - int decimal_point = 0; - int sign = 0; - - int prec = (precision == 0) ? precision_ : precision; - - int err = _ecvt_s(buf, _CVTBUFSIZE, val, prec, &decimal_point, &sign); - if (err != 0) - { - throw std::runtime_error("Failed attempting double to string conversion"); - } - char* s = buf; - char* se = s + prec; - - int i, k; - int j; - - if (sign) - { - os.put('-'); - } - if (decimal_point <= -4 || decimal_point > se - s + 5) - { - os.put(*s++); - if (s < se) - { - os.put('.'); - while ((se-1) > s && *(se-1) == '0') - { - --se; - } - - while(s < se) - { - os.put(*s++); - } - } - os.put('e'); - /* sprintf(b, "%+.2d", decimal_point - 1); */ - if (--decimal_point < 0) { - os.put('-'); - decimal_point = -decimal_point; - } - else - os.put('+'); - for(j = 2, k = 10; 10*k <= decimal_point; j++, k *= 10); - for(;;) - { - i = decimal_point / k; - os.put(i + '0'); - if (--j <= 0) - break; - decimal_point -= i*k; - decimal_point *= 10; - } - } - else if (decimal_point <= 0) - { - os.put('0'); - os.put('.'); - while ((se-1) > s && *(se-1) == '0') - { - --se; - } - for(; decimal_point < 0; decimal_point++) - { - os.put('0'); - } - while(s < se) - { - os.put(*s++); - } - } - else { - while(s < se) - { - os.put(*s++); - if ((--decimal_point == 0) && s < se) - { - os.put('.'); - while ((se-1) > s && *(se-1) == '0') - { - --se; - } - } - } - for(; decimal_point > 0; decimal_point--) - { - os.put('0'); - } - } - } -}; - -#else - -template <typename CharT> -class float_printer -{ - jsoncons::basic_ovectorstream<CharT> vs_; - uint8_t precision_; -public: - float_printer(uint8_t precision) - : vs_(255), precision_(precision) - { - vs_.set_locale(std::locale::classic()); - vs_.precision(precision); - } - - void print(double val, uint8_t precision, buffered_ostream<CharT>& os) - { - vs_.reset(); - vs_.precision(precision == 0 ? precision_ : precision); - vs_ << val; - - const CharT* s = vs_.data(); - const CharT* se = s + vs_.length(); - - bool dot = false; - while (s < se) - { - if (*s == '.') - { - dot = true; - } - else if (*s == 'e') - { - if (!dot) - { - os.put('.'); - os.put('0'); - dot = true; - } - } - os.put(*s); - ++s; - } - if (!dot) - { - os.put('.'); - os.put('0'); - } - } -}; - -#endif - -// string_to_float only requires narrow char -#ifdef _MSC_VER -class float_reader -{ -private: - _locale_t locale_; -public: - float_reader() - { - locale_ = _create_locale(LC_NUMERIC, "C"); - } - ~float_reader() - { - _free_locale(locale_); - } - - double read(const char* s, size_t length) - { - const char *begin = s; - char *end = nullptr; - double val = _strtod_l(begin, &end, locale_); - if (begin == end) - { - throw std::invalid_argument("Invalid float value"); - } - return val; - } - - float_reader(const float_reader& fr) = delete; - float_reader& operator=(const float_reader& fr) = delete; -}; - -#else -class float_reader -{ -private: - std::vector<char> buffer_; - std::string decimal_point_; - bool is_dot_; -public: - float_reader() - : buffer_() - { - struct lconv * lc = localeconv(); - if (lc != nullptr) - { - decimal_point_ = std::string(lc->decimal_point); - } - else - { - decimal_point_ = std::string("."); - } - buffer_.reserve(100); - is_dot_ = decimal_point_ == "."; - } - - double read(const char* s, size_t length) - { - double val; - if (is_dot_) - { - const char *begin = s; - char *end = nullptr; - val = strtod(begin, &end); - if (begin == end) - { - throw std::invalid_argument("Invalid float value"); - } - } - else - { - buffer_.clear(); - size_t j = 0; - const char* pe = s + length; - for (const char* p = s; p < pe; ++p) - { - if (*p == '.') - { - buffer_.insert(buffer_.begin() + j, decimal_point_.begin(), decimal_point_.end()); - j += decimal_point_.length(); - } - else - { - buffer_.push_back(*p); - ++j; - } - } - const char *begin = buffer_.data(); - char *end = nullptr; - val = strtod(begin, &end); - if (begin == end) - { - throw std::invalid_argument("Invalid float value"); - } - } - return val; - } - - float_reader(const float_reader& fr) = delete; - float_reader& operator=(const float_reader& fr) = delete; -}; -#endif - -} - -#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons/output_format.hpp b/vendor/jsoncons-0.99.2/jsoncons/output_format.hpp deleted file mode 100644 index 54e74874..00000000 --- a/vendor/jsoncons-0.99.2/jsoncons/output_format.hpp +++ /dev/null @@ -1,330 +0,0 @@ -// Copyright 2013 Daniel Parker -// Distributed under the Boost license, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -// See https://github.com/danielaparker/jsoncons for latest version - -#ifndef JSONCONS_OUTPUT_FORMAT_HPP -#define JSONCONS_OUTPUT_FORMAT_HPP - -#include <string> -#include <sstream> -#include <vector> -#include <istream> -#include <ostream> -#include <cstdlib> -#include <limits> -#include <cwchar> - -namespace jsoncons { - -enum class block_options {next_line,same_line}; - -template <typename CharT> -class buffered_ostream; - -template <typename CharT> -class basic_output_format -{ - int indent_; - uint8_t precision_; - bool replace_nan_; - bool replace_pos_inf_; - bool replace_neg_inf_; - std::basic_string<CharT> nan_replacement_; - std::basic_string<CharT> pos_inf_replacement_; - std::basic_string<CharT> neg_inf_replacement_; - bool escape_all_non_ascii_; - bool escape_solidus_; - block_options object_array_block_option_; - block_options array_array_block_option_; - block_options object_object_block_option_; - block_options array_object_block_option_; -public: - static const size_t default_indent = 4; - -// Constructors - - basic_output_format() - : - indent_(default_indent), - precision_(16), - replace_nan_(true), - replace_pos_inf_(true), - replace_neg_inf_(true), - nan_replacement_(json_literals<CharT>::null_literal().first), - pos_inf_replacement_(json_literals<CharT>::null_literal().first), - neg_inf_replacement_(json_literals<CharT>::null_literal().first), - escape_all_non_ascii_(false), - escape_solidus_(false), - object_array_block_option_(block_options::same_line), - array_array_block_option_(block_options::next_line), - object_object_block_option_(block_options::same_line), - array_object_block_option_(block_options::next_line) - { - } - -// Accessors - - block_options object_array_block_option() - { - return object_array_block_option_; - } - - basic_output_format<CharT>& object_array_block_option(block_options value) - { - object_array_block_option_ = value; - return *this; - } - - block_options object_object_block_option() - { - return object_object_block_option_; - } - - basic_output_format<CharT>& object_object_block_option(block_options value) - { - object_object_block_option_ = value; - return *this; - } - - block_options array_array_block_option() - { - return array_array_block_option_; - } - - basic_output_format<CharT>& array_array_block_option(block_options value) - { - array_array_block_option_ = value; - return *this; - } - - block_options array_object_block_option() - { - return array_object_block_option_; - } - - basic_output_format<CharT>& array_object_block_option(block_options value) - { - array_object_block_option_ = value; - return *this; - } - - int indent() const - { - return indent_; - } - - uint8_t precision() const - { - return precision_; - } - - bool escape_all_non_ascii() const - { - return escape_all_non_ascii_; - } - - bool escape_solidus() const - { - return escape_solidus_; - } - - bool replace_nan() const {return replace_nan_;} - - bool replace_pos_inf() const {return replace_pos_inf_;} - - bool replace_neg_inf() const {return replace_neg_inf_;} - - std::basic_string<CharT> nan_replacement() const - { - return nan_replacement_; - } - - std::basic_string<CharT> pos_inf_replacement() const - { - return pos_inf_replacement_; - } - - std::basic_string<CharT> neg_inf_replacement() const - { - return neg_inf_replacement_; - } - -// Modifiers - - basic_output_format<CharT>& precision(uint8_t prec) - { - precision_ = prec; - return *this; - } - - basic_output_format<CharT>& escape_all_non_ascii(bool value) - { - escape_all_non_ascii_ = value; - return *this; - } - - basic_output_format<CharT>& escape_solidus(bool value) - { - escape_solidus_ = value; - return *this; - } - - basic_output_format<CharT>& replace_nan(bool replace) - { - replace_nan_ = replace; - return *this; - } - - basic_output_format<CharT>& replace_inf(bool replace) - { - replace_pos_inf_ = replace; - replace_neg_inf_ = replace; - return *this; - } - - basic_output_format<CharT>& replace_pos_inf(bool replace) - { - replace_pos_inf_ = replace; - return *this; - } - - basic_output_format<CharT>& replace_neg_inf(bool replace) - { - replace_neg_inf_ = replace; - return *this; - } - - basic_output_format<CharT>& nan_replacement(const std::basic_string<CharT>& replacement) - { - nan_replacement_ = replacement; - return *this; - } - - basic_output_format<CharT>& pos_inf_replacement(const std::basic_string<CharT>& replacement) - { - pos_inf_replacement_ = replacement; - return *this; - } - - basic_output_format<CharT>& neg_inf_replacement(const std::basic_string<CharT>& replacement) - { - neg_inf_replacement_ = replacement; - return *this; - } - - basic_output_format<CharT>& indent(int value) - { - indent_ = value; - return *this; - } -}; - -template<typename CharT> -void escape_string(const CharT* s, - size_t length, - const basic_output_format<CharT>& format, - buffered_ostream<CharT>& os) -{ - const CharT* begin = s; - const CharT* end = s + length; - for (const CharT* it = begin; it != end; ++it) - { - CharT c = *it; - switch (c) - { - case '\\': - os.put('\\'); - os.put('\\'); - break; - case '"': - os.put('\\'); - os.put('\"'); - break; - case '\b': - os.put('\\'); - os.put('b'); - break; - case '\f': - os.put('\\'); - os.put('f'); - break; - case '\n': - os.put('\\'); - os.put('n'); - break; - case '\r': - os.put('\\'); - os.put('r'); - break; - case '\t': - os.put('\\'); - os.put('t'); - break; - default: - uint32_t u(c >= 0 ? c : 256 + c); - if (format.escape_solidus() && c == '/') - { - os.put('\\'); - os.put('/'); - } - else if (is_control_character(u) || format.escape_all_non_ascii()) - { - // convert utf8 to codepoint - uint32_t cp = json_char_traits<CharT, sizeof(CharT)>::convert_char_to_codepoint(it, end); - if (is_non_ascii_character(cp) || is_control_character(u)) - { - if (cp > 0xFFFF) - { - cp -= 0x10000; - uint32_t first = (cp >> 10) + 0xD800; - uint32_t second = ((cp & 0x03FF) + 0xDC00); - - os.put('\\'); - os.put('u'); - os.put(to_hex_character(first >> 12 & 0x000F)); - os.put(to_hex_character(first >> 8 & 0x000F)); - os.put(to_hex_character(first >> 4 & 0x000F)); - os.put(to_hex_character(first & 0x000F)); - os.put('\\'); - os.put('u'); - os.put(to_hex_character(second >> 12 & 0x000F)); - os.put(to_hex_character(second >> 8 & 0x000F)); - os.put(to_hex_character(second >> 4 & 0x000F)); - os.put(to_hex_character(second & 0x000F)); - } - else - { - os.put('\\'); - os.put('u'); - os.put(to_hex_character(cp >> 12 & 0x000F)); - os.put(to_hex_character(cp >> 8 & 0x000F)); - os.put(to_hex_character(cp >> 4 & 0x000F)); - os.put(to_hex_character(cp & 0x000F)); - } - } - else - { - os.put(c); - } - } - else if (format.escape_solidus() && c == '/') - { - os.put('\\'); - os.put('/'); - } - else - { - os.put(c); - } - break; - } - } -} - -typedef basic_output_format<char> output_format; -typedef basic_output_format<wchar_t> woutput_format; - -} -#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons/ovectorstream.hpp b/vendor/jsoncons-0.99.2/jsoncons/ovectorstream.hpp deleted file mode 100644 index e19f5085..00000000 --- a/vendor/jsoncons-0.99.2/jsoncons/ovectorstream.hpp +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright 2016 Daniel Parker -// Distributed under the Boost license, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -// See https://github.com/danielaparker/jsoncons for latest version - -#ifndef JSONCONS_OVECTORSTREAM_HPP -#define JSONCONS_OVECTORSTREAM_HPP - -#include <ios> -#include <ostream> -#include <string> -#include <cstddef> -#include <vector> -#include "jsoncons/jsoncons_config.hpp" - -namespace jsoncons { - -template< - class CharT, - class Traits = std::char_traits<CharT> -> class basic_ovectorstream; - -template<class CharT, class CharTraits> -class basic_ovectorbuf - : public std::basic_streambuf<CharT, CharTraits> -{ -private: - std::ios_base::openmode mode_; - std::vector<CharT> buf_; - -public: - typedef CharT char_type; - typedef typename CharTraits::int_type int_type; - typedef typename CharTraits::pos_type pos_type; - typedef typename CharTraits::off_type off_type; - typedef CharTraits traits_type; - typedef std::basic_streambuf<char_type, traits_type> base_streambuf; - -public: - - explicit basic_ovectorbuf(std::size_t length) JSONCONS_NOEXCEPT - : base_streambuf(), - mode_(std::ios_base::out | std::ios_base::binary), - buf_(length) - { - // Set write position to beginning of buffer. - this->setp(buf_.data(), buf_.data() + buf_.size()); - } - - virtual ~basic_ovectorbuf() {} - - const CharT* data() const - { - return buf_.data(); - } - -protected: - int_type underflow() override - { - return this->gptr() != this->egptr() ? - CharTraits::to_int_type(*this->gptr()) : CharTraits::eof(); - } - - int_type pbackfail(int_type c = CharTraits::eof()) override - { - if (this->gptr() != this->eback()) - { - if (!CharTraits::eq_int_type(c, CharTraits::eof())) - { - if (CharTraits::eq(CharTraits::to_char_type(c), this->gptr()[-1])) - { - this->gbump(-1); - return c; - } - this->gbump(-1); - *this->gptr() = c; - return c; - } - else - { - this->gbump(-1); - return CharTraits::not_eof(c); - } - } - else - { - return CharTraits::eof(); - } - } - - int_type overflow(int_type c = CharTraits::eof()) override - { - if (!CharTraits::eq_int_type(c, CharTraits::eof())) - { - size_t pos = buf_.size(); - buf_.resize(pos*2); - this->setp(buf_.data(), buf_.data() + buf_.size()); - this->pubseekpos(pos, std::ios_base::out); - *this->pptr() = CharTraits::to_char_type(c); - this->pbump(1); - this->pubsync(); - return c; - } - else - { - return CharTraits::not_eof(c); - } - } - - pos_type seekoff(off_type off, std::ios_base::seekdir dir, - std::ios_base::openmode mode = std::ios_base::out) override - { - (void)mode; // Always out - - std::streamoff newoff; - switch (dir) - { - case std::ios_base::beg: - newoff = 0; - break; - case std::ios_base::end: - newoff = static_cast<std::streamoff>(buf_.size()); - break; - case std::ios_base::cur: - newoff = static_cast<std::streamoff>(this->pptr() - this->pbase()); - break; - default: - return pos_type(off_type(-1)); - } - - off += newoff; - - std::ptrdiff_t n = this->epptr() - this->pbase(); - - if (off < 0 || off > n) return pos_type(off_type(-1)); - else - { - this->setp(this->pbase(), this->pbase() + n); - this->pbump(static_cast<int>(off)); - } - - return pos_type(off); - } - - pos_type seekoff_beg(off_type off) - { - std::ptrdiff_t n = this->epptr() - this->pbase(); - - if (off < 0 || off > n) - { - return pos_type(off_type(-1)); - } - else - { - this->setp(this->pbase(), this->pbase() + n); - this->pbump(static_cast<int>(off)); - } - - return pos_type(off); - } - - pos_type seekpos(pos_type pos, std::ios_base::openmode mode - = std::ios_base::out) override - { - (void)mode; // Always out - - return seekoff_beg(pos - pos_type(off_type(0))); - } -}; - -template<class CharT, class CharTraits> -class basic_ovectorstream : - private basic_ovectorbuf<CharT, CharTraits>, - public std::basic_ostream<CharT, CharTraits> -{ -public: - typedef typename std::basic_ios - <CharT, CharTraits>::char_type char_type; - typedef typename std::basic_ios<char_type, CharTraits>::int_type int_type; - typedef typename std::basic_ios<char_type, CharTraits>::pos_type pos_type; - typedef typename std::basic_ios<char_type, CharTraits>::off_type off_type; - typedef typename std::basic_ios<char_type, CharTraits>::traits_type traits_type; - -private: - typedef basic_ovectorbuf<CharT, CharTraits> base_ouputbuf; - typedef std::basic_ios<char_type, CharTraits> base_ios; - typedef std::basic_ostream<char_type, CharTraits> base_streambuf; - base_ouputbuf& get_buf() {return *this;} - const base_ouputbuf& get_buf() const {return *this;} - -public: - basic_ovectorstream(std::size_t length) JSONCONS_NOEXCEPT - : base_ouputbuf(length), - base_streambuf(&get_buf()) - {} - - ~basic_ovectorstream() {} - -public: - - size_t length() - { - return this->pptr() - this->pbase(); - } - - void set_locale(const std::locale& loc) - { - std::locale result = std::basic_ostream<CharT, CharTraits>::imbue(loc); - this->pubimbue(loc); - } - - void reset() - { - this->clear(); - this->seekp(0, std::ios::beg); - } - - const CharT* data() const - { - return get_buf().data(); - } -}; - -} - -#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons/parse_error_handler.hpp b/vendor/jsoncons-0.99.2/jsoncons/parse_error_handler.hpp deleted file mode 100644 index 9081fc95..00000000 --- a/vendor/jsoncons-0.99.2/jsoncons/parse_error_handler.hpp +++ /dev/null @@ -1,172 +0,0 @@ -/// Copyright 2013 Daniel Parker -// Distributed under the Boost license, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -// See https://github.com/danielaparker/jsoncons for latest version - -#ifndef JSONCONS_PARSE_ERROR_HANDLER_HPP -#define JSONCONS_PARSE_ERROR_HANDLER_HPP - -#include "jsoncons/jsoncons.hpp" -#include <system_error> - -namespace jsoncons { - -class parse_exception : public std::exception, public virtual json_exception -{ -public: - parse_exception(std::error_code ec, - size_t line, - size_t column) - : error_code_(ec), - line_number_(line), - column_number_(column) - { - } - parse_exception(const parse_exception& other) - : error_code_(other.error_code_), - line_number_(other.line_number_), - column_number_(other.column_number_) - { - } - const char* what() const JSONCONS_NOEXCEPT - { - std::ostringstream os; - os << error_code_.message() << " at line " << line_number_ << " and column " << column_number_; - const_cast<std::string&>(buffer_) = os.str(); - return buffer_.c_str(); - } - - const std::error_code code() const - { - return error_code_; - } - - size_t line_number() const - { - return line_number_; - } - - size_t column_number() const - { - return column_number_; - } -private: - std::error_code error_code_; - std::string buffer_; - size_t line_number_; - size_t column_number_; -}; - -typedef parse_exception json_parse_exception; - -template<typename CharT> -class basic_parsing_context -{ -public: - virtual ~basic_parsing_context() {} - - size_t line_number() const - { - return do_line_number(); - } - size_t column_number() const - { - return do_column_number(); - } - CharT current_char() const - { - return do_current_char(); - } - -#if !defined(JSONCONS_NO_DEPRECATED) - CharT last_char() const - { - return do_current_char(); - } -#endif - -private: - virtual size_t do_line_number() const = 0; - virtual size_t do_column_number() const = 0; - virtual CharT do_current_char() const = 0; -}; - -typedef basic_parsing_context<char> parsing_context; -typedef basic_parsing_context<wchar_t> wparsing_context; - -template <typename CharT> -class basic_parse_error_handler -{ -public: - virtual ~basic_parse_error_handler() - { - } - - void warning(std::error_code ec, - const basic_parsing_context<CharT>& context) throw (parse_exception) - { - do_warning(ec,context); - } - - void error(std::error_code ec, - const basic_parsing_context<CharT>& context) throw (parse_exception) - { - do_error(ec,context); - } - - void fatal_error(std::error_code ec, - const basic_parsing_context<CharT>& context) throw (parse_exception) - { - do_fatal_error(ec,context); - throw parse_exception(ec,context.line_number(),context.column_number()); - } - -private: - virtual void do_warning(std::error_code, - const basic_parsing_context<CharT>& context) throw (parse_exception) = 0; - - virtual void do_error(std::error_code, - const basic_parsing_context<CharT>& context) throw (parse_exception) = 0; - - virtual void do_fatal_error(std::error_code, - const basic_parsing_context<CharT>& context) throw (parse_exception) - { - (void)context; - } -}; - -template <typename CharT> -class basic_default_parse_error_handler : public basic_parse_error_handler<CharT> -{ -public: - static basic_parse_error_handler<CharT>& instance() - { - static basic_default_parse_error_handler<CharT> instance; - return instance; - } -private: - virtual void do_warning(std::error_code, - const basic_parsing_context<CharT>& context) throw (parse_exception) - { - (void)context; - } - - virtual void do_error(std::error_code ec, - const basic_parsing_context<CharT>& context) throw (parse_exception) - { - throw parse_exception(ec,context.line_number(),context.column_number()); - } -}; - -typedef basic_parse_error_handler<char> parse_error_handler; -typedef basic_parse_error_handler<wchar_t> wparse_error_handler; - -typedef basic_default_parse_error_handler<char> default_parse_error_handler; -typedef basic_default_parse_error_handler<wchar_t> wdefault_parse_error_handler; - -typedef basic_parsing_context<char> parsing_context; -typedef basic_parsing_context<wchar_t> wparsing_context; - -} -#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons_ext/boost/type_extensions.hpp b/vendor/jsoncons-0.99.2/jsoncons_ext/boost/type_extensions.hpp deleted file mode 100644 index 59936cd7..00000000 --- a/vendor/jsoncons-0.99.2/jsoncons_ext/boost/type_extensions.hpp +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2013 Daniel Parker -// Distributed under the Boost license, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -// See https://github.com/danielaparker/jsoncons for latest version - -#ifndef JSONCONS_EXT_TYPE_EXTENSIONS_HPP -#define JSONCONS_EXT_TYPE_EXTENSIONS_HPP - -#include "jsoncons/json.hpp" -#include "boost/date_time/gregorian/gregorian.hpp" - -#if defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wswitch" -#endif - -namespace jsoncons -{ - template <typename JsonT> - class json_type_traits<JsonT,boost::gregorian::date> - { - public: - static bool is(const JsonT& val) JSONCONS_NOEXCEPT - { - if (!val.is_string()) - { - return false; - } - std::string s = val.template as<std::string>(); - try - { - boost::gregorian::date_from_iso_string(s); - return true; - } - catch (...) - { - return false; - } - } - - static boost::gregorian::date as(const JsonT& val) - { - std::string s = val.template as<std::string>(); - return boost::gregorian::from_simple_string(s); - } - - static void assign(JsonT& lhs, boost::gregorian::date val) - { - lhs = to_iso_extended_string(val); - } - }; -} - -#if defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - -#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons_ext/csv/csv_parameters.hpp b/vendor/jsoncons-0.99.2/jsoncons_ext/csv/csv_parameters.hpp deleted file mode 100644 index 099a154f..00000000 --- a/vendor/jsoncons-0.99.2/jsoncons_ext/csv/csv_parameters.hpp +++ /dev/null @@ -1,341 +0,0 @@ -// Copyright 2013 Daniel Parker -// Distributed under the Boost license, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -// See https://github.com/danielaparker/jsoncons for latest version - -#ifndef JSONCONS_CSV_CSV_PARAMETERS_HPP -#define JSONCONS_CSV_CSV_PARAMETERS_HPP - -#include <string> -#include <sstream> -#include <vector> -#include <istream> -#include <ostream> -#include <cstdlib> -#include <limits> -#include <cwchar> - -namespace jsoncons { namespace csv { - -enum class quote_styles -{ - all,minimal,none,nonnumeric -}; - -template <typename CharT> -class basic_csv_parameters -{ -public: - static const size_t default_indent = 4; - -// Constructors - - basic_csv_parameters() - : - assume_header_(false), - ignore_empty_values_(false), - trim_leading_(false), - trim_trailing_(false), - trim_leading_inside_quotes_(false), - trim_trailing_inside_quotes_(false), - unquoted_empty_value_is_null_(false), - field_delimiter_(','), - quote_char_('\"'), - quote_escape_char_('\"'), - comment_starter_('\0'), - quote_style_(quote_styles::minimal), - max_lines_(std::numeric_limits<unsigned long>::max JSONCONS_NO_MACRO_EXP()), - header_lines_(0) - { - line_delimiter_.push_back('\n'); - } - -// Properties - - size_t header_lines() const - { - return (assume_header_ && header_lines_ <= 1) ? 1 : header_lines_; - } - - basic_csv_parameters<CharT>& header_lines(size_t value) - { - header_lines_ = value; - return *this; - } - - bool assume_header() const - { - return assume_header_; - } - - basic_csv_parameters<CharT>& assume_header(bool value) - { - assume_header_ = value; - return *this; - } - - bool ignore_empty_values() const - { - return ignore_empty_values_; - } - - basic_csv_parameters<CharT>& ignore_empty_values(bool value) - { - ignore_empty_values_ = value; - return *this; - } - - bool trim_leading() const - { - return trim_leading_; - } - - basic_csv_parameters<CharT>& trim_leading(bool value) - { - trim_leading_ = value; - return *this; - } - - bool trim_trailing() const - { - return trim_trailing_; - } - - basic_csv_parameters<CharT>& trim_trailing(bool value) - { - trim_trailing_ = value; - return *this; - } - - bool trim_leading_inside_quotes() const - { - return trim_leading_inside_quotes_; - } - - basic_csv_parameters<CharT>& trim_leading_inside_quotes(bool value) - { - trim_leading_inside_quotes_ = value; - return *this; - } - - bool trim_trailing_inside_quotes() const - { - return trim_trailing_inside_quotes_; - } - - basic_csv_parameters<CharT>& trim_trailing_inside_quotes(bool value) - { - trim_trailing_inside_quotes_ = value; - return *this; - } - - bool trim() const - { - return trim_leading_ && trim_trailing_; - } - - basic_csv_parameters<CharT>& trim(bool value) - { - trim_leading_ = value; - trim_trailing_ = value; - return *this; - } - - bool trim_inside_quotes() const - { - return trim_leading_inside_quotes_ && trim_trailing_inside_quotes_; - } - - basic_csv_parameters<CharT>& trim_inside_quotes(bool value) - { - trim_leading_inside_quotes_ = value; - trim_trailing_inside_quotes_ = value; - return *this; - } - - bool unquoted_empty_value_is_null() const - { - return unquoted_empty_value_is_null_; - } - - basic_csv_parameters<CharT>& unquoted_empty_value_is_null(bool value) - { - unquoted_empty_value_is_null_ = value; - return *this; - } - - std::vector<std::basic_string<CharT>> column_names() const - { - return column_names_; - } - - basic_csv_parameters<CharT>& column_names(const std::vector<std::basic_string<CharT>>& value) - { - column_names_ = value; - return *this; - } - - std::vector<std::basic_string<CharT>> column_types() const - { - return column_types_; - } - - basic_csv_parameters<CharT>& column_types(const std::vector<std::basic_string<CharT>>& value) - { - column_types_ = value; - return *this; - } - - std::vector<std::basic_string<CharT>> column_defaults() const - { - return column_defaults_; - } - - basic_csv_parameters<CharT>& column_defaults(const std::vector<std::basic_string<CharT>>& value) - { - column_defaults_ = value; - return *this; - } - - CharT field_delimiter() const - { - return field_delimiter_; - } - - basic_csv_parameters<CharT>& field_delimiter(CharT value) - { - field_delimiter_ = value; - return *this; - } - - std::basic_string<CharT> line_delimiter() const - { - return line_delimiter_; - } - - basic_csv_parameters<CharT>& line_delimiter(std::basic_string<CharT> value) - { - line_delimiter_ = value; - return *this; - } - - CharT quote_char() const - { - return quote_char_; - } - - basic_csv_parameters<CharT>& quote_char(CharT value) - { - quote_char_ = value; - return *this; - } - - CharT quote_escape_char() const - { - return quote_escape_char_; - } - - basic_csv_parameters<CharT>& quote_escape_char(CharT value) - { - quote_escape_char_ = value; - return *this; - } - - CharT comment_starter() const - { - return comment_starter_; - } - - basic_csv_parameters<CharT>& comment_starter(CharT value) - { - comment_starter_ = value; - return *this; - } - - quote_styles quote_style() const - { - return quote_style_; - } - - basic_csv_parameters<CharT>& assume_header(quote_styles value) - { - quote_style_ = value; - return *this; - } - - unsigned long max_lines() const - { - return max_lines_; - } - - basic_csv_parameters<CharT>& max_lines(unsigned long value) - { - max_lines_ = value; - return *this; - } - -#if !defined(JSONCONS_NO_DEPRECATED) - - std::basic_string<CharT> header() const - { - return header_; - } - - basic_csv_parameters<CharT>& header(const std::basic_string<CharT>& value) - { - header_ = value; - return *this; - } - - std::basic_string<CharT> data_types() const - { - return data_types_; - } - - basic_csv_parameters<CharT>& data_types(const std::basic_string<CharT>& value) - { - data_types_ = value; - return *this; - } - - std::basic_string<CharT> default_values() const - { - return default_values_; - } - - basic_csv_parameters<CharT>& default_values(const std::basic_string<CharT>& value) - { - default_values_ = value; - return *this; - } -#endif -private: - bool assume_header_; - bool ignore_empty_values_; - bool trim_leading_; - bool trim_trailing_; - bool trim_leading_inside_quotes_; - bool trim_trailing_inside_quotes_; - bool unquoted_empty_value_is_null_; - CharT field_delimiter_; - CharT quote_char_; - CharT quote_escape_char_; - CharT comment_starter_; - quote_styles quote_style_; - unsigned long max_lines_; - size_t header_lines_; - std::basic_string<CharT> line_delimiter_; - std::basic_string<CharT> header_; - std::basic_string<CharT> data_types_; - std::basic_string<CharT> default_values_; - std::vector<std::basic_string<CharT>> column_names_; - std::vector<std::basic_string<CharT>> column_types_; - std::vector<std::basic_string<CharT>> column_defaults_; -}; - -typedef basic_csv_parameters<char> csv_parameters; -typedef basic_csv_parameters<wchar_t> wcsv_parameters; - -}} -#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons_ext/csv/csv_parser.hpp b/vendor/jsoncons-0.99.2/jsoncons_ext/csv/csv_parser.hpp deleted file mode 100644 index 14323666..00000000 --- a/vendor/jsoncons-0.99.2/jsoncons_ext/csv/csv_parser.hpp +++ /dev/null @@ -1,903 +0,0 @@ -// Copyright 2015 Daniel Parker -// Distributed under the Boost license, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -// See https://github.com/danielaparker/jsoncons for latest version - -#ifndef JSONCONS_CSV_CSV_PARSER_HPP -#define JSONCONS_CSV_CSV_PARSER_HPP - -#include <memory> -#include <string> -#include <sstream> -#include <vector> -#include <istream> -#include <cstdlib> -#include <stdexcept> -#include <system_error> -#include <cctype> -#include "jsoncons/jsoncons.hpp" -#include "jsoncons/json_input_handler.hpp" -#include "jsoncons/parse_error_handler.hpp" -#include "jsoncons/json_parser.hpp" -#include "jsoncons/json_filter.hpp" -#include "jsoncons_ext/csv/csv_error_category.hpp" -#include "jsoncons_ext/csv/csv_parameters.hpp" - -namespace jsoncons { namespace csv { - -template <typename CharT> -struct json_csv_parser_traits -{ -}; - -template <> -struct json_csv_parser_traits<char> -{ - static const std::string string_literal() {return "string";}; - - static const std::string integer_literal() {return "integer";}; - - static const std::string float_literal() {return "float";}; - - static const std::string boolean_literal() {return "boolean";}; -}; - -template <> -struct json_csv_parser_traits<wchar_t> // assume utf16 -{ - static const std::wstring string_literal() {return L"string";}; - - static const std::wstring integer_literal() {return L"integer";}; - - static const std::wstring float_literal() {return L"float";}; - - static const std::wstring boolean_literal() {return L"boolean";}; -}; - -enum class csv_modes { - done, - header, - array, - object -}; - -enum class csv_states -{ - start, - comment, - expect_value, - between_fields, - quoted_string, - unquoted_string, - escaped_value, - minus, - zero, - integer, - fraction, - exp1, - exp2, - exp3, - done -}; - -enum class data_types -{ - string_t,integer_t,float_t,boolean_t -}; - -template<typename CharT> -class basic_csv_parser : private basic_parsing_context<CharT> -{ - static const int default_depth = 3; - - csv_states state_; - int top_; - std::vector<csv_modes> stack_; - basic_json_input_handler<CharT> *handler_; - basic_parse_error_handler<CharT> *err_handler_; - bool is_negative_; - uint32_t cp_; - size_t index_; - unsigned long column_; - unsigned long line_; - int curr_char_; - int prev_char_; - std::basic_string<CharT> string_buffer_; - csv_states saved_state_; - int depth_; - basic_csv_parameters<CharT> parameters_; - std::vector<std::basic_string<CharT>> column_names_; - std::vector<data_types> column_types_; - std::vector<std::basic_string<CharT>> column_defaults_; - size_t column_index_; - basic_begin_end_json_filter<CharT> filter_; - basic_json_parser<CharT> parser_; - -public: - basic_csv_parser(basic_json_input_handler<CharT>& handler) - : top_(-1), - stack_(default_depth), - handler_(std::addressof(handler)), - err_handler_(std::addressof(basic_default_parse_error_handler<CharT>::instance())), - is_negative_(false), - cp_(0), - index_(0), - filter_(handler), - parser_(filter_) - { - depth_ = default_depth; - state_ = csv_states::start; - top_ = -1; - line_ = 1; - column_ = 0; - column_index_ = 0; - } - - basic_csv_parser(basic_json_input_handler<CharT>& handler, - basic_csv_parameters<CharT> params) - : top_(-1), - stack_(default_depth), - handler_(std::addressof(handler)), - err_handler_(std::addressof(basic_default_parse_error_handler<CharT>::instance())), - is_negative_(false), - cp_(0), - index_(0), - parameters_(params), - filter_(handler), - parser_(filter_) - { - depth_ = default_depth; - state_ = csv_states::start; - top_ = -1; - line_ = 1; - column_ = 0; - column_index_ = 0; - } - - basic_csv_parser(basic_json_input_handler<CharT>& handler, - basic_parse_error_handler<CharT>& err_handler) - : top_(-1), - stack_(default_depth), - handler_(std::addressof(handler)), - err_handler_(std::addressof(err_handler)), - is_negative_(false), - cp_(0), - index_(0), - filter_(handler), - parser_(filter_) - { - depth_ = default_depth; - state_ = csv_states::start; - top_ = -1; - line_ = 1; - column_ = 0; - column_index_ = 0; - } - - basic_csv_parser(basic_json_input_handler<CharT>& handler, - basic_parse_error_handler<CharT>& err_handler, - basic_csv_parameters<CharT> params) - : top_(-1), - stack_(default_depth), - handler_(std::addressof(handler)), - err_handler_(std::addressof(err_handler)), - is_negative_(false), - cp_(0), - index_(0), - parameters_(params), - filter_(handler), - parser_(filter_) - { - depth_ = default_depth; - state_ = csv_states::start; - top_ = -1; - line_ = 1; - column_ = 0; - column_index_ = 0; - } - - ~basic_csv_parser() - { - } - - const basic_parsing_context<CharT>& parsing_context() const - { - return *this; - } - - bool done() const - { - return state_ == csv_states::done; - } - - const std::vector<std::basic_string<CharT>>& column_labels() const - { - return column_names_; - } - - void after_field() - { - ++column_index_; - } - - void before_record() - { - if (column_index_ == 0) - { - switch (stack_[top_]) - { - case csv_modes::array: - handler_->begin_array(*this); - break; - case csv_modes::object: - handler_->begin_object(*this); - break; - default: - break; - } - } - } - - void after_record() - { - switch (stack_[top_]) - { - case csv_modes::array: - handler_->end_array(*this); - break; - case csv_modes::object: - handler_->end_object(*this); - break; - case csv_modes::header: - if (line_ >= parameters_.header_lines()) - { - if (column_names_.size() > 0) - { - flip(csv_modes::header, csv_modes::object); - } - else - { - flip(csv_modes::header, csv_modes::array); - } - } - break; - default: - break; - } - column_index_ = 0; - } - - void begin_parse() - { - push(csv_modes::done); - handler_->begin_json(); - - if (parameters_.column_names().size() > 0) - { - column_names_ = parameters_.column_names(); - } -#if !defined(JSONCONS_NO_DEPRECATED) - else if (parameters_.header().length() > 0) - { - basic_empty_json_input_handler<CharT> ih; - basic_csv_parameters<CharT> params; - params.field_delimiter(parameters_.field_delimiter()); - params.quote_char(parameters_.quote_char()); - params.quote_escape_char(parameters_.quote_escape_char()); - params.assume_header(true); - basic_csv_parser<CharT> p(ih,params); - p.begin_parse(); - p.parse(parameters_.header().data(),0,parameters_.header().length()); - p.end_parse(); - column_names_ = p.column_labels(); - } -#endif - if (parameters_.column_types().size() > 0) - { - column_types_.resize(parameters_.column_types().size()); - for (size_t i = 0; i < parameters_.column_types().size(); ++i) - { - if (parameters_.column_types()[i] == json_csv_parser_traits<CharT>::string_literal()) - { - column_types_[i] = data_types::string_t; - } - else if (parameters_.column_types()[i] == json_csv_parser_traits<CharT>::integer_literal()) - { - column_types_[i] = data_types::integer_t; - } - else if (parameters_.column_types()[i] == json_csv_parser_traits<CharT>::float_literal()) - { - column_types_[i] = data_types::float_t; - } - else if (parameters_.column_types()[i] == json_csv_parser_traits<CharT>::boolean_literal()) - { - column_types_[i] = data_types::boolean_t; - } - } - } -#if !defined(JSONCONS_NO_DEPRECATED) - else if (parameters_.data_types().length() > 0) - { - basic_empty_json_input_handler<CharT> ih; - basic_csv_parameters<CharT> params; - params.field_delimiter(parameters_.field_delimiter()); - params.assume_header(true); - basic_csv_parser<CharT> p(ih,params); - p.begin_parse(); - p.parse(parameters_.data_types().data(),0,parameters_.data_types().length()); - p.end_parse(); - column_types_.resize(p.column_labels().size()); - for (size_t i = 0; i < p.column_labels().size(); ++i) - { - if (p.column_labels()[i] == json_csv_parser_traits<CharT>::string_literal()) - { - column_types_[i] = data_types::string_t; - } - else if (p.column_labels()[i] == json_csv_parser_traits<CharT>::integer_literal()) - { - column_types_[i] = data_types::integer_t; - } - else if (p.column_labels()[i] == json_csv_parser_traits<CharT>::float_literal()) - { - column_types_[i] = data_types::float_t; - } - else if (p.column_labels()[i] == json_csv_parser_traits<CharT>::boolean_literal()) - { - column_types_[i] = data_types::boolean_t; - } - } - } -#endif - if (parameters_.column_defaults().size() > 0) - { - column_defaults_ = parameters_.column_defaults(); - } -#if !defined(JSONCONS_NO_DEPRECATED) - else if (parameters_.default_values().length() > 0) - { - basic_empty_json_input_handler<CharT> ih; - basic_csv_parameters<CharT> params; - params.field_delimiter(parameters_.field_delimiter()); - params.assume_header(true); - basic_csv_parser<CharT> p(ih,params); - p.begin_parse(); - p.parse(parameters_.default_values().data(),0,parameters_.default_values().length()); - p.end_parse(); - column_defaults_.resize(p.column_labels().size()); - for (size_t i = 0; i < p.column_labels().size(); ++i) - { - column_defaults_[i] = p.column_labels()[i]; - } - } -#endif - if (parameters_.header_lines() > 0) - { - push(csv_modes::header); - } - else - { - push(csv_modes::array); - } - handler_->begin_array(*this); - state_ = csv_states::expect_value; - column_index_ = 0; - prev_char_ = 0; - curr_char_ = 0; - column_ = 1; - } - - void parse(const CharT* p, size_t start, size_t length) - { - index_ = start; - for (; index_ < length && state_ != csv_states::done; ++index_) - { - curr_char_ = p[index_]; -all_csv_states: - switch (state_) - { - case csv_states::comment: - if (curr_char_ == '\n') - { - state_ = csv_states::expect_value; - } - else if (prev_char_ == '\r') - { - state_ = csv_states::expect_value; - goto all_csv_states; - } - break; - case csv_states::expect_value: - if (column_ == 1 && curr_char_ == parameters_.comment_starter()) - { - state_ = csv_states::comment; - } - else - { - state_ = csv_states::unquoted_string; - goto all_csv_states; - } - break; - case csv_states::between_fields: - if (curr_char_ == '\r' || (prev_char_ != '\r' && curr_char_ == '\n')) - { - after_record(); - state_ = csv_states::expect_value; - } - else if (curr_char_ == parameters_.field_delimiter()) - { - state_ = csv_states::expect_value; - } - break; - case csv_states::escaped_value: - { - if (curr_char_ == parameters_.quote_char()) - { - string_buffer_.push_back(curr_char_); - state_ = csv_states::quoted_string; - } - else if (parameters_.quote_escape_char() == parameters_.quote_char()) - { - before_record(); - end_quoted_string_value(); - after_field(); - state_ = csv_states::between_fields; - goto all_csv_states; - } - } - break; - case csv_states::quoted_string: - { - if (curr_char_ == parameters_.quote_escape_char()) - { - state_ = csv_states::escaped_value; - } - else if (curr_char_ == parameters_.quote_char()) - { - before_record(); - end_quoted_string_value(); - after_field(); - state_ = csv_states::between_fields; - } - else - { - string_buffer_.push_back(curr_char_); - } - } - break; - case csv_states::unquoted_string: - { - if (curr_char_ == '\r' || (prev_char_ != '\r' && curr_char_ == '\n')) - { - before_record(); - end_unquoted_string_value(); - after_field(); - after_record(); - state_ = csv_states::expect_value; - } - else if (curr_char_ == '\n') - { - if (prev_char_ != '\r') - { - before_record(); - end_unquoted_string_value(); - after_field(); - after_record(); - state_ = csv_states::expect_value; - } - } - else if (curr_char_ == parameters_.field_delimiter()) - { - before_record(); - end_unquoted_string_value(); - after_field(); - state_ = csv_states::expect_value; - } - else if (curr_char_ == parameters_.quote_char()) - { - string_buffer_.clear(); - state_ = csv_states::quoted_string; - } - else - { - string_buffer_.push_back(curr_char_); - } - } - break; - default: - err_handler_->error(std::error_code(csv_parser_errc::invalid_state, csv_error_category()), *this); - break; - } - if (line_ > parameters_.max_lines()) - { - state_ = csv_states::done; - } - switch (curr_char_) - { - case '\r': - ++line_; - column_ = 1; - break; - case '\n': - if (prev_char_ != '\r') - { - ++line_; - } - column_ = 1; - break; - default: - ++column_; - break; - } - prev_char_ = curr_char_; - } - } - - void end_parse() - { - switch (state_) - { - case csv_states::unquoted_string: - before_record(); - end_unquoted_string_value(); - after_field(); - break; - case csv_states::escaped_value: - if (parameters_.quote_escape_char() == parameters_.quote_char()) - { - before_record(); - end_quoted_string_value(); - after_field(); - } - break; - default: - break; - } - if (column_index_ > 0) - { - after_record(); - } - switch (stack_[top_]) - { - case csv_modes::array: - if (!pop(csv_modes::array)) - { - err_handler_->error(std::error_code(csv_parser_errc::unexpected_eof, csv_error_category()), *this); - } - break; - case csv_modes::object: - if (!pop(csv_modes::object)) - { - err_handler_->error(std::error_code(csv_parser_errc::unexpected_eof, csv_error_category()), *this); - } - break; - case csv_modes::header: - if (!pop(csv_modes::header)) - { - err_handler_->error(std::error_code(csv_parser_errc::unexpected_eof, csv_error_category()), *this); - } - break; - default: - break; - } - handler_->end_array(*this); - if (!pop(csv_modes::done)) - { - err_handler_->error(std::error_code(csv_parser_errc::unexpected_eof, csv_error_category()), *this); - } - handler_->end_json(); - } - - csv_states state() const - { - return state_; - } - - size_t index() const - { - return index_; - } -private: - - void trim_string_buffer(bool trim_leading, bool trim_trailing) - { - size_t start = 0; - size_t length = string_buffer_.length(); - if (trim_leading) - { - bool done = false; - while (!done && start < string_buffer_.length()) - { - if ((string_buffer_[start] < 256) && std::isspace(string_buffer_[start])) - { - ++start; - } - else - { - done = true; - } - } - } - if (trim_trailing) - { - bool done = false; - while (!done && length > 0) - { - if ((string_buffer_[length-1] < 256) && std::isspace(string_buffer_[length-1])) - { - --length; - } - else - { - done = true; - } - } - } - if (start != 0 || length != string_buffer_.size()) - { - string_buffer_ = string_buffer_.substr(start,length-start); - } - } - - void end_unquoted_string_value() - { - if (parameters_.trim_leading() | parameters_.trim_trailing()) - { - trim_string_buffer(parameters_.trim_leading(),parameters_.trim_trailing()); - } - switch (stack_[top_]) - { - case csv_modes::header: - if (parameters_.assume_header() && line_ == 1) - { - column_names_.push_back(string_buffer_); - } - break; - case csv_modes::object: - if (!(parameters_.ignore_empty_values() && string_buffer_.size() == 0)) - { - if (column_index_ < column_names_.size()) - { - handler_->name(column_names_[column_index_].data(), column_names_[column_index_].length(), *this); - if (parameters_.unquoted_empty_value_is_null() && string_buffer_.length() == 0) - { - handler_->value(jsoncons::null_type(),*this); - } - else - { - end_value(); - } - } - } - break; - case csv_modes::array: - if (parameters_.unquoted_empty_value_is_null() && string_buffer_.length() == 0) - { - handler_->value(jsoncons::null_type(),*this); - } - else - { - end_value(); - } - break; - default: - err_handler_->error(std::error_code(csv_parser_errc::invalid_csv_text, csv_error_category()), *this); - break; - } - state_ = csv_states::expect_value; - string_buffer_.clear(); - } - - void end_quoted_string_value() - { - if (parameters_.trim_leading_inside_quotes() | parameters_.trim_trailing_inside_quotes()) - { - trim_string_buffer(parameters_.trim_leading_inside_quotes(),parameters_.trim_trailing_inside_quotes()); - } - switch (stack_[top_]) - { - case csv_modes::header: - if (parameters_.assume_header() && line_ == 1) - { - column_names_.push_back(string_buffer_); - } - break; - case csv_modes::object: - if (!(parameters_.ignore_empty_values() && string_buffer_.size() == 0)) - { - if (column_index_ < column_names_.size()) - { - handler_->name(column_names_[column_index_].data(), column_names_[column_index_].length(), *this); - end_value(); - } - } - break; - case csv_modes::array: - end_value(); - break; - default: - err_handler_->error(std::error_code(csv_parser_errc::invalid_csv_text, csv_error_category()), *this); - break; - } - state_ = csv_states::expect_value; - string_buffer_.clear(); - } - - void end_value() - { - if (column_index_ < column_types_.size()) - { - switch (column_types_[column_index_]) - { - case data_types::integer_t: - { - std::istringstream iss(string_buffer_); - long long val; - iss >> val; - if (!iss.fail()) - { - handler_->value(val, *this); - } - else - { - if (column_index_ < column_defaults_.size() && column_defaults_[column_index_].length() > 0) - { - parser_.begin_parse(); - parser_.parse(column_defaults_[column_index_].data(),0,column_defaults_[column_index_].length()); - parser_.end_parse(); - } - else - { - handler_->value(null_type(), *this); - } - } - } - break; - case data_types::float_t: - { - std::istringstream iss(string_buffer_); - double val; - iss >> val; - if (!iss.fail()) - { - handler_->value(val, 0, *this); - } - else - { - if (column_index_ < column_defaults_.size() && column_defaults_[column_index_].length() > 0) - { - parser_.begin_parse(); - parser_.parse(column_defaults_[column_index_].data(),0,column_defaults_[column_index_].length()); - parser_.end_parse(); - } - else - { - handler_->value(null_type(), *this); - } - } - } - break; - case data_types::boolean_t: - { - if (string_buffer_.length() == 1 && string_buffer_[0] == '0') - { - handler_->value(false, *this); - } - else if (string_buffer_.length() == 1 && string_buffer_[0] == '1') - { - handler_->value(true, *this); - } - else if (string_buffer_.length() == 5 && ((string_buffer_[0] == 'f' || string_buffer_[0] == 'F') && (string_buffer_[1] == 'a' || string_buffer_[1] == 'A') && (string_buffer_[2] == 'l' || string_buffer_[2] == 'L') && (string_buffer_[3] == 's' || string_buffer_[3] == 'S') && (string_buffer_[4] == 'e' || string_buffer_[4] == 'E'))) - { - handler_->value(false, *this); - } - else if (string_buffer_.length() == 4 && ((string_buffer_[0] == 't' || string_buffer_[0] == 'T') && (string_buffer_[1] == 'r' || string_buffer_[1] == 'R') && (string_buffer_[2] == 'u' || string_buffer_[2] == 'U') && (string_buffer_[3] == 'e' || string_buffer_[3] == 'E'))) - { - handler_->value(true, *this); - } - else - { - if (column_index_ < column_defaults_.size() && column_defaults_[column_index_].length() > 0) - { - parser_.begin_parse(); - parser_.parse(column_defaults_[column_index_].data(),0,column_defaults_[column_index_].length()); - parser_.end_parse(); - } - else - { - handler_->value(null_type(), *this); - } - } - } - break; - default: - if (string_buffer_.length() > 0) - { - handler_->value(string_buffer_.data(), string_buffer_.length(), *this); - } - else - { - if (column_index_ < column_defaults_.size() && column_defaults_[column_index_].length() > 0) - { - parser_.begin_parse(); - parser_.parse(column_defaults_[column_index_].data(),0,column_defaults_[column_index_].length()); - parser_.end_parse(); - } - else - { - handler_->value("", *this); - } - } - break; - } - } - else - { - handler_->value(string_buffer_.data(), string_buffer_.length(), *this); - } - } - - size_t do_line_number() const override - { - return line_; - } - - size_t do_column_number() const override - { - return column_; - } - - CharT do_current_char() const override - { - return (CharT)prev_char_; - } - - void push(csv_modes mode) - { - ++top_; - if (top_ >= depth_) - { - depth_ *= 2; - stack_.resize(depth_); - } - stack_[top_] = mode; - } - - int peek() - { - return stack_[top_]; - } - - bool peek(csv_modes mode) - { - return stack_[top_] == mode; - } - - bool flip(csv_modes mode1, csv_modes mode2) - { - if (top_ < 0 || stack_[top_] != mode1) - { - return false; - } - stack_[top_] = mode2; - return true; - } - - bool pop(csv_modes mode) - { - if (top_ < 0 || stack_[top_] != mode) - { - return false; - } - --top_; - return true; - } -}; - -typedef basic_csv_parser<char> csv_parser; -typedef basic_csv_parser<wchar_t> wcsv_parser; - -}} - -#endif - diff --git a/vendor/jsoncons-0.99.2/jsoncons_ext/csv/csv_reader.hpp b/vendor/jsoncons-0.99.2/jsoncons_ext/csv/csv_reader.hpp deleted file mode 100644 index 38213e25..00000000 --- a/vendor/jsoncons-0.99.2/jsoncons_ext/csv/csv_reader.hpp +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright 2013 Daniel Parker -// Distributed under the Boost license, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -// See https://github.com/danielaparker/jsoncons for latest version - -#ifndef JSONCONS_CSV_CSV_READER_HPP -#define JSONCONS_CSV_CSV_READER_HPP - -#include <string> -#include <sstream> -#include <vector> -#include <istream> -#include <cstdlib> -#include <stdexcept> -#include "jsoncons/jsoncons.hpp" -#include "jsoncons/json_input_handler.hpp" -#include "jsoncons/parse_error_handler.hpp" -#include "jsoncons_ext/csv/csv_error_category.hpp" -#include "jsoncons_ext/csv/csv_parser.hpp" -#include "jsoncons/json.hpp" - -namespace jsoncons { namespace csv { - -template<typename CharT> -class basic_csv_reader -{ - struct stack_item - { - stack_item() - : array_begun_(false) - { - } - - bool array_begun_; - }; -public: - // Structural characters - static const size_t default_max_buffer_length = 16384; - //! Parse an input stream of CSV text into a json object - /*! - \param is The input stream to read from - */ - - basic_csv_reader(std::basic_istream<CharT>& is, - basic_json_input_handler<CharT>& handler) - - : parser_(handler), - is_(std::addressof(is)), - buffer_(default_max_buffer_length), - buffer_capacity_(default_max_buffer_length), - buffer_position_(0), - buffer_length_(0), - eof_(false), - index_(0) - { - } - - basic_csv_reader(std::basic_istream<CharT>& is, - basic_json_input_handler<CharT>& handler, - basic_csv_parameters<CharT> params) - - : parser_(handler,params), - is_(std::addressof(is)), - buffer_(default_max_buffer_length), - buffer_capacity_(default_max_buffer_length), - buffer_position_(0), - buffer_length_(0), - eof_(false), - index_(0) - { - } - - basic_csv_reader(std::basic_istream<CharT>& is, - basic_json_input_handler<CharT>& handler, - basic_parse_error_handler<CharT>& err_handler) - : - parser_(handler,err_handler), - is_(std::addressof(is)), - buffer_(), - buffer_capacity_(default_max_buffer_length), - buffer_position_(0), - buffer_length_(0), - eof_(false), - index_(0) - - - { - } - - basic_csv_reader(std::basic_istream<CharT>& is, - basic_json_input_handler<CharT>& handler, - basic_parse_error_handler<CharT>& err_handler, - basic_csv_parameters<CharT> params) - : - parser_(handler,err_handler,params), - is_(std::addressof(is)), - buffer_(), - buffer_capacity_(default_max_buffer_length), - buffer_position_(0), - buffer_length_(0), - eof_(false), - index_(0) - { - } - - ~basic_csv_reader() - { - } - - void read() - { - parser_.begin_parse(); - while (!eof_ && !parser_.done()) - { - if (!(index_ < buffer_length_)) - { - if (!is_->eof()) - { - is_->read(buffer_.data(), buffer_capacity_); - buffer_length_ = static_cast<size_t>(is_->gcount()); - if (buffer_length_ == 0) - { - eof_ = true; - } - index_ = 0; - } - else - { - eof_ = true; - } - } - if (!eof_) - { - parser_.parse(buffer_.data(),index_,buffer_length_); - index_ = parser_.index(); - } - } - parser_.end_parse(); - } - - bool eof() const - { - return eof_; - } - - size_t buffer_capacity() const - { - return buffer_capacity_; - } - - void buffer_capacity(size_t buffer_capacity) - { - buffer_capacity_ = buffer_capacity; - } - -private: - basic_csv_reader(const basic_csv_reader&) = delete; - basic_csv_reader& operator = (const basic_csv_reader&) = delete; - - basic_csv_parser<CharT> parser_; - std::basic_istream<CharT>* is_; - std::vector<CharT> buffer_; - size_t buffer_capacity_; - size_t buffer_position_; - size_t buffer_length_; - bool eof_; - size_t index_; -}; - -typedef basic_csv_reader<char> csv_reader; - -}} - -#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons_ext/csv/csv_serializer.hpp b/vendor/jsoncons-0.99.2/jsoncons_ext/csv/csv_serializer.hpp deleted file mode 100644 index f331b629..00000000 --- a/vendor/jsoncons-0.99.2/jsoncons_ext/csv/csv_serializer.hpp +++ /dev/null @@ -1,445 +0,0 @@ -// Copyright 2013 Daniel Parker -// Distributed under the Boost license, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -// See https://github.com/danielaparker/jsoncons for latest version - -#ifndef JSONCONS_CSV_CSV_SERIALIZER_HPP -#define JSONCONS_CSV_CSV_SERIALIZER_HPP - -#include <string> -#include <sstream> -#include <vector> -#include <ostream> -#include <cstdlib> -#include <map> -#include "jsoncons/jsoncons.hpp" -#include "jsoncons/output_format.hpp" -#include "jsoncons/json_output_handler.hpp" -#include <limits> // std::numeric_limits - -namespace jsoncons { namespace csv { - -template <typename CharT> -struct csv_char_traits -{ -}; - -template <> -struct csv_char_traits<char> -{ - static const std::string all_literal() {return "all";}; - - static const std::string minimal_literal() {return "minimal";}; - - static const std::string none_literal() {return "none";}; - - static const std::string nonnumeric_literal() {return "nonumeric";}; -}; - -template <> -struct csv_char_traits<wchar_t> -{ - static const std::wstring all_literal() {return L"all";}; - - static const std::wstring minimal_literal() {return L"minimal";}; - - static const std::wstring none_literal() {return L"none";}; - - static const std::wstring nonnumeric_literal() {return L"nonumeric";}; -}; - -template <typename CharT> -void escape_string(const CharT* s, - size_t length, - CharT quote_char, CharT quote_escape_char, - buffered_ostream<CharT>& os) -{ - const CharT* begin = s; - const CharT* end = s + length; - for (const CharT* it = begin; it != end; ++it) - { - CharT c = *it; - if (c == quote_char) - { - os.put(quote_escape_char); - os.put(quote_char); - } - else - { - os.put(c); - } - } -} - -template<typename CharT> -class basic_csv_serializer : public basic_json_output_handler<CharT> -{ - struct stack_item - { - stack_item(bool is_object) - : is_object_(is_object), count_(0), skip_(false) - { - } - bool is_object() const - { - return is_object_; - } - - bool is_object_; - size_t count_; - bool skip_; - }; - buffered_ostream<CharT> os_; - basic_csv_parameters<CharT> parameters_; - basic_output_format<CharT> format_; - std::vector<stack_item> stack_; - std::streamsize original_precision_; - std::ios_base::fmtflags original_format_flags_; - std::basic_ostringstream<CharT> header_oss_; - buffered_ostream<CharT> header_os_; - std::map<std::basic_string<CharT>,size_t> header_; - float_printer<CharT> fp_; -public: - basic_csv_serializer(std::basic_ostream<CharT>& os) - : - os_(os), - format_(), - stack_(), - original_precision_(), - original_format_flags_(), - header_os_(header_oss_), - header_(), - fp_(format_.precision()) - { - } - - basic_csv_serializer(std::basic_ostream<CharT>& os, - basic_csv_parameters<CharT> params) - : - os_(os), - parameters_(params), - format_(), - stack_(), - original_precision_(), - original_format_flags_(), - header_os_(header_oss_), - header_(), - fp_(format_.precision()) - { - } - - ~basic_csv_serializer() - { - } - -private: - - void do_begin_json() override - { - } - - void do_end_json() override - { - } - - void do_begin_object() override - { - stack_.push_back(stack_item(true)); - } - - void do_end_object() override - { - if (stack_.size() == 2) - { - os_.write(parameters_.line_delimiter()); - if (stack_[0].count_ == 0) - { - os_.write(header_oss_.str()); - os_.write(parameters_.line_delimiter()); - } - } - stack_.pop_back(); - - end_value(); - } - - void do_begin_array() override - { - stack_.push_back(stack_item(false)); - } - - void do_end_array() override - { - if (stack_.size() == 2) - { - os_.write(parameters_.line_delimiter()); - } - stack_.pop_back(); - - end_value(); - } - - void do_name(const CharT* name, size_t length) override - { - if (stack_.size() == 2) - { - if (stack_[0].count_ == 0) - { - if (stack_.back().count_ > 0) - { - os_.put(parameters_.field_delimiter()); - } - bool quote = false; - if (parameters_.quote_style() == quote_styles::all || parameters_.quote_style() == quote_styles::nonnumeric || - (parameters_.quote_style() == quote_styles::minimal && std::char_traits<CharT>::find(name,length,parameters_.field_delimiter()) != nullptr)) - { - quote = true; - os_.put(parameters_.quote_char()); - } - jsoncons::csv::escape_string<CharT>(name, length, parameters_.quote_char(), parameters_.quote_escape_char(), os_); - if (quote) - { - os_.put(parameters_.quote_char()); - } - header_[name] = stack_.back().count_; - } - else - { - typename std::map<std::basic_string<CharT>,size_t>::iterator it = header_.find(std::basic_string<CharT>(name,length)); - if (it == header_.end()) - { - stack_.back().skip_ = true; - //std::cout << " Not found "; - } - else - { - stack_.back().skip_ = false; - while (stack_.back().count_ < it->second) - { - os_.put(parameters_.field_delimiter()); - ++stack_.back().count_; - } - // std::cout << " (" << it->value() << " " << stack_.back().count_ << ") "; - } - } - } - } - - void do_null_value() override - { - if (stack_.size() == 2 && !stack_.back().skip_) - { - if (stack_.back().is_object() && stack_[0].count_ == 0) - { - do_null_value(header_os_); - } - else - { - do_null_value(os_); - } - } - } - - void do_string_value(const CharT* val, size_t length) override - { - if (stack_.size() == 2 && !stack_.back().skip_) - { - if (stack_.back().is_object() && stack_[0].count_ == 0) - { - value(val,length,header_os_); - } - else - { - value(val,length,os_); - } - } - } - - void do_double_value(double val, uint8_t precision) override - { - if (stack_.size() == 2 && !stack_.back().skip_) - { - if (stack_.back().is_object() && stack_[0].count_ == 0) - { - value(val,header_os_); - } - else - { - value(val,os_); - } - } - } - - void do_integer_value(int64_t val) override - { - if (stack_.size() == 2 && !stack_.back().skip_) - { - if (stack_.back().is_object() && stack_[0].count_ == 0) - { - value(val,header_os_); - } - else - { - value(val,os_); - } - } - } - - void do_uinteger_value(uint64_t val) override - { - if (stack_.size() == 2 && !stack_.back().skip_) - { - if (stack_.back().is_object() && stack_[0].count_ == 0) - { - value(val,header_os_); - } - else - { - value(val,os_); - } - } - } - - void do_bool_value(bool val) override - { - if (stack_.size() == 2 && !stack_.back().skip_) - { - if (stack_.back().is_object() && stack_[0].count_ == 0) - { - value(val,header_os_); - } - else - { - value(val,os_); - } - } - } - - void value(const CharT* val, size_t length, buffered_ostream<CharT>& os) - { - begin_value(os); - - bool quote = false; - if (parameters_.quote_style() == quote_styles::all || parameters_.quote_style() == quote_styles::nonnumeric || - (parameters_.quote_style() == quote_styles::minimal && std::char_traits<CharT>::find(val, length, parameters_.field_delimiter()) != nullptr)) - { - quote = true; - os.put(parameters_.quote_char()); - } - jsoncons::csv::escape_string<CharT>(val, length, parameters_.quote_char(), parameters_.quote_escape_char(), os); - if (quote) - { - os.put(parameters_.quote_char()); - } - - end_value(); - } - - void value(double val, buffered_ostream<CharT>& os) - { - begin_value(os); - - if (is_nan(val) && format_.replace_nan()) - { - os.write(format_.nan_replacement()); - } - else if (is_pos_inf(val) && format_.replace_pos_inf()) - { - os.write(format_.pos_inf_replacement()); - } - else if (is_neg_inf(val) && format_.replace_neg_inf()) - { - os.write(format_.neg_inf_replacement()); - } - //else if (format_.floatfield() != 0) - //{ - // std::basic_ostringstream<CharT> ss; - // ss.imbue(std::locale::classic()); - // ss.setf(format_.floatfield(), std::ios::floatfield); - // ss << std::showpoint << std::setprecision(format_.precision()) << val; - // os.write(ss.str()); - //} - else - { - fp_.print(val,format_.precision(),os); - } - - end_value(); - - } - - void value(int64_t val, buffered_ostream<CharT>& os) - { - begin_value(os); - - std::basic_ostringstream<CharT> ss; - ss << val; - os.write(ss.str()); - - end_value(); - } - - void value(uint64_t val, buffered_ostream<CharT>& os) - { - begin_value(os); - - std::basic_ostringstream<CharT> ss; - ss << val; - os.write(ss.str()); - - end_value(); - } - - void value(bool val, buffered_ostream<CharT>& os) - { - begin_value(os); - - if (val) - { - auto buf = json_literals<CharT>::true_literal(); - os.write(buf.first,buf.second); - } - else - { - auto buf = json_literals<CharT>::false_literal(); - os.write(buf.first,buf.second); - } - - end_value(); - } - - void do_null_value(buffered_ostream<CharT>& os) - { - begin_value(os); - auto buf = json_literals<CharT>::null_literal(); - os.write(buf.first,buf.second); - end_value(); - - } - - void begin_value(buffered_ostream<CharT>& os) - { - if (!stack_.empty()) - { - if (stack_.back().count_ > 0) - { - os.put(parameters_.field_delimiter()); - } - } - } - - void end_value() - { - if (!stack_.empty()) - { - ++stack_.back().count_; - } - } -}; - -typedef basic_csv_serializer<char> csv_serializer; - -}} - -#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/json_query.hpp b/vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/json_query.hpp deleted file mode 100644 index 7e530abd..00000000 --- a/vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/json_query.hpp +++ /dev/null @@ -1,921 +0,0 @@ -// Copyright 2013 Daniel Parker -// Distributed under the Boost license, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -// See https://github.com/danielaparker/jsoncons for latest version - -#ifndef JSONCONS_JSONPATH_JSONQUERY_HPP -#define JSONCONS_JSONPATH_JSONQUERY_HPP - -#include <string> -#include <sstream> -#include <vector> -#include <istream> -#include <cstdlib> -#include <memory> -#include "jsoncons/json.hpp" -#include "jsonpath_filter.hpp" -#include "jsonpath_error_category.hpp" - -namespace jsoncons { namespace jsonpath { - - template<typename CharT> - bool try_string_to_index(const CharT *s, size_t length, size_t* value) - { - static const size_t max_value = std::numeric_limits<size_t>::max JSONCONS_NO_MACRO_EXP(); - static const size_t max_value_div_10 = max_value / 10; - - size_t n = 0; - for (size_t i = 0; i < length; ++i) - { - CharT c = s[i]; - switch (c) - { - case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': - { - size_t x = c - '0'; - if (n > max_value_div_10) - { - return false; - } - n = n * 10; - if (n > max_value - x) - { - return false; - } - - n += x; - } - break; - default: - return false; - break; - } - } - *value = n; - return true; - } - - template <typename CharT> - struct json_jsonpath_traits - { - }; - - template <> - struct json_jsonpath_traits<char> - { - static const std::string length_literal() {return "length";}; - }; - - template <> - struct json_jsonpath_traits<wchar_t> // assume utf16 - { - static const std::wstring length_literal() {return L"length";}; - }; - -// here - -template<class JsonT> -JsonT json_query(const JsonT& root, const typename JsonT::char_type* path, size_t length) -{ - jsonpath_evaluator<JsonT> evaluator; - evaluator.evaluate(root,path,length); - return evaluator.get_values(); -} - -template<class JsonT> -JsonT json_query(const JsonT& root, const typename JsonT::string_type& path) -{ - return json_query(root,path.data(),path.length()); -} - -template<class JsonT> -JsonT json_query(const JsonT& root, const typename JsonT::char_type* path) -{ - return json_query(root,path,std::char_traits<typename JsonT::char_type>::length(path)); -} - -enum class states -{ - start, - cr, - lf, - expect_separator, - expect_unquoted_name, - unquoted_name, - single_quoted_name, - double_quoted_name, - left_bracket, - left_bracket_start, - left_bracket_end, - left_bracket_end2, - left_bracket_step, - left_bracket_step2, - expect_right_bracket, - dot -}; - -template<class JsonT> -class jsonpath_evaluator : private basic_parsing_context<typename JsonT::char_type> -{ -private: - typedef typename JsonT::char_type char_type; - typedef typename JsonT::string_type string_type; - typedef const JsonT* cjson_ptr; - typedef std::vector<cjson_ptr> node_set; - - basic_parse_error_handler<char_type> *err_handler_; - states state_; - string_type buffer_; - size_t start_; - size_t end_; - size_t step_; - bool positive_start_; - bool positive_end_; - bool positive_step_; - bool end_undefined_; - std::vector<node_set> stack_; - bool recursive_descent_; - std::vector<cjson_ptr> nodes_; - std::vector<std::shared_ptr<JsonT>> temp_; - size_t line_; - size_t column_; - const char_type* begin_input_; - const char_type* end_input_; - const char_type* p_; - states pre_line_break_state_; - - void transfer_nodes() - { - stack_.push_back(nodes_); - nodes_.clear(); - } - -public: - jsonpath_evaluator() - : err_handler_(std::addressof(basic_default_parse_error_handler<char_type>::instance())) - { - } - - JsonT get_values() const - { - JsonT result = JsonT::make_array(); - - if (stack_.size() > 0) - { - for (size_t i = 0; i < stack_.back().size(); ++i) - { - cjson_ptr p = stack_.back()[i]; - result.add(*p); - } - } - return result; - } - - void evaluate(const JsonT& root, const string_type& path) - { - evaluate(root,path.data(),path.length()); - } - void evaluate(const JsonT& root, const char_type* path) - { - evaluate(root,path,std::char_traits<char_type>::length(path)); - } - - void evaluate(const JsonT& root, const char_type* path, size_t length) - { - begin_input_ = path; - end_input_ = path + length; - p_ = begin_input_; - - line_ = 1; - column_ = 1; - state_ = states::start; - buffer_.clear(); - start_ = 0; - end_ = 0; - step_ = 1; - recursive_descent_ = false; - positive_start_ = true; - positive_end_ = true; - positive_step_ = true; - end_undefined_ = false; - - while (p_ < end_input_) - { - switch (state_) - { - case states::cr: - ++line_; - column_ = 1; - switch (*p_) - { - case '\n': - state_ = pre_line_break_state_; - ++p_; - ++column_; - break; - default: - state_ = pre_line_break_state_; - break; - } - break; - case states::lf: - ++line_; - column_ = 1; - state_ = pre_line_break_state_; - break; - case states::start: - switch (*p_) - { - case '\r': - pre_line_break_state_ = state_; - state_ = states::cr; - break; - case '\n': - pre_line_break_state_ = state_; - state_ = states::lf; - break; - case ' ':case '\t': - ++p_; - ++column_; - break; - case '$': - case '@': - { - node_set v; - v.push_back(std::addressof(root)); - stack_.push_back(v); - state_ = states::expect_separator; - } - break; - default: - err_handler_->fatal_error(std::error_code(jsonpath_parser_errc::expected_root, jsonpath_error_category()), *this); - break; - }; - ++p_; - ++column_; - break; - case states::dot: - switch (*p_) - { - case '.': - recursive_descent_ = true; - ++p_; - ++column_; - state_ = states::expect_unquoted_name; - break; - default: - state_ = states::expect_unquoted_name; - break; - } - break; - case states::expect_unquoted_name: - switch (*p_) - { - case '\r': - pre_line_break_state_ = state_; - state_ = states::cr; - break; - case '\n': - pre_line_break_state_ = state_; - state_ = states::lf; - break; - case '.': - err_handler_->fatal_error(std::error_code(jsonpath_parser_errc::expected_name, jsonpath_error_category()), *this); - ++p_; - ++column_; - break; - case '*': - end_all(); - transfer_nodes(); - state_ = states::expect_separator; - ++p_; - ++column_; - break; - default: - state_ = states::unquoted_name; - break; - } - break; - case states::expect_separator: - switch (*p_) - { - case '\r': - pre_line_break_state_ = state_; - state_ = states::cr; - break; - case '\n': - pre_line_break_state_ = state_; - state_ = states::lf; - break; - case ' ':case '\t': - ++p_; - ++column_; - break; - case '.': - state_ = states::dot; - break; - case '[': - state_ = states::left_bracket; - break; - default: - err_handler_->fatal_error(std::error_code(jsonpath_parser_errc::expected_separator, jsonpath_error_category()), *this); - break; - }; - ++p_; - ++column_; - break; - case states::expect_right_bracket: - switch (*p_) - { - case '\r': - pre_line_break_state_ = state_; - state_ = states::cr; - break; - case '\n': - pre_line_break_state_ = state_; - state_ = states::lf; - break; - case ',': - state_ = states::left_bracket; - break; - case ']': - transfer_nodes(); - state_ = states::expect_separator; - break; - case ' ':case '\t': - break; - default: - err_handler_->fatal_error(std::error_code(jsonpath_parser_errc::expected_right_bracket, jsonpath_error_category()), *this); - break; - } - ++p_; - ++column_; - break; - case states::left_bracket_step: - switch (*p_) - { - case '\r': - pre_line_break_state_ = state_; - state_ = states::cr; - break; - case '\n': - pre_line_break_state_ = state_; - state_ = states::lf; - break; - case '-': - positive_step_ = false; - state_ = states::left_bracket_step2; - break; - case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': - step_ = static_cast<size_t>(*p_-'0'); - state_ = states::left_bracket_step2; - break; - case ']': - end_array_slice(); - transfer_nodes(); - state_ = states::expect_separator; - break; - } - ++p_; - ++column_; - break; - case states::left_bracket_step2: - switch (*p_) - { - case '\r': - pre_line_break_state_ = state_; - state_ = states::cr; - break; - case '\n': - pre_line_break_state_ = state_; - state_ = states::lf; - break; - case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': - step_ = step_*10 + static_cast<size_t>(*p_-'0'); - break; - case ']': - end_array_slice(); - transfer_nodes(); - state_ = states::expect_separator; - break; - } - ++p_; - ++column_; - break; - case states::left_bracket_end: - switch (*p_) - { - case '\r': - pre_line_break_state_ = state_; - state_ = states::cr; - break; - case '\n': - pre_line_break_state_ = state_; - state_ = states::lf; - break; - case '-': - positive_end_ = false; - state_ = states::left_bracket_end2; - break; - case ':': - step_ = 0; - state_ = states::left_bracket_step; - break; - case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': - end_undefined_ = false; - end_ = static_cast<size_t>(*p_-'0'); - state_ = states::left_bracket_end2; - break; - case ']': - end_array_slice(); - transfer_nodes(); - state_ = states::expect_separator; - break; - } - ++p_; - ++column_; - break; - case states::left_bracket_end2: - switch (*p_) - { - case '\r': - pre_line_break_state_ = state_; - state_ = states::cr; - break; - case '\n': - pre_line_break_state_ = state_; - state_ = states::lf; - break; - case ':': - step_ = 0; - state_ = states::left_bracket_step; - break; - case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': - end_undefined_ = false; - end_ = end_*10 + static_cast<size_t>(*p_-'0'); - break; - case ']': - end_array_slice(); - transfer_nodes(); - state_ = states::expect_separator; - break; - } - ++p_; - ++column_; - break; - case states::left_bracket_start: - switch (*p_) - { - case '\r': - pre_line_break_state_ = state_; - state_ = states::cr; - break; - case '\n': - pre_line_break_state_ = state_; - state_ = states::lf; - break; - case ':': - step_ = 1; - end_undefined_ = true; - state_ = states::left_bracket_end; - break; - case ',': - find_elements(); - break; - case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': - start_ = start_*10 + static_cast<size_t>(*p_-'0'); - break; - case ']': - find_elements(); - transfer_nodes(); - state_ = states::expect_separator; - break; - } - ++p_; - ++column_; - break; - case states::left_bracket: - switch (*p_) - { - case '\r': - pre_line_break_state_ = state_; - state_ = states::cr; - break; - case '\n': - pre_line_break_state_ = state_; - state_ = states::lf; - break; - case ' ':case '\t': - ++p_; - ++column_; - break; - case '(': - { - if (stack_.back().size() == 1) - { - jsonpath_filter_parser<JsonT> parser(&p_,&line_,&column_); - parser.parse(p_,end_input_); - auto index = parser.eval(*(stack_.back()[0])); - if (index.template is<size_t>()) - { - start_ = index. template as<size_t>(); - find_elements(); - } - else if (index.is_string()) - { - find(index.as_string()); - } - } - else - { - ++p_; - ++column_; - } - } - break; - case '?': - { - jsonpath_filter_parser<JsonT> parser(&p_,&line_,&column_); - parser.parse(p_,end_input_); - nodes_.clear(); - for (size_t j = 0; j < stack_.back().size(); ++j) - { - accept(*(stack_.back()[j]),parser); - } - } - break; - - case ':': - step_ = 1; - end_undefined_ = true; - state_ = states::left_bracket_end; - ++p_; - ++column_; - break; - case ',': - find_elements(); - ++p_; - ++column_; - break; - case '-': - positive_start_ = false; - state_ = states::left_bracket_start; - ++p_; - ++column_; - break; - case '0':case '1':case '2':case '3':case '4':case '5':case '6':case '7':case '8':case '9': - start_ = static_cast<size_t>(*p_-'0'); - state_ = states::left_bracket_start; - ++p_; - ++column_; - break; - case ']': - //find_elements(); - transfer_nodes(); - state_ = states::expect_separator; - ++p_; - ++column_; - break; - case '*': - end_all(); - //transfer_nodes(); - state_ = states::expect_right_bracket; - ++p_; - ++column_; - break; - case '\'': - state_ = states::single_quoted_name; - ++p_; - ++column_; - break; - case '\"': - state_ = states::double_quoted_name; - ++p_; - ++column_; - break; - default: - ++p_; - ++column_; - break; - } - break; - case states::unquoted_name: - switch (*p_) - { - case '\r': - pre_line_break_state_ = state_; - state_ = states::cr; - break; - case '\n': - pre_line_break_state_ = state_; - state_ = states::lf; - break; - case '[': - find(buffer_); - buffer_.clear(); - transfer_nodes(); - start_ = 0; - state_ = states::left_bracket; - break; - case '.': - find(buffer_); - buffer_.clear(); - transfer_nodes(); - state_ = states::dot; - break; - case ' ':case '\t': - break; - default: - buffer_.push_back(*p_); - break; - }; - ++p_; - ++column_; - break; - case states::single_quoted_name: - switch (*p_) - { - case '\'': - find(buffer_); - buffer_.clear(); - state_ = states::expect_right_bracket; - break; - case '\\': - buffer_.push_back(*p_); - if (p_+1 < end_input_) - { - ++p_; - ++column_; - buffer_.push_back(*p_); - } - break; - default: - buffer_.push_back(*p_); - break; - }; - ++p_; - ++column_; - break; - case states::double_quoted_name: - switch (*p_) - { - case '\"': - find(buffer_); - buffer_.clear(); - state_ = states::expect_right_bracket; - break; - case '\\': - buffer_.push_back(*p_); - if (p_+1 < end_input_) - { - ++p_; - ++column_; - buffer_.push_back(*p_); - } - break; - default: - buffer_.push_back(*p_); - break; - }; - ++p_; - ++column_; - break; - default: - ++p_; - ++column_; - break; - } - } - switch (state_) - { - case states::unquoted_name: - { - find(buffer_); - buffer_.clear(); - transfer_nodes(); - } - break; - default: - break; - } - } - - void accept(const JsonT& val, - jsonpath_filter_parser<JsonT>& filter) - { - if (val.is_object()) - { - if (recursive_descent_ && val.is_object()) - { - for (auto it = val.members().begin(); it != val.members().end(); ++it) - { - accept(it->value(),filter); - } - } - if (filter.exists(val)) - { - nodes_.push_back(std::addressof(val)); - } - } - else if (val.is_array()) - { - for (auto it = val.elements().begin(); it != val.elements().end(); ++it) - { - accept(*it,filter); - } - } - } - - - - void end_all() - { - for (size_t i = 0; i < stack_.back().size(); ++i) - { - cjson_ptr p = stack_.back()[i]; - if (p->is_array()) - { - for (auto it = p->elements().begin(); it != p->elements().end(); ++it) - { - nodes_.push_back(std::addressof(*it)); - } - } - else if (p->is_object()) - { - for (auto it = p->members().begin(); it != p->members().end(); ++it) - { - nodes_.push_back(std::addressof(it->value())); - } - } - - } - start_ = 0; - } - - void find_elements() - { - for (size_t i = 0; i < stack_.back().size(); ++i) - { - cjson_ptr p = stack_.back()[i]; - if (p->is_array() && start_ < p->size()) - { - nodes_.push_back(std::addressof((*p)[start_])); - } - } - start_ = 0; - } - - void end_array_slice() - { - if (positive_step_) - { - end_array_slice1(); - } - else - { - end_array_slice2(); - } - start_ = 0; - end_ = 0; - step_ = 1; - positive_start_ = positive_end_ = positive_step_ = true; - end_undefined_ = true; - } - - void end_array_slice1() - { - for (size_t i = 0; i < stack_.back().size(); ++i) - { - cjson_ptr p = stack_.back()[i]; - if (p->is_array()) - { - size_t start = positive_start_ ? start_ : p->size() - start_; - size_t end; - if (!end_undefined_) - { - end = positive_end_ ? end_ : p->size() - end_; - } - else - { - end = p->size(); - } - for (size_t j = start; j < end; j += step_) - { - if (p->is_array() && j < p->size()) - { - nodes_.push_back(std::addressof((*p)[j])); - } - } - } - } - } - - void end_array_slice2() - { - for (size_t i = 0; i < stack_.back().size(); ++i) - { - cjson_ptr p = stack_.back()[i]; - size_t start = positive_start_ ? start_ : p->size() - start_; - size_t end; - if (!end_undefined_) - { - end = positive_end_ ? end_ : p->size() - end_; - } - else - { - end = p->size(); - } - - size_t j = end + step_ - 1; - while (j > (start+step_-1)) - { - j -= step_; - if (p->is_array() && j < p->size()) - { - nodes_.push_back(std::addressof((*p)[j])); - } - } - } - } - - void find(const string_type& name) - { - if (name.length() > 0) - { - for (size_t i = 0; i < stack_.back().size(); ++i) - { - find1(*(stack_.back()[i]), name); - } - recursive_descent_ = false; - } - } - - void find1(const JsonT& context_val, const string_type& name) - { - if (context_val.is_object()) - { - if (context_val.count(name) > 0) - { - nodes_.push_back(std::addressof(context_val.at(name))); - } - if (recursive_descent_) - { - for (auto it = context_val.members().begin(); it != context_val.members().end(); ++it) - { - if (it->value().is_object() || it->value().is_array()) - { - find1(it->value(), name); - } - } - } - } - else if (context_val.is_array()) - { - size_t index = 0; - if (try_string_to_index(name.data(),name.size(),&index)) - { - if (index < context_val.size()) - { - nodes_.push_back(std::addressof(context_val[index])); - } - } - else if (name == json_jsonpath_traits<char_type>::length_literal() && context_val.size() > 0) - { - auto q = std::make_shared<JsonT>(context_val.size()); - temp_.push_back(q); - nodes_.push_back(q.get()); - } - if (recursive_descent_) - { - for (auto it = context_val.elements().begin(); it != context_val.elements().end(); ++it) - { - if (it->is_object() || it->is_array()) - { - find1(*it, name); - } - } - } - } - } - - size_t do_line_number() const override - { - return line_; - } - - size_t do_column_number() const override - { - return column_; - } - - char_type do_current_char() const override - { - return 0; //p_ < end_input_? *p_ : 0; - } - -}; - -}} - -#endif diff --git a/vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/jsonpath_filter.hpp b/vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/jsonpath_filter.hpp deleted file mode 100644 index b0ac51c6..00000000 --- a/vendor/jsoncons-0.99.2/jsoncons_ext/jsonpath/jsonpath_filter.hpp +++ /dev/null @@ -1,1495 +0,0 @@ -// Copyright 2013 Daniel Parker -// Distributed under the Boost license, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - -// See https://github.com/danielaparker/jsoncons for latest version - -#ifndef JSONCONS_JSONPATH_FILTER_HPP -#define JSONCONS_JSONPATH_FILTER_HPP - -#include <string> -#include <sstream> -#include <vector> -#include <istream> -#include <cstdlib> -#include <memory> -#include <regex> -#include "jsoncons/json.hpp" -#include "jsonpath_error_category.hpp" - -namespace jsoncons { namespace jsonpath { - -template <class JsonT> -class jsonpath_evaluator; - -enum class filter_states -{ - start, - cr, - lf, - expect_right_round_bracket, - expect_oper_or_right_round_bracket, - expect_path_or_value, - expect_regex, - regex, - single_quoted_text, - double_quoted_text, - unquoted_text, - path, - value, - oper -}; - -enum class token_types -{ - left_paren, - right_paren, - term, - eq, - ne, - regex, - ampamp, - pipepipe, - lt, - gt, - lte, - gte, - plus, - minus, - exclaim, - done -}; - -template <class JsonT> -class term -{ -public: - typedef typename JsonT::string_type string_type; - typedef typename JsonT::char_type char_type; - - virtual void initialize(const JsonT& context_node) - { - } - virtual bool accept_single_node() const - { - throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); - } - virtual JsonT evaluate_single_node() const - { - throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); - } - virtual bool exclaim() const - { - throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); - } - virtual bool eq(const term& rhs) const - { - throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); - } - virtual bool eq(const JsonT& rhs) const - { - throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); - } - virtual bool ne(const term& rhs) const - { - throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); - } - virtual bool ne(const JsonT& rhs) const - { - throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); - } - virtual bool regex(const term& rhs) const - { - throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); - } - virtual bool regex2(const string_type& subject) const - { - throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); - } - virtual bool ampamp(const term& rhs) const - { - throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); - } - virtual bool ampamp(const JsonT& rhs) const - { - throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); - } - virtual bool pipepipe(const term& rhs) const - { - throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); - } - virtual bool pipepipe(const JsonT& rhs) const - { - throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); - } - virtual bool lt(const term& rhs) const - { - throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); - } - virtual bool lt(const JsonT& rhs) const - { - throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); - } - virtual bool gt(const term& rhs) const - { - throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); - } - virtual bool gt(const JsonT& rhs) const - { - throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); - } - virtual JsonT minus(const term& rhs) const - { - throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); - } - virtual JsonT minus(const JsonT& rhs) const - { - throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); - } - virtual JsonT unary_minus() const - { - throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); - } - virtual JsonT plus(const term& rhs) const - { - throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); - } - virtual JsonT plus(const JsonT& rhs) const - { - throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unsupported_operator, jsonpath_error_category()),1,1); - } -}; - -template <class JsonT> -class token -{ - token_types type_; - std::shared_ptr<term<JsonT>> term_ptr_; -public: - token(token_types type) - : type_(type) - { - } - token(token_types type, std::shared_ptr<term<JsonT>> term_ptr) - : type_(type), term_ptr_(term_ptr) - { - } - token(const token& t) - : type_(t.type_), term_ptr_(t.term_ptr_) - { - } - - token_types type() const - { - return type_; - } - - std::shared_ptr<term<JsonT>> term_ptr() - { - return term_ptr_; - } - - void initialize(const JsonT& context_node) - { - if (term_ptr_.get() != nullptr) - { - term_ptr_->initialize(context_node); - } - } -}; - -template <class JsonT> -class token_stream -{ - std::vector<token<JsonT>>& tokens_; - size_t index_; -public: - token_stream(std::vector<token<JsonT>>& tokens) - : tokens_(tokens), index_(0) - { - } - - token<JsonT> get() - { - static token<JsonT> done = token<JsonT>(token_types::done); - return index_ < tokens_.size() ? tokens_[index_++] : done; - } - void putback() - { - --index_; - } -}; - -template <class JsonT> -bool ampamp(const JsonT& lhs, const JsonT& rhs) -{ - return lhs.as_bool() && rhs.as_bool(); -} - -template <class JsonT> -bool pipepipe(const JsonT& lhs, const JsonT& rhs) -{ - return lhs.as_bool() || rhs.as_bool(); -} - -template <class JsonT> -bool lt(const JsonT& lhs, const JsonT& rhs) -{ - bool result = false; - if (lhs. template is<unsigned long long>() && rhs. template is<unsigned long long>()) - { - result = lhs. template as<unsigned long long>() < rhs. template as<unsigned long long>(); - } - else if (lhs. template is<long long>() && rhs. template is<long long>()) - { - result = lhs. template as<long long>() < rhs. template as<long long>(); - } - else if ((lhs.is_number() && rhs.is_double()) || (lhs.is_double() && rhs.is_number())) - { - result = lhs.as_double() < rhs.as_double(); - } - else if (lhs.is_string() && rhs.is_string()) - { - result = lhs.as_string() < rhs.as_string(); - } - return result; -} - -template <class JsonT> -bool gt(const JsonT& lhs, const JsonT& rhs) -{ - return lt(rhs,lhs); -} - -template <class JsonT> -JsonT plus(const JsonT& lhs, const JsonT& rhs) -{ - JsonT result = jsoncons::null_type(); - if (lhs.is_integer() && rhs.is_integer()) - { - result = ((lhs.as_integer() + rhs.as_integer())); - } - else if ((lhs.is_number() && rhs.is_double()) || (lhs.is_double() && rhs.is_number())) - { - result = (lhs.as_double() + rhs.as_double()); - } - else if (lhs.is_uinteger() && rhs.is_uinteger()) - { - result = (lhs.as_uinteger() + rhs.as_uinteger()); - } - return result; -} - -template <class JsonT> -JsonT unary_minus(const JsonT& lhs) -{ - JsonT result = jsoncons::null_type(); - if (lhs.is_integer()) - { - result = -lhs.as_integer(); - } - else if (lhs.is_double()) - { - result = -lhs.as_double(); - } - return result; -} - -template <class JsonT> -JsonT minus(const JsonT& lhs, const JsonT& rhs) -{ - JsonT result = jsoncons::null_type(); - if (lhs.is_integer() && rhs.is_integer()) - { - result = ((lhs.as_integer() - rhs.as_integer())); - } - else if ((lhs.is_number() && rhs.is_double()) || (lhs.is_double() && rhs.is_number())) - { - result = (lhs.as_double() - rhs.as_double()); - } - else if (lhs.is_uinteger() && rhs.is_uinteger() && lt(rhs,lhs)) - { - result = (lhs.as_uinteger() - rhs.as_uinteger()); - } - return result; -} - -template <class JsonT> -class value_term : public term<JsonT> -{ - JsonT value_; -public: - template <class T> - value_term(const T& value) - : value_(value) - { - } - - bool accept_single_node() const override - { - return value_.as_bool(); - } - - JsonT evaluate_single_node() const override - { - return value_; - } - - bool exclaim() const override - { - return !value_.as_bool(); - } - - bool eq(const term<JsonT>& rhs) const override - { - return rhs.eq(value_); - } - - bool eq(const JsonT& rhs) const override - { - return value_ == rhs; - } - - bool ne(const term<JsonT>& rhs) const override - { - return rhs.ne(value_); - } - bool ne(const JsonT& rhs) const override - { - return value_ != rhs; - } - bool regex(const term<JsonT>& rhs) const override - { - return rhs.regex2(value_.as_string()); - } - bool ampamp(const term<JsonT>& rhs) const override - { - return rhs.ampamp(value_); - } - bool ampamp(const JsonT& rhs) const override - { - return jsoncons::jsonpath::ampamp(value_,rhs); - } - bool pipepipe(const term<JsonT>& rhs) const override - { - return rhs.pipepipe(value_); - } - bool pipepipe(const JsonT& rhs) const override - { - return jsoncons::jsonpath::pipepipe(value_,rhs); - } - - bool lt(const term<JsonT>& rhs) const override - { - return rhs.gt(value_); - } - - bool lt(const JsonT& rhs) const override - { - return jsoncons::jsonpath::lt(value_,rhs); - } - - bool gt(const term<JsonT>& rhs) const override - { - return rhs.lt(value_); - } - - bool gt(const JsonT& rhs) const override - { - return jsoncons::jsonpath::gt(value_,rhs); - } - - JsonT minus(const term<JsonT>& rhs) const override - { - return jsoncons::jsonpath::plus(rhs.unary_minus(),value_); - } - - JsonT minus(const JsonT& rhs) const override - { - return jsoncons::jsonpath::minus(value_,rhs); - } - - JsonT unary_minus() const override - { - return jsoncons::jsonpath::unary_minus(value_); - } - - JsonT plus(const term<JsonT>& rhs) const override - { - return rhs.plus(value_); - } - - JsonT plus(const JsonT& rhs) const override - { - return jsoncons::jsonpath::plus(value_,rhs); - } -}; - -template <class JsonT> -class regex_term : public term<JsonT> -{ - typedef typename JsonT::char_type char_type; - typedef typename JsonT::string_type string_type; - string_type pattern_; - std::regex::flag_type flags_; -public: - regex_term(const string_type& pattern, std::regex::flag_type flags) - : pattern_(pattern), flags_(flags) - { - } - - bool regex2(const string_type& subject) const override - { - std::basic_regex<char_type> pattern(pattern_, - flags_); - return std::regex_match(subject, pattern); - } -}; - -template <class JsonT> -class path_term : public term<JsonT> -{ - typedef typename JsonT::string_type string_type; - - string_type path_; - JsonT nodes_; -public: - path_term(const string_type& path) - : path_(path) - { - } - - void initialize(const JsonT& context_node) override - { - jsonpath_evaluator<JsonT> evaluator; - evaluator.evaluate(context_node,path_); - nodes_ = evaluator.get_values(); - } - - bool accept_single_node() const override - { - return nodes_.size() != 0; - } - - JsonT evaluate_single_node() const override - { - return nodes_.size() == 1 ? nodes_[0] : nodes_; - } - - bool exclaim() const override - { - return nodes_.size() == 0; - } - - bool eq(const term<JsonT>& rhs) const override - { - bool result = false; - if (nodes_.size() > 0) - { - result = true; - for (size_t i = 0; result && i < nodes_.size(); ++i) - { - result = rhs.eq(nodes_[i]); - } - } - return result; - } - - bool eq(const JsonT& rhs) const override - { - bool result = false; - if (nodes_.size() > 0) - { - result = true; - for (size_t i = 0; result && i < nodes_.size(); ++i) - { - result = nodes_[i] == rhs; - } - } - return result; - } - - bool ne(const term<JsonT>& rhs) const override - { - bool result = false; - if (nodes_.size() > 0) - { - result = true; - for (size_t i = 0; result && i < nodes_.size(); ++i) - { - result = rhs.ne(nodes_[i]); - } - } - return result; - - } - bool ne(const JsonT& rhs) const override - { - bool result = false; - if (nodes_.size() > 0) - { - result = true; - for (size_t i = 0; result && i < nodes_.size(); ++i) - { - result = nodes_[i] != rhs; - } - } - return result; - } - bool regex(const term<JsonT>& rhs) const override - { - bool result = false; - if (nodes_.size() > 0) - { - result = true; - for (size_t i = 0; result && i < nodes_.size(); ++i) - { - result = rhs.regex2(nodes_[i].as_string()); - } - } - return result; - } - bool ampamp(const term<JsonT>& rhs) const override - { - bool result = false; - if (nodes_.size() > 0) - { - result = true; - for (size_t i = 0; result && i < nodes_.size(); ++i) - { - result = rhs.ampamp(nodes_[i]); - } - } - return result; - } - bool ampamp(const JsonT& rhs) const override - { - bool result = false; - if (nodes_.size() > 0) - { - result = true; - for (size_t i = 0; result && i < nodes_.size(); ++i) - { - result = jsoncons::jsonpath::ampamp(nodes_[i],rhs); - } - } - return result; - } - bool pipepipe(const term<JsonT>& rhs) const override - { - bool result = false; - if (nodes_.size() > 0) - { - result = true; - for (size_t i = 0; result && i < nodes_.size(); ++i) - { - result = rhs.pipepipe(nodes_[i]); - } - } - return result; - } - bool pipepipe(const JsonT& rhs) const override - { - bool result = false; - if (nodes_.size() > 0) - { - result = true; - for (size_t i = 0; result && i < nodes_.size(); ++i) - { - result = jsoncons::jsonpath::pipepipe(nodes_[i],rhs); - } - } - return result; - } - - bool lt(const JsonT& rhs) const override - { - bool result = false; - if (nodes_.size() > 0) - { - result = true; - for (size_t i = 0; result && i < nodes_.size(); ++i) - { - result = jsoncons::jsonpath::lt(nodes_[i],rhs); - } - } - return result; - } - - bool lt(const term<JsonT>& rhs) const override - { - bool result = false; - if (nodes_.size() > 0) - { - result = true; - for (size_t i = 0; result && i < nodes_.size(); ++i) - { - result = rhs.gt(nodes_[i]); - } - } - return result; - } - - bool gt(const JsonT& rhs) const override - { - bool result = false; - if (nodes_.size() > 0) - { - result = true; - for (size_t i = 0; result && i < nodes_.size(); ++i) - { - result = jsoncons::jsonpath::gt(nodes_[i],rhs); - } - } - return result; - } - - bool gt(const term<JsonT>& rhs) const override - { - bool result = false; - if (nodes_.size() > 0) - { - result = true; - for (size_t i = 0; result && i < nodes_.size(); ++i) - { - result = rhs.lt(nodes_[i]); - } - } - return result; - } - - JsonT minus(const JsonT& rhs) const override - { - return nodes_.size() == 1 ? jsoncons::jsonpath::minus(nodes_[0],rhs) : jsoncons::null_type(); - } - - JsonT minus(const term<JsonT>& rhs) const override - { - - return nodes_.size() == 1 ? jsoncons::jsonpath::plus(rhs.unary_minus(),nodes_[0]) : jsoncons::null_type(); - } - - JsonT unary_minus() const override - { - return nodes_.size() == 1 ? jsoncons::jsonpath::unary_minus(nodes_[0]) : jsoncons::null_type(); - } - - JsonT plus(const JsonT& rhs) const override - { - static auto a_null = jsoncons::null_type(); - return nodes_.size() == 1 ? jsoncons::jsonpath::plus(nodes_[0],rhs) : a_null; - } - - JsonT plus(const term<JsonT>& rhs) const override - { - static auto a_null = jsoncons::null_type(); - return nodes_.size() == 1 ? rhs.plus(nodes_[0]) : a_null; - } -}; - -template <class JsonT> -class jsonpath_filter_parser -{ - typedef typename JsonT::string_type string_type; - typedef typename JsonT::char_type char_type; - - size_t& line_; - size_t& column_; - filter_states state_; - string_type buffer_; - std::vector<token<JsonT>> tokens_; - int depth_; - const char_type* begin_input_; - const char_type* end_input_; - const char_type*& p_; - filter_states pre_line_break_state_; -public: - jsonpath_filter_parser(const char_type** expr, size_t* line,size_t* column) - : line_(*line), column_(*column),p_(*expr) - { - } - - bool exists(const JsonT& context_node) - { - for (auto it=tokens_.begin(); it != tokens_.end(); ++it) - { - it->initialize(context_node); - } - bool result = false; - - token_stream<JsonT> ts(tokens_); - auto e = expression(ts); - result = e->accept_single_node(); - - return result; - } - - JsonT eval(const JsonT& context_node) - { - try - { - for (auto it=tokens_.begin(); it != tokens_.end(); ++it) - { - it->initialize(context_node); - } - - token_stream<JsonT> ts(tokens_); - auto e = expression(ts); - JsonT result = e->evaluate_single_node(); - - return result; - } - catch (const parse_exception& e) - { - throw parse_exception(e.code(),line_,column_); - } - } - - std::shared_ptr<term<JsonT>> primary(token_stream<JsonT>& ts) - { - auto t = ts.get(); - - switch (t.type()) - { - case token_types::left_paren: - { - auto expr = expression(ts); - t = ts.get(); - if (t.type() != token_types::right_paren) - { - throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_expected_right_brace, jsonpath_error_category()),line_,column_); - } - return expr; - } - case token_types::term: - return t.term_ptr(); - case token_types::exclaim: - { - JsonT val = primary(ts)->exclaim(); - auto expr = std::make_shared<value_term<JsonT>>(val); - return expr; - } - case token_types::minus: - { - JsonT val = primary(ts)->unary_minus(); - auto expr = std::make_shared<value_term<JsonT>>(val); - return expr; - } - default: - throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_expected_primary, jsonpath_error_category()),line_,column_); - } - } - - std::shared_ptr<term<JsonT>> expression(token_stream<JsonT>& ts) - { - auto left = make_term(ts); - auto t = ts.get(); - while (true) - { - switch (t.type()) - { - case token_types::plus: - { - JsonT val = left->plus(*(make_term(ts))); - left = std::make_shared<value_term<JsonT>>(val); - t = ts.get(); - } - break; - case token_types::minus: - { - JsonT val = left->minus(*(make_term(ts))); - left = std::make_shared<value_term<JsonT>>(val); - t = ts.get(); - } - break; - default: - ts.putback(); - return left; - } - } - return left; - } - - std::shared_ptr<term<JsonT>> make_term(token_stream<JsonT>& ts) - { - auto left = primary(ts); - auto t = ts.get(); - while (true) - { - switch (t.type()) - { - case token_types::eq: - { - bool e = left->eq(*(primary(ts))); - JsonT val(e); - left = std::make_shared<value_term<JsonT>>(val); - t = ts.get(); - } - break; - case token_types::ne: - { - bool e = left->ne(*(primary(ts))); - JsonT val(e); - left = std::make_shared<value_term<JsonT>>(val); - t = ts.get(); - } - break; - case token_types::regex: - { - bool e = left->regex(*(primary(ts))); - JsonT val(e); - left = std::make_shared<value_term<JsonT>>(val); - t = ts.get(); - } - break; - case token_types::ampamp: - { - bool e = left->ampamp(*(primary(ts))); - JsonT val(e); - left = std::make_shared<value_term<JsonT>>(val); - t = ts.get(); - } - break; - case token_types::pipepipe: - { - bool e = left->pipepipe(*(primary(ts))); - JsonT val(e); - left = std::make_shared<value_term<JsonT>>(val); - t = ts.get(); - } - break; - case token_types::lt: - { - bool e = left->lt(*(primary(ts))); - JsonT val(e); - left = std::make_shared<value_term<JsonT>>(val); - t = ts.get(); - } - break; - case token_types::gt: - { - bool e = left->gt(*(primary(ts))); - JsonT val(e); - left = std::make_shared<value_term<JsonT>>(val); - t = ts.get(); - } - break; - case token_types::lte: - { - bool e = left->lt(*(primary(ts))) || left->eq(*(primary(ts))); - JsonT val(e); - left = std::make_shared<value_term<JsonT>>(val); - t = ts.get(); - } - break; - case token_types::gte: - { - bool e = left->gt(*(primary(ts))) || left->eq(*(primary(ts))); - JsonT val(e); - left = std::make_shared<value_term<JsonT>>(val); - t = ts.get(); - } - break; - default: - ts.putback(); - return left; - } - } - } - - void parse(const char_type* expr, size_t length) - { - parse(expr,expr+length); - } - - void parse(const char_type* expr, const char_type* end_expr) - { - p_ = expr; - end_input_ = end_expr; - depth_ = 0; - tokens_.clear(); - state_ = filter_states::start; - bool done = false; - while (!done && p_ < end_input_) - { - switch (state_) - { - case filter_states::cr: - ++line_; - column_ = 1; - switch (*p_) - { - case '\n': - state_ = pre_line_break_state_; - ++p_; - ++column_; - break; - default: - state_ = pre_line_break_state_; - break; - } - break; - case filter_states::lf: - ++line_; - column_ = 1; - state_ = pre_line_break_state_; - break; - case filter_states::start: - switch (*p_) - { - case '\r': - case '\n': - pre_line_break_state_ = state_; - state_ = filter_states::lf; - break; - case '(': - state_ = filter_states::expect_path_or_value; - ++depth_; - tokens_.push_back(token<JsonT>(token_types::left_paren)); - break; - case ')': - tokens_.push_back(token<JsonT>(token_types::right_paren)); - if (--depth_ == 0) - { - done = true; - } - break; - } - ++p_; - ++column_; - break; - case filter_states::oper: - switch (*p_) - { - case '\r': - case '\n': - ++line_; - column_ = 1; - state_ = pre_line_break_state_; - break; - case '!': - if (p_+1 < end_input_ && *(p_+1) == '=') - { - ++p_; - ++column_; - state_ = filter_states::expect_path_or_value; - tokens_.push_back(token<JsonT>(token_types::ne)); - } - else - { - state_ = filter_states::expect_path_or_value; - tokens_.push_back(token<JsonT>(token_types::exclaim)); - } - break; - case '&': - if (p_+1 < end_input_ && *(p_+1) == '&') - { - ++p_; - ++column_; - state_ = filter_states::expect_path_or_value; - tokens_.push_back(token<JsonT>(token_types::ampamp)); - } - break; - case '|': - if (p_+1 < end_input_ && *(p_+1) == '|') - { - ++p_; - ++column_; - state_ = filter_states::expect_path_or_value; - tokens_.push_back(token<JsonT>(token_types::pipepipe)); - } - break; - case '=': - if (p_+1 < end_input_ && *(p_+1) == '=') - { - ++p_; - ++column_; - state_ = filter_states::expect_path_or_value; - tokens_.push_back(token<JsonT>(token_types::eq)); - } - else if (p_+1 < end_input_ && *(p_+1) == '~') - { - ++p_; - ++column_; - state_ = filter_states::expect_regex; - tokens_.push_back(token<JsonT>(token_types::regex)); - } - break; - case '>': - if (p_+1 < end_input_ && *(p_+1) == '=') - { - ++p_; - ++column_; - state_ = filter_states::expect_path_or_value; - tokens_.push_back(token<JsonT>(token_types::gte)); - } - else - { - state_ = filter_states::expect_path_or_value; - tokens_.push_back(token<JsonT>(token_types::gt)); - } - break; - case '<': - if (p_+1 < end_input_ && *(p_+1) == '=') - { - ++p_; - ++column_; - state_ = filter_states::expect_path_or_value; - tokens_.push_back(token<JsonT>(token_types::lte)); - } - else - { - state_ = filter_states::expect_path_or_value; - tokens_.push_back(token<JsonT>(token_types::lt)); - } - break; - case '+': - state_ = filter_states::expect_path_or_value; - tokens_.push_back(token<JsonT>(token_types::plus)); - break; - case '-': - state_ = filter_states::expect_path_or_value; - tokens_.push_back(token<JsonT>(token_types::minus)); - break; - case ' ':case '\t': - break; - default: - throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter, jsonpath_error_category()),line_,column_); - break; - - } - ++p_; - ++column_; - break; - case filter_states::unquoted_text: - { - switch (*p_) - { - case '\r': - case '\n': - ++line_; - column_ = 1; - state_ = pre_line_break_state_; - break; - case '<': - case '>': - case '!': - case '=': - case '&': - case '|': - case '+': - case '-': - { - if (buffer_.length() > 0) - { - try - { - auto val = JsonT::parse(buffer_); - tokens_.push_back(token<JsonT>(token_types::term,std::make_shared<value_term<JsonT>>(val))); - } - catch (const parse_exception& e) - { - throw parse_exception(e.code(),line_,column_); - } - buffer_.clear(); - } - state_ = filter_states::oper; - } - break; - case ')': - if (buffer_.length() > 0) - { - try - { - auto val = JsonT::parse(buffer_); - tokens_.push_back(token<JsonT>(token_types::term,std::make_shared<value_term<JsonT>>(val))); - } - catch (const parse_exception& e) - { - throw parse_exception(e.code(),line_,column_); - } - buffer_.clear(); - } - tokens_.push_back(token<JsonT>(token_types::right_paren)); - if (--depth_ == 0) - { - state_ = filter_states::start; - done = true; - } - else - { - state_ = filter_states::expect_path_or_value; - } - ++p_; - ++column_; - break; - case ' ':case '\t': - if (buffer_.length() > 0) - { - try - { - auto val = JsonT::parse(buffer_); - tokens_.push_back(token<JsonT>(token_types::term,std::make_shared<value_term<JsonT>>(val))); - } - catch (const parse_exception& e) - { - throw parse_exception(e.code(),line_,column_); - } - buffer_.clear(); - } - ++p_; - ++column_; - break; - default: - buffer_.push_back(*p_); - ++p_; - ++column_; - break; - } - } - break; - case filter_states::single_quoted_text: - { - switch (*p_) - { - case '\r': - case '\n': - ++line_; - column_ = 1; - state_ = pre_line_break_state_; - break; - case '\\': - buffer_.push_back(*p_); - if (p_+1 < end_input_) - { - ++p_; - ++column_; - buffer_.push_back(*p_); - } - break; - case '\'': - buffer_.push_back('\"'); - //if (buffer_.length() > 0) - { - try - { - auto val = JsonT::parse(buffer_); - tokens_.push_back(token<JsonT>(token_types::term,std::make_shared<value_term<JsonT>>(val))); - } - catch (const parse_exception& e) - { - throw parse_exception(e.code(),line_,column_); - } - buffer_.clear(); - } - state_ = filter_states::expect_path_or_value; - break; - - default: - buffer_.push_back(*p_); - break; - } - } - ++p_; - ++column_; - break; - case filter_states::double_quoted_text: - { - switch (*p_) - { - case '\r': - case '\n': - ++line_; - column_ = 1; - state_ = pre_line_break_state_; - break; - case '\\': - buffer_.push_back(*p_); - if (p_+1 < end_input_) - { - ++p_; - ++column_; - buffer_.push_back(*p_); - } - break; - case '\"': - buffer_.push_back(*p_); - //if (buffer_.length() > 0) - { - try - { - auto val = JsonT::parse(buffer_); - tokens_.push_back(token<JsonT>(token_types::term,std::make_shared<value_term<JsonT>>(val))); - } - catch (const parse_exception& e) - { - throw parse_exception(e.code(),line_,column_); - } - buffer_.clear(); - } - state_ = filter_states::expect_path_or_value; - break; - - default: - buffer_.push_back(*p_); - break; - } - } - ++p_; - ++column_; - break; - case filter_states::expect_path_or_value: - switch (*p_) - { - case '\r': - case '\n': - ++line_; - column_ = 1; - state_ = pre_line_break_state_; - break; - case '<': - case '>': - case '!': - case '=': - case '&': - case '|': - case '+': - case '-': - state_ = filter_states::oper; - // don't increment - break; - case '@': - buffer_.push_back(*p_); - state_ = filter_states::path; - ++p_; - ++column_; - break; - case ' ':case '\t': - ++p_; - ++column_; - break; - case '\'': - buffer_.push_back('\"'); - state_ = filter_states::single_quoted_text; - ++p_; - ++column_; - break; - case '\"': - buffer_.push_back(*p_); - state_ = filter_states::double_quoted_text; - ++p_; - ++column_; - break; - case '(': - ++depth_; - tokens_.push_back(token<JsonT>(token_types::left_paren)); - ++p_; - ++column_; - break; - case ')': - tokens_.push_back(token<JsonT>(token_types::right_paren)); - if (--depth_ == 0) - { - done = true; - state_ = filter_states::start; - } - ++p_; - ++column_; - break; - default: - // don't increment - state_ = filter_states::unquoted_text; - break; - }; - break; - case filter_states::expect_oper_or_right_round_bracket: - switch (*p_) - { - case '\r': - case '\n': - ++line_; - column_ = 1; - state_ = pre_line_break_state_; - break; - case ' ':case '\t': - break; - case ')': - tokens_.push_back(token<JsonT>(token_types::right_paren)); - if (--depth_ == 0) - { - done = true; - state_ = filter_states::start; - } - break; - case '<': - case '>': - case '!': - case '=': - case '&': - case '|': - case '+': - case '-': - { - state_ = filter_states::oper; - // don't increment p - } - break; - default: - throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter, jsonpath_error_category()),line_,column_); - break; - }; - break; - case filter_states::expect_right_round_bracket: - switch (*p_) - { - case '\r': - case '\n': - ++line_; - column_ = 1; - state_ = pre_line_break_state_; - break; - case ' ':case '\t': - break; - case ')': - tokens_.push_back(token<JsonT>(token_types::right_paren)); - if (--depth_ == 0) - { - done = true; - state_ = filter_states::start; - } - else - { - state_ = filter_states::expect_oper_or_right_round_bracket; - } - break; - default: - throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter, jsonpath_error_category()),line_,column_); - break; - }; - ++p_; - ++column_; - break; - case filter_states::path: - switch (*p_) - { - case '\r': - case '\n': - ++line_; - column_ = 1; - state_ = pre_line_break_state_; - break; - case '<': - case '>': - case '!': - case '=': - case '&': - case '|': - case '+': - case '-': - { - if (buffer_.length() > 0) - { - tokens_.push_back(token<JsonT>(token_types::term,std::make_shared<path_term<JsonT>>(buffer_))); - buffer_.clear(); - } - state_ = filter_states::oper; - // don't increment - } - break; - case ')': - if (buffer_.length() > 0) - { - tokens_.push_back(token<JsonT>(token_types::term,std::make_shared<path_term<JsonT>>(buffer_))); - tokens_.push_back(token<JsonT>(token_types::right_paren)); - buffer_.clear(); - } - if (--depth_ == 0) - { - state_ = filter_states::start; - done = true; - } - else - { - state_ = filter_states::expect_path_or_value; - } - ++p_; - ++column_; - break; - default: - buffer_.push_back(*p_); - ++p_; - ++column_; - break; - }; - break; - case filter_states::expect_regex: - switch (*p_) - { - case '\r': - case '\n': - ++line_; - column_ = 1; - state_ = pre_line_break_state_; - break; - case '/': - state_ = filter_states::regex; - break; - case ' ':case '\t': - break; - default: - throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_expected_slash, jsonpath_error_category()),line_,column_); - break; - }; - ++p_; - ++column_; - break; - case filter_states::regex: - { - switch (*p_) - { - case '\r': - case '\n': - ++line_; - column_ = 1; - state_ = pre_line_break_state_; - break; - case '/': - //if (buffer_.length() > 0) - { - std::regex::flag_type flags = std::regex_constants::ECMAScript; - if (p_+1 < end_input_ && *(p_+1) == 'i') - { - ++p_; - ++column_; - flags |= std::regex_constants::icase; - } - tokens_.push_back(token<JsonT>(token_types::term,std::make_shared<regex_term<JsonT>>(buffer_,flags))); - buffer_.clear(); - } - state_ = filter_states::expect_path_or_value; - break; - - default: - buffer_.push_back(*p_); - break; - } - } - ++p_; - ++column_; - break; - default: - ++p_; - ++column_; - break; - } - } - if (depth_ != 0) - { - throw parse_exception(std::error_code(jsonpath_parser_errc::invalid_filter_unbalanced_paren, jsonpath_error_category()),line_,column_); - } - } -}; - - -}} -#endif
\ No newline at end of file |