From 2a84d0a032d5ec27ff57982baf2050597a87990c Mon Sep 17 00:00:00 2001 From: briaguya <70942617+briaguya-ai@users.noreply.github.com> Date: Sat, 27 Sep 2025 13:04:41 -0400 Subject: [PATCH] valijson from package managers --- .github/workflows/generate-builds.yml | 17 +- CMakeLists.txt | 2 +- soh/CMakeLists.txt | 15 +- subprojects/valijson/Authors | 38 - subprojects/valijson/LICENSE | 23 - .../valijson/include/compat/optional.hpp | 1043 -------- .../include/valijson/adapters/adapter.hpp | 472 ---- .../valijson/adapters/basic_adapter.hpp | 859 ------- .../valijson/adapters/frozen_value.hpp | 52 - .../valijson/adapters/json11_adapter.hpp | 711 ----- .../valijson/adapters/jsoncpp_adapter.hpp | 724 ------ .../adapters/nlohmann_json_adapter.hpp | 713 ----- .../valijson/adapters/picojson_adapter.hpp | 732 ------ .../valijson/adapters/poco_json_adapter.hpp | 720 ------ .../adapters/property_tree_adapter.hpp | 753 ------ .../valijson/adapters/qtjson_adapter.hpp | 722 ------ .../valijson/adapters/rapidjson_adapter.hpp | 937 ------- .../valijson/adapters/std_string_adapter.hpp | 491 ---- .../include/valijson/constraint_builder.hpp | 21 - .../valijson/constraints/basic_constraint.hpp | 55 - .../constraints/concrete_constraints.hpp | 1247 --------- .../valijson/constraints/constraint.hpp | 50 - .../constraints/constraint_visitor.hpp | 104 - .../valijson/include/valijson/exceptions.hpp | 41 - .../valijson/internal/custom_allocator.hpp | 107 - .../include/valijson/internal/debug.hpp | 30 - .../valijson/internal/json_pointer.hpp | 275 -- .../valijson/internal/json_reference.hpp | 60 - .../include/valijson/internal/optional.hpp | 14 - .../include/valijson/internal/uri.hpp | 33 - .../valijson/include/valijson/schema.hpp | 224 -- .../include/valijson/schema_parser.hpp | 2282 ----------------- .../valijson/include/valijson/subschema.hpp | 311 --- .../include/valijson/utils/file_utils.hpp | 44 - .../include/valijson/utils/json11_utils.hpp | 34 - .../include/valijson/utils/jsoncpp_utils.hpp | 35 - .../valijson/utils/nlohmann_json_utils.hpp | 43 - .../include/valijson/utils/picojson_utils.hpp | 39 - .../valijson/utils/poco_json_utils.hpp | 37 - .../valijson/utils/property_tree_utils.hpp | 74 - .../include/valijson/utils/qtjson_utils.hpp | 44 - .../valijson/utils/rapidjson_utils.hpp | 46 - .../include/valijson/utils/utf8_utils.hpp | 63 - .../include/valijson/validation_results.hpp | 107 - .../include/valijson/validation_visitor.hpp | 1792 ------------- .../valijson/include/valijson/validator.hpp | 77 - 46 files changed, 30 insertions(+), 16283 deletions(-) delete mode 100644 subprojects/valijson/Authors delete mode 100644 subprojects/valijson/LICENSE delete mode 100644 subprojects/valijson/include/compat/optional.hpp delete mode 100644 subprojects/valijson/include/valijson/adapters/adapter.hpp delete mode 100644 subprojects/valijson/include/valijson/adapters/basic_adapter.hpp delete mode 100644 subprojects/valijson/include/valijson/adapters/frozen_value.hpp delete mode 100644 subprojects/valijson/include/valijson/adapters/json11_adapter.hpp delete mode 100644 subprojects/valijson/include/valijson/adapters/jsoncpp_adapter.hpp delete mode 100644 subprojects/valijson/include/valijson/adapters/nlohmann_json_adapter.hpp delete mode 100644 subprojects/valijson/include/valijson/adapters/picojson_adapter.hpp delete mode 100644 subprojects/valijson/include/valijson/adapters/poco_json_adapter.hpp delete mode 100644 subprojects/valijson/include/valijson/adapters/property_tree_adapter.hpp delete mode 100644 subprojects/valijson/include/valijson/adapters/qtjson_adapter.hpp delete mode 100644 subprojects/valijson/include/valijson/adapters/rapidjson_adapter.hpp delete mode 100644 subprojects/valijson/include/valijson/adapters/std_string_adapter.hpp delete mode 100644 subprojects/valijson/include/valijson/constraint_builder.hpp delete mode 100644 subprojects/valijson/include/valijson/constraints/basic_constraint.hpp delete mode 100644 subprojects/valijson/include/valijson/constraints/concrete_constraints.hpp delete mode 100644 subprojects/valijson/include/valijson/constraints/constraint.hpp delete mode 100644 subprojects/valijson/include/valijson/constraints/constraint_visitor.hpp delete mode 100644 subprojects/valijson/include/valijson/exceptions.hpp delete mode 100644 subprojects/valijson/include/valijson/internal/custom_allocator.hpp delete mode 100644 subprojects/valijson/include/valijson/internal/debug.hpp delete mode 100644 subprojects/valijson/include/valijson/internal/json_pointer.hpp delete mode 100644 subprojects/valijson/include/valijson/internal/json_reference.hpp delete mode 100644 subprojects/valijson/include/valijson/internal/optional.hpp delete mode 100644 subprojects/valijson/include/valijson/internal/uri.hpp delete mode 100644 subprojects/valijson/include/valijson/schema.hpp delete mode 100644 subprojects/valijson/include/valijson/schema_parser.hpp delete mode 100644 subprojects/valijson/include/valijson/subschema.hpp delete mode 100644 subprojects/valijson/include/valijson/utils/file_utils.hpp delete mode 100644 subprojects/valijson/include/valijson/utils/json11_utils.hpp delete mode 100644 subprojects/valijson/include/valijson/utils/jsoncpp_utils.hpp delete mode 100644 subprojects/valijson/include/valijson/utils/nlohmann_json_utils.hpp delete mode 100644 subprojects/valijson/include/valijson/utils/picojson_utils.hpp delete mode 100644 subprojects/valijson/include/valijson/utils/poco_json_utils.hpp delete mode 100644 subprojects/valijson/include/valijson/utils/property_tree_utils.hpp delete mode 100644 subprojects/valijson/include/valijson/utils/qtjson_utils.hpp delete mode 100644 subprojects/valijson/include/valijson/utils/rapidjson_utils.hpp delete mode 100644 subprojects/valijson/include/valijson/utils/utf8_utils.hpp delete mode 100644 subprojects/valijson/include/valijson/validation_results.hpp delete mode 100644 subprojects/valijson/include/valijson/validation_visitor.hpp delete mode 100644 subprojects/valijson/include/valijson/validator.hpp diff --git a/.github/workflows/generate-builds.yml b/.github/workflows/generate-builds.yml index d68092d99..57330c5c5 100644 --- a/.github/workflows/generate-builds.yml +++ b/.github/workflows/generate-builds.yml @@ -113,8 +113,8 @@ jobs: echo "MacPorts already installed" else echo "Installing MacPorts" - wget https://github.com/macports/macports-base/releases/download/v2.9.3/MacPorts-2.9.3-14-Sonoma.pkg - sudo installer -pkg ./MacPorts-2.9.3-14-Sonoma.pkg -target / + wget https://github.com/macports/macports-base/releases/download/v2.11.5/MacPorts-2.11.5-14-Sonoma.pkg + sudo installer -pkg ./MacPorts-2.11.5-14-Sonoma.pkg -target / fi echo "/opt/local/bin:/opt/local/sbin" >> "$GITHUB_PATH" - name: Install dependencies @@ -233,6 +233,19 @@ jobs: make sudo make install sudo cp -av /usr/local/lib/libzip* /lib/x86_64-linux-gnu/ + # this is available in 24.04 but not in 22.04, manually install it + - name: Install valijson + run: | + export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH" + if [ ! -d "deps/valijson-1.0.6" ]; then + wget https://github.com/tristanpenman/valijson/archive/refs/tags/v1.0.6.tar.gz + tar -xzf v1.0.6.tar.gz -C deps + fi + cd deps/valijson-1.0.6 + mkdir -p build + cd build + cmake .. + sudo cmake --install . - name: Download soh.o2r uses: actions/download-artifact@v4 with: diff --git a/CMakeLists.txt b/CMakeLists.txt index b1c2598fd..d9ffc1377 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,7 +83,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows") set(VCPKG_TARGET_TRIPLET x64-windows-static) vcpkg_bootstrap() - vcpkg_install_packages(zlib bzip2 libzip libpng sdl2 sdl2-net glew glfw3 nlohmann-json tinyxml2 spdlog libogg libvorbis opus opusfile openssl) + vcpkg_install_packages(zlib bzip2 libzip libpng sdl2 sdl2-net glew glfw3 nlohmann-json tinyxml2 spdlog libogg libvorbis opus opusfile openssl valijson) if (CMAKE_C_COMPILER_LAUNCHER MATCHES "ccache|sccache") set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT Embedded) endif() diff --git a/soh/CMakeLists.txt b/soh/CMakeLists.txt index 82bb6a15e..60625f0af 100644 --- a/soh/CMakeLists.txt +++ b/soh/CMakeLists.txt @@ -289,11 +289,24 @@ endif() ################################################################################ add_compile_definitions(ASIO_STANDALONE) +if(BUILD_REMOTE_CONTROL) + if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + FetchContent_Declare( + valijson + GIT_REPOSITORY https://github.com/tristanpenman/valijson.git + GIT_TAG v1.0.6 + ) + FetchContent_MakeAvailable(valijson) + target_include_directories(${PROJECT_NAME} PRIVATE ${valijson_SOURCE_DIR}/include) + else() + find_package(valijson REQUIRED) + endif() +endif() + target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../subprojects/asio/include ${CMAKE_CURRENT_SOURCE_DIR}/../subprojects/websocketpp ${CMAKE_CURRENT_SOURCE_DIR}/../subprojects/wswrap/include - ${CMAKE_CURRENT_SOURCE_DIR}/../subprojects/valijson/include ${CMAKE_CURRENT_SOURCE_DIR}/../subprojects/apclientpp ) diff --git a/subprojects/valijson/Authors b/subprojects/valijson/Authors deleted file mode 100644 index d2c0206d3..000000000 --- a/subprojects/valijson/Authors +++ /dev/null @@ -1,38 +0,0 @@ -Tristan Penman, tristan@tristanpenman.com - Core library development - -James Jensen, jjensen@akamai.com, changes Copyright (c) 2016 Akamai Technologies - Polymorphic constraint support - -Tengiz Sharafiev, btolfa+github@gmail.com - Adapter for nlohmann/json parser library - -hotwatermorning (github username), hotwatermorning@gmail.com - Adapter for json11 parser library - -shsfre09 (github username), - Adapter for picojson parser library - -Michael Smith, michael.smith@puppetlabs.com - Memory management improvements for RapidJson parser library - -Richard Clamp, richardc@unixbeard.net - Boost-related fixes - -Lars Immisch, lars@ibp.de - noboost branch - -Nicolas Witczak, n_witczak@yahoo.com - C++11 improvements - -Martin Robinson, 0x4d52@gmail.com - Bug fixes - -Pierre Lamot, pierre.lamot@yahoo.fr - Adapter for Qt JSON parser - -drewxa (github username), bo.ro.da@mail.ru - Adapter for Poco JSON parser - -Jordan Bayles (jophba), jophba@chromium.org - JsonCpp owner diff --git a/subprojects/valijson/LICENSE b/subprojects/valijson/LICENSE deleted file mode 100644 index 77d38164c..000000000 --- a/subprojects/valijson/LICENSE +++ /dev/null @@ -1,23 +0,0 @@ -Copyright (c) 2016, Tristan Penman -Copyright (c) 2016, Akamai Technolgies, Inc. -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. diff --git a/subprojects/valijson/include/compat/optional.hpp b/subprojects/valijson/include/compat/optional.hpp deleted file mode 100644 index b0182dfbf..000000000 --- a/subprojects/valijson/include/compat/optional.hpp +++ /dev/null @@ -1,1043 +0,0 @@ -// Copyright (C) 2011 - 2012 Andrzej Krzemienski. -// -// Use, modification, and distribution is subject to 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) -// -// The idea and interface is based on Boost.Optional library -// authored by Fernando Luis Cacciola Carballal - -# ifndef ___OPTIONAL_HPP___ -# define ___OPTIONAL_HPP___ - -# include -# include -# include -# include -# include -# include -# include -# include - -# define TR2_OPTIONAL_REQUIRES(...) typename enable_if<__VA_ARGS__::value, bool>::type = false - -# if defined __GNUC__ // NOTE: GNUC is also defined for Clang -# if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 8) -# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ -# elif (__GNUC__ > 4) -# define TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ -# endif -# -# if (__GNUC__ == 4) && (__GNUC_MINOR__ >= 7) -# define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___ -# elif (__GNUC__ > 4) -# define TR2_OPTIONAL_GCC_4_7_AND_HIGHER___ -# endif -# -# if (__GNUC__ == 4) && (__GNUC_MINOR__ == 8) && (__GNUC_PATCHLEVEL__ >= 1) -# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ -# elif (__GNUC__ == 4) && (__GNUC_MINOR__ >= 9) -# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ -# elif (__GNUC__ > 4) -# define TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ -# endif -# endif -# -# if defined __clang_major__ -# if (__clang_major__ == 3 && __clang_minor__ >= 5) -# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ -# elif (__clang_major__ > 3) -# define TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ -# endif -# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ -# define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ -# elif (__clang_major__ == 3 && __clang_minor__ == 4 && __clang_patchlevel__ >= 2) -# define TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ -# endif -# endif -# -# if defined _MSC_VER -# if (_MSC_VER >= 1900) -# define TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ -# endif -# endif - -# if defined __clang__ -# if (__clang_major__ > 2) || (__clang_major__ == 2) && (__clang_minor__ >= 9) -# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 -# else -# define OPTIONAL_HAS_THIS_RVALUE_REFS 0 -# endif -# elif defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ -# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 -# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ -# define OPTIONAL_HAS_THIS_RVALUE_REFS 1 -# else -# define OPTIONAL_HAS_THIS_RVALUE_REFS 0 -# endif - - -# if defined TR2_OPTIONAL_GCC_4_8_1_AND_HIGHER___ -# define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 1 -# define OPTIONAL_CONSTEXPR_INIT_LIST constexpr -# else -# define OPTIONAL_HAS_CONSTEXPR_INIT_LIST 0 -# define OPTIONAL_CONSTEXPR_INIT_LIST -# endif - -# if defined TR2_OPTIONAL_CLANG_3_5_AND_HIGHTER_ && (defined __cplusplus) && (__cplusplus != 201103L) -# define OPTIONAL_HAS_MOVE_ACCESSORS 1 -# else -# define OPTIONAL_HAS_MOVE_ACCESSORS 0 -# endif - -# // In C++11 constexpr implies const, so we need to make non-const members also non-constexpr -# if (defined __cplusplus) && (__cplusplus == 201103L) -# define OPTIONAL_MUTABLE_CONSTEXPR -# else -# define OPTIONAL_MUTABLE_CONSTEXPR constexpr -# endif - -namespace std{ - - namespace experimental{ - - // BEGIN workaround for missing is_trivially_destructible -# if defined TR2_OPTIONAL_GCC_4_8_AND_HIGHER___ - // leave it: it is already there -# elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ - // leave it: it is already there -# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ - // leave it: it is already there -# elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS - // leave it: the user doesn't want it -# else - template - using is_trivially_destructible = std::has_trivial_destructor; -# endif - // END workaround for missing is_trivially_destructible - -# if (defined TR2_OPTIONAL_GCC_4_7_AND_HIGHER___) - // leave it; our metafunctions are already defined. -# elif defined TR2_OPTIONAL_CLANG_3_4_2_AND_HIGHER_ - // leave it; our metafunctions are already defined. -# elif defined TR2_OPTIONAL_MSVC_2015_AND_HIGHER___ - // leave it: it is already there -# elif defined TR2_OPTIONAL_DISABLE_EMULATION_OF_TYPE_TRAITS - // leave it: the user doesn't want it -# else - - - // workaround for missing traits in GCC and CLANG - template - struct is_nothrow_move_constructible - { - constexpr static bool value = std::is_nothrow_constructible::value; - }; - - - template - struct is_assignable - { - template - constexpr static bool has_assign(...) { return false; } - - template () = std::declval(), true)) > - // the comma operator is necessary for the cases where operator= returns void - constexpr static bool has_assign(bool) { return true; } - - constexpr static bool value = has_assign(true); - }; - - - template - struct is_nothrow_move_assignable - { - template - struct has_nothrow_move_assign { - constexpr static bool value = false; - }; - - template - struct has_nothrow_move_assign { - constexpr static bool value = noexcept( std::declval() = std::declval() ); - }; - - constexpr static bool value = has_nothrow_move_assign::value>::value; - }; - // end workaround - - -# endif - - - - // 20.5.4, optional for object types - template class optional; - - // 20.5.5, optional for lvalue reference types - template class optional; - - - // workaround: std utility functions aren't constexpr yet - template inline constexpr T&& constexpr_forward(typename std::remove_reference::type& t) noexcept - { - return static_cast(t); - } - - template inline constexpr T&& constexpr_forward(typename std::remove_reference::type&& t) noexcept - { - static_assert(!std::is_lvalue_reference::value, "!!"); - return static_cast(t); - } - - template inline constexpr typename std::remove_reference::type&& constexpr_move(T&& t) noexcept - { - return static_cast::type&&>(t); - } - - -#if defined NDEBUG -# define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) (EXPR) -#else -# define TR2_OPTIONAL_ASSERTED_EXPRESSION(CHECK, EXPR) ((CHECK) ? (EXPR) : ([]{assert(!#CHECK);}(), (EXPR))) -#endif - - - namespace detail_ - { - - // static_addressof: a constexpr version of addressof - template - struct has_overloaded_addressof - { - template - constexpr static bool has_overload(...) { return false; } - - template ().operator&()) > - constexpr static bool has_overload(bool) { return true; } - - constexpr static bool value = has_overload(true); - }; - - template )> - constexpr T* static_addressof(T& ref) - { - return &ref; - } - - template )> - T* static_addressof(T& ref) - { - return std::addressof(ref); - } - - - // the call to convert(b) has return type A and converts b to type A iff b decltype(b) is implicitly convertible to A - template - constexpr U convert(U v) { return v; } - - } // namespace detail - - - constexpr struct trivial_init_t{} trivial_init{}; - - - // 20.5.6, In-place construction - constexpr struct in_place_t{} in_place{}; - - - // 20.5.7, Disengaged state indicator - struct nullopt_t - { - struct init{}; - constexpr explicit nullopt_t(init){} - }; - constexpr nullopt_t nullopt{nullopt_t::init()}; - - - // 20.5.8, class bad_optional_access - class bad_optional_access : public logic_error { - public: - explicit bad_optional_access(const string& what_arg) : logic_error{what_arg} {} - explicit bad_optional_access(const char* what_arg) : logic_error{what_arg} {} - }; - - - template - union storage_t - { - unsigned char dummy_; - T value_; - - constexpr storage_t( trivial_init_t ) noexcept : dummy_() {}; - - template - constexpr storage_t( Args&&... args ) : value_(constexpr_forward(args)...) {} - - ~storage_t(){} - }; - - - template - union constexpr_storage_t - { - unsigned char dummy_; - T value_; - - constexpr constexpr_storage_t( trivial_init_t ) noexcept : dummy_() {}; - - template - constexpr constexpr_storage_t( Args&&... args ) : value_(constexpr_forward(args)...) {} - - ~constexpr_storage_t() = default; - }; - - - template - struct optional_base - { - bool init_; - storage_t storage_; - - constexpr optional_base() noexcept : init_(false), storage_(trivial_init) {}; - - explicit constexpr optional_base(const T& v) : init_(true), storage_(v) {} - - explicit constexpr optional_base(T&& v) : init_(true), storage_(constexpr_move(v)) {} - - template explicit optional_base(in_place_t, Args&&... args) - : init_(true), storage_(constexpr_forward(args)...) {} - - template >)> - explicit optional_base(in_place_t, std::initializer_list il, Args&&... args) - : init_(true), storage_(il, std::forward(args)...) {} - - ~optional_base() { if (init_) storage_.value_.T::~T(); } - }; - - - template - struct constexpr_optional_base - { - bool init_; - constexpr_storage_t storage_; - - constexpr constexpr_optional_base() noexcept : init_(false), storage_(trivial_init) {}; - - explicit constexpr constexpr_optional_base(const T& v) : init_(true), storage_(v) {} - - explicit constexpr constexpr_optional_base(T&& v) : init_(true), storage_(constexpr_move(v)) {} - - template explicit constexpr constexpr_optional_base(in_place_t, Args&&... args) - : init_(true), storage_(constexpr_forward(args)...) {} - - template >)> - OPTIONAL_CONSTEXPR_INIT_LIST explicit constexpr_optional_base(in_place_t, std::initializer_list il, Args&&... args) - : init_(true), storage_(il, std::forward(args)...) {} - - ~constexpr_optional_base() = default; - }; - - template - using OptionalBase = typename std::conditional< - is_trivially_destructible::value, - constexpr_optional_base::type>, - optional_base::type> - >::type; - - - - template - class optional : private OptionalBase - { - static_assert( !std::is_same::type, nullopt_t>::value, "bad T" ); - static_assert( !std::is_same::type, in_place_t>::value, "bad T" ); - - - constexpr bool initialized() const noexcept { return OptionalBase::init_; } - typename std::remove_const::type* dataptr() { return std::addressof(OptionalBase::storage_.value_); } - constexpr const T* dataptr() const { return detail_::static_addressof(OptionalBase::storage_.value_); } - -# if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 - constexpr const T& contained_val() const& { return OptionalBase::storage_.value_; } -# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 - OPTIONAL_MUTABLE_CONSTEXPR T&& contained_val() && { return std::move(OptionalBase::storage_.value_); } - OPTIONAL_MUTABLE_CONSTEXPR T& contained_val() & { return OptionalBase::storage_.value_; } -# else - T& contained_val() & { return OptionalBase::storage_.value_; } - T&& contained_val() && { return std::move(OptionalBase::storage_.value_); } -# endif -# else - constexpr const T& contained_val() const { return OptionalBase::storage_.value_; } - T& contained_val() { return OptionalBase::storage_.value_; } -# endif - - void clear() noexcept { - if (initialized()) dataptr()->T::~T(); - OptionalBase::init_ = false; - } - - template - void initialize(Args&&... args) noexcept(noexcept(T(std::forward(args)...))) - { - assert(!OptionalBase::init_); - ::new (static_cast(dataptr())) T(std::forward(args)...); - OptionalBase::init_ = true; - } - - template - void initialize(std::initializer_list il, Args&&... args) noexcept(noexcept(T(il, std::forward(args)...))) - { - assert(!OptionalBase::init_); - ::new (static_cast(dataptr())) T(il, std::forward(args)...); - OptionalBase::init_ = true; - } - - public: - typedef T value_type; - - // 20.5.5.1, constructors - constexpr optional() noexcept : OptionalBase() {}; - constexpr optional(nullopt_t) noexcept : OptionalBase() {}; - - optional(const optional& rhs) - : OptionalBase() - { - if (rhs.initialized()) { - ::new (static_cast(dataptr())) T(*rhs); - OptionalBase::init_ = true; - } - } - - optional(optional&& rhs) noexcept(is_nothrow_move_constructible::value) - : OptionalBase() - { - if (rhs.initialized()) { - ::new (static_cast(dataptr())) T(std::move(*rhs)); - OptionalBase::init_ = true; - } - } - - constexpr optional(const T& v) : OptionalBase(v) {} - - constexpr optional(T&& v) : OptionalBase(constexpr_move(v)) {} - - template - explicit constexpr optional(in_place_t, Args&&... args) - : OptionalBase(in_place_t{}, constexpr_forward(args)...) {} - - template >)> - OPTIONAL_CONSTEXPR_INIT_LIST explicit optional(in_place_t, std::initializer_list il, Args&&... args) - : OptionalBase(in_place_t{}, il, constexpr_forward(args)...) {} - - // 20.5.4.2, Destructor - ~optional() = default; - - // 20.5.4.3, assignment - optional& operator=(nullopt_t) noexcept - { - clear(); - return *this; - } - - optional& operator=(const optional& rhs) - { - if (initialized() == true && rhs.initialized() == false) clear(); - else if (initialized() == false && rhs.initialized() == true) initialize(*rhs); - else if (initialized() == true && rhs.initialized() == true) contained_val() = *rhs; - return *this; - } - - optional& operator=(optional&& rhs) - noexcept(is_nothrow_move_assignable::value && is_nothrow_move_constructible::value) - { - if (initialized() == true && rhs.initialized() == false) clear(); - else if (initialized() == false && rhs.initialized() == true) initialize(std::move(*rhs)); - else if (initialized() == true && rhs.initialized() == true) contained_val() = std::move(*rhs); - return *this; - } - - template - auto operator=(U&& v) - -> typename enable_if - < - is_same::type, T>::value, - optional& - >::type - { - if (initialized()) { contained_val() = std::forward(v); } - else { initialize(std::forward(v)); } - return *this; - } - - - template - void emplace(Args&&... args) - { - clear(); - initialize(std::forward(args)...); - } - - template - void emplace(initializer_list il, Args&&... args) - { - clear(); - initialize(il, std::forward(args)...); - } - - // 20.5.4.4, Swap - void swap(optional& rhs) noexcept(is_nothrow_move_constructible::value && noexcept(swap(declval(), declval()))) - { - if (initialized() == true && rhs.initialized() == false) { rhs.initialize(std::move(**this)); clear(); } - else if (initialized() == false && rhs.initialized() == true) { initialize(std::move(*rhs)); rhs.clear(); } - else if (initialized() == true && rhs.initialized() == true) { using std::swap; swap(**this, *rhs); } - } - - // 20.5.4.5, Observers - - explicit constexpr operator bool() const noexcept { return initialized(); } - - constexpr T const* operator ->() const { - return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), dataptr()); - } - -# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 - - OPTIONAL_MUTABLE_CONSTEXPR T* operator ->() { - assert (initialized()); - return dataptr(); - } - - constexpr T const& operator *() const& { - return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); - } - - OPTIONAL_MUTABLE_CONSTEXPR T& operator *() & { - assert (initialized()); - return contained_val(); - } - - OPTIONAL_MUTABLE_CONSTEXPR T&& operator *() && { - assert (initialized()); - return constexpr_move(contained_val()); - } - - constexpr T const& value() const& { - return initialized() ? contained_val() : (valijson::throwRuntimeError("bad optional access"), contained_val()); - } - - OPTIONAL_MUTABLE_CONSTEXPR T& value() & { - return initialized() ? contained_val() : (valijson::throwRuntimeError("bad optional access"), contained_val()); - } - - OPTIONAL_MUTABLE_CONSTEXPR T&& value() && { - if (!initialized()) valijson::throwRuntimeError("bad optional access"); - return std::move(contained_val()); - } - -# else - - T* operator ->() { - assert (initialized()); - return dataptr(); - } - - constexpr T const& operator *() const { - return TR2_OPTIONAL_ASSERTED_EXPRESSION(initialized(), contained_val()); - } - - T& operator *() { - assert (initialized()); - return contained_val(); - } - - constexpr T const& value() const { - return initialized() ? contained_val() : (valijson::throwRuntimeError("bad optional access"), contained_val()); - } - - T& value() { - return initialized() ? contained_val() : (valijson::throwRuntimeError("bad optional access"), contained_val()); - } - -# endif - -# if OPTIONAL_HAS_THIS_RVALUE_REFS == 1 - - template - constexpr T value_or(V&& v) const& - { - return *this ? **this : detail_::convert(constexpr_forward(v)); - } - -# if OPTIONAL_HAS_MOVE_ACCESSORS == 1 - - template - OPTIONAL_MUTABLE_CONSTEXPR T value_or(V&& v) && - { - return *this ? constexpr_move(const_cast&>(*this).contained_val()) : detail_::convert(constexpr_forward(v)); - } - -# else - - template - T value_or(V&& v) && - { - return *this ? constexpr_move(const_cast&>(*this).contained_val()) : detail_::convert(constexpr_forward(v)); - } - -# endif - -# else - - template - constexpr T value_or(V&& v) const - { - return *this ? **this : detail_::convert(constexpr_forward(v)); - } - -# endif - - }; - - - template - class optional - { - static_assert( !std::is_same::value, "bad T" ); - static_assert( !std::is_same::value, "bad T" ); - T* ref; - - public: - - // 20.5.5.1, construction/destruction - constexpr optional() noexcept : ref(nullptr) {} - - constexpr optional(nullopt_t) noexcept : ref(nullptr) {} - - constexpr optional(T& v) noexcept : ref(detail_::static_addressof(v)) {} - - optional(T&&) = delete; - - constexpr optional(const optional& rhs) noexcept : ref(rhs.ref) {} - - explicit constexpr optional(in_place_t, T& v) noexcept : ref(detail_::static_addressof(v)) {} - - explicit optional(in_place_t, T&&) = delete; - - ~optional() = default; - - // 20.5.5.2, mutation - optional& operator=(nullopt_t) noexcept { - ref = nullptr; - return *this; - } - - // optional& operator=(const optional& rhs) noexcept { - // ref = rhs.ref; - // return *this; - // } - - // optional& operator=(optional&& rhs) noexcept { - // ref = rhs.ref; - // return *this; - // } - - template - auto operator=(U&& rhs) noexcept - -> typename enable_if - < - is_same::type, optional>::value, - optional& - >::type - { - ref = rhs.ref; - return *this; - } - - template - auto operator=(U&& rhs) noexcept - -> typename enable_if - < - !is_same::type, optional>::value, - optional& - >::type - = delete; - - void emplace(T& v) noexcept { - ref = detail_::static_addressof(v); - } - - void emplace(T&&) = delete; - - - void swap(optional& rhs) noexcept - { - std::swap(ref, rhs.ref); - } - - // 20.5.5.3, observers - constexpr T* operator->() const { - return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, ref); - } - - constexpr T& operator*() const { - return TR2_OPTIONAL_ASSERTED_EXPRESSION(ref, *ref); - } - - constexpr T& value() const { - return ref ? *ref : (valijson::throwRuntimeError("bad optional access"), *ref); - } - - explicit constexpr operator bool() const noexcept { - return ref != nullptr; - } - - template - constexpr typename decay::type value_or(V&& v) const - { - return *this ? **this : detail_::convert::type>(constexpr_forward(v)); - } - }; - - - template - class optional - { - static_assert( sizeof(T) == 0, "optional rvalue references disallowed" ); - }; - - - // 20.5.8, Relational operators - template constexpr bool operator==(const optional& x, const optional& y) - { - return bool(x) != bool(y) ? false : bool(x) == false ? true : *x == *y; - } - - template constexpr bool operator!=(const optional& x, const optional& y) - { - return !(x == y); - } - - template constexpr bool operator<(const optional& x, const optional& y) - { - return (!y) ? false : (!x) ? true : *x < *y; - } - - template constexpr bool operator>(const optional& x, const optional& y) - { - return (y < x); - } - - template constexpr bool operator<=(const optional& x, const optional& y) - { - return !(y < x); - } - - template constexpr bool operator>=(const optional& x, const optional& y) - { - return !(x < y); - } - - - // 20.5.9, Comparison with nullopt - template constexpr bool operator==(const optional& x, nullopt_t) noexcept - { - return (!x); - } - - template constexpr bool operator==(nullopt_t, const optional& x) noexcept - { - return (!x); - } - - template constexpr bool operator!=(const optional& x, nullopt_t) noexcept - { - return bool(x); - } - - template constexpr bool operator!=(nullopt_t, const optional& x) noexcept - { - return bool(x); - } - - template constexpr bool operator<(const optional&, nullopt_t) noexcept - { - return false; - } - - template constexpr bool operator<(nullopt_t, const optional& x) noexcept - { - return bool(x); - } - - template constexpr bool operator<=(const optional& x, nullopt_t) noexcept - { - return (!x); - } - - template constexpr bool operator<=(nullopt_t, const optional&) noexcept - { - return true; - } - - template constexpr bool operator>(const optional& x, nullopt_t) noexcept - { - return bool(x); - } - - template constexpr bool operator>(nullopt_t, const optional&) noexcept - { - return false; - } - - template constexpr bool operator>=(const optional&, nullopt_t) noexcept - { - return true; - } - - template constexpr bool operator>=(nullopt_t, const optional& x) noexcept - { - return (!x); - } - - - - // 20.5.10, Comparison with T - template constexpr bool operator==(const optional& x, const T& v) - { - return bool(x) ? *x == v : false; - } - - template constexpr bool operator==(const T& v, const optional& x) - { - return bool(x) ? v == *x : false; - } - - template constexpr bool operator!=(const optional& x, const T& v) - { - return bool(x) ? *x != v : true; - } - - template constexpr bool operator!=(const T& v, const optional& x) - { - return bool(x) ? v != *x : true; - } - - template constexpr bool operator<(const optional& x, const T& v) - { - return bool(x) ? *x < v : true; - } - - template constexpr bool operator>(const T& v, const optional& x) - { - return bool(x) ? v > *x : true; - } - - template constexpr bool operator>(const optional& x, const T& v) - { - return bool(x) ? *x > v : false; - } - - template constexpr bool operator<(const T& v, const optional& x) - { - return bool(x) ? v < *x : false; - } - - template constexpr bool operator>=(const optional& x, const T& v) - { - return bool(x) ? *x >= v : false; - } - - template constexpr bool operator<=(const T& v, const optional& x) - { - return bool(x) ? v <= *x : false; - } - - template constexpr bool operator<=(const optional& x, const T& v) - { - return bool(x) ? *x <= v : true; - } - - template constexpr bool operator>=(const T& v, const optional& x) - { - return bool(x) ? v >= *x : true; - } - - - // Comparison of optional with T - template constexpr bool operator==(const optional& x, const T& v) - { - return bool(x) ? *x == v : false; - } - - template constexpr bool operator==(const T& v, const optional& x) - { - return bool(x) ? v == *x : false; - } - - template constexpr bool operator!=(const optional& x, const T& v) - { - return bool(x) ? *x != v : true; - } - - template constexpr bool operator!=(const T& v, const optional& x) - { - return bool(x) ? v != *x : true; - } - - template constexpr bool operator<(const optional& x, const T& v) - { - return bool(x) ? *x < v : true; - } - - template constexpr bool operator>(const T& v, const optional& x) - { - return bool(x) ? v > *x : true; - } - - template constexpr bool operator>(const optional& x, const T& v) - { - return bool(x) ? *x > v : false; - } - - template constexpr bool operator<(const T& v, const optional& x) - { - return bool(x) ? v < *x : false; - } - - template constexpr bool operator>=(const optional& x, const T& v) - { - return bool(x) ? *x >= v : false; - } - - template constexpr bool operator<=(const T& v, const optional& x) - { - return bool(x) ? v <= *x : false; - } - - template constexpr bool operator<=(const optional& x, const T& v) - { - return bool(x) ? *x <= v : true; - } - - template constexpr bool operator>=(const T& v, const optional& x) - { - return bool(x) ? v >= *x : true; - } - - // Comparison of optional with T - template constexpr bool operator==(const optional& x, const T& v) - { - return bool(x) ? *x == v : false; - } - - template constexpr bool operator==(const T& v, const optional& x) - { - return bool(x) ? v == *x : false; - } - - template constexpr bool operator!=(const optional& x, const T& v) - { - return bool(x) ? *x != v : true; - } - - template constexpr bool operator!=(const T& v, const optional& x) - { - return bool(x) ? v != *x : true; - } - - template constexpr bool operator<(const optional& x, const T& v) - { - return bool(x) ? *x < v : true; - } - - template constexpr bool operator>(const T& v, const optional& x) - { - return bool(x) ? v > *x : true; - } - - template constexpr bool operator>(const optional& x, const T& v) - { - return bool(x) ? *x > v : false; - } - - template constexpr bool operator<(const T& v, const optional& x) - { - return bool(x) ? v < *x : false; - } - - template constexpr bool operator>=(const optional& x, const T& v) - { - return bool(x) ? *x >= v : false; - } - - template constexpr bool operator<=(const T& v, const optional& x) - { - return bool(x) ? v <= *x : false; - } - - template constexpr bool operator<=(const optional& x, const T& v) - { - return bool(x) ? *x <= v : true; - } - - template constexpr bool operator>=(const T& v, const optional& x) - { - return bool(x) ? v >= *x : true; - } - - - // 20.5.12, Specialized algorithms - template - void swap(optional& x, optional& y) noexcept(noexcept(x.swap(y))) - { - x.swap(y); - } - - - template - constexpr optional::type> make_optional(T&& v) - { - return optional::type>(constexpr_forward(v)); - } - - template - constexpr optional make_optional(reference_wrapper v) - { - return optional(v.get()); - } - - - } // namespace experimental -} // namespace std - -namespace std -{ - template - struct hash> - { - typedef typename hash::result_type result_type; - typedef std::experimental::optional argument_type; - - constexpr result_type operator()(argument_type const& arg) const { - return arg ? std::hash{}(*arg) : result_type{}; - } - }; - - template - struct hash> - { - typedef typename hash::result_type result_type; - typedef std::experimental::optional argument_type; - - constexpr result_type operator()(argument_type const& arg) const { - return arg ? std::hash{}(*arg) : result_type{}; - } - }; -} - -# undef TR2_OPTIONAL_REQUIRES -# undef TR2_OPTIONAL_ASSERTED_EXPRESSION - -# endif //___OPTIONAL_HPP___ diff --git a/subprojects/valijson/include/valijson/adapters/adapter.hpp b/subprojects/valijson/include/valijson/adapters/adapter.hpp deleted file mode 100644 index 146156b50..000000000 --- a/subprojects/valijson/include/valijson/adapters/adapter.hpp +++ /dev/null @@ -1,472 +0,0 @@ -#pragma once - -#include - -namespace valijson { -namespace adapters { - -class FrozenValue; - -/** - * @brief An interface that encapsulates access to the JSON values provided - * by a JSON parser implementation. - * - * This interface allows JSON processing code to be parser-agnostic. It provides - * functions to access the plain old datatypes (PODs) that are described in the - * JSON specification, and callback-based access to the contents of arrays and - * objects. - * - * The interface also defines a set of functions that allow for type-casting and - * type-comparison based on value rather than on type. - */ -class Adapter -{ -public: - - /// Typedef for callback function supplied to applyToArray. - typedef std::function - ArrayValueCallback; - - /// Typedef for callback function supplied to applyToObject. - typedef std::function - ObjectMemberCallback; - - /** - * @brief Virtual destructor defined to ensure deletion via base-class - * pointers is safe. - */ - virtual ~Adapter() = default; - - /** - * @brief Apply a callback function to each value in an array. - * - * The callback function is invoked for each element in the array, until - * it has been applied to all values, or it returns false. - * - * @param fn Callback function to invoke - * - * @returns true if Adapter contains an array and all values are equal, - * false otherwise. - */ - virtual bool applyToArray(ArrayValueCallback fn) const = 0; - - /** - * @brief Apply a callback function to each member in an object. - * - * The callback function shall be invoked for each member in the object, - * until it has been applied to all values, or it returns false. - * - * @param fn Callback function to invoke - * - * @returns true if Adapter contains an object, and callback function - * returns true for each member in the object, false otherwise. - */ - virtual bool applyToObject(ObjectMemberCallback fn) const = 0; - - /** - * @brief Return the boolean representation of the contained value. - * - * This function shall return a boolean value if the Adapter contains either - * an actual boolean value, or one of the strings 'true' or 'false'. - * The string comparison is case sensitive. - * - * An exception shall be thrown if the value cannot be cast to a boolean. - * - * @returns Boolean representation of contained value. - */ - virtual bool asBool() const = 0; - - /** - * @brief Retrieve the boolean representation of the contained value. - * - * This function shall retrieve a boolean value if the Adapter contains - * either an actual boolean value, or one of the strings 'true' or 'false'. - * The string comparison is case sensitive. - * - * The retrieved value is returned via reference. - * - * @param result reference to a bool to set with retrieved value. - * - * @returns true if the value could be retrieved, false otherwise - */ - virtual bool asBool(bool &result) const = 0; - - /** - * @brief Return the double representation of the contained value. - * - * This function shall return a double value if the Adapter contains either - * an actual double, an integer, or a string that contains a valid - * representation of a numeric value (according to the C++ Std Library). - * - * An exception shall be thrown if the value cannot be cast to a double. - * - * @returns Double representation of contained value. - */ - virtual double asDouble() const = 0; - - /** - * @brief Retrieve the double representation of the contained value. - * - * This function shall retrieve a double value if the Adapter contains either - * an actual double, an integer, or a string that contains a valid - * representation of a numeric value (according to the C++ Std Library). - * - * The retrieved value is returned via reference. - * - * @param result reference to a double to set with retrieved value. - * - * @returns true if the value could be retrieved, false otherwise - */ - virtual bool asDouble(double &result) const = 0; - - /** - * @brief Return the int64_t representation of the contained value. - * - * This function shall return an int64_t value if the Adapter contains either - * an actual integer, or a string that contains a valid representation of an - * integer value (according to the C++ Std Library). - * - * An exception shall be thrown if the value cannot be cast to an int64_t. - * - * @returns int64_t representation of contained value. - */ - virtual int64_t asInteger() const = 0; - - /** - * @brief Retrieve the int64_t representation of the contained value. - * - * This function shall retrieve an int64_t value if the Adapter contains - * either an actual integer, or a string that contains a valid - * representation of an integer value (according to the C++ Std Library). - * - * The retrieved value is returned via reference. - * - * @param result reference to a int64_t to set with retrieved value. - * - * @returns true if the value could be retrieved, false otherwise - */ - virtual bool asInteger(int64_t &result) const = 0; - - /** - * @brief Return the string representation of the contained value. - * - * This function shall return a string value if the Adapter contains either - * an actual string, a literal value of another POD type, an empty array, - * an empty object, or null. - * - * An exception shall be thrown if the value cannot be cast to a string. - * - * @returns string representation of contained value. - */ - virtual std::string asString() const = 0; - - /** - * @brief Retrieve the string representation of the contained value. - * - * This function shall retrieve a string value if the Adapter contains either - * an actual string, a literal value of another POD type, an empty array, - * an empty object, or null. - * - * The retrieved value is returned via reference. - * - * @param result reference to a string to set with retrieved value. - * - * @returns true if the value could be retrieved, false otherwise - */ - virtual bool asString(std::string &result) const = 0; - - /** - * @brief Compare the value held by this Adapter instance with the value - * held by another Adapter instance. - * - * @param other the other adapter instance - * @param strict flag to use strict type comparison - * - * @returns true if values are equal, false otherwise - */ - virtual bool equalTo(const Adapter &other, bool strict) const = 0; - - /** - * @brief Create a new FrozenValue instance that is equivalent to the - * value contained by the Adapter. - * - * @returns pointer to a new FrozenValue instance, belonging to the caller. - */ - virtual FrozenValue* freeze() const = 0; - - /** - * @brief Return the number of elements in the array. - * - * Throws an exception if the value is not an array. - * - * @return number of elements if value is an array - */ - virtual size_t getArraySize() const = 0; - - /** - * @brief Retrieve the number of elements in the array. - * - * This function shall return true or false to indicate whether or not the - * result value was set. If the contained value is not an array, the - * result value shall not be set. This applies even if the value could be - * cast to an empty array. The calling code is expected to handles those - * cases manually. - * - * @param result reference to size_t variable to set with result. - * - * @return true if value retrieved successfully, false otherwise. - */ - virtual bool getArraySize(size_t &result) const = 0; - - /** - * @brief Return the contained boolean value. - * - * This function shall throw an exception if the contained value is not a - * boolean. - * - * @returns contained boolean value. - */ - virtual bool getBool() const = 0; - - /** - * @brief Retrieve the contained boolean value. - * - * This function shall retrieve the boolean value contained by this Adapter, - * and store it in the result variable that was passed by reference. - * - * @param result reference to boolean variable to set with result. - * - * @returns true if the value was retrieved, false otherwise. - */ - virtual bool getBool(bool &result) const = 0; - - /** - * @brief Return the contained double value. - * - * This function shall throw an exception if the contained value is not a - * double. - * - * @returns contained double value. - */ - virtual double getDouble() const = 0; - - /** - * @brief Retrieve the contained double value. - * - * This function shall retrieve the double value contained by this Adapter, - * and store it in the result variable that was passed by reference. - * - * @param result reference to double variable to set with result. - * - * @returns true if the value was retrieved, false otherwise. - */ - virtual bool getDouble(double &result) const = 0; - - /** - * @brief Return the contained integer value. - * - * This function shall throw an exception if the contained value is not a - * integer. - * - * @returns contained integer value. - */ - virtual int64_t getInteger() const = 0; - - /** - * @brief Retrieve the contained integer value. - * - * This function shall retrieve the integer value contained by this Adapter, - * and store it in the result variable that was passed by reference. - * - * @param result reference to integer variable to set with result. - * - * @returns true if the value was retrieved, false otherwise. - */ - virtual bool getInteger(int64_t &result) const = 0; - - /** - * @brief Return the contained numeric value as a double. - * - * This function shall throw an exception if the contained value is not a - * integer or a double. - * - * @returns contained double or integral value. - */ - virtual double getNumber() const = 0; - - /** - * @brief Retrieve the contained numeric value as a double. - * - * This function shall retrieve the double or integral value contained by - * this Adapter, and store it in the result variable that was passed by - * reference. - * - * @param result reference to double variable to set with result. - * - * @returns true if the value was retrieved, false otherwise. - */ - virtual bool getNumber(double &result) const = 0; - - /** - * @brief Return the number of members in the object. - * - * Throws an exception if the value is not an object. - * - * @return number of members if value is an object - */ - virtual size_t getObjectSize() const = 0; - - /** - * @brief Retrieve the number of members in the object. - * - * This function shall return true or false to indicate whether or not the - * result value was set. If the contained value is not an object, the - * result value shall not be set. This applies even if the value could be - * cast to an empty object. The calling code is expected to handles those - * cases manually. - * - * @param result reference to size_t variable to set with result. - * - * @return true if value retrieved successfully, false otherwise. - */ - virtual bool getObjectSize(size_t &result) const = 0; - - /** - * @brief Return the contained string value. - * - * This function shall throw an exception if the contained value is not a - * string - even if the value could be cast to a string. The asString() - * function should be used when casting is allowed. - * - * @returns string contained by this Adapter - */ - virtual std::string getString() const = 0; - - /** - * @brief Retrieve the contained string value. - * - * This function shall retrieve the string value contained by this Adapter, - * and store it in result variable that is passed by reference. - * - * @param result reference to string to set with result - * - * @returns true if string was retrieved, false otherwise - */ - virtual bool getString(std::string &result) const = 0; - - /** - * @brief Returns whether or not this Adapter supports strict types. - * - * This function shall return true if the Adapter implementation supports - * strict types, or false if the Adapter fails to store any part of the - * type information supported by the Adapter interface. - * - * For example, the PropertyTreeAdapter implementation stores POD values as - * strings, effectively discarding any other type information. If you were - * to call isDouble() on a double stored by this Adapter, the result would - * be false. The maybeDouble(), asDouble() and various related functions - * are provided to perform type checking based on value rather than on type. - * - * The BasicAdapter template class provides implementations for the type- - * casting functions so that Adapter implementations are semantically - * equivalent in their type-casting behaviour. - * - * @returns true if Adapter supports strict types, false otherwise - */ - virtual bool hasStrictTypes() const = 0; - - /// Returns true if the contained value is definitely an array. - virtual bool isArray() const = 0; - - /// Returns true if the contained value is definitely a boolean. - virtual bool isBool() const = 0; - - /// Returns true if the contained value is definitely a double. - virtual bool isDouble() const = 0; - - /// Returns true if the contained value is definitely an integer. - virtual bool isInteger() const = 0; - - /// Returns true if the contained value is definitely a null. - virtual bool isNull() const = 0; - - /// Returns true if the contained value is either a double or an integer. - virtual bool isNumber() const = 0; - - /// Returns true if the contained value is definitely an object. - virtual bool isObject() const = 0; - - /// Returns true if the contained value is definitely a string. - virtual bool isString() const = 0; - - /** - * @brief Returns true if the contained value can be cast to an array. - * - * @returns true if the contained value is an array, an empty string, or an - * empty object. - */ - virtual bool maybeArray() const = 0; - - /** - * @brief Returns true if the contained value can be cast to a boolean. - * - * @returns true if the contained value is a boolean, or one of the strings - * 'true' or 'false'. Note that numeric values are not to be cast - * to boolean values. - */ - virtual bool maybeBool() const = 0; - - /** - * @brief Returns true if the contained value can be cast to a double. - * - * @returns true if the contained value is a double, an integer, or a string - * containing a double or integral value. - */ - virtual bool maybeDouble() const = 0; - - /** - * @brief Returns true if the contained value can be cast to an integer. - * - * @returns true if the contained value is an integer, or a string - * containing an integral value. - */ - virtual bool maybeInteger() const = 0; - - /** - * @brief Returns true if the contained value can be cast to a null. - * - * @returns true if the contained value is null or an empty string. - */ - virtual bool maybeNull() const = 0; - - /** - * @brief Returns true if the contained value can be cast to an object. - * - * @returns true if the contained value is an object, an empty array or - * an empty string. - */ - virtual bool maybeObject() const = 0; - - /** - * @brief Returns true if the contained value can be cast to a string. - * - * @returns true if the contained value is a non-null POD type, an empty - * array, or an empty object. - */ - virtual bool maybeString() const = 0; -}; - -/** - * @brief Template struct that should be specialised for each concrete Adapter - * class. - * - * @deprecated This is a bit of a hack, and I'd like to remove it. - */ -template -struct AdapterTraits -{ - -}; - -} // namespace adapters -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/adapters/basic_adapter.hpp b/subprojects/valijson/include/valijson/adapters/basic_adapter.hpp deleted file mode 100644 index 84b2abdd1..000000000 --- a/subprojects/valijson/include/valijson/adapters/basic_adapter.hpp +++ /dev/null @@ -1,859 +0,0 @@ -#pragma once - -#include -#include - -#include -#include -#include - -namespace valijson { -namespace adapters { - -/** - * @brief A helper for the array and object member iterators. - * - * See http://www.stlsoft.org/doc-1.9/group__group____pattern____dereference__proxy.html - * for motivation - * - * @tparam Value Name of the value type - */ -template -struct DerefProxy -{ - explicit DerefProxy(const Value& x) - : m_ref(x) { } - - Value* operator->() - { - return std::addressof(m_ref); - } - - explicit operator Value*() - { - return std::addressof(m_ref); - } - -private: - Value m_ref; -}; - -/** - * @brief Template class that implements the expected semantics of an Adapter. - * - * Implementing all of the type-casting functionality for each Adapter is error - * prone and tedious, so this template class aims to minimise the duplication - * of code between various Adapter implementations. This template doesn't quite - * succeed in removing all duplication, but it has greatly simplified the - * implementation of a new Adapter by encapsulating the type-casting semantics - * and a lot of the trivial functionality associated with the Adapter interface. - * - * By inheriting from this template class, Adapter implementations will inherit - * the exception throwing behaviour that is expected by other parts of the - * Valijson library. - * - * @tparam AdapterType Self-referential name of the Adapter being - * specialised. - * @tparam ArrayType Name of the type that will be returned by the - * getArray() function. Instances of this type should - * provide begin(), end() and size() functions so - * that it is possible to iterate over the values in - * the array. - * @tparam ObjectMemberType Name of the type exposed when iterating over the - * contents of an object returned by getObject(). - * @tparam ObjectType Name of the type that will be returned by the - * getObject() function. Instances of this type - * should provide begin(), end(), find() and size() - * functions so that it is possible to iterate over - * the members of the object. - * @tparam ValueType Name of the type that provides a consistent - * interface to a JSON value for a parser. For - * example, this type should provide the getDouble() - * and isDouble() functions. But it does not need to - * know how to cast values from one type to another - - * that functionality is provided by this template - * class. - */ -template< - typename AdapterType, - typename ArrayType, - typename ObjectMemberType, - typename ObjectType, - typename ValueType> -class BasicAdapter: public Adapter -{ -protected: - - /** - * @brief Functor for comparing two arrays. - * - * This functor is used to compare the elements in an array of the type - * ArrayType with individual values provided as generic Adapter objects. - * Comparison is performed by the () operator. - * - * The functor works by maintaining an iterator for the current position - * in an array. Each time the () operator is called, the value at this - * position is compared with the value passed as an argument to (). - * Immediately after the comparison, the iterator will be incremented. - * - * This functor is designed to be passed to the applyToArray() function - * of an Adapter object. - */ - class ArrayComparisonFunctor - { - public: - - /** - * @brief Construct an ArrayComparisonFunctor for an array. - * - * @param array Array to compare values against - * @param strict Flag to use strict type comparison - */ - ArrayComparisonFunctor(const ArrayType &array, bool strict) - : m_itr(array.begin()), - m_end(array.end()), - m_strict(strict) { } - - /** - * @brief Compare a value against the current element in the array. - * - * @param adapter Value to be compared with current element - * - * @returns true if values are equal, false otherwise. - */ - bool operator()(const Adapter &adapter) - { - if (m_itr == m_end) { - return false; - } - - return AdapterType(*m_itr++).equalTo(adapter, m_strict); - } - - private: - - /// Iterator for current element in the array - typename ArrayType::const_iterator m_itr; - - /// Iterator for one-past the last element of the array - typename ArrayType::const_iterator m_end; - - /// Flag to use strict type comparison - const bool m_strict; - }; - - /** - * @brief Functor for comparing two objects - * - * This functor is used to compare the members of an object of the type - * ObjectType with key-value pairs belonging to another object. - * - * The functor works by maintaining a reference to an object provided via - * the constructor. When time the () operator is called with a key-value - * pair as arguments, the function will attempt to find the key in the - * base object. If found, the associated value will be compared with the - * value provided to the () operator. - * - * This functor is designed to be passed to the applyToObject() function - * of an Adapter object. - */ - class ObjectComparisonFunctor - { - public: - - /** - * @brief Construct a new ObjectComparisonFunctor for an object. - * - * @param object object to use as comparison baseline - * @param strict flag to use strict type-checking - */ - ObjectComparisonFunctor(const ObjectType &object, bool strict) - : m_object(object), - m_strict(strict) { } - - /** - * @brief Find a key in the object and compare its value. - * - * @param key Key to find - * @param value Value to be compared against - * - * @returns true if key is found and values are equal, false otherwise. - */ - bool operator()(const std::string &key, const Adapter &value) - { - const typename ObjectType::const_iterator itr = m_object.find(key); - if (itr == m_object.end()) { - return false; - } - - return (*itr).second.equalTo(value, m_strict); - } - - private: - - /// Object to be used as a comparison baseline - const ObjectType &m_object; - - /// Flag to use strict type-checking - bool m_strict; - }; - - -public: - - /// Alias for ArrayType template parameter - typedef ArrayType Array; - - /// Alias for ObjectMemberType template parameter - typedef ObjectMemberType ObjectMember; - - /// Alias for ObjectType template parameter - typedef ObjectType Object; - - /** - * @brief Construct an Adapter using the default value. - * - * This constructor relies on the default constructor of the ValueType - * class provided as a template argument. - */ - BasicAdapter() = default; - - /** - * @brief Construct an Adapter using a specified ValueType object. - * - * This constructor relies on the copy constructor of the ValueType - * class provided as template argument. - */ - explicit BasicAdapter(const ValueType &value) - : m_value(value) { } - - bool applyToArray(ArrayValueCallback fn) const override - { - if (!maybeArray()) { - return false; - } - - // Due to the fact that the only way a value can be 'maybe an array' is - // if it is an empty string or empty object, we only need to go to - // effort of constructing an ArrayType instance if the value is - // definitely an array. - if (m_value.isArray()) { - const opt::optional array = m_value.getArrayOptional(); - for (const AdapterType element : *array) { - if (!fn(element)) { - return false; - } - } - } - - return true; - } - - bool applyToObject(ObjectMemberCallback fn) const override - { - if (!maybeObject()) { - return false; - } - - if (m_value.isObject()) { - const opt::optional object = m_value.getObjectOptional(); - for (const ObjectMemberType member : *object) { - if (!fn(member.first, AdapterType(member.second))) { - return false; - } - } - } - - return true; - } - - /** - * @brief Return an ArrayType instance containing an array representation - * of the value held by this Adapter. - * - * This is a convenience function that is not actually declared in the - * Adapter interface, but allows for useful techniques such as procedural - * iteration over the elements in an array. The ArrayType instance that is - * returned by this function is compatible with the BOOST_FOREACH macro. - * - * If the contained value is either an empty object, or an empty string, - * then this function will cast the value to an empty array. - * - * @returns ArrayType instance containing an array representation of the - * value held by this Adapter. - */ - ArrayType asArray() const - { - if (m_value.isArray()) { - return *m_value.getArrayOptional(); - } else if (m_value.isObject()) { - size_t objectSize; - if (m_value.getObjectSize(objectSize) && objectSize == 0) { - return ArrayType(); - } - } else if (m_value.isString()) { - std::string stringValue; - if (m_value.getString(stringValue) && stringValue.empty()) { - return ArrayType(); - } - } - - throwRuntimeError("JSON value cannot be cast to an array."); - } - - bool asBool() const override - { - bool result; - if (asBool(result)) { - return result; - } - - throwRuntimeError("JSON value cannot be cast to a boolean."); - } - - bool asBool(bool &result) const override - { - if (m_value.isBool()) { - return m_value.getBool(result); - } else if (m_value.isString()) { - std::string s; - if (m_value.getString(s)) { - if (s == "true") { - result = true; - return true; - } else if (s == "false") { - result = false; - return true; - } - } - } - - return false; - } - - double asDouble() const override - { - double result; - if (asDouble(result)) { - return result; - } - - throwRuntimeError("JSON value cannot be cast to a double."); - } - - bool asDouble(double &result) const override - { - if (m_value.isDouble()) { - return m_value.getDouble(result); - } else if (m_value.isInteger()) { - int64_t i; - if (m_value.getInteger(i)) { - result = double(i); - return true; - } - } else if (m_value.isString()) { - std::string s; - if (m_value.getString(s)) { - const char *b = s.c_str(); - char *e = nullptr; - double x = strtod(b, &e); - if (e == b || e != b + s.length()) { - return false; - } - result = x; - return true; - } - } - - return false; - } - - int64_t asInteger() const override - { - int64_t result; - if (asInteger(result)) { - return result; - } - - throwRuntimeError("JSON value cannot be cast as an integer."); - } - - bool asInteger(int64_t &result) const override - { - if (m_value.isInteger()) { - return m_value.getInteger(result); - } else if (m_value.isString()) { - std::string s; - if (m_value.getString(s)) { - std::istringstream i(s); - int64_t x; - char c; - if (!(!(i >> x) || i.get(c))) { - result = x; - return true; - } - } - } - - return false; - } - - /** - * @brief Return an ObjectType instance containing an array representation - * of the value held by this Adapter. - * - * This is a convenience function that is not actually declared in the - * Adapter interface, but allows for useful techniques such as procedural - * iteration over the members of the object. The ObjectType instance that is - * returned by this function is compatible with the BOOST_FOREACH macro. - * - * @returns ObjectType instance containing an object representation of the - * value held by this Adapter. - */ - ObjectType asObject() const - { - if (m_value.isObject()) { - return *m_value.getObjectOptional(); - } else if (m_value.isArray()) { - size_t arraySize; - if (m_value.getArraySize(arraySize) && arraySize == 0) { - return ObjectType(); - } - } else if (m_value.isString()) { - std::string stringValue; - if (m_value.getString(stringValue) && stringValue.empty()) { - return ObjectType(); - } - } - - throwRuntimeError("JSON value cannot be cast to an object."); - } - - std::string asString() const override - { - std::string result; - if (asString(result)) { - return result; - } - - throwRuntimeError("JSON value cannot be cast to a string."); - } - - bool asString(std::string &result) const override - { - if (m_value.isString()) { - return m_value.getString(result); - } else if (m_value.isNull()) { - result.clear(); - return true; - } else if (m_value.isArray()) { - size_t arraySize; - if (m_value.getArraySize(arraySize) && arraySize == 0) { - result.clear(); - return true; - } - } else if (m_value.isObject()) { - size_t objectSize; - if (m_value.getObjectSize(objectSize) && objectSize == 0) { - result.clear(); - return true; - } - } else if (m_value.isBool()) { - bool boolValue; - if (m_value.getBool(boolValue)) { - result = boolValue ? "true" : "false"; - return true; - } - } else if (m_value.isInteger()) { - int64_t integerValue; - if (m_value.getInteger(integerValue)) { - result = std::to_string(integerValue); - return true; - } - } else if (m_value.isDouble()) { - double doubleValue; - if (m_value.getDouble(doubleValue)) { - result = std::to_string(doubleValue); - return true; - } - } - - return false; - } - - bool equalTo(const Adapter &other, bool strict) const override - { - if (isNull() || (!strict && maybeNull())) { - return other.isNull() || (!strict && other.maybeNull()); - } else if (isBool() || (!strict && maybeBool())) { - return (other.isBool() || (!strict && other.maybeBool())) && other.asBool() == asBool(); - } else if (isNumber() && strict) { - return other.isNumber() && other.getNumber() == getNumber(); - } else if (!strict && maybeDouble()) { - return (other.maybeDouble() && other.asDouble() == asDouble()); - } else if (!strict && maybeInteger()) { - return (other.maybeInteger() && other.asInteger() == asInteger()); - } else if (isString() || (!strict && maybeString())) { - return (other.isString() || (!strict && other.maybeString())) && - other.asString() == asString(); - } else if (isArray()) { - if (other.isArray() && getArraySize() == other.getArraySize()) { - const opt::optional array = m_value.getArrayOptional(); - if (array) { - ArrayComparisonFunctor fn(*array, strict); - return other.applyToArray(fn); - } - } else if (!strict && other.maybeArray() && getArraySize() == 0) { - return true; - } - } else if (isObject()) { - if (other.isObject() && other.getObjectSize() == getObjectSize()) { - const opt::optional object = m_value.getObjectOptional(); - if (object) { - ObjectComparisonFunctor fn(*object, strict); - return other.applyToObject(fn); - } - } else if (!strict && other.maybeObject() && getObjectSize() == 0) { - return true; - } - } - - return false; - } - - /** - * @brief Return an ArrayType instance representing the array contained - * by this Adapter instance. - * - * This is a convenience function that is not actually declared in the - * Adapter interface, but allows for useful techniques such as procedural - * iteration over the elements in an array. The ArrayType instance that is - * returned by this function is compatible with the BOOST_FOREACH macro. - * - * If the contained is not an array, this function will throw an exception. - * - * @returns ArrayType instance containing an array representation of the - * value held by this Adapter. - */ - ArrayType getArray() const - { - opt::optional arrayValue = m_value.getArrayOptional(); - if (arrayValue) { - return *arrayValue; - } - - throwRuntimeError("JSON value is not an array."); - } - - size_t getArraySize() const override - { - size_t result; - if (m_value.getArraySize(result)) { - return result; - } - - throwRuntimeError("JSON value is not an array."); - } - - bool getArraySize(size_t &result) const override - { - return m_value.getArraySize(result); - } - - bool getBool() const override - { - bool result; - if (getBool(result)) { - return result; - } - - throwRuntimeError("JSON value is not a boolean."); - } - - bool getBool(bool &result) const override - { - return m_value.getBool(result); - } - - double getDouble() const override - { - double result; - if (getDouble(result)) { - return result; - } - - throwRuntimeError("JSON value is not a double."); - } - - bool getDouble(double &result) const override - { - return m_value.getDouble(result); - } - - int64_t getInteger() const override - { - int64_t result; - if (getInteger(result)) { - return result; - } - - throwRuntimeError("JSON value is not an integer."); - } - - bool getInteger(int64_t &result) const override - { - return m_value.getInteger(result); - } - - double getNumber() const override - { - double result; - if (getNumber(result)) { - return result; - } - - throwRuntimeError("JSON value is not a number."); - } - - bool getNumber(double &result) const override - { - if (isDouble()) { - return getDouble(result); - } else if (isInteger()) { - int64_t integerResult; - if (getInteger(integerResult)) { - result = static_cast(integerResult); - return true; - } - } - - return false; - } - - /** - * @brief Return an ObjectType instance representing the object contained - * by this Adapter instance. - * - * This is a convenience function that is not actually declared in the - * Adapter interface, but allows for useful techniques such as procedural - * iteration over the members of an object. The ObjectType instance that is - * returned by this function is compatible with the BOOST_FOREACH macro. - * - * If the contained is not an object, this function will throw an exception. - * - * @returns ObjectType instance containing an array representation of the - * value held by this Adapter. - */ - ObjectType getObject() const - { - opt::optional objectValue = m_value.getObjectOptional(); - if (objectValue) { - return *objectValue; - } - - throwRuntimeError("JSON value is not an object."); - } - - size_t getObjectSize() const override - { - size_t result; - if (getObjectSize(result)) { - return result; - } - - throwRuntimeError("JSON value is not an object."); - } - - bool getObjectSize(size_t &result) const override - { - return m_value.getObjectSize(result); - } - - std::string getString() const override - { - std::string result; - if (getString(result)) { - return result; - } - - throwRuntimeError("JSON value is not a string."); - } - - bool getString(std::string &result) const override - { - return m_value.getString(result); - } - - FrozenValue * freeze() const override - { - return m_value.freeze(); - } - - bool hasStrictTypes() const override - { - return ValueType::hasStrictTypes(); - } - - bool isArray() const override - { - return m_value.isArray(); - } - - bool isBool() const override - { - return m_value.isBool(); - } - - bool isDouble() const override - { - return m_value.isDouble(); - } - - bool isInteger() const override - { - return m_value.isInteger(); - } - - bool isNull() const override - { - return m_value.isNull(); - } - - bool isNumber() const override - { - return m_value.isInteger() || m_value.isDouble(); - } - - bool isObject() const override - { - return m_value.isObject(); - } - - bool isString() const override - { - return m_value.isString(); - } - - bool maybeArray() const override - { - if (m_value.isArray()) { - return true; - } else if (m_value.isObject()) { - size_t objectSize; - if (m_value.getObjectSize(objectSize) && objectSize == 0) { - return true; - } - } - - return false; - } - - bool maybeBool() const override - { - if (m_value.isBool()) { - return true; - } else if (maybeString()) { - std::string stringValue; - if (m_value.getString(stringValue)) { - if (stringValue == "true" || stringValue == "false") { - return true; - } - } - } - - return false; - } - - bool maybeDouble() const override - { - if (m_value.isNumber()) { - return true; - } else if (maybeString()) { - std::string s; - if (m_value.getString(s)) { - const char *b = s.c_str(); - char *e = nullptr; - strtod(b, &e); - return e != b && e == b + s.length(); - } - } - - return false; - } - - bool maybeInteger() const override - { - if (m_value.isInteger()) { - return true; - } else if (maybeString()) { - std::string s; - if (m_value.getString(s)) { - std::istringstream i(s); - int64_t x; - char c; - if (!(i >> x) || i.get(c)) { - return false; - } - return true; - } - } - - return false; - } - - bool maybeNull() const override - { - if (m_value.isNull()) { - return true; - } else if (maybeString()) { - std::string stringValue; - if (m_value.getString(stringValue)) { - if (stringValue.empty()) { - return true; - } - } - } - - return false; - } - - bool maybeObject() const override - { - if (m_value.isObject()) { - return true; - } else if (maybeArray()) { - size_t arraySize; - if (m_value.getArraySize(arraySize) && arraySize == 0) { - return true; - } - } - - return false; - } - - bool maybeString() const override - { - if (m_value.isString() || m_value.isBool() || m_value.isInteger() || m_value.isDouble()) { - return true; - } else if (m_value.isObject()) { - size_t objectSize; - if (m_value.getObjectSize(objectSize) && objectSize == 0) { - return true; - } - } else if (m_value.isArray()) { - size_t arraySize; - if (m_value.getArraySize(arraySize) && arraySize == 0) { - return true; - } - } - - return false; - } - -private: - - const ValueType m_value; -}; - -} // namespace adapters -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/adapters/frozen_value.hpp b/subprojects/valijson/include/valijson/adapters/frozen_value.hpp deleted file mode 100644 index 56b5eafc5..000000000 --- a/subprojects/valijson/include/valijson/adapters/frozen_value.hpp +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once - -#include - -namespace valijson { -namespace adapters { - -/** - * @brief An interface that provides minimal access to a stored JSON value. - * - * The main reason that this interface exists is to support the 'enum' - * constraint. Each Adapter type is expected to provide an implementation of - * this interface. That class should be able to maintain its own copy of a - * JSON value, independent of the original document. - * - * This interface currently provides just the clone and equalTo functions, but - * could be expanded to include other functions declared in the Adapter - * interface. - * - * @todo it would be nice to better integrate this with the Adapter interface - */ -class FrozenValue -{ -public: - - /** - * @brief Virtual destructor defined to ensure deletion via base-class - * pointers is safe. - */ - virtual ~FrozenValue() { } - - /** - * @brief Clone the stored value and return a pointer to a new FrozenValue - * object containing the value. - */ - virtual FrozenValue *clone() const = 0; - - /** - * @brief Return true if the stored value is equal to the value contained - * by an Adapter instance. - * - * @param adapter Adapter to compare value against - * @param strict Flag to use strict type comparison - * - * @returns true if values are equal, false otherwise - */ - virtual bool equalTo(const Adapter &adapter, bool strict) const = 0; - -}; - -} // namespace adapters -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/adapters/json11_adapter.hpp b/subprojects/valijson/include/valijson/adapters/json11_adapter.hpp deleted file mode 100644 index 41749b2fc..000000000 --- a/subprojects/valijson/include/valijson/adapters/json11_adapter.hpp +++ /dev/null @@ -1,711 +0,0 @@ -/** - * @file - * - * @brief Adapter implementation for the json11 parser library. - * - * Include this file in your program to enable support for json11. - * - * This file defines the following classes (not in this order): - * - Json11Adapter - * - Json11Array - * - Json11ArrayValueIterator - * - Json11FrozenValue - * - Json11Object - * - Json11ObjectMember - * - Json11ObjectMemberIterator - * - Json11Value - * - * Due to the dependencies that exist between these classes, the ordering of - * class declarations and definitions may be a bit confusing. The best place to - * start is Json11Adapter. This class definition is actually very small, - * since most of the functionality is inherited from the BasicAdapter class. - * Most of the classes in this file are provided as template arguments to the - * inherited BasicAdapter class. - */ - -#pragma once - -#include -#include - -#include -#include -#include -#include - -namespace valijson { -namespace adapters { - -class Json11Adapter; -class Json11ArrayValueIterator; -class Json11ObjectMemberIterator; - -typedef std::pair Json11ObjectMember; - -/** - * @brief Light weight wrapper for a Json11 array value. - * - * This class is light weight wrapper for a Json11 array. It provides a - * minimum set of container functions and typedefs that allow it to be used as - * an iterable container. - * - * An instance of this class contains a single reference to the underlying - * Json11 value, assumed to be an array, so there is very little overhead - * associated with copy construction and passing by value. - */ -class Json11Array -{ -public: - - typedef Json11ArrayValueIterator const_iterator; - typedef Json11ArrayValueIterator iterator; - - /// Construct a Json11Array referencing an empty array. - Json11Array() - : m_value(emptyArray()) { } - - /** - * @brief Construct a Json11Array referencing a specific Json11 - * value. - * - * @param value reference to a Json11 value - * - * Note that this constructor will throw an exception if the value is not - * an array. - */ - Json11Array(const json11::Json &value) - : m_value(value) - { - if (!value.is_array()) { - throwRuntimeError("Value is not an array."); - } - } - - /** - * @brief Return an iterator for the first element of the array. - * - * The iterator return by this function is effectively the iterator - * returned by the underlying Json11 implementation. - */ - Json11ArrayValueIterator begin() const; - - /** - * @brief Return an iterator for one-past the last element of the array. - * - * The iterator return by this function is effectively the iterator - * returned by the underlying Json11 implementation. - */ - Json11ArrayValueIterator end() const; - - /// Return the number of elements in the array - size_t size() const - { - return m_value.array_items().size(); - } - -private: - - /** - * @brief Return a reference to a Json11 value that is an empty array. - * - * Note that the value returned by this function is a singleton. - */ - static const json11::Json & emptyArray() - { - static const json11::Json array((json11::Json::array())); - return array; - } - - /// Reference to the contained value - const json11::Json &m_value; -}; - -/** - * @brief Light weight wrapper for a Json11 object. - * - * This class is light weight wrapper for a Json11 object. It provides a - * minimum set of container functions and typedefs that allow it to be used as - * an iterable container. - * - * An instance of this class contains a single reference to the underlying - * Json11 value, assumed to be an object, so there is very little overhead - * associated with copy construction and passing by value. - */ -class Json11Object -{ -public: - - typedef Json11ObjectMemberIterator const_iterator; - typedef Json11ObjectMemberIterator iterator; - - /// Construct a Json11Object referencing an empty object singleton. - Json11Object() - : m_value(emptyObject()) { } - - /** - * @brief Construct a Json11Object referencing a specific Json11 - * value. - * - * @param value reference to a Json11 value - * - * Note that this constructor will throw an exception if the value is not - * an object. - */ - Json11Object(const json11::Json &value) - : m_value(value) - { - if (!value.is_object()) { - throwRuntimeError("Value is not an object."); - } - } - - /** - * @brief Return an iterator for this first object member - * - * The iterator return by this function is effectively a wrapper around - * the iterator value returned by the underlying Json11 implementation. - */ - Json11ObjectMemberIterator begin() const; - - /** - * @brief Return an iterator for an invalid object member that indicates - * the end of the collection. - * - * The iterator return by this function is effectively a wrapper around - * the iterator value returned by the underlying Json11 implementation. - */ - Json11ObjectMemberIterator end() const; - - /** - * @brief Return an iterator for the object member with the specified - * property name. - * - * If an object member with the specified name does not exist, the iterator - * returned will be the same as the iterator returned by the end() function. - * - * @param propertyName property name to search for - */ - Json11ObjectMemberIterator find(const std::string &propertyName) const; - - /// Returns the number of members belonging to this object. - size_t size() const - { - return m_value.object_items().size(); - } - -private: - - /** - * @brief Return a reference to a Json11 value that is empty object. - * - * Note that the value returned by this function is a singleton. - */ - static const json11::Json & emptyObject() - { - static const json11::Json object((json11::Json::object())); - return object; - } - - /// Reference to the contained object - const json11::Json &m_value; -}; - -/** - * @brief Stores an independent copy of a Json11 value. - * - * This class allows a Json11 value to be stored independent of its original - * document. Json11 makes this easy to do, as it does not perform any - * custom memory management. - * - * @see FrozenValue - */ -class Json11FrozenValue: public FrozenValue -{ -public: - - /** - * @brief Make a copy of a Json11 value - * - * @param source the Json11 value to be copied - */ - explicit Json11FrozenValue(json11::Json source) - : m_value(std::move(source)) { } - - FrozenValue * clone() const override - { - return new Json11FrozenValue(m_value); - } - - bool equalTo(const Adapter &other, bool strict) const override; - -private: - - /// Stored Json11 value - json11::Json m_value; -}; - -/** - * @brief Light weight wrapper for a Json11 value. - * - * This class is passed as an argument to the BasicAdapter template class, - * and is used to provide access to a Json11 value. This class is responsible - * for the mechanics of actually reading a Json11 value, whereas the - * BasicAdapter class is responsible for the semantics of type comparisons - * and conversions. - * - * The functions that need to be provided by this class are defined implicitly - * by the implementation of the BasicAdapter template class. - * - * @see BasicAdapter - */ -class Json11Value -{ -public: - - /// Construct a wrapper for the empty object singleton - Json11Value() - : m_value(emptyObject()) { } - - /// Construct a wrapper for a specific Json11 value - Json11Value(const json11::Json &value) - : m_value(value) { } - - /** - * @brief Create a new Json11FrozenValue instance that contains the - * value referenced by this Json11Value instance. - * - * @returns pointer to a new Json11FrozenValue instance, belonging to the - * caller. - */ - FrozenValue * freeze() const - { - return new Json11FrozenValue(m_value); - } - - /** - * @brief Optionally return a Json11Array instance. - * - * If the referenced Json11 value is an array, this function will return - * a std::optional containing a Json11Array instance referencing the - * array. - * - * Otherwise it will return an empty optional. - */ - opt::optional getArrayOptional() const - { - if (m_value.is_array()) { - return opt::make_optional(Json11Array(m_value)); - } - - return {}; - } - - /** - * @brief Retrieve the number of elements in the array - * - * If the referenced Json11 value is an array, this function will - * retrieve the number of elements in the array and store it in the output - * variable provided. - * - * @param result reference to size_t to set with result - * - * @returns true if the number of elements was retrieved, false otherwise. - */ - bool getArraySize(size_t &result) const - { - if (m_value.is_array()) { - result = m_value.array_items().size(); - return true; - } - - return false; - } - - bool getBool(bool &result) const - { - if (m_value.is_bool()) { - result = m_value.bool_value(); - return true; - } - - return false; - } - - bool getDouble(double &result) const - { - if (m_value.is_number()) { - result = m_value.number_value(); - return true; - } - - return false; - } - - bool getInteger(int64_t &result) const - { - if (isInteger()) { - result = m_value.int_value(); - return true; - } - return false; - } - - /** - * @brief Optionally return a Json11Object instance. - * - * If the referenced Json11 value is an object, this function will return a - * std::optional containing a Json11Object instance referencing the - * object. - * - * Otherwise it will return an empty optional. - */ - opt::optional getObjectOptional() const - { - if (m_value.is_object()) { - return opt::make_optional(Json11Object(m_value)); - } - - return {}; - } - - /** - * @brief Retrieve the number of members in the object - * - * If the referenced Json11 value is an object, this function will - * retrieve the number of members in the object and store it in the output - * variable provided. - * - * @param result reference to size_t to set with result - * - * @returns true if the number of members was retrieved, false otherwise. - */ - bool getObjectSize(size_t &result) const - { - if (m_value.is_object()) { - result = m_value.object_items().size(); - return true; - } - - return false; - } - - bool getString(std::string &result) const - { - if (m_value.is_string()) { - result = m_value.string_value(); - return true; - } - - return false; - } - - static bool hasStrictTypes() - { - return true; - } - - bool isArray() const - { - return m_value.is_array(); - } - - bool isBool() const - { - return m_value.is_bool(); - } - - bool isDouble() const - { - return m_value.is_number(); - } - - bool isInteger() const - { - return m_value.is_number() && m_value.int_value() == m_value.number_value(); - } - - bool isNull() const - { - return m_value.is_null(); - } - - bool isNumber() const - { - return m_value.is_number(); - } - - bool isObject() const - { - return m_value.is_object(); - } - - bool isString() const - { - return m_value.is_string(); - } - -private: - - /// Return a reference to an empty object singleton - static const json11::Json & emptyObject() - { - static const json11::Json object((json11::Json::object())); - return object; - } - - /// Reference to the contained Json11 value. - const json11::Json &m_value; -}; - -/** - * @brief An implementation of the Adapter interface supporting Json11. - * - * This class is defined in terms of the BasicAdapter template class, which - * helps to ensure that all of the Adapter implementations behave consistently. - * - * @see Adapter - * @see BasicAdapter - */ -class Json11Adapter: - public BasicAdapter -{ -public: - - /// Construct a Json11Adapter that contains an empty object - Json11Adapter() - : BasicAdapter() { } - - /// Construct a Json11Adapter containing a specific Json11 value - Json11Adapter(const json11::Json &value) - : BasicAdapter(value) { } -}; - -/** - * @brief Class for iterating over values held in a JSON array. - * - * This class provides a JSON array iterator that dereferences as an instance of - * Json11Adapter representing a value stored in the array. It has been - * implemented using the boost iterator_facade template. - * - * @see Json11Array - */ -class Json11ArrayValueIterator -{ -public: - using iterator_category = std::bidirectional_iterator_tag; - using value_type = Json11Adapter; - using difference_type = Json11Adapter; - using pointer = Json11Adapter*; - using reference = Json11Adapter&; - - /** - * @brief Construct a new Json11ArrayValueIterator using an existing - * Json11 iterator. - * - * @param itr Json11 iterator to store - */ - Json11ArrayValueIterator(const json11::Json::array::const_iterator &itr) - : m_itr(itr) { } - - /// Returns a Json11Adapter that contains the value of the current - /// element. - Json11Adapter operator*() const - { - return Json11Adapter(*m_itr); - } - - DerefProxy operator->() const - { - return DerefProxy(**this); - } - - /** - * @brief Compare this iterator against another iterator. - * - * Note that this directly compares the iterators, not the underlying - * values, and assumes that two identical iterators will point to the same - * underlying object. - * - * @param other iterator to compare against - * - * @returns true if the iterators are equal, false otherwise. - */ - bool operator==(const Json11ArrayValueIterator &other) const - { - return m_itr == other.m_itr; - } - - bool operator!=(const Json11ArrayValueIterator &other) const - { - return !(m_itr == other.m_itr); - } - - const Json11ArrayValueIterator& operator++() - { - m_itr++; - - return *this; - } - - Json11ArrayValueIterator operator++(int) - { - Json11ArrayValueIterator iterator_pre(m_itr); - ++(*this); - return iterator_pre; - } - - const Json11ArrayValueIterator& operator--() - { - m_itr--; - - return *this; - } - - void advance(std::ptrdiff_t n) - { - m_itr += n; - } - -private: - - json11::Json::array::const_iterator m_itr; -}; - -/** - * @brief Class for iterating over the members belonging to a JSON object. - * - * This class provides a JSON object iterator that dereferences as an instance - * of Json11ObjectMember representing one of the members of the object. It - * has been implemented using the boost iterator_facade template. - * - * @see Json11Object - * @see Json11ObjectMember - */ -class Json11ObjectMemberIterator -{ -public: - using iterator_category = std::bidirectional_iterator_tag; - using value_type = Json11ObjectMember; - using difference_type = Json11ObjectMember; - using pointer = Json11ObjectMember*; - using reference = Json11ObjectMember&; - - /** - * @brief Construct an iterator from a Json11 iterator. - * - * @param itr Json11 iterator to store - */ - Json11ObjectMemberIterator(const json11::Json::object::const_iterator &itr) - : m_itr(itr) { } - - /** - * @brief Returns a Json11ObjectMember that contains the key and value - * belonging to the object member identified by the iterator. - */ - Json11ObjectMember operator*() const - { - return Json11ObjectMember(m_itr->first, m_itr->second); - } - - DerefProxy operator->() const - { - return DerefProxy(**this); - } - - /** - * @brief Compare this iterator with another iterator. - * - * Note that this directly compares the iterators, not the underlying - * values, and assumes that two identical iterators will point to the same - * underlying object. - * - * @param other Iterator to compare with - * - * @returns true if the underlying iterators are equal, false otherwise - */ - bool operator==(const Json11ObjectMemberIterator &other) const - { - return m_itr == other.m_itr; - } - - bool operator!=(const Json11ObjectMemberIterator &other) const - { - return !(m_itr == other.m_itr); - } - - const Json11ObjectMemberIterator& operator++() - { - m_itr++; - - return *this; - } - - Json11ObjectMemberIterator operator++(int) - { - Json11ObjectMemberIterator iterator_pre(m_itr); - ++(*this); - return iterator_pre; - } - - const Json11ObjectMemberIterator& operator--() - { - m_itr--; - - return *this; - } - -private: - - /// Iternal copy of the original Json11 iterator - json11::Json::object::const_iterator m_itr; -}; - -/// Specialisation of the AdapterTraits template struct for Json11Adapter. -template<> -struct AdapterTraits -{ - typedef json11::Json DocumentType; - - static std::string adapterName() - { - return "Json11Adapter"; - } -}; - -inline bool Json11FrozenValue::equalTo(const Adapter &other, bool strict) const -{ - return Json11Adapter(m_value).equalTo(other, strict); -} - -inline Json11ArrayValueIterator Json11Array::begin() const -{ - return m_value.array_items().begin(); -} - -inline Json11ArrayValueIterator Json11Array::end() const -{ - return m_value.array_items().end(); -} - -inline Json11ObjectMemberIterator Json11Object::begin() const -{ - return m_value.object_items().begin(); -} - -inline Json11ObjectMemberIterator Json11Object::end() const -{ - return m_value.object_items().end(); -} - -inline Json11ObjectMemberIterator Json11Object::find( - const std::string &propertyName) const -{ - return m_value.object_items().find(propertyName); -} - -} // namespace adapters -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/adapters/jsoncpp_adapter.hpp b/subprojects/valijson/include/valijson/adapters/jsoncpp_adapter.hpp deleted file mode 100644 index 2fd1fe74b..000000000 --- a/subprojects/valijson/include/valijson/adapters/jsoncpp_adapter.hpp +++ /dev/null @@ -1,724 +0,0 @@ -/** - * @file - * - * @brief Adapter implementation for the JsonCpp parser library. - * - * Include this file in your program to enable support for JsonCpp. - * - * This file defines the following classes (not in this order): - * - JsonCppAdapter - * - JsonCppArray - * - JsonCppArrayValueIterator - * - JsonCppFrozenValue - * - JsonCppObject - * - JsonCppObjectMember - * - JsonCppObjectMemberIterator - * - JsonCppValue - * - * Due to the dependencies that exist between these classes, the ordering of - * class declarations and definitions may be a bit confusing. The best place to - * start is JsonCppAdapter. This class definition is actually very small, - * since most of the functionality is inherited from the BasicAdapter class. - * Most of the classes in this file are provided as template arguments to the - * inherited BasicAdapter class. - */ - -#pragma once - -#include -#include -#include - -#include - -#include -#include -#include -#include - -namespace valijson { -namespace adapters { - -class JsonCppAdapter; -class JsonCppArrayValueIterator; -class JsonCppObjectMemberIterator; - -typedef std::pair JsonCppObjectMember; - -/** - * @brief Light weight wrapper for a JsonCpp array value. - * - * This class is light weight wrapper for a JsonCpp array. It provides a - * minimum set of container functions and typedefs that allow it to be used as - * an iterable container. - * - * An instance of this class contains a single reference to the underlying - * JsonCpp value, assumed to be an array, so there is very little overhead - * associated with copy construction and passing by value. - */ -class JsonCppArray -{ -public: - - typedef JsonCppArrayValueIterator const_iterator; - typedef JsonCppArrayValueIterator iterator; - - /// Construct a JsonCppArray referencing an empty array. - JsonCppArray() - : m_value(emptyArray()) { } - - /** - * @brief Construct a JsonCppArray referencing a specific JsonCpp value. - * - * @param value reference to a JsonCpp value - * - * Note that this constructor will throw an exception if the value is not - * an array. - */ - JsonCppArray(const Json::Value &value) - : m_value(value) - { - if (!value.isArray()) { - throwRuntimeError("Value is not an array."); - } - } - - /** - * @brief Return an iterator for the first element of the array. - * - * The iterator return by this function is effectively the iterator - * returned by the underlying JsonCpp implementation. - */ - JsonCppArrayValueIterator begin() const; - - /** - * @brief Return an iterator for one-past the last element of the array. - * - * The iterator return by this function is effectively the iterator - * returned by the underlying JsonCpp implementation. - */ - JsonCppArrayValueIterator end() const; - - /// Return the number of elements in the array. - size_t size() const - { - return m_value.size(); - } - -private: - - /** - * @brief Return a reference to a JsonCpp value that is an empty array. - * - * Note that the value returned by this function is a singleton. - */ - static const Json::Value & emptyArray() - { - static const Json::Value array(Json::arrayValue); - return array; - } - - /// Reference to the contained array - const Json::Value &m_value; - -}; - -/** - * @brief Light weight wrapper for a JsonCpp object. - * - * This class is light weight wrapper for a JsonCpp object. It provides a - * minimum set of container functions and typedefs that allow it to be used as - * an iterable container. - * - * An instance of this class contains a single reference to the underlying - * JsonCpp object, assumed to be an object, so there is very little overhead - * associated with copy construction and passing by value. - */ -class JsonCppObject -{ -public: - - typedef JsonCppObjectMemberIterator const_iterator; - typedef JsonCppObjectMemberIterator iterator; - - /// Construct a JsonCppObject referencing an empty object singleton. - JsonCppObject() - : m_value(emptyObject()) { } - - /** - * @brief Construct a JsonCppObject referencing a specific JsonCpp value. - * - * @param value reference to a JsonCpp value - * - * Note that this constructor will throw an exception if the value is not - * an object. - */ - JsonCppObject(const Json::Value &value) - : m_value(value) - { - if (!value.isObject()) { - throwRuntimeError("Value is not an object."); - } - } - - /** - * @brief Return an iterator for this first object member - * - * The iterator return by this function is effectively a wrapper around - * the iterator value returned by the underlying JsonCpp implementation. - */ - JsonCppObjectMemberIterator begin() const; - - /** - * @brief Return an iterator for an invalid object member that indicates - * the end of the collection. - * - * The iterator return by this function is effectively a wrapper around - * the iterator value returned by the underlying JsonCpp implementation. - */ - JsonCppObjectMemberIterator end() const; - - /** - * @brief Return an iterator for a member/property with the given name - * - * @param propertyName Property name - * - * @returns a valid iterator if found, or an invalid iterator if not found - */ - JsonCppObjectMemberIterator find(const std::string &propertyName) const; - - /// Return the number of members in the object - size_t size() const - { - return m_value.size(); - } - -private: - - /// Return a reference to an empty JsonCpp object - static const Json::Value & emptyObject() - { - static const Json::Value object(Json::objectValue); - return object; - } - - /// Reference to the contained object - const Json::Value &m_value; -}; - -/** - * @brief Stores an independent copy of a JsonCpp value. - * - * This class allows a JsonCpp value to be stored independent of its original - * document. JsonCpp makes this easy to do, as it does not perform any - * custom memory management. - * - * @see FrozenValue - */ -class JsonCppFrozenValue: public FrozenValue -{ -public: - - /** - * @brief Make a copy of a JsonCpp value - * - * @param source the JsonCpp value to be copied - */ - explicit JsonCppFrozenValue(const Json::Value &source) - : m_value(source) { } - - FrozenValue * clone() const override - { - return new JsonCppFrozenValue(m_value); - } - - bool equalTo(const Adapter &other, bool strict) const override; - -private: - - /// Stored JsonCpp value - Json::Value m_value; -}; - -/** - * @brief Light weight wrapper for a JsonCpp value. - * - * This class is passed as an argument to the BasicAdapter template class, - * and is used to provide access to a JsonCpp value. This class is responsible - * for the mechanics of actually reading a JsonCpp value, whereas the - * BasicAdapter class is responsible for the semantics of type comparisons - * and conversions. - * - * The functions that need to be provided by this class are defined implicitly - * by the implementation of the BasicAdapter template class. - * - * @see BasicAdapter - */ -class JsonCppValue -{ -public: - - /// Construct a wrapper for the empty object singleton - JsonCppValue() - : m_value(emptyObject()) { } - - /// Construct a wrapper for a specific JsonCpp value - JsonCppValue(const Json::Value &value) - : m_value(value) { } - - /** - * @brief Create a new JsonCppFrozenValue instance that contains the - * value referenced by this JsonCppValue instance. - * - * @returns pointer to a new JsonCppFrozenValue instance, belonging to the - * caller. - */ - FrozenValue * freeze() const - { - return new JsonCppFrozenValue(m_value); - } - - /** - * @brief Optionally return a JsonCppArray instance. - * - * If the referenced JsonCpp value is an array, this function will return a - * std::optional containing a JsonCppArray instance referencing the - * array. - * - * Otherwise it will return an empty optional. - */ - opt::optional getArrayOptional() const - { - if (m_value.isArray()) { - return opt::make_optional(JsonCppArray(m_value)); - } - - return {}; - } - - /** - * @brief Retrieve the number of elements in the array - * - * If the referenced JsonCpp value is an array, this function will retrieve - * the number of elements in the array and store it in the output variable - * provided. - * - * @param result reference to size_t to set with result - * - * @returns true if the number of elements was retrieved, false otherwise. - */ - bool getArraySize(size_t &result) const - { - if (m_value.isArray()) { - result = m_value.size(); - return true; - } - - return false; - } - - bool getBool(bool &result) const - { - if (m_value.isBool()) { - result = m_value.asBool(); - return true; - } - - return false; - } - - bool getDouble(double &result) const - { - if (m_value.isDouble()) { - result = m_value.asDouble(); - return true; - } - - return false; - } - - bool getInteger(int64_t &result) const - { - if (m_value.isIntegral()) { - result = static_cast(m_value.asInt()); - return true; - } - - return false; - } - - /** - * @brief Optionally return a JsonCppObject instance. - * - * If the referenced JsonCpp value is an object, this function will return a - * std::optional containing a JsonCppObject instance referencing the - * object. - * - * Otherwise it will return an empty optional. - */ - opt::optional getObjectOptional() const - { - if (m_value.isObject()) { - return opt::make_optional(JsonCppObject(m_value)); - } - - return {}; - } - - /** - * @brief Retrieve the number of members in the object - * - * If the referenced JsonCpp value is an object, this function will retrieve - * the number of members in the object and store it in the output variable - * provided. - * - * @param result reference to size_t to set with result - * - * @returns true if the number of members was retrieved, false otherwise. - */ - bool getObjectSize(size_t &result) const - { - if (m_value.isObject()) { - result = m_value.size(); - return true; - } - - return false; - } - - bool getString(std::string &result) const - { - if (m_value.isString()) { - result = m_value.asString(); - return true; - } - - return false; - } - - static bool hasStrictTypes() - { - return true; - } - - bool isArray() const - { - return m_value.isArray() && !m_value.isNull(); - } - - bool isBool() const - { - return m_value.isBool(); - } - - bool isDouble() const - { - return m_value.isDouble(); - } - - bool isInteger() const - { - return m_value.isIntegral() && !m_value.isBool(); - } - - bool isNull() const - { - return m_value.isNull(); - } - - bool isNumber() const - { - return m_value.isNumeric() && !m_value.isBool(); - } - - bool isObject() const - { - return m_value.isObject() && !m_value.isNull(); - } - - bool isString() const - { - return m_value.isString(); - } - -private: - - /// Return a reference to an empty object singleton. - static const Json::Value &emptyObject() - { - static Json::Value object(Json::objectValue); - return object; - } - - /// Reference to the contained JsonCpp value - const Json::Value &m_value; -}; - -/** - * @brief An implementation of the Adapter interface supporting JsonCpp. - * - * This class is defined in terms of the BasicAdapter template class, which - * helps to ensure that all of the Adapter implementations behave consistently. - * - * @see Adapter - * @see BasicAdapter - */ -class JsonCppAdapter: - public BasicAdapter -{ -public: - - /// Construct a JsonCppAdapter that contains an empty object - JsonCppAdapter() - : BasicAdapter() { } - - /// Construct a JsonCppAdapter containing a specific JsonCpp value - JsonCppAdapter(const Json::Value &value) - : BasicAdapter(value) { } -}; - -/** - * @brief Class for iterating over values held in a JSON array. - * - * This class provides a JSON array iterator that dereferences as an instance of - * JsonCppAdapter representing a value stored in the array. It has been - * implemented using the boost iterator_facade template. - * - * @see JsonCppArray - */ -class JsonCppArrayValueIterator -{ -public: - using iterator_category = std::bidirectional_iterator_tag; - using value_type = JsonCppAdapter; - using difference_type = JsonCppAdapter; - using pointer = JsonCppAdapter*; - using reference = JsonCppAdapter&; - - /** - * @brief Construct a new JsonCppArrayValueIterator using an existing - * JsonCpp iterator. - * - * @param itr JsonCpp iterator to store - */ - JsonCppArrayValueIterator(const Json::Value::const_iterator &itr) - : m_itr(itr) { } - - /// Returns a JsonCppAdapter that contains the value of the current element. - JsonCppAdapter operator*() const - { - return JsonCppAdapter(*m_itr); - } - - DerefProxy operator->() const - { - return DerefProxy(**this); - } - - /** - * @brief Compare this iterator against another iterator. - * - * Note that this directly compares the iterators, not the underlying - * values, and assumes that two identical iterators will point to the same - * underlying object. - * - * @param rhs iterator to compare against - * - * @returns true if the iterators are equal, false otherwise. - */ - bool operator==(const JsonCppArrayValueIterator &rhs) const - { - return m_itr == rhs.m_itr; - } - - bool operator!=(const JsonCppArrayValueIterator &rhs) const - { - return !(m_itr == rhs.m_itr); - } - - JsonCppArrayValueIterator& operator++() - { - m_itr++; - - return *this; - } - - JsonCppArrayValueIterator operator++(int) - { - JsonCppArrayValueIterator iterator_pre(m_itr); - ++(*this); - return iterator_pre; - } - - JsonCppArrayValueIterator& operator--() - { - m_itr--; - - return *this; - } - - void advance(std::ptrdiff_t n) - { - if (n > 0) { - while (n-- > 0) { - m_itr++; - } - } else { - while (n++ < 0) { - m_itr--; - } - } - } - -private: - - Json::Value::const_iterator m_itr; -}; - -/** - * @brief Class for iterating over the members belonging to a JSON object. - * - * This class provides a JSON object iterator that dereferences as an instance - * of JsonCppObjectMember representing one of the members of the object. It has - * been implemented using the boost iterator_facade template. - * - * @see JsonCppObject - * @see JsonCppObjectMember - */ -class JsonCppObjectMemberIterator -{ -public: - using iterator_category = std::bidirectional_iterator_tag; - using value_type = JsonCppObjectMember; - using difference_type = JsonCppObjectMember; - using pointer = JsonCppObjectMember*; - using reference = JsonCppObjectMember&; - - /** - * @brief Construct an iterator from a JsonCpp iterator. - * - * @param itr JsonCpp iterator to store - */ - JsonCppObjectMemberIterator(const Json::ValueConstIterator &itr) - : m_itr(itr) { } - - /** - * @brief Returns a JsonCppObjectMember that contains the key and value - * belonging to the object member identified by the iterator. - */ - JsonCppObjectMember operator*() const - { - return JsonCppObjectMember(m_itr.key().asString(), *m_itr); - } - - DerefProxy operator->() const - { - return DerefProxy(**this); - } - - /** - * @brief Compare this iterator with another iterator. - * - * Note that this directly compares the iterators, not the underlying - * values, and assumes that two identical iterators will point to the same - * underlying object. - * - * @param rhs Iterator to compare with - * - * @returns true if the underlying iterators are equal, false otherwise - */ - bool operator==(const JsonCppObjectMemberIterator &rhs) const - { - return m_itr == rhs.m_itr; - } - - bool operator!=(const JsonCppObjectMemberIterator &rhs) const - { - return !(m_itr == rhs.m_itr); - } - - const JsonCppObjectMemberIterator& operator++() - { - m_itr++; - - return *this; - } - - JsonCppObjectMemberIterator operator++(int) - { - JsonCppObjectMemberIterator iterator_pre(m_itr); - ++(*this); - return iterator_pre; - } - - JsonCppObjectMemberIterator operator--() - { - m_itr--; - - return *this; - } - -private: - - /// Iternal copy of the original JsonCpp iterator - Json::ValueConstIterator m_itr; -}; - -/// Specialisation of the AdapterTraits template struct for JsonCppAdapter. -template<> -struct AdapterTraits -{ - typedef Json::Value DocumentType; - - static std::string adapterName() - { - return "JsonCppAdapter"; - } -}; - -inline bool JsonCppFrozenValue::equalTo(const Adapter &other, bool strict) const -{ - return JsonCppAdapter(m_value).equalTo(other, strict); -} - -inline JsonCppArrayValueIterator JsonCppArray::begin() const -{ - return m_value.begin(); -} - -inline JsonCppArrayValueIterator JsonCppArray::end() const -{ - return m_value.end(); -} - -inline JsonCppObjectMemberIterator JsonCppObject::begin() const -{ - return m_value.begin(); -} - -inline JsonCppObjectMemberIterator JsonCppObject::end() const -{ - return m_value.end(); -} - -inline JsonCppObjectMemberIterator JsonCppObject::find( - const std::string &propertyName) const -{ - if (m_value.isMember(propertyName)) { - Json::ValueConstIterator itr; - for (itr = m_value.begin(); itr != m_value.end(); ++itr) { - if (itr.key() == propertyName) { - return itr; - } - } - } - - return m_value.end(); -} - -} // namespace adapters -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/adapters/nlohmann_json_adapter.hpp b/subprojects/valijson/include/valijson/adapters/nlohmann_json_adapter.hpp deleted file mode 100644 index aeb156476..000000000 --- a/subprojects/valijson/include/valijson/adapters/nlohmann_json_adapter.hpp +++ /dev/null @@ -1,713 +0,0 @@ -/** - * @file - * - * @brief Adapter implementation for the nlohmann json parser library. - * - * Include this file in your program to enable support for nlohmann json. - * - * This file defines the following classes (not in this order): - * - NlohmannJsonAdapter - * - NlohmannJsonArray - * - NlohmannJsonValueIterator - * - NlohmannJsonFrozenValue - * - NlohmannJsonObject - * - NlohmannJsonObjectMember - * - NlohmannJsonObjectMemberIterator - * - NlohmannJsonValue - * - * Due to the dependencies that exist between these classes, the ordering of - * class declarations and definitions may be a bit confusing. The best place to - * start is NlohmannJsonAdapter. This class definition is actually very small, - * since most of the functionality is inherited from the BasicAdapter class. - * Most of the classes in this file are provided as template arguments to the - * inherited BasicAdapter class. - */ - -#pragma once - -#include -#include - -#include -#include -#include -#include -#include - -namespace valijson { -namespace adapters { - -class NlohmannJsonAdapter; -class NlohmannJsonArrayValueIterator; -class NlohmannJsonObjectMemberIterator; - -typedef std::pair NlohmannJsonObjectMember; - -/** - * @brief Light weight wrapper for a NlohmannJson array value. - * - * This class is light weight wrapper for a NlohmannJson array. It provides a - * minimum set of container functions and typedefs that allow it to be used as - * an iterable container. - * - * An instance of this class contains a single reference to the underlying - * NlohmannJson value, assumed to be an array, so there is very little overhead - * associated with copy construction and passing by value. - */ -class NlohmannJsonArray -{ -public: - - typedef NlohmannJsonArrayValueIterator const_iterator; - typedef NlohmannJsonArrayValueIterator iterator; - - /// Construct a NlohmannJsonArray referencing an empty array. - NlohmannJsonArray() - : m_value(emptyArray()) { } - - /** - * @brief Construct a NlohmannJsonArray referencing a specific NlohmannJson - * value. - * - * @param value reference to a NlohmannJson value - * - * Note that this constructor will throw an exception if the value is not - * an array. - */ - NlohmannJsonArray(const nlohmann::json &value) - : m_value(value) - { - if (!value.is_array()) { - throwRuntimeError("Value is not an array."); - } - } - - /** - * @brief Return an iterator for the first element of the array. - * - * The iterator return by this function is effectively the iterator - * returned by the underlying NlohmannJson implementation. - */ - NlohmannJsonArrayValueIterator begin() const; - - /** - * @brief Return an iterator for one-past the last element of the array. - * - * The iterator return by this function is effectively the iterator - * returned by the underlying NlohmannJson implementation. - */ - NlohmannJsonArrayValueIterator end() const; - - /// Return the number of elements in the array - size_t size() const - { - return m_value.size(); - } - -private: - - /** - * @brief Return a reference to a NlohmannJson value that is an empty array. - * - * Note that the value returned by this function is a singleton. - */ - static const nlohmann::json & emptyArray() - { - static const nlohmann::json array = nlohmann::json::array(); - return array; - } - - /// Reference to the contained value - const nlohmann::json &m_value; -}; - -/** - * @brief Light weight wrapper for a NlohmannJson object. - * - * This class is light weight wrapper for a NlohmannJson object. It provides a - * minimum set of container functions and typedefs that allow it to be used as - * an iterable container. - * - * An instance of this class contains a single reference to the underlying - * NlohmannJson value, assumed to be an object, so there is very little overhead - * associated with copy construction and passing by value. - */ -class NlohmannJsonObject -{ -public: - - typedef NlohmannJsonObjectMemberIterator const_iterator; - typedef NlohmannJsonObjectMemberIterator iterator; - - /// Construct a NlohmannJsonObject referencing an empty object singleton. - NlohmannJsonObject() - : m_value(emptyObject()) { } - - /** - * @brief Construct a NlohmannJsonObject referencing a specific NlohmannJson - * value. - * - * @param value reference to a NlohmannJson value - * - * Note that this constructor will throw an exception if the value is not - * an object. - */ - NlohmannJsonObject(const nlohmann::json &value) - : m_value(value) - { - if (!value.is_object()) { - throwRuntimeError("Value is not an object."); - } - } - - /** - * @brief Return an iterator for this first object member - * - * The iterator return by this function is effectively a wrapper around - * the iterator value returned by the underlying NlohmannJson implementation. - */ - NlohmannJsonObjectMemberIterator begin() const; - - /** - * @brief Return an iterator for an invalid object member that indicates - * the end of the collection. - * - * The iterator return by this function is effectively a wrapper around - * the iterator value returned by the underlying NlohmannJson implementation. - */ - NlohmannJsonObjectMemberIterator end() const; - - /** - * @brief Return an iterator for the object member with the specified - * property name. - * - * If an object member with the specified name does not exist, the iterator - * returned will be the same as the iterator returned by the end() function. - * - * @param propertyName property name to search for - */ - NlohmannJsonObjectMemberIterator find(const std::string &propertyName) const; - - /// Returns the number of members belonging to this object. - size_t size() const - { - return m_value.size(); - } - -private: - - /** - * @brief Return a reference to a NlohmannJson value that is empty object. - * - * Note that the value returned by this function is a singleton. - */ - static const nlohmann::json & emptyObject() - { - static const nlohmann::json object = nlohmann::json::object(); - return object; - } - - /// Reference to the contained object - const nlohmann::json &m_value; -}; - - -/** - * @brief Stores an independent copy of a NlohmannJson value. - * - * This class allows a NlohmannJson value to be stored independent of its original - * document. NlohmannJson makes this easy to do, as it does not perform any - * custom memory management. - * - * @see FrozenValue - */ -class NlohmannJsonFrozenValue: public FrozenValue -{ -public: - - /** - * @brief Make a copy of a NlohmannJson value - * - * @param source the NlohmannJson value to be copied - */ - explicit NlohmannJsonFrozenValue(nlohmann::json source) - : m_value(std::move(source)) { } - - FrozenValue * clone() const override - { - return new NlohmannJsonFrozenValue(m_value); - } - - bool equalTo(const Adapter &other, bool strict) const override; - -private: - - /// Stored NlohmannJson value - nlohmann::json m_value; -}; - - -/** - * @brief Light weight wrapper for a NlohmannJson value. - * - * This class is passed as an argument to the BasicAdapter template class, - * and is used to provide access to a NlohmannJson value. This class is responsible - * for the mechanics of actually reading a NlohmannJson value, whereas the - * BasicAdapter class is responsible for the semantics of type comparisons - * and conversions. - * - * The functions that need to be provided by this class are defined implicitly - * by the implementation of the BasicAdapter template class. - * - * @see BasicAdapter - */ -class NlohmannJsonValue -{ -public: - - /// Construct a wrapper for the empty object singleton - NlohmannJsonValue() - : m_value(emptyObject()) { } - - /// Construct a wrapper for a specific NlohmannJson value - NlohmannJsonValue(const nlohmann::json &value) - : m_value(value) { } - - /** - * @brief Create a new NlohmannJsonFrozenValue instance that contains the - * value referenced by this NlohmannJsonValue instance. - * - * @returns pointer to a new NlohmannJsonFrozenValue instance, belonging to the - * caller. - */ - FrozenValue * freeze() const - { - return new NlohmannJsonFrozenValue(m_value); - } - - /** - * @brief Optionally return a NlohmannJsonArray instance. - * - * If the referenced NlohmannJson value is an array, this function will return - * a std::optional containing a NlohmannJsonArray instance referencing the - * array. - * - * Otherwise it will return an empty optional. - */ - opt::optional getArrayOptional() const - { - if (m_value.is_array()) { - return opt::make_optional(NlohmannJsonArray(m_value)); - } - - return {}; - } - - /** - * @brief Retrieve the number of elements in the array - * - * If the referenced NlohmannJson value is an array, this function will - * retrieve the number of elements in the array and store it in the output - * variable provided. - * - * @param result reference to size_t to set with result - * - * @returns true if the number of elements was retrieved, false otherwise. - */ - bool getArraySize(size_t &result) const - { - if (m_value.is_array()) { - result = m_value.size(); - return true; - } - - return false; - } - - bool getBool(bool &result) const - { - if (m_value.is_boolean()) { - result = m_value.get(); - return true; - } - - return false; - } - - bool getDouble(double &result) const - { - if (m_value.is_number_float()) { - result = m_value.get(); - return true; - } - - return false; - } - - bool getInteger(int64_t &result) const - { - if(m_value.is_number_integer()) { - result = m_value.get(); - return true; - } - return false; - } - - /** - * @brief Optionally return a NlohmannJsonObject instance. - * - * If the referenced NlohmannJson value is an object, this function will return a - * std::optional containing a NlohmannJsonObject instance referencing the - * object. - * - * Otherwise it will return an empty optional. - */ - opt::optional getObjectOptional() const - { - if (m_value.is_object()) { - return opt::make_optional(NlohmannJsonObject(m_value)); - } - - return {}; - } - - /** - * @brief Retrieve the number of members in the object - * - * If the referenced NlohmannJson value is an object, this function will - * retrieve the number of members in the object and store it in the output - * variable provided. - * - * @param result reference to size_t to set with result - * - * @returns true if the number of members was retrieved, false otherwise. - */ - bool getObjectSize(size_t &result) const - { - if (m_value.is_object()) { - result = m_value.size(); - return true; - } - - return false; - } - - bool getString(std::string &result) const - { - if (m_value.is_string()) { - result = m_value.get(); - return true; - } - - return false; - } - - static bool hasStrictTypes() - { - return true; - } - - bool isArray() const - { - return m_value.is_array(); - } - - bool isBool() const - { - return m_value.is_boolean(); - } - - bool isDouble() const - { - return m_value.is_number_float(); - } - - bool isInteger() const - { - return m_value.is_number_integer(); - } - - bool isNull() const - { - return m_value.is_null(); - } - - bool isNumber() const - { - return m_value.is_number(); - } - - bool isObject() const - { - return m_value.is_object(); - } - - bool isString() const - { - return m_value.is_string(); - } - -private: - - /// Return a reference to an empty object singleton - static const nlohmann::json & emptyObject() - { - static const nlohmann::json object = nlohmann::json::object(); - return object; - } - - /// Reference to the contained NlohmannJson value. - const nlohmann::json &m_value; -}; - -/** - * @brief An implementation of the Adapter interface supporting NlohmannJson. - * - * This class is defined in terms of the BasicAdapter template class, which - * helps to ensure that all of the Adapter implementations behave consistently. - * - * @see Adapter - * @see BasicAdapter - */ -class NlohmannJsonAdapter: - public BasicAdapter -{ -public: - /// Construct a NlohmannJsonAdapter that contains an empty object - NlohmannJsonAdapter() - : BasicAdapter() { } - - /// Construct a NlohmannJsonAdapter containing a specific Nlohmann Json object - NlohmannJsonAdapter(const nlohmann::json &value) - : BasicAdapter(NlohmannJsonValue{value}) { } -}; - -/** - * @brief Class for iterating over values held in a JSON array. - * - * This class provides a JSON array iterator that dereferences as an instance of - * NlohmannJsonAdapter representing a value stored in the array. It has been - * implemented using the boost iterator_facade template. - * - * @see NlohmannJsonArray - */ -class NlohmannJsonArrayValueIterator -{ -public: - using iterator_category = std::bidirectional_iterator_tag; - using value_type = NlohmannJsonAdapter; - using difference_type = NlohmannJsonAdapter; - using pointer = NlohmannJsonAdapter*; - using reference = NlohmannJsonAdapter&; - - /** - * @brief Construct a new NlohmannJsonArrayValueIterator using an existing - * NlohmannJson iterator. - * - * @param itr NlohmannJson iterator to store - */ - NlohmannJsonArrayValueIterator(const nlohmann::json::const_iterator &itr) - : m_itr(itr) { } - - /// Returns a NlohmannJsonAdapter that contains the value of the current - /// element. - NlohmannJsonAdapter operator*() const - { - return NlohmannJsonAdapter(*m_itr); - } - - DerefProxy operator->() const - { - return DerefProxy(**this); - } - - /** - * @brief Compare this iterator against another iterator. - * - * Note that this directly compares the iterators, not the underlying - * values, and assumes that two identical iterators will point to the same - * underlying object. - * - * @param other iterator to compare against - * - * @returns true if the iterators are equal, false otherwise. - */ - bool operator==(const NlohmannJsonArrayValueIterator &other) const - { - return m_itr == other.m_itr; - } - - bool operator!=(const NlohmannJsonArrayValueIterator &other) const - { - return !(m_itr == other.m_itr); - } - - const NlohmannJsonArrayValueIterator& operator++() - { - m_itr++; - - return *this; - } - - NlohmannJsonArrayValueIterator operator++(int) - { - NlohmannJsonArrayValueIterator iterator_pre(m_itr); - ++(*this); - return iterator_pre; - } - - const NlohmannJsonArrayValueIterator& operator--() - { - m_itr--; - - return *this; - } - - void advance(std::ptrdiff_t n) - { - m_itr += n; - } - -private: - nlohmann::json::const_iterator m_itr; -}; - - -/** - * @brief Class for iterating over the members belonging to a JSON object. - * - * This class provides a JSON object iterator that dereferences as an instance - * of NlohmannJsonObjectMember representing one of the members of the object. It - * has been implemented using the boost iterator_facade template. - * - * @see NlohmannJsonObject - * @see NlohmannJsonObjectMember - */ -class NlohmannJsonObjectMemberIterator -{ -public: - using iterator_category = std::bidirectional_iterator_tag; - using value_type = NlohmannJsonObjectMember; - using difference_type = NlohmannJsonObjectMember; - using pointer = NlohmannJsonObjectMember*; - using reference = NlohmannJsonObjectMember&; - - /** - * @brief Construct an iterator from a NlohmannJson iterator. - * - * @param itr NlohmannJson iterator to store - */ - NlohmannJsonObjectMemberIterator(const nlohmann::json::const_iterator &itr) - : m_itr(itr) { } - - /** - * @brief Returns a NlohmannJsonObjectMember that contains the key and value - * belonging to the object member identified by the iterator. - */ - NlohmannJsonObjectMember operator*() const - { - return NlohmannJsonObjectMember(m_itr.key(), m_itr.value()); - } - - DerefProxy operator->() const - { - return DerefProxy(**this); - } - - /** - * @brief Compare this iterator with another iterator. - * - * Note that this directly compares the iterators, not the underlying - * values, and assumes that two identical iterators will point to the same - * underlying object. - * - * @param other Iterator to compare with - * - * @returns true if the underlying iterators are equal, false otherwise - */ - bool operator==(const NlohmannJsonObjectMemberIterator &other) const - { - return m_itr == other.m_itr; - } - - bool operator!=(const NlohmannJsonObjectMemberIterator &other) const - { - return !(m_itr == other.m_itr); - } - - const NlohmannJsonObjectMemberIterator& operator++() - { - m_itr++; - - return *this; - } - - NlohmannJsonObjectMemberIterator operator++(int) - { - NlohmannJsonObjectMemberIterator iterator_pre(m_itr); - ++(*this); - return iterator_pre; - } - - const NlohmannJsonObjectMemberIterator& operator--() - { - m_itr--; - - return *this; - } - -private: - - /// Iternal copy of the original NlohmannJson iterator - nlohmann::json::const_iterator m_itr; -}; - -/// Specialisation of the AdapterTraits template struct for NlohmannJsonAdapter. -template<> -struct AdapterTraits -{ - typedef nlohmann::json DocumentType; - - static std::string adapterName() - { - return "NlohmannJsonAdapter"; - } -}; - -inline bool NlohmannJsonFrozenValue::equalTo(const Adapter &other, bool strict) const -{ - return NlohmannJsonAdapter(m_value).equalTo(other, strict); -} - -inline NlohmannJsonArrayValueIterator NlohmannJsonArray::begin() const -{ - return m_value.begin(); -} - -inline NlohmannJsonArrayValueIterator NlohmannJsonArray::end() const -{ - return m_value.end(); -} - -inline NlohmannJsonObjectMemberIterator NlohmannJsonObject::begin() const -{ - return m_value.begin(); -} - -inline NlohmannJsonObjectMemberIterator NlohmannJsonObject::end() const -{ - return m_value.end(); -} - -inline NlohmannJsonObjectMemberIterator NlohmannJsonObject::find( - const std::string &propertyName) const -{ - return m_value.find(propertyName); -} - -} // namespace adapters -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/adapters/picojson_adapter.hpp b/subprojects/valijson/include/valijson/adapters/picojson_adapter.hpp deleted file mode 100644 index 4f5e5b6b7..000000000 --- a/subprojects/valijson/include/valijson/adapters/picojson_adapter.hpp +++ /dev/null @@ -1,732 +0,0 @@ -/** - * @file - * - * @brief Adapter implementation for the PicoJson parser library. - * - * Include this file in your program to enable support for PicoJson. - * - * This file defines the following classes (not in this order): - * - PicoJsonAdapter - * - PicoJsonArray - * - PicoJsonArrayValueIterator - * - PicoJsonFrozenValue - * - PicoJsonObject - * - PicoJsonObjectMember - * - PicoJsonObjectMemberIterator - * - PicoJsonValue - * - * Due to the dependencies that exist between these classes, the ordering of - * class declarations and definitions may be a bit confusing. The best place to - * start is PicoJsonAdapter. This class definition is actually very small, - * since most of the functionality is inherited from the BasicAdapter class. - * Most of the classes in this file are provided as template arguments to the - * inherited BasicAdapter class. - */ - -#pragma once - -#include - -#ifdef _MSC_VER -#pragma warning(disable: 4706) -#include -#pragma warning(default: 4706) -#else -#include -#endif - -#include -#include -#include -#include - -namespace valijson { -namespace adapters { - -class PicoJsonAdapter; -class PicoJsonArrayValueIterator; -class PicoJsonObjectMemberIterator; - -typedef std::pair PicoJsonObjectMember; - -/** - * @brief Light weight wrapper for a PicoJson array value. - * - * This class is light weight wrapper for a PicoJson array. It provides a - * minimum set of container functions and typedefs that allow it to be used as - * an iterable container. - * - * An instance of this class contains a single reference to the underlying - * PicoJson value, assumed to be an array, so there is very little overhead - * associated with copy construction and passing by value. - */ -class PicoJsonArray -{ -public: - - typedef PicoJsonArrayValueIterator const_iterator; - typedef PicoJsonArrayValueIterator iterator; - - /// Construct a PicoJsonArray referencing an empty array. - PicoJsonArray() - : m_value(emptyArray()) { } - - /** - * @brief Construct a PicoJsonArray referencing a specific PicoJson - * value. - * - * @param value reference to a PicoJson value - * - * Note that this constructor will throw an exception if the value is not - * an array. - */ - explicit PicoJsonArray(const picojson::value &value) - : m_value(value) - { - if (!value.is()) { - throwRuntimeError("Value is not an array."); - } - } - - /** - * @brief Return an iterator for the first element of the array. - * - * The iterator return by this function is effectively the iterator - * returned by the underlying PicoJson implementation. - */ - PicoJsonArrayValueIterator begin() const; - - /** - * @brief Return an iterator for one-past the last element of the array. - * - * The iterator return by this function is effectively the iterator - * returned by the underlying PicoJson implementation. - */ - PicoJsonArrayValueIterator end() const; - - /// Return the number of elements in the array - size_t size() const - { - const picojson::array &array = m_value.get(); - return array.size(); - } - -private: - - /** - * @brief Return a reference to a PicoJson value that is an empty array. - * - * Note that the value returned by this function is a singleton. - */ - static const picojson::value & emptyArray() - { - static const picojson::value array(picojson::array_type, false); - return array; - } - - /// Reference to the contained value - const picojson::value &m_value; -}; - -/** - * @brief Light weight wrapper for a PicoJson object. - * - * This class is light weight wrapper for a PicoJson object. It provides a - * minimum set of container functions and typedefs that allow it to be used as - * an iterable container. - * - * An instance of this class contains a single reference to the underlying - * PicoJson value, assumed to be an object, so there is very little overhead - * associated with copy construction and passing by value. - */ -class PicoJsonObject -{ -public: - - typedef PicoJsonObjectMemberIterator const_iterator; - typedef PicoJsonObjectMemberIterator iterator; - - /// Construct a PicoJsonObject referencing an empty object singleton. - PicoJsonObject() - : m_value(emptyObject()) { } - - /** - * @brief Construct a PicoJsonObject referencing a specific PicoJson - * value. - * - * @param value reference to a PicoJson value - * - * Note that this constructor will throw an exception if the value is not - * an object. - */ - PicoJsonObject(const picojson::value &value) - : m_value(value) - { - if (!value.is()) { - throwRuntimeError("Value is not an object."); - } - } - - /** - * @brief Return an iterator for this first object member - * - * The iterator return by this function is effectively a wrapper around - * the iterator value returned by the underlying PicoJson implementation. - */ - PicoJsonObjectMemberIterator begin() const; - - /** - * @brief Return an iterator for an invalid object member that indicates - * the end of the collection. - * - * The iterator return by this function is effectively a wrapper around - * the iterator value returned by the underlying PicoJson implementation. - */ - PicoJsonObjectMemberIterator end() const; - - /** - * @brief Return an iterator for the object member with the specified - * property name. - * - * If an object member with the specified name does not exist, the iterator - * returned will be the same as the iterator returned by the end() function. - * - * @param propertyName property name to search for - */ - PicoJsonObjectMemberIterator find(const std::string &propertyName) const; - - /// Returns the number of members belonging to this object. - size_t size() const - { - const picojson::object &object = m_value.get(); - return object.size(); - } - -private: - - /** - * @brief Return a reference to a PicoJson value that is empty object. - * - * Note that the value returned by this function is a singleton. - */ - static const picojson::value & emptyObject() - { - static const picojson::value object(picojson::object_type, false); - return object; - } - - /// Reference to the contained object - const picojson::value &m_value; -}; - -/** - * @brief Stores an independent copy of a PicoJson value. - * - * This class allows a PicoJson value to be stored independent of its original - * document. PicoJson makes this easy to do, as it does not perform any - * custom memory management. - * - * @see FrozenValue - */ -class PicoJsonFrozenValue: public FrozenValue -{ -public: - - /** - * @brief Make a copy of a PicoJson value - * - * @param source the PicoJson value to be copied - */ - explicit PicoJsonFrozenValue(const picojson::value &source) - : m_value(source) { } - - FrozenValue * clone() const override - { - return new PicoJsonFrozenValue(m_value); - } - - bool equalTo(const Adapter &other, bool strict) const override; - -private: - - /// Stored PicoJson value - picojson::value m_value; -}; - -/** - * @brief Light weight wrapper for a PicoJson value. - * - * This class is passed as an argument to the BasicAdapter template class, - * and is used to provide access to a PicoJson value. This class is responsible - * for the mechanics of actually reading a PicoJson value, whereas the - * BasicAdapter class is responsible for the semantics of type comparisons - * and conversions. - * - * The functions that need to be provided by this class are defined implicitly - * by the implementation of the BasicAdapter template class. - * - * @see BasicAdapter - */ -class PicoJsonValue -{ -public: - - /// Construct a wrapper for the empty object singleton - PicoJsonValue() - : m_value(emptyObject()) { } - - /// Construct a wrapper for a specific PicoJson value - PicoJsonValue(const picojson::value &value) - : m_value(value) { } - - /** - * @brief Create a new PicoJsonFrozenValue instance that contains the - * value referenced by this PicoJsonValue instance. - * - * @returns pointer to a new PicoJsonFrozenValue instance, belonging to the - * caller. - */ - FrozenValue * freeze() const - { - return new PicoJsonFrozenValue(m_value); - } - - /** - * @brief Optionally return a PicoJsonArray instance. - * - * If the referenced PicoJson value is an array, this function will return - * a std::optional containing a PicoJsonArray instance referencing the - * array. - * - * Otherwise it will return an empty optional. - */ - opt::optional getArrayOptional() const - { - if (m_value.is()) { - return opt::make_optional(PicoJsonArray(m_value)); - } - - return {}; - } - - /** - * @brief Retrieve the number of elements in the array - * - * If the referenced PicoJson value is an array, this function will - * retrieve the number of elements in the array and store it in the output - * variable provided. - * - * @param result reference to size_t to set with result - * - * @returns true if the number of elements was retrieved, false otherwise. - */ - bool getArraySize(size_t &result) const - { - if (m_value.is()) { - const picojson::array& array = m_value.get(); - result = array.size(); - return true; - } - - return false; - } - - bool getBool(bool &result) const - { - if (m_value.is()) { - result = m_value.get(); - return true; - } - - return false; - } - - bool getDouble(double &result) const - { - if (m_value.is()) { - result = m_value.get(); - return true; - } - - return false; - } - - bool getInteger(int64_t &result) const - { - if (m_value.is()) { - result = m_value.get(); - return true; - } - - return false; - } - - /** - * @brief Optionally return a PicoJsonObject instance. - * - * If the referenced PicoJson value is an object, this function will return a - * std::optional containing a PicoJsonObject instance referencing the - * object. - * - * Otherwise it will return an empty optional. - */ - opt::optional getObjectOptional() const - { - if (m_value.is()) { - return opt::make_optional(PicoJsonObject(m_value)); - } - - return {}; - } - - /** - * @brief Retrieve the number of members in the object - * - * If the referenced PicoJson value is an object, this function will - * retrieve the number of members in the object and store it in the output - * variable provided. - * - * @param result reference to size_t to set with result - * - * @returns true if the number of members was retrieved, false otherwise. - */ - bool getObjectSize(size_t &result) const - { - if (m_value.is()) { - const picojson::object &object = m_value.get(); - result = object.size(); - return true; - } - - return false; - } - - bool getString(std::string &result) const - { - if (m_value.is()) { - result = m_value.get(); - return true; - } - - return false; - } - - static bool hasStrictTypes() - { - return true; - } - - bool isArray() const - { - return m_value.is(); - } - - bool isBool() const - { - return m_value.is(); - } - - bool isDouble() const - { - if (m_value.is()) { - return false; - } - - return m_value.is(); - } - - bool isInteger() const - { - return m_value.is(); - } - - bool isNull() const - { - return m_value.is(); - } - - bool isNumber() const - { - return m_value.is(); - } - - bool isObject() const - { - return m_value.is(); - } - - bool isString() const - { - return m_value.is(); - } - -private: - - /// Return a reference to an empty object singleton - static const picojson::value & emptyObject() - { - static const picojson::value object(picojson::object_type, false); - return object; - } - - /// Reference to the contained PicoJson value. - const picojson::value &m_value; -}; - -/** - * @brief An implementation of the Adapter interface supporting PicoJson. - * - * This class is defined in terms of the BasicAdapter template class, which - * helps to ensure that all of the Adapter implementations behave consistently. - * - * @see Adapter - * @see BasicAdapter - */ -class PicoJsonAdapter: - public BasicAdapter -{ -public: - - /// Construct a PicoJsonAdapter that contains an empty object - PicoJsonAdapter() - : BasicAdapter() { } - - /// Construct a PicoJsonAdapter containing a specific PicoJson value - PicoJsonAdapter(const picojson::value &value) - : BasicAdapter(value) { } -}; - -/** - * @brief Class for iterating over values held in a JSON array. - * - * This class provides a JSON array iterator that dereferences as an instance of - * PicoJsonAdapter representing a value stored in the array. It has been - * implemented using the std::iterator template. - * - * @see PicoJsonArray - */ -class PicoJsonArrayValueIterator -{ -public: - using iterator_category = std::bidirectional_iterator_tag; - using value_type = PicoJsonAdapter; - using difference_type = PicoJsonAdapter; - using pointer = PicoJsonAdapter*; - using reference = PicoJsonAdapter&; - - /** - * @brief Construct a new PicoJsonArrayValueIterator using an existing - * PicoJson iterator. - * - * @param itr PicoJson iterator to store - */ - PicoJsonArrayValueIterator(const picojson::array::const_iterator &itr) - : m_itr(itr) { } - - /// Returns a PicoJsonAdapter that contains the value of the current - /// element. - PicoJsonAdapter operator*() const - { - return PicoJsonAdapter(*m_itr); - } - - DerefProxy operator->() const - { - return DerefProxy(**this); - } - - /** - * @brief Compare this iterator against another iterator. - * - * Note that this directly compares the iterators, not the underlying - * values, and assumes that two identical iterators will point to the same - * underlying object. - * - * @param other iterator to compare against - * - * @returns true if the iterators are equal, false otherwise. - */ - bool operator==(const PicoJsonArrayValueIterator &other) const - { - return m_itr == other.m_itr; - } - - bool operator!=(const PicoJsonArrayValueIterator &other) const - { - return !(m_itr == other.m_itr); - } - - const PicoJsonArrayValueIterator& operator++() - { - m_itr++; - - return *this; - } - - PicoJsonArrayValueIterator operator++(int) - { - PicoJsonArrayValueIterator iterator_pre(m_itr); - ++(*this); - return iterator_pre; - } - - const PicoJsonArrayValueIterator& operator--() - { - m_itr--; - - return *this; - } - - void advance(std::ptrdiff_t n) - { - m_itr += n; - } - -private: - - picojson::array::const_iterator m_itr; -}; - -/** - * @brief Class for iterating over the members belonging to a JSON object. - * - * This class provides a JSON object iterator that dereferences as an instance - * of PicoJsonObjectMember representing one of the members of the object. It - * has been implemented using the boost iterator_facade template. - * - * @see PicoJsonObject - * @see PicoJsonObjectMember - */ -class PicoJsonObjectMemberIterator -{ -public: - using iterator_category = std::bidirectional_iterator_tag; - using value_type = PicoJsonObjectMember; - using difference_type = PicoJsonObjectMember; - using pointer = PicoJsonObjectMember*; - using reference = PicoJsonObjectMember&; - - /** - * @brief Construct an iterator from a PicoJson iterator. - * - * @param itr PicoJson iterator to store - */ - PicoJsonObjectMemberIterator(const picojson::object::const_iterator &itr) - : m_itr(itr) { } - - /** - * @brief Returns a PicoJsonObjectMember that contains the key and value - * belonging to the object member identified by the iterator. - */ - PicoJsonObjectMember operator*() const - { - return PicoJsonObjectMember(m_itr->first, m_itr->second); - } - - DerefProxy operator->() const - { - return DerefProxy(**this); - } - - /** - * @brief Compare this iterator with another iterator. - * - * Note that this directly compares the iterators, not the underlying - * values, and assumes that two identical iterators will point to the same - * underlying object. - * - * @param other Iterator to compare with - * - * @returns true if the underlying iterators are equal, false otherwise - */ - bool operator==(const PicoJsonObjectMemberIterator &other) const - { - return m_itr == other.m_itr; - } - - bool operator!=(const PicoJsonObjectMemberIterator &other) const - { - return !(m_itr == other.m_itr); - } - - const PicoJsonObjectMemberIterator& operator++() - { - m_itr++; - - return *this; - } - - PicoJsonObjectMemberIterator operator++(int) - { - PicoJsonObjectMemberIterator iterator_pre(m_itr); - ++(*this); - return iterator_pre; - } - - const PicoJsonObjectMemberIterator& operator--(int) - { - m_itr--; - - return *this; - } - -private: - - /// Iternal copy of the original PicoJson iterator - picojson::object::const_iterator m_itr; -}; - -/// Specialisation of the AdapterTraits template struct for PicoJsonAdapter. -template<> -struct AdapterTraits -{ - typedef picojson::value DocumentType; - - static std::string adapterName() - { - return "PicoJsonAdapter"; - } -}; - -inline bool PicoJsonFrozenValue::equalTo(const Adapter &other, bool strict) const -{ - return PicoJsonAdapter(m_value).equalTo(other, strict); -} - -inline PicoJsonArrayValueIterator PicoJsonArray::begin() const -{ - const picojson::array &array = m_value.get(); - return array.begin(); -} - -inline PicoJsonArrayValueIterator PicoJsonArray::end() const -{ - const picojson::array &array = m_value.get(); - return array.end(); -} - -inline PicoJsonObjectMemberIterator PicoJsonObject::begin() const -{ - const picojson::object &object = m_value.get(); - return object.begin(); -} - -inline PicoJsonObjectMemberIterator PicoJsonObject::end() const -{ - const picojson::object &object = m_value.get(); - return object.end(); -} - -inline PicoJsonObjectMemberIterator PicoJsonObject::find( - const std::string &propertyName) const -{ - const picojson::object &object = m_value.get(); - return object.find(propertyName); -} - -} // namespace adapters -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/adapters/poco_json_adapter.hpp b/subprojects/valijson/include/valijson/adapters/poco_json_adapter.hpp deleted file mode 100644 index a997debfa..000000000 --- a/subprojects/valijson/include/valijson/adapters/poco_json_adapter.hpp +++ /dev/null @@ -1,720 +0,0 @@ -/** -* @file -* -* @brief Adapter implementation for the Poco json parser library. -* -* Include this file in your program to enable support for Poco json. -* -* This file defines the following classes (not in this order): -* - PocoJsonAdapter -* - PocoJsonArray -* - PocoJsonValueIterator -* - PocoJsonFrozenValue -* - PocoJsonObject -* - PocoJsonObjectMember -* - PocoJsonObjectMemberIterator -* - PocoJsonValue -* -* Due to the dependencies that exist between these classes, the ordering of -* class declarations and definitions may be a bit confusing. The best place to -* start is PocoJsonAdapter. This class definition is actually very small, -* since most of the functionality is inherited from the BasicAdapter class. -* Most of the classes in this file are provided as template arguments to the -* inherited BasicAdapter class. -*/ - -#pragma once - -#include -#include - -#include -#include -#include -#include - -namespace valijson { -namespace adapters { - -class PocoJsonAdapter; -class PocoJsonArrayValueIterator; -class PocoJsonObjectMemberIterator; - -typedef std::pair PocoJsonObjectMember; - -/** -* @brief Light weight wrapper for a PocoJson array value. -* -* This class is light weight wrapper for a PocoJson array. It provides a -* minimum set of container functions and typedefs that allow it to be used as -* an iterable container. -* -* An instance of this class contains a single reference to the underlying -* PocoJson value, assumed to be an array, so there is very little overhead -* associated with copy construction and passing by value. -*/ -class PocoJsonArray -{ -public: - - typedef PocoJsonArrayValueIterator const_iterator; - typedef PocoJsonArrayValueIterator iterator; - - /// Construct a PocoJsonArray referencing an empty array. - PocoJsonArray() - : m_value(emptyArray()) - { } - - /** - * @brief Construct a PocoJsonArray referencing a specific PocoJson - * value. - * - * @param value reference to a PocoJson value - * - * Note that this constructor will throw an exception if the value is not - * an array. - */ - PocoJsonArray(const Poco::Dynamic::Var &value) - : m_value(value) - { - if (value.type() != typeid(Poco::JSON::Array::Ptr)) { - throwRuntimeError("Value is not an array."); - } - } - - /** - * @brief Return an iterator for the first element of the array. - * - * The iterator return by this function is effectively the iterator - * returned by the underlying PocoJson implementation. - */ - PocoJsonArrayValueIterator begin() const; - - /** - * @brief Return an iterator for one-past the last element of the array. - * - * The iterator return by this function is effectively the iterator - * returned by the underlying PocoJson implementation. - */ - PocoJsonArrayValueIterator end() const; - - /// Return the number of elements in the array - size_t size() const - { - return m_value.extract()->size(); - } - -private: - - /** - * @brief Return a PocoJson value that is an empty array. - */ - static Poco::Dynamic::Var emptyArray() - { - Poco::Dynamic::Var array = Poco::JSON::Array::Ptr(); - return array; - } - - /// Contained value - Poco::Dynamic::Var m_value; -}; - -/** -* @brief Light weight wrapper for a PocoJson object. -* -* This class is light weight wrapper for a PocoJson object. It provides a -* minimum set of container functions and typedefs that allow it to be used as -* an iterable container. -* -* An instance of this class contains a single reference to the underlying -* PocoJson value, assumed to be an object, so there is very little overhead -* associated with copy construction and passing by value. -*/ -class PocoJsonObject -{ -public: - - typedef PocoJsonObjectMemberIterator const_iterator; - typedef PocoJsonObjectMemberIterator iterator; - - /// Construct a PocoJsonObject an empty object. - PocoJsonObject() - : m_value(emptyObject()) - { } - - /** - * @brief Construct a PocoJsonObject referencing a specific PocoJson - * value. - * - * @param value reference to a PocoJson value - * - * Note that this constructor will throw an exception if the value is not - * an object. - */ - PocoJsonObject(const Poco::Dynamic::Var &value) - : m_value(value) - { - if (value.type() != typeid(Poco::JSON::Object::Ptr)) { - throwRuntimeError("Value is not an object."); - } - } - - /** - * @brief Return an iterator for this first object member - * - * The iterator return by this function is effectively a wrapper around - * the iterator value returned by the underlying PocoJson implementation. - */ - PocoJsonObjectMemberIterator begin() const; - - /** - * @brief Return an iterator for an invalid object member that indicates - * the end of the collection. - * - * The iterator return by this function is effectively a wrapper around - * the iterator value returned by the underlying PocoJson implementation. - */ - PocoJsonObjectMemberIterator end() const; - - /** - * @brief Return an iterator for the object member with the specified - * property name. - * - * If an object member with the specified name does not exist, the iterator - * returned will be the same as the iterator returned by the end() function. - * - * @param propertyName property name to search for - */ - PocoJsonObjectMemberIterator find(const std::string &propertyName) const; - - /// Returns the number of members belonging to this object. - size_t size() const - { - return m_value.extract()->size(); - } - -private: - - /** - * @brief Return a PocoJson value that is empty object. - */ - static Poco::Dynamic::Var emptyObject() - { - Poco::Dynamic::Var object = Poco::JSON::Object::Ptr(); - return object; - } - - /// Contained value - Poco::Dynamic::Var m_value; -}; - -/** -* @brief Stores an independent copy of a PocoJson value. -* -* This class allows a PocoJson value to be stored independent of its original -* document. PocoJson makes this easy to do, as it does not perform any -* custom memory management. -* -* @see FrozenValue -*/ -class PocoJsonFrozenValue : public FrozenValue -{ -public: - - /** - * @brief Make a copy of a PocoJson value - * - * @param source the PocoJson value to be copied - */ - explicit PocoJsonFrozenValue(const Poco::Dynamic::Var &source) - : m_value(source) - { } - - virtual FrozenValue * clone() const - { - return new PocoJsonFrozenValue(m_value); - } - - virtual bool equalTo(const Adapter &other, bool strict) const; - -private: - - /// Stored PocoJson value - Poco::Dynamic::Var m_value; -}; - - -/** -* @brief Light weight wrapper for a PocoJson value. -* -* This class is passed as an argument to the BasicAdapter template class, -* and is used to provide access to a PocoJson value. This class is responsible -* for the mechanics of actually reading a PocoJson value, whereas the -* BasicAdapter class is responsible for the semantics of type comparisons -* and conversions. -* -* The functions that need to be provided by this class are defined implicitly -* by the implementation of the BasicAdapter template class. -* -* @see BasicAdapter -*/ -class PocoJsonValue -{ -public: - - /// Construct a wrapper for the empty object - PocoJsonValue() - : m_value(emptyObject()) - { } - - /// Construct a wrapper for a specific PocoJson value - PocoJsonValue(const Poco::Dynamic::Var& value) - : m_value(value) - { } - - /** - * @brief Create a new PocoJsonFrozenValue instance that contains the - * value referenced by this PocoJsonValue instance. - * - * @returns pointer to a new PocoJsonFrozenValue instance, belonging to the - * caller. - */ - FrozenValue * freeze() const - { - return new PocoJsonFrozenValue(m_value); - } - - /** - * @brief Optionally return a PocoJsonArray instance. - * - * If the referenced PocoJson value is an array, this function will return - * a std::optional containing a PocoJsonArray instance referencing the - * array. - * - * Otherwise it will return an empty optional. - */ - opt::optional getArrayOptional() const - { - if (m_value.type() == typeid(Poco::JSON::Array::Ptr)) { - return opt::make_optional(PocoJsonArray(m_value)); - } - - return opt::optional(); - } - - /** - * @brief Retrieve the number of elements in the array - * - * If the referenced PocoJson value is an array, this function will - * retrieve the number of elements in the array and store it in the output - * variable provided. - * - * @param result reference to size_t to set with result - * - * @returns true if the number of elements was retrieved, false otherwise. - */ - bool getArraySize(size_t &result) const - { - if (m_value.type() == typeid(Poco::JSON::Array::Ptr)) { - result = m_value.extract()->size(); - return true; - } - - return false; - } - - bool getBool(bool &result) const - { - if (m_value.isBoolean()) { - result = m_value.convert(); - return true; - } - - return false; - } - - bool getDouble(double &result) const - { - if (m_value.isNumeric() && !m_value.isInteger()) { - result = m_value.convert(); - return true; - } - - return false; - } - - bool getInteger(int64_t &result) const - { - if (m_value.isInteger()) { - result = m_value.convert(); - return true; - } - return false; - } - - /** - * @brief Optionally return a PocoJsonObject instance. - * - * If the referenced PocoJson value is an object, this function will return a - * std::optional containing a PocoJsonObject instance referencing the - * object. - * - * Otherwise it will return an empty optional. - */ - opt::optional getObjectOptional() const - { - if (m_value.type() == typeid(Poco::JSON::Object::Ptr)) { - return opt::make_optional(PocoJsonObject(m_value)); - } - - return opt::optional(); - } - - /** - * @brief Retrieve the number of members in the object - * - * If the referenced PocoJson value is an object, this function will - * retrieve the number of members in the object and store it in the output - * variable provided. - * - * @param result reference to size_t to set with result - * - * @returns true if the number of members was retrieved, false otherwise. - */ - bool getObjectSize(size_t &result) const - { - if (m_value.type() == typeid(Poco::JSON::Object::Ptr)) { - result = m_value.extract()->size(); - return true; - } - - return false; - } - - bool getString(std::string &result) const - { - if (m_value.isString()) { - result = m_value.convert(); - return true; - } - - return false; - } - - static bool hasStrictTypes() - { - return true; - } - - bool isArray() const - { - return m_value.type() == typeid(Poco::JSON::Array::Ptr); - } - - bool isBool() const - { - return m_value.isBoolean(); - } - - bool isDouble() const - { - return m_value.isNumeric() && !m_value.isInteger(); - } - - bool isInteger() const - { - return !isBool() && m_value.isInteger(); - } - - bool isNull() const - { - return m_value.isEmpty(); - } - - bool isNumber() const - { - return m_value.isNumeric(); - } - - bool isObject() const - { - return m_value.type() == typeid(Poco::JSON::Object::Ptr); - } - - bool isString() const - { - return m_value.isString(); - } - -private: - - /// Return an empty object - static Poco::Dynamic::Var emptyObject() - { - Poco::Dynamic::Var object = Poco::JSON::Object::Ptr(); - return object; - } - - /// Contained value - Poco::Dynamic::Var m_value; -}; - -/** -* @brief An implementation of the Adapter interface supporting PocoJson. -* -* This class is defined in terms of the BasicAdapter template class, which -* helps to ensure that all of the Adapter implementations behave consistently. -* -* @see Adapter -* @see BasicAdapter -*/ -class PocoJsonAdapter : - public BasicAdapter -{ -public: - /// Construct a PocoJsonAdapter that contains an empty object - PocoJsonAdapter() - : BasicAdapter() - { } - - /// Construct a PocoJsonAdapter containing a specific Poco Json object - PocoJsonAdapter(const Poco::Dynamic::Var &value) - : BasicAdapter(PocoJsonValue {value}) - { } -}; - -/** -* @brief Class for iterating over values held in a JSON array. -* -* This class provides a JSON array iterator that dereferences as an instance of -* PocoJsonAdapter representing a value stored in the array. It has been -* implemented using the boost iterator_facade template. -* -* @see PocoJsonArray -*/ -class PocoJsonArrayValueIterator -{ -public: - using iterator_category = std::bidirectional_iterator_tag; - using value_type = PocoJsonAdapter; - using difference_type = PocoJsonAdapter; - using pointer = PocoJsonAdapter*; - using reference = PocoJsonAdapter&; - - /** - * @brief Construct a new PocoJsonArrayValueIterator using an existing - * PocoJson iterator. - * - * @param itr PocoJson iterator to store - */ - PocoJsonArrayValueIterator(const Poco::JSON::Array::ConstIterator &itr) - : m_itr(itr) - { } - - /// Returns a PocoJsonAdapter that contains the value of the current - /// element. - PocoJsonAdapter operator*() const - { - return PocoJsonAdapter(*m_itr); - } - - DerefProxy operator->() const - { - return DerefProxy(**this); - } - - /** - * @brief Compare this iterator against another iterator. - * - * Note that this directly compares the iterators, not the underlying - * values, and assumes that two identical iterators will point to the same - * underlying object. - * - * @param other iterator to compare against - * - * @returns true if the iterators are equal, false otherwise. - */ - bool operator==(const PocoJsonArrayValueIterator &other) const - { - return m_itr == other.m_itr; - } - - bool operator!=(const PocoJsonArrayValueIterator &other) const - { - return !(m_itr == other.m_itr); - } - - const PocoJsonArrayValueIterator& operator++() - { - m_itr++; - - return *this; - } - - PocoJsonArrayValueIterator operator++(int) - { - PocoJsonArrayValueIterator iterator_pre(m_itr); - ++(*this); - return iterator_pre; - } - - const PocoJsonArrayValueIterator& operator--() - { - m_itr--; - - return *this; - } - - void advance(std::ptrdiff_t n) - { - m_itr += n; - } - -private: - Poco::JSON::Array::ConstIterator m_itr; -}; - - -/** -* @brief Class for iterating over the members belonging to a JSON object. -* -* This class provides a JSON object iterator that dereferences as an instance -* of PocoJsonObjectMember representing one of the members of the object. It -* has been implemented using the boost iterator_facade template. -* -* @see PocoJsonObject -* @see PocoJsonObjectMember -*/ -class PocoJsonObjectMemberIterator -{ -public: - using iterator_category = std::bidirectional_iterator_tag; - using value_type = PocoJsonObjectMember; - using difference_type = PocoJsonObjectMember; - using pointer = PocoJsonObjectMember*; - using reference = PocoJsonObjectMember&; - - /** - * @brief Construct an iterator from a PocoJson iterator. - * - * @param itr PocoJson iterator to store - */ - PocoJsonObjectMemberIterator(const Poco::JSON::Object::ConstIterator &itr) - : m_itr(itr) - { } - - /** - * @brief Returns a PocoJsonObjectMember that contains the key and value - * belonging to the object member identified by the iterator. - */ - PocoJsonObjectMember operator*() const - { - return PocoJsonObjectMember(m_itr->first, m_itr->second); - } - - DerefProxy operator->() const - { - return DerefProxy(**this); - } - - /** - * @brief Compare this iterator with another iterator. - * - * Note that this directly compares the iterators, not the underlying - * values, and assumes that two identical iterators will point to the same - * underlying object. - * - * @param other Iterator to compare with - * - * @returns true if the underlying iterators are equal, false otherwise - */ - bool operator==(const PocoJsonObjectMemberIterator &other) const - { - return m_itr == other.m_itr; - } - - bool operator!=(const PocoJsonObjectMemberIterator &other) const - { - return !(m_itr == other.m_itr); - } - - const PocoJsonObjectMemberIterator& operator++() - { - m_itr++; - - return *this; - } - - PocoJsonObjectMemberIterator operator++(int) - { - PocoJsonObjectMemberIterator iterator_pre(m_itr); - ++(*this); - return iterator_pre; - } - - const PocoJsonObjectMemberIterator& operator--() - { - m_itr--; - - return *this; - } - -private: - - /// Iternal copy of the original PocoJson iterator - Poco::JSON::Object::ConstIterator m_itr; -}; - -/// Specialisation of the AdapterTraits template struct for PocoJsonAdapter. -template<> -struct AdapterTraits -{ - typedef Poco::Dynamic::Var DocumentType; - - static std::string adapterName() - { - return "PocoJsonAdapter"; - } -}; - -inline PocoJsonArrayValueIterator PocoJsonArray::begin() const -{ - return m_value.extract()->begin(); -} - -inline PocoJsonArrayValueIterator PocoJsonArray::end() const -{ - return m_value.extract()->end(); -} - -inline PocoJsonObjectMemberIterator PocoJsonObject::begin() const -{ - return m_value.extract()->begin(); -} - -inline PocoJsonObjectMemberIterator PocoJsonObject::end() const -{ - return m_value.extract()->end(); -} - -inline PocoJsonObjectMemberIterator PocoJsonObject::find(const std::string &propertyName) const -{ - auto& ptr = m_value.extract(); - - auto it = std::find_if(ptr->begin(), ptr->end(), [&propertyName](const Poco::JSON::Object::ValueType& p) { - return p.first == propertyName; - }); - return it; -} - -inline bool PocoJsonFrozenValue::equalTo(const Adapter &other, bool strict) const -{ - return PocoJsonAdapter(m_value).equalTo(other, strict); -} - -} // namespace adapters -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/adapters/property_tree_adapter.hpp b/subprojects/valijson/include/valijson/adapters/property_tree_adapter.hpp deleted file mode 100644 index 425547fb6..000000000 --- a/subprojects/valijson/include/valijson/adapters/property_tree_adapter.hpp +++ /dev/null @@ -1,753 +0,0 @@ -/** - * @file - * - * @brief Adapter implementation for the Boost property tree library. - * - * Include this file in your program to enable support for boost property trees. - * - * This file defines the following classes (not in this order): - * - PropertyTreeAdapter - * - PropertyTreeArray - * - PropertyTreeArrayValueIterator - * - PropertyTreeFrozenValue - * - PropertyTreeObject - * - PropertyTreeObjectMember - * - PropertyTreeObjectMemberIterator - * - PropertyTreeValue - * - * Due to the dependencies that exist between these classes, the ordering of - * class declarations and definitions may be a bit confusing. The best place to - * start is PropertyTreeAdapter. This class definition is actually very small, - * since most of the functionality is inherited from the BasicAdapter class. - * Most of the classes in this file are provided as template arguments to the - * inherited BasicAdapter class. - */ - -#pragma once - -#include - -#include - -#include -#include -#include - -namespace valijson { -namespace adapters { - -class PropertyTreeAdapter; -class PropertyTreeArrayValueIterator; -class PropertyTreeObjectMemberIterator; - -typedef std::pair PropertyTreeObjectMember; - -/** - * @brief Light weight wrapper for a Boost property tree that contains - * array-like data. - * - * This class is light weight wrapper for a Boost property tree. It provides a - * minimum set of container functions and typedefs that allow it to be used as - * an iterable container. - * - * An instance of this class contains a single reference to a Boost property - * tree that is assumed to contain unnamed key-value pairs. There is very little - * associated with copy construction and passing by value. - */ -class PropertyTreeArray -{ -public: - - typedef PropertyTreeArrayValueIterator const_iterator; - typedef PropertyTreeArrayValueIterator iterator; - - /// Construct a PropertyTreeArray referencing an empty property tree - /// singleton. - PropertyTreeArray() - : m_array(emptyTree()) { } - - /** - * @brief Construct PropertyTreeArray referencing a specific Boost - * property tree. - * - * @param array reference to a property tree containing an array - * - * It is assumed that this value contains array-like data, but this is not - * checked due to runtime cost. - */ - explicit PropertyTreeArray(const boost::property_tree::ptree &array) - : m_array(array) { } - - /// Return an iterator for the first element in the array. - PropertyTreeArrayValueIterator begin() const; - - /// Return an iterator for one-past the last element of the array. - PropertyTreeArrayValueIterator end() const; - - /// Return the number of elements in the array - size_t size() const - { - return m_array.size(); - } - -private: - - /** - * @brief Return a reference to a property tree that looks like an - * empty array. - * - * Note that the value returned by this function is a singleton. - */ - static const boost::property_tree::ptree & emptyTree() - { - static const boost::property_tree::ptree tree; - return tree; - } - - /// Reference to the contained value - const boost::property_tree::ptree &m_array; -}; - -/** - * @brief Light weight wrapper for a Boost property tree that contains - * object-like data. - * - * This class is light weight wrapper for a Boost property tree. It provides a - * minimum set of container functions and typedefs that allow it to be used as - * an iterable container. - * - * An instance of this class contains a single reference to the underlying - * property tree value, assumed to be object-like, so there is very little - * overhead associated with copy construction and passing by value. - */ -class PropertyTreeObject -{ -public: - - typedef PropertyTreeObjectMemberIterator const_iterator; - typedef PropertyTreeObjectMemberIterator iterator; - - /// Construct a PropertyTreeObject referencing an empty property tree. - PropertyTreeObject() - : m_object(emptyTree()) { } - - /** - * @brief Construct a PropertyTreeObject referencing a specific property - * tree. - * - * @param object reference to a property tree containing an object - * - * Note that the value of the property tree is not checked, due to the - * runtime cost of doing so. - */ - PropertyTreeObject(const boost::property_tree::ptree &object) - : m_object(object) { } - - /** - * @brief Return an iterator for this first object member - * - * The iterator return by this function is effectively a wrapper around - * the iterator value returned by the underlying property tree - * implementation. - */ - PropertyTreeObjectMemberIterator begin() const; - - /** - * @brief Return an iterator for an invalid object member that indicates - * the end of the collection. - * - * The iterator return by this function is effectively a wrapper around - * the pointer value returned by the underlying property tree - * implementation. - */ - PropertyTreeObjectMemberIterator end() const; - - /** - * @brief Return an iterator for the object member with the specified - * property name. - * - * If an object member with the specified name does not exist, the iterator - * returned will be the same as the iterator returned by the end() function. - * - * @param property property name to search for - */ - PropertyTreeObjectMemberIterator find(const std::string &property) const; - - /// Returns the number of members belonging to this object. - size_t size() const - { - return m_object.size(); - } - -private: - - /** - * @brief Return a reference to an empty property tree. - * - * Note that the value returned by this function is a singleton. - */ - static const boost::property_tree::ptree & emptyTree() - { - static const boost::property_tree::ptree tree; - return tree; - } - - /// Reference to the contained object - const boost::property_tree::ptree &m_object; - -}; - -/** - * @brief Stores an independent copy of a Boost property tree. - * - * This class allows a property tree value to be stored independent of its - * original 'document'. Boost property trees make this easy to do, as they do - * not perform any custom memory management. - * - * @see FrozenValue - */ -class PropertyTreeFrozenValue: public FrozenValue -{ -public: - - /** - * @brief Make a copy of a Boost property tree POD value - * - * @param source string containing the POD vlaue - */ - explicit PropertyTreeFrozenValue(const boost::property_tree::ptree::data_type &source) - : m_value(source) { } - - /** - * @brief Make a copy of a Boost property tree object or array value - * - * @param source the property tree to be copied - */ - explicit PropertyTreeFrozenValue(const boost::property_tree::ptree &source) - : m_value(source) { } - - FrozenValue * clone() const override - { - return new PropertyTreeFrozenValue(m_value); - } - - bool equalTo(const Adapter &other, bool strict) const override; - -private: - - /// Stored value - boost::property_tree::ptree m_value; -}; - -/** - * @brief Light weight wrapper for a Boost property tree. - * - * This class is passed as an argument to the BasicAdapter template class, - * and is used to provide access to a Boost property tree value. This class - * is responsible for the mechanics of actually reading a property tree, whereas - * BasicAdapter class is responsible for the semantics of type comparisons - * and conversions. - * - * The functions that need to be provided by this class are defined implicitly - * by the implementation of the BasicAdapter template class. - * - * @see BasicAdapter - */ -class PropertyTreeValue -{ -public: - - /// Construct a wrapper for an empty property tree - PropertyTreeValue() - : m_object(emptyTree()) { } - - /** - * @brief Construct a PropertyTreeValue from a tree object - * - * This function will determine whether the tree object represents an array - * or an object by scanning the key names for any non-empty strings. In the - * case of an empty tree object, it is not possible to determine whether it - * is an array or an object, so it will be treated as an array by default. - * Empty arrays are considered equal to empty objects when compared using - * non-strict type comparison. Empty strings will also be stored as empty - * arrays. - * - * @param tree Tree object to be wrapped - */ - PropertyTreeValue(const boost::property_tree::ptree &tree) - { - if (tree.data().empty()) { // No string content - if (tree.empty()) { // No children - m_array.emplace(tree); // Treat as empty array - } else { - bool isArray = true; - for (const auto &node : tree) { - if (!node.first.empty()) { - isArray = false; - break; - } - } - - if (isArray) { - m_array.emplace(tree); - } else { - m_object.emplace(tree); - } - } - } else { - m_value = tree.data(); - } - } - - /** - * @brief Create a new PropertyTreeFrozenValue instance that contains the - * value referenced by this PropertyTreeValue instance. - * - * @returns pointer to a new PropertyTreeFrozenValue instance, belonging to - * the caller. - */ - FrozenValue* freeze() const - { - if (m_array) { - return new PropertyTreeFrozenValue(*m_array); - } else if (m_object) { - return new PropertyTreeFrozenValue(*m_object); - } else { - return new PropertyTreeFrozenValue(*m_value); - } - } - - /** - * @brief Return an instance of PropertyTreeArrayAdapter. - * - * If the referenced property tree value is an array, this function will - * return a std::optional containing a PropertyTreeArray instance - * referencing the array. - * - * Otherwise it will return an empty optional. - */ - opt::optional getArrayOptional() const - { - if (m_array) { - return opt::make_optional(PropertyTreeArray(*m_array)); - } - - return {}; - } - - /** - * @brief Retrieve the number of elements in the array - * - * If the referenced property tree value is an array, this function will - * retrieve the number of elements in the array and store it in the output - * variable provided. - * - * @param result reference to size_t to set with result - * - * @returns true if the number of elements was retrieved, false otherwise. - */ - bool getArraySize(size_t &result) const - { - if (m_array) { - result = m_array->size(); - return true; - } - - return false; - } - - static bool getBool(bool &) - { - return false; - } - - static bool getDouble(double &) - { - return false; - } - - static bool getInteger(int64_t &) - { - return false; - } - - /** - * @brief Optionally return a PropertyTreeObject instance. - * - * If the referenced property tree is an object, this function will return a - * std::optional containing a PropertyTreeObject instance referencing the - * object. - * - * Otherwise it will return an empty optional. - */ - opt::optional getObjectOptional() const - { - if (m_object) { - return opt::make_optional(PropertyTreeObject(*m_object)); - } - - return {}; - } - - /** - * @brief Retrieve the number of members in the object - * - * If the referenced property tree value is an object, this function will - * retrieve the number of members in the object and store it in the output - * variable provided. - * - * @param result reference to size_t to set with result - * - * @returns true if the number of members was retrieved, false otherwise. - */ - bool getObjectSize(size_t &result) const - { - if (m_object) { - result = m_object->size(); - return true; - } - - return false; - } - - bool getString(std::string &result) const - { - if (m_value) { - result = *m_value; - return true; - } - - return false; - } - - static bool hasStrictTypes() - { - return false; - } - - bool isArray() const - { - return static_cast(m_array); - } - - static bool isBool() - { - return false; - } - - static bool isDouble() - { - return false; - } - - static bool isInteger() - { - return false; - } - - static bool isNull() - { - return false; - } - - static bool isNumber() - { - return false; - } - - bool isObject() const - { - return static_cast(m_object); - } - - bool isString() const - { - return static_cast(m_value); - } - -private: - - static const boost::property_tree::ptree & emptyTree() - { - static const boost::property_tree::ptree tree; - return tree; - } - - /// Reference used if the value is known to be an array - opt::optional m_array; - - /// Reference used if the value is known to be an object - opt::optional m_object; - - /// Reference used if the value is known to be a POD type - opt::optional m_value; -}; - -/** - * @brief An implementation of the Adapter interface supporting the Boost - * property tree library. - * - * This class is defined in terms of the BasicAdapter template class, which - * helps to ensure that all of the Adapter implementations behave consistently. - * - * @see Adapter - * @see BasicAdapter - */ -class PropertyTreeAdapter: - public BasicAdapter -{ -public: - - /// Construct a PropertyTreeAdapter for an empty property tree - PropertyTreeAdapter() - : BasicAdapter() { } - - /// Construct a PropertyTreeAdapter using a specific property tree - PropertyTreeAdapter(const boost::property_tree::ptree &value) - : BasicAdapter(value) { } -}; - -/** - * @brief Class for iterating over values held in a JSON array. - * - * This class provides a JSON array iterator that dereferences as an instance of - * PropertyTreeAdapter representing a value stored in the array. It has been - * implemented using the boost iterator_facade template. - * - * @see PropertyTreeArray - */ -class PropertyTreeArrayValueIterator -{ -public: - using iterator_category = std::bidirectional_iterator_tag; - using value_type = PropertyTreeAdapter; - using difference_type = PropertyTreeAdapter; - using pointer = PropertyTreeAdapter*; - using reference = PropertyTreeAdapter&; - - /** - * @brief Construct a new PropertyTreeArrayValueIterator using an existing - * property tree iterator. - * - * @param itr property tree iterator to store - */ - PropertyTreeArrayValueIterator( - const boost::property_tree::ptree::const_iterator &itr) - : m_itr(itr) { } - - /// Returns a PropertyTreeAdapter that contains the value of the current - /// element. - PropertyTreeAdapter operator*() const - { - return PropertyTreeAdapter(m_itr->second); - } - - DerefProxy operator->() const - { - return DerefProxy(**this); - } - - /** - * @brief Compare this iterator against another iterator. - * - * Note that this directly compares the iterators, not the underlying - * values, and assumes that two identical iterators will point to the same - * underlying object. - * - * @param rhs iterator to compare against - * - * @returns true if the iterators are equal, false otherwise. - */ - bool operator==(const PropertyTreeArrayValueIterator &rhs) const - { - return m_itr == rhs.m_itr; - } - - bool operator!=(const PropertyTreeArrayValueIterator &rhs) const - { - return !(m_itr == rhs.m_itr); - } - - const PropertyTreeArrayValueIterator& operator++() - { - m_itr++; - - return *this; - } - - PropertyTreeArrayValueIterator operator++(int) - { - PropertyTreeArrayValueIterator iterator_pre(m_itr); - ++(*this); - return iterator_pre; - } - - const PropertyTreeArrayValueIterator& operator--() - { - m_itr--; - - return *this; - } - - void advance(std::ptrdiff_t n) - { - if (n > 0) { - while (n-- > 0) { - m_itr++; - } - } else { - while (n++ < 0) { - m_itr--; - } - } - } - -private: - - boost::property_tree::ptree::const_iterator m_itr; -}; - -/** - * @brief Class for iterating over the members belonging to a JSON object. - * - * This class provides a JSON object iterator that dereferences as an instance - * of PropertyTreeObjectMember representing one of the members of the object. - * It has been implemented using the boost iterator_facade template. - * - * @see PropertyTreeObject - * @see PropertyTreeObjectMember - */ -class PropertyTreeObjectMemberIterator -{ -public: - using iterator_category = std::bidirectional_iterator_tag; - using value_type = PropertyTreeObjectMember; - using difference_type = PropertyTreeObjectMember; - using pointer = PropertyTreeObjectMember*; - using reference = PropertyTreeObjectMember&; - - /** - * @brief Construct an iterator from a PropertyTree iterator. - * - * @param itr PropertyTree iterator to store - */ - PropertyTreeObjectMemberIterator( - boost::property_tree::ptree::const_assoc_iterator itr) - : m_itr(itr) { } - - /** - * @brief Returns a PropertyTreeObjectMember that contains the key and - * value belonging to the object member identified by the iterator. - */ - PropertyTreeObjectMember operator*() const - { - return PropertyTreeObjectMember(m_itr->first, m_itr->second); - } - - DerefProxy operator->() const - { - return DerefProxy(**this); - } - - /** - * @brief Compare this iterator with another iterator. - * - * Note that this directly compares the iterators, not the underlying - * values, and assumes that two identical iterators will point to the same - * underlying object. - * - * @param rhs Iterator to compare with - * - * @returns true if the underlying iterators are equal, false otherwise - */ - bool operator==(const PropertyTreeObjectMemberIterator &rhs) const - { - return m_itr == rhs.m_itr; - } - - bool operator!=(const PropertyTreeObjectMemberIterator &rhs) const - { - return !(m_itr == rhs.m_itr); - } - - const PropertyTreeObjectMemberIterator& operator++() - { - m_itr++; - - return *this; - } - - PropertyTreeObjectMemberIterator operator++(int) - { - PropertyTreeObjectMemberIterator iterator_pre(m_itr); - ++(*this); - return iterator_pre; - } - - const PropertyTreeObjectMemberIterator& operator--() - { - m_itr--; - - return *this; - } - -private: - - boost::property_tree::ptree::const_assoc_iterator m_itr; -}; - -/// Specialisation of the AdapterTraits template struct for PropertyTreeAdapter. -template<> -struct AdapterTraits -{ - typedef boost::property_tree::ptree DocumentType; - - static std::string adapterName() - { - return "PropertyTreeAdapter"; - } -}; - -inline bool PropertyTreeFrozenValue::equalTo(const Adapter &other, bool strict) const -{ - return PropertyTreeAdapter(m_value).equalTo(other, strict); -} - -inline PropertyTreeArrayValueIterator PropertyTreeArray::begin() const -{ - return m_array.begin(); -} - -inline PropertyTreeArrayValueIterator PropertyTreeArray::end() const -{ - return m_array.end(); -} - -inline PropertyTreeObjectMemberIterator PropertyTreeObject::begin() const -{ - return m_object.ordered_begin(); -} - -inline PropertyTreeObjectMemberIterator PropertyTreeObject::end() const -{ - return m_object.not_found(); -} - -inline PropertyTreeObjectMemberIterator PropertyTreeObject::find( - const std::string &propertyName) const -{ - const boost::property_tree::ptree::const_assoc_iterator itr = m_object.find(propertyName); - - if (itr != m_object.not_found()) { - return itr; - } - - return m_object.not_found(); -} - -} // namespace adapters -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/adapters/qtjson_adapter.hpp b/subprojects/valijson/include/valijson/adapters/qtjson_adapter.hpp deleted file mode 100644 index 2307fb5c3..000000000 --- a/subprojects/valijson/include/valijson/adapters/qtjson_adapter.hpp +++ /dev/null @@ -1,722 +0,0 @@ -/** - * @file - * - * @brief Adapter implementation for the QtJson parser library. - * - * Include this file in your program to enable support for QtJson. - * - * This file defines the following classes (not in this order): - * - QtJsonAdapter - * - QtJsonArray - * - QtJsonArrayValueIterator - * - QtJsonFrozenValue - * - QtJsonObject - * - QtJsonObjectMember - * - QtJsonObjectMemberIterator - * - QtJsonValue - * - * Due to the dependencies that exist between these classes, the ordering of - * class declarations and definitions may be a bit confusing. The best place to - * start is QtJsonAdapter. This class definition is actually very small, - * since most of the functionality is inherited from the BasicAdapter class. - * Most of the classes in this file are provided as template arguments to the - * inherited BasicAdapter class. - */ - -#pragma once - -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -namespace valijson { -namespace adapters { - -class QtJsonAdapter; -class QtJsonArrayValueIterator; -class QtJsonObjectMemberIterator; - -typedef std::pair QtJsonObjectMember; - -/** - * @brief Light weight wrapper for a QtJson array value. - * - * This class is light weight wrapper for a QtJson array. It provides a - * minimum set of container functions and typedefs that allow it to be used as - * an iterable container. - * - * An instance of this class contains a single reference to the underlying - * QtJson value, assumed to be an array, so there is very little overhead - * associated with copy construction and passing by value. - */ -class QtJsonArray -{ -public: - - typedef QtJsonArrayValueIterator const_iterator; - typedef QtJsonArrayValueIterator iterator; - - /// Construct a QtJsonArray referencing an empty array. - QtJsonArray() - : m_value(emptyArray()) - { - } - - /** - * @brief Construct a QtJsonArray referencing a specific QtJson - * value. - * - * @param value reference to a QtJson value - * - * Note that this constructor will throw an exception if the value is not - * an array. - */ - explicit QtJsonArray(const QJsonValue &value) - : m_value(value.toArray()) - { - if (!value.isArray()) { - throwRuntimeError("Value is not an array."); - } - } - - /** - * @brief Return an iterator for the first element of the array. - * - * The iterator return by this function is effectively the iterator - * returned by the underlying QtJson implementation. - */ - QtJsonArrayValueIterator begin() const; - - /** - * @brief Return an iterator for one-past the last element of the array. - * - * The iterator return by this function is effectively the iterator - * returned by the underlying QtJson implementation. - */ - QtJsonArrayValueIterator end() const; - - /// Return the number of elements in the array - size_t size() const - { - return m_value.size(); - } - -private: - - /** - * @brief Return a reference to a QtJson value that is an empty array. - * - * Note that the value returned by this function is a singleton. - */ - static QJsonArray emptyArray() - { - static const QJsonArray array; - return array; - } - - /// Reference to the contained value - const QJsonArray m_value; -}; - -/** - * @brief Light weight wrapper for a QtJson object. - * - * This class is light weight wrapper for a QtJson object. It provides a - * minimum set of container functions and typedefs that allow it to be used as - * an iterable container. - * - * An instance of this class contains a single reference to the underlying - * QtJson value, assumed to be an object, so there is very little overhead - * associated with copy construction and passing by value. - */ -class QtJsonObject -{ -public: - - typedef QtJsonObjectMemberIterator const_iterator; - typedef QtJsonObjectMemberIterator iterator; - - /// Construct a QtJsonObject referencing an empty object singleton. - QtJsonObject() - : m_value(emptyObject()) - { - } - - /** - * @brief Construct a QtJsonObject referencing a specific QtJson - * value. - * - * @param value reference to a QtJson value - * - * Note that this constructor will throw an exception if the value is not - * an object. - */ - QtJsonObject(const QJsonValue &value) - : m_value(value.toObject()) - { - if (!value.isObject()) { - throwRuntimeError("Value is not an object."); - } - } - - /** - * @brief Return an iterator for this first object member - * - * The iterator return by this function is effectively a wrapper around - * the iterator value returned by the underlying QtJson implementation. - */ - QtJsonObjectMemberIterator begin() const; - - /** - * @brief Return an iterator for an invalid object member that indicates - * the end of the collection. - * - * The iterator return by this function is effectively a wrapper around - * the iterator value returned by the underlying QtJson implementation. - */ - QtJsonObjectMemberIterator end() const; - - /** - * @brief Return an iterator for the object member with the specified - * property name. - * - * If an object member with the specified name does not exist, the iterator - * returned will be the same as the iterator returned by the end() function. - * - * @param propertyName property name to search for - */ - QtJsonObjectMemberIterator find(const std::string &propertyName) const; - - /// Returns the number of members belonging to this object. - size_t size() const - { - return m_value.size(); - } - -private: - - /** - * @brief Return a reference to a QtJson value that is empty object. - * - * Note that the value returned by this function is a singleton. - */ - static const QJsonObject emptyObject() - { - static const QJsonObject object; - return object; - } - - /// Reference to the contained object - const QJsonObject m_value; -}; - -/** - * @brief Stores an independent copy of a QtJson value. - * - * This class allows a QtJson value to be stored independent of its original - * document. QtJson makes this easy to do, as it does not perform any - * custom memory management. - * - * @see FrozenValue - */ -class QtJsonFrozenValue: public FrozenValue -{ -public: - - /** - * @brief Make a copy of a QtJson value - * - * @param source the QtJson value to be copied - */ - explicit QtJsonFrozenValue(QJsonValue source) - : m_value(std::move(source)) { } - - FrozenValue * clone() const override - { - return new QtJsonFrozenValue(m_value); - } - - bool equalTo(const Adapter &other, bool strict) const override; - -private: - - /// Stored QtJson value - QJsonValue m_value; -}; - -/** - * @brief Light weight wrapper for a QtJson value. - * - * This class is passed as an argument to the BasicAdapter template class, - * and is used to provide access to a QtJson value. This class is responsible - * for the mechanics of actually reading a QtJson value, whereas the - * BasicAdapter class is responsible for the semantics of type comparisons - * and conversions. - * - * The functions that need to be provided by this class are defined implicitly - * by the implementation of the BasicAdapter template class. - * - * @see BasicAdapter - */ -class QtJsonValue -{ -public: - - /// Construct a wrapper for the empty object singleton - QtJsonValue() - : m_value(emptyObject()) { } - - /// Construct a wrapper for a specific QtJson value - QtJsonValue(QJsonValue value) - : m_value(std::move(value)) { } - - /** - * @brief Create a new QtJsonFrozenValue instance that contains the - * value referenced by this QtJsonValue instance. - * - * @returns pointer to a new QtJsonFrozenValue instance, belonging to the - * caller. - */ - FrozenValue * freeze() const - { - return new QtJsonFrozenValue(m_value); - } - - /** - * @brief Optionally return a QtJsonArray instance. - * - * If the referenced QtJson value is an array, this function will return - * a std::optional containing a QtJsonArray instance referencing the - * array. - * - * Otherwise it will return an empty optional. - */ - opt::optional getArrayOptional() const - { - if (m_value.isArray()) { - return opt::make_optional(QtJsonArray(m_value)); - } - - return opt::optional(); - } - - /** - * @brief Retrieve the number of elements in the array - * - * If the referenced QtJson value is an array, this function will - * retrieve the number of elements in the array and store it in the output - * variable provided. - * - * @param result reference to size_t to set with result - * - * @returns true if the number of elements was retrieved, false otherwise. - */ - bool getArraySize(size_t &result) const - { - if (m_value.isArray()) { - const QJsonArray array = m_value.toArray(); - result = array.size(); - return true; - } - - return false; - } - - bool getBool(bool &result) const - { - if (m_value.isBool()) { - result = m_value.toBool(); - return true; - } - - return false; - } - - bool getDouble(double &result) const - { - if (m_value.isDouble()) { - result = m_value.toDouble(); - return true; - } - - return false; - } - - bool getInteger(int64_t &result) const - { - if (m_value.isDouble()) { - result = m_value.toInt(); - return true; - } - - return false; - } - - /** - * @brief Optionally return a QtJsonObject instance. - * - * If the referenced QtJson value is an object, this function will return a - * std::optional containing a QtJsonObject instance referencing the - * object. - * - * Otherwise it will return an empty optional. - */ - opt::optional getObjectOptional() const - { - if (m_value.isObject()) { - return opt::make_optional(QtJsonObject(m_value)); - } - - return opt::optional(); - } - - /** - * @brief Retrieve the number of members in the object - * - * If the referenced QtJson value is an object, this function will - * retrieve the number of members in the object and store it in the output - * variable provided. - * - * @param result reference to size_t to set with result - * - * @returns true if the number of members was retrieved, false otherwise. - */ - bool getObjectSize(size_t &result) const - { - if (m_value.isObject()) { - const QJsonObject &object = m_value.toObject(); - result = object.size(); - return true; - } - - return false; - } - - bool getString(std::string &result) const - { - if (m_value.isString()) { - result = m_value.toString().toStdString(); - return true; - } - - return false; - } - - static bool hasStrictTypes() - { - return true; - } - - bool isArray() const - { - return m_value.isArray(); - } - - bool isBool() const - { - return m_value.isBool(); - } - - bool isDouble() const - { - return m_value.isDouble(); - } - - bool isInteger() const - { - //toInt returns the default value (0, 1) if the value is not a whole number - return m_value.isDouble() && (m_value.toInt(0) == m_value.toInt(1)); - } - - bool isNull() const - { - return m_value.isNull(); - } - - bool isNumber() const - { - return m_value.isDouble(); - } - - bool isObject() const - { - return m_value.isObject(); - } - - bool isString() const - { - return m_value.isString(); - } - -private: - - /// Return a reference to an empty object singleton - static QJsonValue emptyObject() - { - static const QJsonValue object; - return object; - } - - /// Reference to the contained QtJson value. - const QJsonValue m_value; -}; - -/** - * @brief An implementation of the Adapter interface supporting QtJson. - * - * This class is defined in terms of the BasicAdapter template class, which - * helps to ensure that all of the Adapter implementations behave consistently. - * - * @see Adapter - * @see BasicAdapter - */ -class QtJsonAdapter: - public BasicAdapter -{ -public: - - /// Construct a QtJsonAdapter that contains an empty object - QtJsonAdapter() - : BasicAdapter() { } - - /// Construct a QtJsonAdapter containing a specific QtJson value - QtJsonAdapter(const QJsonValue &value) - : BasicAdapter(value) { } -}; - -/** - * @brief Class for iterating over values held in a JSON array. - * - * This class provides a JSON array iterator that dereferences as an instance of - * QtJsonAdapter representing a value stored in the array. - * - * @see QtJsonArray - */ -class QtJsonArrayValueIterator -{ -public: - using iterator_category = std::bidirectional_iterator_tag; - using value_type = QtJsonAdapter; - using difference_type = QtJsonAdapter; - using pointer = QtJsonAdapter*; - using reference = QtJsonAdapter&; - - /** - * @brief Construct a new QtJsonArrayValueIterator using an existing - * QtJson iterator. - * - * @param itr QtJson iterator to store - */ - QtJsonArrayValueIterator(const QJsonArray::const_iterator &itr) - : m_itr(itr) { } - - /// Returns a QtJsonAdapter that contains the value of the current - /// element. - QtJsonAdapter operator*() const - { - return QtJsonAdapter(*m_itr); - } - - DerefProxy operator->() const - { - return DerefProxy(**this); - } - - /** - * @brief Compare this iterator against another iterator. - * - * Note that this directly compares the iterators, not the underlying - * values, and assumes that two identical iterators will point to the same - * underlying object. - * - * @param other iterator to compare against - * - * @returns true if the iterators are equal, false otherwise. - */ - bool operator==(const QtJsonArrayValueIterator &other) const - { - return m_itr == other.m_itr; - } - - bool operator!=(const QtJsonArrayValueIterator &other) const - { - return !(m_itr == other.m_itr); - } - - const QtJsonArrayValueIterator& operator++() - { - m_itr++; - - return *this; - } - - QtJsonArrayValueIterator operator++(int) - { - QtJsonArrayValueIterator iterator_pre(m_itr); - ++(*this); - return iterator_pre; - } - - const QtJsonArrayValueIterator& operator--() - { - m_itr--; - - return *this; - } - - void advance(std::ptrdiff_t n) - { - m_itr += n; - } - -private: - - QJsonArray::const_iterator m_itr; -}; - -/** - * @brief Class for iterating over the members belonging to a JSON object. - * - * This class provides a JSON object iterator that dereferences as an instance - * of QtJsonObjectMember representing one of the members of the object. It - * has been implemented using the boost iterator_facade template. - * - * @see QtJsonObject - * @see QtJsonObjectMember - */ -class QtJsonObjectMemberIterator -{ -public: - using iterator_category = std::bidirectional_iterator_tag; - using value_type = QtJsonObjectMember; - using difference_type = QtJsonObjectMember; - using pointer = QtJsonObjectMember*; - using reference = QtJsonObjectMember&; - - /** - * @brief Construct an iterator from a QtJson iterator. - * - * @param itr QtJson iterator to store - */ - QtJsonObjectMemberIterator(const QJsonObject::const_iterator &itr) - : m_itr(itr) { } - - /** - * @brief Returns a QtJsonObjectMember that contains the key and value - * belonging to the object member identified by the iterator. - */ - QtJsonObjectMember operator*() const - { - std::string key = m_itr.key().toStdString(); - return QtJsonObjectMember(key, m_itr.value()); - } - - DerefProxy operator->() const - { - return DerefProxy(**this); - } - - /** - * @brief Compare this iterator with another iterator. - * - * Note that this directly compares the iterators, not the underlying - * values, and assumes that two identical iterators will point to the same - * underlying object. - * - * @param other Iterator to compare with - * - * @returns true if the underlying iterators are equal, false otherwise - */ - bool operator==(const QtJsonObjectMemberIterator &other) const - { - return m_itr == other.m_itr; - } - - bool operator!=(const QtJsonObjectMemberIterator &other) const - { - return !(m_itr == other.m_itr); - } - - const QtJsonObjectMemberIterator& operator++() - { - m_itr++; - return *this; - } - - QtJsonObjectMemberIterator operator++(int) - { - QtJsonObjectMemberIterator iterator_pre(m_itr); - ++(*this); - return iterator_pre; - } - - const QtJsonObjectMemberIterator& operator--(int) - { - m_itr--; - - return *this; - } - -private: - - /// Iternal copy of the original QtJson iterator - QJsonObject::const_iterator m_itr; -}; - -/// Specialisation of the AdapterTraits template struct for QtJsonAdapter. -template<> -struct AdapterTraits -{ - typedef QJsonValue DocumentType; - - static std::string adapterName() - { - return "QtJsonAdapter"; - } -}; - -inline bool QtJsonFrozenValue::equalTo(const Adapter &other, bool strict) const -{ - return QtJsonAdapter(m_value).equalTo(other, strict); -} - -inline QtJsonArrayValueIterator QtJsonArray::begin() const -{ - return m_value.begin(); -} - -inline QtJsonArrayValueIterator QtJsonArray::end() const -{ - return m_value.end(); -} - -inline QtJsonObjectMemberIterator QtJsonObject::begin() const -{ - return m_value.begin(); -} - -inline QtJsonObjectMemberIterator QtJsonObject::end() const -{ - return m_value.end(); -} - -inline QtJsonObjectMemberIterator QtJsonObject::find( - const std::string &propertyName) const -{ - return m_value.find(QString::fromStdString(propertyName)); -} - -} // namespace adapters -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/adapters/rapidjson_adapter.hpp b/subprojects/valijson/include/valijson/adapters/rapidjson_adapter.hpp deleted file mode 100644 index c9ec75dcc..000000000 --- a/subprojects/valijson/include/valijson/adapters/rapidjson_adapter.hpp +++ /dev/null @@ -1,937 +0,0 @@ -/** - * @file - * - * @brief Adapter implementation for the RapidJson parser library. - * - * Include this file in your program to enable support for RapidJson. - * - * This file defines the following template classes (not in this order): - * - GenericRapidJsonAdapter - * - GenericRapidJsonArray - * - GenericRapidJsonArrayValueIterator - * - GenericRapidJsonFrozenValue - * - GenericRapidJsonObject - * - GenericRapidJsonObjectMember - * - GenericRapidJsonObjectMemberIterator - * - GenericRapidJsonValue - * - * All of these classes share a template argument called 'ValueType', which can - * be used to choose the underlying the RapidJson value type that is used. This - * allows different RapidJson encodings and allocators to be used. - * - * This file also defines the following typedefs, which use RapidJson's default - * ValueType: - * - RapidJsonAdapter - * - RapidJsonArray - * - RapidJsonArrayValueIterator - * - RapidJsonFrozenValue - * - RapidJsonObject - * - RapidJsonObjectMember - * - RapidJsonObjectMemberIterator - * - RapidJsonValue - * - * Due to the dependencies that exist between these classes, the ordering of - * class declarations and definitions may be a bit confusing. The best place to - * start is RapidJsonAdapter. This class definition is actually very small, - * since most of the functionality is inherited from the BasicAdapter class. - * Most of the classes in this file are provided as template arguments to the - * inherited BasicAdapter class. - */ - -#pragma once - -#include -#include - -#ifdef VALIJSON_USE_EXCEPTIONS - #ifdef RAPIDJSON_ASSERT - #warning "RAPIDJSON_ASSERT already defined." - #warning "Please include valijson/adapters/rapidjson_adapter.hpp before any RapidJSON headers." - #else - template - T rapidjson_assert(T t, const std::string& file, const int line) { - if (t) { - return t; - } - - throw std::runtime_error("assertion failed; file: " + file + "; line: " + std::to_string(line)); - } - - #define RAPIDJSON_ASSERT(x) rapidjson_assert(x, __FILE__, __LINE__) - #endif -#endif - -#include - -#include -#include -#include -#include - -namespace valijson { -namespace adapters { - -template -class GenericRapidJsonAdapter; - -template -class GenericRapidJsonArrayValueIterator; - -template -class GenericRapidJsonObjectMemberIterator; - -/// Container for a property name and an associated RapidJson value -template -class GenericRapidJsonObjectMember : - public std::pair> -{ -private: - typedef std::pair> Super; - -public: - GenericRapidJsonObjectMember( - const std::string &name, - const GenericRapidJsonAdapter &value) - : Super(name, value) { } -}; - -/** - * @brief Light weight wrapper for a RapidJson array value. - * - * This class is light weight wrapper for a RapidJson array. It provides a - * minimum set of container functions and typedefs that allow it to be used as - * an iterable container. - * - * An instance of this class contains a single reference to an underlying - * RapidJson value, assumed to be an array, so there is very little overhead - * associated with copy construction and passing by value. - */ -template -class GenericRapidJsonArray -{ -public: - - typedef GenericRapidJsonArrayValueIterator const_iterator; - typedef GenericRapidJsonArrayValueIterator iterator; - - /// Construct a RapidJsonArray referencing an empty array singleton. - GenericRapidJsonArray() - : m_value(emptyArray()) { } - - /** - * @brief Construct a RapidJsonArray referencing a specific RapidJson - * value. - * - * @param value reference to a RapidJson value - * - * Note that this constructor will throw an exception if the value is not - * an array. - */ - GenericRapidJsonArray(const ValueType &value) - : m_value(value) - { - if (!value.IsArray()) { - throwRuntimeError("Value is not an array."); - } - } - - /// Return an iterator for the first element in the array. - iterator begin() const; - - /// Return an iterator for one-past the last element of the array. - iterator end() const; - - /// Return the number of elements in the array - size_t size() const - { - return m_value.Size(); - } - -private: - - /** - * @brief Return a reference to a RapidJson value that is an empty array. - * - * Note that the value returned by this function is a singleton. - */ - static const ValueType & emptyArray() - { - static const ValueType array(rapidjson::kArrayType); - return array; - } - - /// Reference to the contained value - const ValueType &m_value; -}; - -/** - * @brief Light weight wrapper for a RapidJson object. - * - * This class is light weight wrapper for a RapidJson object. It provides a - * minimum set of container functions and typedefs that allow it to be used as - * an iterable container. - * - * An instance of this class contains a single reference to the underlying - * RapidJson value, assumed to be an object, so there is very little overhead - * associated with copy construction and passing by value. - */ -template -class GenericRapidJsonObject -{ -public: - - typedef GenericRapidJsonObjectMemberIterator const_iterator; - typedef GenericRapidJsonObjectMemberIterator iterator; - - /// Construct a GenericRapidJsonObject referencing an empty object singleton. - GenericRapidJsonObject() - : m_value(emptyObject()) { } - - /** - * @brief Construct a GenericRapidJsonObject referencing a specific - * RapidJson value. - * - * @param value reference to a RapidJson value - * - * Note that this constructor will throw an exception if the value is not - * an object. - */ - GenericRapidJsonObject(const ValueType &value) - : m_value(value) - { - if (!value.IsObject()) { - throwRuntimeError("Value is not an object."); - } - } - - /** - * @brief Return an iterator for this first object member - * - * The iterator return by this function is effectively a wrapper around - * the pointer value returned by the underlying RapidJson implementation. - */ - iterator begin() const; - - /** - * @brief Return an iterator for an invalid object member that indicates - * the end of the collection. - * - * The iterator return by this function is effectively a wrapper around - * the pointer value returned by the underlying RapidJson implementation. - */ - iterator end() const; - - /** - * @brief Return an iterator for the object member with the specified - * property name. - * - * If an object member with the specified name does not exist, the iterator - * returned will be the same as the iterator returned by the end() function. - * - * @param property property name to search for - */ - iterator find(const std::string &property) const; - - /// Returns the number of members belonging to this object. - size_t size() const - { - return m_value.MemberEnd() - m_value.MemberBegin(); - } - -private: - - /** - * @brief Return a reference to a RapidJson value that is empty object. - * - * Note that the value returned by this function is a singleton. - */ - static const ValueType & emptyObject() - { - static ValueType object(rapidjson::kObjectType); - return object; - } - - /// Reference to the contained object - const ValueType &m_value; -}; - -/** - * @brief Stores an independent copy of a RapidJson value. - * - * This class allows a RapidJson value to be stored independent of its original - * document. RapidJson makes this a bit harder than usual, because RapidJson - * values are associated with a custom memory allocator. As such, RapidJson - * values have to be copied recursively, referencing a custom allocator held - * by this class. - * - * @see FrozenValue - */ -template -class GenericRapidJsonFrozenValue: public FrozenValue -{ -public: - - explicit GenericRapidJsonFrozenValue(const char *str) - { - m_value.SetString(str, m_allocator); - } - - explicit GenericRapidJsonFrozenValue(const std::string &str) - { - m_value.SetString(str.c_str(), (unsigned int)str.length(), m_allocator); - } - - /** - * @brief Make a copy of a RapidJson value - * - * @param source the RapidJson value to be copied - */ - explicit GenericRapidJsonFrozenValue(const ValueType &source) - { - if (!copy(source, m_value, m_allocator)) { - throwRuntimeError("Failed to copy ValueType"); - } - } - - FrozenValue * clone() const override - { - return new GenericRapidJsonFrozenValue(m_value); - } - - bool equalTo(const Adapter &other, bool strict) const override; - -private: - - /** - * @brief Recursively copy a RapidJson value using a separate allocator - * - * @param source value to copy from - * @param dest value to copy into - * @param allocator reference to an allocator held by this class - * - * @tparam Allocator type of RapidJson Allocator to be used - * - * @returns true if copied successfully, false otherwise. - */ - template - static bool copy(const ValueType &source, - ValueType &dest, - Allocator &allocator) - { - switch (source.GetType()) { - case rapidjson::kNullType: - dest.SetNull(); - return true; - case rapidjson::kFalseType: - dest.SetBool(false); - return true; - case rapidjson::kTrueType: - dest.SetBool(true); - return true; - case rapidjson::kObjectType: - dest.SetObject(); - for (typename ValueType::ConstMemberIterator itr = source.MemberBegin(); itr != source.MemberEnd(); ++itr) { - ValueType name(itr->name.GetString(), itr->name.GetStringLength(), allocator); - ValueType value; - copy(itr->value, value, allocator); - dest.AddMember(name, value, allocator); - } - return true; - case rapidjson::kArrayType: - dest.SetArray(); - for (typename ValueType::ConstValueIterator itr = source.Begin(); itr != source.End(); ++itr) { - ValueType value; - copy(*itr, value, allocator); - dest.PushBack(value, allocator); - } - return true; - case rapidjson::kStringType: - dest.SetString(source.GetString(), source.GetStringLength(), allocator); - return true; - case rapidjson::kNumberType: - if (source.IsInt()) { - dest.SetInt(source.GetInt()); - } else if (source.IsUint()) { - dest.SetUint(source.GetUint()); - } else if (source.IsInt64()) { - dest.SetInt64(source.GetInt64()); - } else if (source.IsUint64()) { - dest.SetUint64(source.GetUint64()); - } else { - dest.SetDouble(source.GetDouble()); - } - return true; - default: - break; - } - - return false; - } - - /// Local memory allocator for RapidJson value - typename ValueType::AllocatorType m_allocator; - - /// Local RapidJson value - ValueType m_value; -}; - -/** - * @brief Light weight wrapper for a RapidJson value. - * - * This class is passed as an argument to the BasicAdapter template class, - * and is used to provide access to a RapidJson value. This class is responsible - * for the mechanics of actually reading a RapidJson value, whereas the - * BasicAdapter class is responsible for the semantics of type comparisons - * and conversions. - * - * The functions that need to be provided by this class are defined implicitly - * by the implementation of the BasicAdapter template class. - * - * @see BasicAdapter - */ -template -class GenericRapidJsonValue -{ -public: - /// Construct a wrapper for the empty object singleton - GenericRapidJsonValue() - : m_value(emptyObject()) { } - - /// Construct a wrapper for a specific RapidJson value - GenericRapidJsonValue(const ValueType &value) - : m_value(value) { } - - /** - * @brief Create a new GenericRapidJsonFrozenValue instance that contains - * the value referenced by this GenericRapidJsonValue instance. - * - * @returns pointer to a new GenericRapidJsonFrozenValue instance, belonging - * to the caller. - */ - FrozenValue * freeze() const - { - return new GenericRapidJsonFrozenValue(m_value); - } - - /** - * @brief Optionally return a GenericRapidJsonArray instance. - * - * If the referenced RapidJson value is an array, this function will return - * a std::optional containing a GenericRapidJsonArray instance referencing - * the array. - * - * Otherwise it will return an empty optional. - */ - opt::optional> getArrayOptional() const - { - if (m_value.IsArray()) { - return opt::make_optional(GenericRapidJsonArray(m_value)); - } - - return {}; - } - - /** - * @brief Retrieve the number of elements in the array - * - * If the referenced RapidJson value is an array, this function will - * retrieve the number of elements in the array and store it in the output - * variable provided. - * - * @param result reference to size_t to set with result - * - * @returns true if the number of elements was retrieved, false otherwise. - */ - bool getArraySize(size_t &result) const - { - if (m_value.IsArray()) { - result = m_value.Size(); - return true; - } - - return false; - } - - bool getBool(bool &result) const - { - if (m_value.IsBool()) { - result = m_value.GetBool(); - return true; - } - - return false; - } - - bool getDouble(double &result) const - { - if (m_value.IsDouble()) { - result = m_value.GetDouble(); - return true; - } - - return false; - } - - bool getInteger(int64_t &result) const - { - if (m_value.IsInt()) { - result = m_value.GetInt(); - return true; - } else if (m_value.IsInt64()) { - result = m_value.GetInt64(); - return true; - } else if (m_value.IsUint()) { - result = static_cast(m_value.GetUint()); - return true; - } else if (m_value.IsUint64()) { - result = static_cast(m_value.GetUint64()); - return true; - } - - return false; - } - - /** - * @brief Optionally return a GenericRapidJsonObject instance. - * - * If the referenced RapidJson value is an object, this function will return - * a std::optional containing a GenericRapidJsonObject instance - * referencing the object. - * - * Otherwise it will return an empty optional. - */ - opt::optional> getObjectOptional() const - { - if (m_value.IsObject()) { - return opt::make_optional(GenericRapidJsonObject(m_value)); - } - - return {}; - } - - /** - * @brief Retrieve the number of members in the object - * - * If the referenced RapidJson value is an object, this function will - * retrieve the number of members in the object and store it in the output - * variable provided. - * - * @param result reference to size_t to set with result - * - * @returns true if the number of members was retrieved, false otherwise. - */ - bool getObjectSize(size_t &result) const - { - if (m_value.IsObject()) { - result = m_value.MemberEnd() - m_value.MemberBegin(); - return true; - } - - return false; - } - - bool getString(std::string &result) const - { - if (m_value.IsString()) { - result.assign(m_value.GetString(), m_value.GetStringLength()); - return true; - } - - return false; - } - - static bool hasStrictTypes() - { - return true; - } - - bool isArray() const - { - return m_value.IsArray(); - } - - bool isBool() const - { - return m_value.IsBool(); - } - - bool isDouble() const - { - return m_value.IsDouble(); - } - - bool isInteger() const - { - return m_value.IsInt() || m_value.IsInt64() || m_value.IsUint() || m_value.IsUint64(); - } - - bool isNull() const - { - return m_value.IsNull(); - } - - bool isNumber() const - { - return m_value.IsNumber(); - } - - bool isObject() const - { - return m_value.IsObject(); - } - - bool isString() const - { - return m_value.IsString(); - } - -private: - - /// Return a reference to an empty object singleton - static const ValueType & emptyObject() - { - static const ValueType object(rapidjson::kObjectType); - return object; - } - - /// Reference to the contained RapidJson value. - const ValueType &m_value; -}; - -/** - * @brief An implementation of the Adapter interface supporting RapidJson. - * - * This class is defined in terms of the BasicAdapter template class, which - * helps to ensure that all of the Adapter implementations behave consistently. - * - * @see Adapter - * @see BasicAdapter - */ -template -class GenericRapidJsonAdapter: - public BasicAdapter, - GenericRapidJsonArray, - GenericRapidJsonObjectMember, - GenericRapidJsonObject, - GenericRapidJsonValue> -{ -public: - - /// Construct a RapidJsonAdapter that contains an empty object - GenericRapidJsonAdapter() - : BasicAdapter, - GenericRapidJsonArray, - GenericRapidJsonObjectMember, - GenericRapidJsonObject, - GenericRapidJsonValue>() { } - - /// Construct a RapidJsonAdapter containing a specific RapidJson value - GenericRapidJsonAdapter(const ValueType &value) - : BasicAdapter, - GenericRapidJsonArray, - GenericRapidJsonObjectMember, - GenericRapidJsonObject, - GenericRapidJsonValue>(value) { } -}; - -/** - * @brief Class for iterating over values held in a JSON array. - * - * This class provides a JSON array iterator that dereferences as an instance of - * RapidJsonAdapter representing a value stored in the array. - * - * @see RapidJsonArray - */ -template -class GenericRapidJsonArrayValueIterator -{ -public: - using iterator_category = std::bidirectional_iterator_tag; - using value_type = GenericRapidJsonAdapter; - using difference_type = GenericRapidJsonAdapter; - using pointer = GenericRapidJsonAdapter*; - using reference = GenericRapidJsonAdapter&; - - /** - * @brief Construct a new GenericRapidJsonArrayValueIterator using an - * existing RapidJson iterator. - * - * @param itr RapidJson iterator to store - */ - GenericRapidJsonArrayValueIterator( - const typename ValueType::ConstValueIterator &itr) - : m_itr(itr) { } - - /// Returns a GenericRapidJsonAdapter that contains the value of the current - /// element. - GenericRapidJsonAdapter operator*() const - { - return GenericRapidJsonAdapter(*m_itr); - } - - /// Returns a proxy for the value of the current element - DerefProxy> operator->() const - { - return DerefProxy>(**this); - } - - /** - * @brief Compare this iterator against another iterator. - * - * Note that this directly compares the iterators, not the underlying - * values, and assumes that two identical iterators will point to the same - * underlying object. - * - * @param other iterator to compare against - * - * @returns true if the iterators are equal, false otherwise. - */ - bool operator==(const GenericRapidJsonArrayValueIterator &other) const - { - return m_itr == other.m_itr; - } - - bool operator!=(const GenericRapidJsonArrayValueIterator& other) const - { - return m_itr != other.m_itr; - } - - GenericRapidJsonArrayValueIterator& operator++() - { - m_itr++; - - return *this; - } - - GenericRapidJsonArrayValueIterator operator++(int) { - GenericRapidJsonArrayValueIterator iterator_pre(m_itr); - ++(*this); - return iterator_pre; - } - - GenericRapidJsonArrayValueIterator& operator--() - { - m_itr--; - - return *this; - } - - void advance(std::ptrdiff_t n) - { - m_itr += n; - } - - std::ptrdiff_t difference(const GenericRapidJsonArrayValueIterator &other) - { - return std::distance(m_itr, other.itr); - } - -private: - - typename ValueType::ConstValueIterator m_itr; -}; - -/** - * @brief Class for iterating over the members belonging to a JSON object. - * - * This class provides a JSON object iterator that dereferences as an instance - * of GenericRapidJsonObjectMember representing one of the members of the - * object. - * - * @see GenericRapidJsonObject - * @see GenericRapidJsonObjectMember - */ -template -class GenericRapidJsonObjectMemberIterator -{ -public: - using iterator_category = std::bidirectional_iterator_tag; - using value_type = GenericRapidJsonObjectMember; - using difference_type = GenericRapidJsonObjectMember; - using pointer = GenericRapidJsonObjectMember*; - using reference = GenericRapidJsonObjectMember&; - - /** - * @brief Construct an iterator from a RapidJson iterator. - * - * @param itr RapidJson iterator to store - */ - GenericRapidJsonObjectMemberIterator( - const typename ValueType::ConstMemberIterator &itr) - : m_itr(itr) { } - - - /** - * @brief Returns a GenericRapidJsonObjectMember that contains the key and - * value belonging to the object member identified by the iterator. - */ - GenericRapidJsonObjectMember operator*() const - { - return GenericRapidJsonObjectMember( - std::string(m_itr->name.GetString(), m_itr->name.GetStringLength()), - m_itr->value); - } - - /// Returns a proxy for the value of the current element - DerefProxy> operator->() const - { - return DerefProxy>(**this); - } - - /** - * @brief Compare this iterator with another iterator. - * - * Note that this directly compares the iterators, not the underlying - * values, and assumes that two identical iterators will point to the same - * underlying object. - * - * @param other Iterator to compare with - * - * @returns true if the underlying iterators are equal, false otherwise - */ - bool operator==(const GenericRapidJsonObjectMemberIterator &other) const - { - return m_itr == other.m_itr; - } - - bool operator!=(const GenericRapidJsonObjectMemberIterator &other) const - { - return m_itr != other.m_itr; - } - - GenericRapidJsonObjectMemberIterator& operator++() - { - m_itr++; - return *this; - } - - GenericRapidJsonObjectMemberIterator operator++(int) - { - GenericRapidJsonObjectMemberIterator iterator_pre(m_itr); - ++(*this); - return iterator_pre; - } - - GenericRapidJsonObjectMemberIterator& operator--() - { - m_itr--; - return *this; - } - - std::ptrdiff_t difference(const GenericRapidJsonObjectMemberIterator &other) - { - return std::distance(m_itr, other.itr); - } - -private: - - /// Iternal copy of the original RapidJson iterator - typename ValueType::ConstMemberIterator m_itr; -}; - -template -inline bool GenericRapidJsonFrozenValue::equalTo(const Adapter &other, bool strict) const -{ - return GenericRapidJsonAdapter(m_value).equalTo(other, strict); -} - -template -inline typename GenericRapidJsonArray::iterator GenericRapidJsonArray::begin() const -{ - return m_value.Begin(); -} - -template -inline typename GenericRapidJsonArray::iterator GenericRapidJsonArray::end() const -{ - return m_value.End(); -} - -template -inline typename GenericRapidJsonObject::iterator GenericRapidJsonObject::begin() const -{ - return m_value.MemberBegin(); -} - -template -inline typename GenericRapidJsonObject::iterator GenericRapidJsonObject::end() const -{ - return m_value.MemberEnd(); -} - -template -inline typename GenericRapidJsonObject::iterator - GenericRapidJsonObject::find(const std::string &propertyName) const -{ - // Hack to support older versions of rapidjson where pointers are used as - // the built in iterator type. In those versions, the FindMember function - // would return a null pointer when the requested member could not be - // found. After calling FindMember on an empty object, we compare the - // result against what we would expect if a non-null-pointer iterator was - // returned. - const ValueType empty(rapidjson::kObjectType); - const typename ValueType::ConstMemberIterator maybeEnd = empty.FindMember(""); - if (maybeEnd != empty.MemberBegin() + 1) { - // In addition to the pointer-based iterator issue, RapidJson's internal - // string comparison code seemed to rely on the query string being - // initialised to a length greater than or equal to that of the - // properties being compared. We get around this by implementing our - // own linear scan. - const size_t propertyNameLength = propertyName.length(); - for (typename ValueType::ConstMemberIterator itr = m_value.MemberBegin(); itr != m_value.MemberEnd(); ++itr) { - const size_t memberNameLength = itr->name.GetStringLength(); - if (memberNameLength == propertyNameLength && - strncmp(itr->name.GetString(), propertyName.c_str(), itr->name.GetStringLength()) == 0) { - return itr; - } - } - - return m_value.MemberEnd(); - } - - return m_value.FindMember(propertyName.c_str()); // Times are good. -} - -typedef GenericRapidJsonAdapter<> RapidJsonAdapter; -typedef GenericRapidJsonArray<> RapidJsonArray; -typedef GenericRapidJsonArrayValueIterator<> RapidJsonArrayValue; -typedef GenericRapidJsonFrozenValue<> RapidJsonFrozenValue; -typedef GenericRapidJsonObject<> RapidJsonObject; -typedef GenericRapidJsonObjectMember<> RapidJsonObjectMember; -typedef GenericRapidJsonObjectMemberIterator<> RapidJsonObjectMemberIterator; -typedef GenericRapidJsonValue<> RapidJsonValue; - -/** - * @brief Specialisation of the AdapterTraits template struct for a - * RapidJsonAdapter that uses a pool allocator - */ -template<> -struct AdapterTraits -{ - typedef rapidjson::Document DocumentType; - - static std::string adapterName() - { - return "RapidJsonAdapter"; - } -}; - -typedef rapidjson::GenericValue, rapidjson::CrtAllocator> RapidJsonCrt; - -/** - * @brief Specialisation of the AdapterTraits template struct for a - * RapidJsonAdapter that uses the default CRT allocator - */ -template<> -struct AdapterTraits> -{ - typedef rapidjson::GenericDocument, rapidjson::CrtAllocator> DocumentType; - - static std::string adapterName() - { - return "GenericRapidJsonAdapter (using CrtAllocator)"; - } -}; - -} // namespace adapters -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/adapters/std_string_adapter.hpp b/subprojects/valijson/include/valijson/adapters/std_string_adapter.hpp deleted file mode 100644 index 2084024f2..000000000 --- a/subprojects/valijson/include/valijson/adapters/std_string_adapter.hpp +++ /dev/null @@ -1,491 +0,0 @@ -/** - * @file - * - * @brief Adapter implementation that wraps a single std::string value - * - * This allows property names to be validated against a schema as though they are a generic JSON - * value, while allowing the rest of Valijson's API to expose property names as plain std::string - * values. - * - * This was added while implementing draft 7 support. This included support for a constraint - * called propertyNames, which can be used to ensure that the property names in an object - * validate against a subschema. - */ - -#pragma once - -#include - -#include -#include -#include -#include - -namespace valijson { -namespace adapters { - -class StdStringAdapter; -class StdStringArrayValueIterator; -class StdStringObjectMemberIterator; - -typedef std::pair StdStringObjectMember; - -class StdStringArray -{ -public: - typedef StdStringArrayValueIterator const_iterator; - typedef StdStringArrayValueIterator iterator; - - StdStringArray() = default; - - StdStringArrayValueIterator begin() const; - - StdStringArrayValueIterator end() const; - - static size_t size() - { - return 0; - } -}; - -class StdStringObject -{ -public: - typedef StdStringObjectMemberIterator const_iterator; - typedef StdStringObjectMemberIterator iterator; - - StdStringObject() = default; - - StdStringObjectMemberIterator begin() const; - - StdStringObjectMemberIterator end() const; - - StdStringObjectMemberIterator find(const std::string &propertyName) const; - - static size_t size() - { - return 0; - } -}; - -class StdStringFrozenValue: public FrozenValue -{ -public: - explicit StdStringFrozenValue(std::string source) - : value(std::move(source)) { } - - FrozenValue * clone() const override - { - return new StdStringFrozenValue(value); - } - - bool equalTo(const Adapter &other, bool strict) const override; - -private: - std::string value; -}; - -class StdStringAdapter: public Adapter -{ -public: - typedef StdStringArray Array; - typedef StdStringObject Object; - typedef StdStringObjectMember ObjectMember; - - explicit StdStringAdapter(const std::string &value) - : m_value(value) { } - - bool applyToArray(ArrayValueCallback) const override - { - return maybeArray(); - } - - bool applyToObject(ObjectMemberCallback) const override - { - return maybeObject(); - } - - StdStringArray asArray() const - { - if (maybeArray()) { - return {}; - } - - throwRuntimeError("String value cannot be cast to array"); - } - - bool asBool() const override - { - return true; - } - - bool asBool(bool &result) const override - { - result = true; - return true; - } - - double asDouble() const override - { - return 0; - } - - bool asDouble(double &result) const override - { - result = 0; - return true; - } - - int64_t asInteger() const override - { - return 0; - } - - bool asInteger(int64_t &result) const override - { - result = 0; - return true; - }; - - StdStringObject asObject() const - { - if (maybeObject()) { - return {}; - } - - throwRuntimeError("String value cannot be cast to object"); - } - - std::string asString() const override - { - return m_value; - } - - bool asString(std::string &result) const override - { - result = m_value; - return true; - } - - bool equalTo(const Adapter &other, bool strict) const override - { - if (strict && !other.isString()) { - return false; - } - - return m_value == other.asString(); - } - - FrozenValue* freeze() const override - { - return new StdStringFrozenValue(m_value); - } - - static StdStringArray getArray() - { - throwNotSupported(); - } - - size_t getArraySize() const override - { - throwNotSupported(); - } - - bool getArraySize(size_t &) const override - { - throwNotSupported(); - } - - bool getBool() const override - { - throwNotSupported(); - } - - bool getBool(bool &) const override - { - throwNotSupported(); - } - - double getDouble() const override - { - throwNotSupported(); - } - - bool getDouble(double &) const override - { - throwNotSupported(); - } - - int64_t getInteger() const override - { - throwNotSupported(); - } - - bool getInteger(int64_t &) const override - { - throwNotSupported(); - } - - double getNumber() const override - { - throwNotSupported(); - } - - bool getNumber(double &) const override - { - throwNotSupported(); - } - - size_t getObjectSize() const override - { - throwNotSupported(); - } - - bool getObjectSize(size_t &) const override - { - throwNotSupported(); - } - - std::string getString() const override - { - return m_value; - } - - bool getString(std::string &result) const override - { - result = m_value; - return true; - } - - bool hasStrictTypes() const override - { - return true; - } - - bool isArray() const override - { - return false; - } - - bool isBool() const override - { - return false; - } - - bool isDouble() const override - { - return false; - } - - bool isInteger() const override - { - return false; - } - - bool isNull() const override - { - return false; - } - - bool isNumber() const override - { - return false; - } - - bool isObject() const override - { - return false; - } - - bool isString() const override - { - return true; - } - - bool maybeArray() const override - { - return false; - } - - bool maybeBool() const override - { - return m_value == "true" || m_value == "false"; - } - - bool maybeDouble() const override - { - const char *b = m_value.c_str(); - char *e = nullptr; - strtod(b, &e); - return e != b && e == b + m_value.length(); - } - - bool maybeInteger() const override - { - std::istringstream i(m_value); - int64_t x; - char c; - if (!(i >> x) || i.get(c)) { - return false; - } - - return true; - } - - bool maybeNull() const override - { - return m_value.empty(); - } - - bool maybeObject() const override - { - return m_value.empty(); - } - - bool maybeString() const override - { - return true; - } - -private: - const std::string &m_value; -}; - -class StdStringArrayValueIterator -{ -public: - using iterator_category = std::bidirectional_iterator_tag; - using value_type = StdStringAdapter; - using difference_type = StdStringAdapter; - using pointer = StdStringAdapter*; - using reference = StdStringAdapter&; - - StdStringAdapter operator*() const - { - throwNotSupported(); - } - - DerefProxy operator->() const - { - throwNotSupported(); - } - - bool operator==(const StdStringArrayValueIterator &) const - { - return true; - } - - bool operator!=(const StdStringArrayValueIterator &) const - { - return false; - } - - const StdStringArrayValueIterator& operator++() - { - throwNotSupported(); - } - - StdStringArrayValueIterator operator++(int) - { - throwNotSupported(); - } - - const StdStringArrayValueIterator& operator--() - { - throwNotSupported(); - } - - void advance(std::ptrdiff_t) - { - throwNotSupported(); - } -}; - -inline StdStringArrayValueIterator StdStringArray::begin() const -{ - return {}; -} - -inline StdStringArrayValueIterator StdStringArray::end() const -{ - return {}; -} - -class StdStringObjectMemberIterator -{ -public: - using iterator_category = std::bidirectional_iterator_tag; - using value_type = StdStringObjectMember; - using difference_type = StdStringObjectMember; - using pointer = StdStringObjectMember*; - using reference = StdStringObjectMember&; - - StdStringObjectMember operator*() const - { - throwNotSupported(); - } - - DerefProxy operator->() const - { - throwNotSupported(); - } - - bool operator==(const StdStringObjectMemberIterator &) const - { - return true; - } - - bool operator!=(const StdStringObjectMemberIterator &) const - { - return false; - } - - const StdStringObjectMemberIterator& operator++() - { - throwNotSupported(); - } - - StdStringObjectMemberIterator operator++(int) - { - throwNotSupported(); - } - - const StdStringObjectMemberIterator& operator--() - { - throwNotSupported(); - } -}; - -inline StdStringObjectMemberIterator StdStringObject::begin() const -{ - return {}; -} - -inline StdStringObjectMemberIterator StdStringObject::end() const -{ - return {}; -} - -inline StdStringObjectMemberIterator StdStringObject::find(const std::string &) const -{ - return {}; -} - -template<> -struct AdapterTraits -{ - typedef std::string DocumentType; - - static std::string adapterName() - { - return "StdStringAdapter"; - } -}; - -inline bool StdStringFrozenValue::equalTo(const Adapter &other, bool strict) const -{ - return StdStringAdapter(value).equalTo(other, strict); -} - -} // namespace adapters -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/constraint_builder.hpp b/subprojects/valijson/include/valijson/constraint_builder.hpp deleted file mode 100644 index 53407a95e..000000000 --- a/subprojects/valijson/include/valijson/constraint_builder.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -namespace valijson { - -namespace adapters { - class Adapter; -} - -namespace constraints { - struct Constraint; -} - -class ConstraintBuilder -{ -public: - virtual ~ConstraintBuilder() = default; - - virtual constraints::Constraint * make(const adapters::Adapter &) const = 0; -}; - -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/constraints/basic_constraint.hpp b/subprojects/valijson/include/valijson/constraints/basic_constraint.hpp deleted file mode 100644 index fd149a0db..000000000 --- a/subprojects/valijson/include/valijson/constraints/basic_constraint.hpp +++ /dev/null @@ -1,55 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace valijson { -namespace constraints { - -/** - * @brief Template class that implements the accept() and clone() functions of the Constraint interface. - * - * @tparam ConstraintType name of the concrete constraint type, which must provide a copy constructor. - */ -template -struct BasicConstraint: Constraint -{ - typedef internal::CustomAllocator Allocator; - - typedef std::basic_string, internal::CustomAllocator> String; - - BasicConstraint() - : m_allocator() { } - - BasicConstraint(Allocator::CustomAlloc allocFn, Allocator::CustomFree freeFn) - : m_allocator(allocFn, freeFn) { } - - BasicConstraint(const BasicConstraint &other) - : m_allocator(other.m_allocator) { } - - ~BasicConstraint() override = default; - - bool accept(ConstraintVisitor &visitor) const override - { - return visitor.visit(*static_cast(this)); - } - - Constraint * clone(CustomAlloc allocFn, CustomFree) const override - { - void *ptr = allocFn(sizeof(ConstraintType)); - if (!ptr) { - throwRuntimeError("Failed to allocate memory for cloned constraint"); - } - - return new (ptr) ConstraintType(*static_cast(this)); - } - -protected: - - Allocator m_allocator; -}; - -} // namespace constraints -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/constraints/concrete_constraints.hpp b/subprojects/valijson/include/valijson/constraints/concrete_constraints.hpp deleted file mode 100644 index 55cc1248a..000000000 --- a/subprojects/valijson/include/valijson/constraints/concrete_constraints.hpp +++ /dev/null @@ -1,1247 +0,0 @@ -/** - * @file - * - * @brief Class definitions to support JSON Schema constraints - * - * This file contains class definitions for all of the constraints required to - * support JSON Schema. These classes all inherit from the BasicConstraint - * template class, which implements the common parts of the Constraint - * interface. - * - * @see BasicConstraint - * @see Constraint - */ - -#pragma once - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#ifdef _MSC_VER -#pragma warning( push ) -#pragma warning( disable : 4702 ) -#endif - -namespace valijson { - -class ValidationResults; - -namespace constraints { - -/** - * @brief Represents an 'allOf' constraint. - * - * An allOf constraint provides a collection of sub-schemas that a value must - * validate against. If a value fails to validate against any of these sub- - * schemas, then validation fails. - */ -class AllOfConstraint: public BasicConstraint -{ -public: - AllOfConstraint() - : m_subschemas(Allocator::rebind::other(m_allocator)) { } - - AllOfConstraint(CustomAlloc allocFn, CustomFree freeFn) - : BasicConstraint(allocFn, freeFn), - m_subschemas(Allocator::rebind::other(m_allocator)) { } - - void addSubschema(const Subschema *subschema) - { - m_subschemas.push_back(subschema); - } - - template - void applyToSubschemas(const FunctorType &fn) const - { - unsigned int index = 0; - for (const Subschema *subschema : m_subschemas) { - if (!fn(index, subschema)) { - return; - } - - index++; - } - } - -private: - typedef std::vector> Subschemas; - - /// Collection of sub-schemas, all of which must be satisfied - Subschemas m_subschemas; -}; - -/** - * @brief Represents an 'anyOf' constraint - * - * An anyOf constraint provides a collection of sub-schemas that a value can - * validate against. If a value validates against one of these sub-schemas, - * then the validation passes. - */ -class AnyOfConstraint: public BasicConstraint -{ -public: - AnyOfConstraint() - : m_subschemas(Allocator::rebind::other(m_allocator)) { } - - AnyOfConstraint(CustomAlloc allocFn, CustomFree freeFn) - : BasicConstraint(allocFn, freeFn), - m_subschemas(Allocator::rebind::other(m_allocator)) { } - - void addSubschema(const Subschema *subschema) - { - m_subschemas.push_back(subschema); - } - - template - void applyToSubschemas(const FunctorType &fn) const - { - unsigned int index = 0; - for (const Subschema *subschema : m_subschemas) { - if (!fn(index, subschema)) { - return; - } - - index++; - } - } - -private: - typedef std::vector> Subschemas; - - /// Collection of sub-schemas, at least one of which must be satisfied - Subschemas m_subschemas; -}; - -/** - * @brief Represents a combination 'if', 'then' and 'else' constraints - * - * The schema provided by an 'if' constraint is used as the expression for a conditional. When the - * target validates against that schema, the 'then' subschema will be also be tested. Otherwise, - * the 'else' subschema will be tested. - */ -class ConditionalConstraint: public BasicConstraint -{ -public: - ConditionalConstraint() - : m_ifSubschema(nullptr), - m_thenSubschema(nullptr), - m_elseSubschema(nullptr) { } - - ConditionalConstraint(CustomAlloc allocFn, CustomFree freeFn) - : BasicConstraint(allocFn, freeFn), - m_ifSubschema(nullptr), - m_thenSubschema(nullptr), - m_elseSubschema(nullptr) { } - - const Subschema * getIfSubschema() const - { - return m_ifSubschema; - } - - const Subschema * getThenSubschema() const - { - return m_thenSubschema; - } - - const Subschema * getElseSubschema() const - { - return m_elseSubschema; - } - - void setIfSubschema(const Subschema *subschema) - { - m_ifSubschema = subschema; - } - - void setThenSubschema(const Subschema *subschema) - { - m_thenSubschema = subschema; - } - - void setElseSubschema(const Subschema *subschema) - { - m_elseSubschema = subschema; - } - -private: - const Subschema *m_ifSubschema; - const Subschema *m_thenSubschema; - const Subschema *m_elseSubschema; -}; - -class ConstConstraint: public BasicConstraint -{ -public: - ConstConstraint() - : m_value(nullptr) { } - - ConstConstraint(CustomAlloc allocFn, CustomFree freeFn) - : BasicConstraint(allocFn, freeFn), - m_value(nullptr) { } - - ConstConstraint(const ConstConstraint &other) - : BasicConstraint(other), - m_value(other.m_value->clone()) { } - - adapters::FrozenValue * getValue() const - { - return m_value.get(); - } - - void setValue(const adapters::Adapter &value) - { - m_value = std::unique_ptr(value.freeze()); - } - -private: - std::unique_ptr m_value; -}; - -/** - * @brief Represents a 'contains' constraint - * - * A 'contains' constraint specifies a schema that must be satisfied by at least one - * of the values in an array. - */ -class ContainsConstraint: public BasicConstraint -{ -public: - ContainsConstraint() - : m_subschema(nullptr) { } - - ContainsConstraint(CustomAlloc allocFn, CustomFree freeFn) - : BasicConstraint(allocFn, freeFn), - m_subschema(nullptr) { } - - const Subschema * getSubschema() const - { - return m_subschema; - } - - void setSubschema(const Subschema *subschema) - { - m_subschema = subschema; - } - -private: - const Subschema *m_subschema; -}; - -/** - * @brief Represents a 'dependencies' constraint. - * - * A dependency constraint ensures that a given property is valid only if the - * properties that it depends on are present. - */ -class DependenciesConstraint: public BasicConstraint -{ -public: - DependenciesConstraint() - : m_propertyDependencies(std::less(), m_allocator), - m_schemaDependencies(std::less(), m_allocator) - { } - - DependenciesConstraint(CustomAlloc allocFn, CustomFree freeFn) - : BasicConstraint(allocFn, freeFn), - m_propertyDependencies(std::less(), m_allocator), - m_schemaDependencies(std::less(), m_allocator) - { } - - template - DependenciesConstraint & addPropertyDependency( - const StringType &propertyName, - const StringType &dependencyName) - { - const String key(propertyName.c_str(), m_allocator); - auto itr = m_propertyDependencies.find(key); - if (itr == m_propertyDependencies.end()) { - itr = m_propertyDependencies.insert(PropertyDependencies::value_type( - key, PropertySet(std::less(), m_allocator))).first; - } - - itr->second.insert(String(dependencyName.c_str(), m_allocator)); - - return *this; - } - - template - DependenciesConstraint & addPropertyDependencies( - const StringType &propertyName, - const ContainerType &dependencyNames) - { - const String key(propertyName.c_str(), m_allocator); - auto itr = m_propertyDependencies.find(key); - if (itr == m_propertyDependencies.end()) { - itr = m_propertyDependencies.insert(PropertyDependencies::value_type( - key, PropertySet(std::less(), m_allocator))).first; - } - - typedef typename ContainerType::value_type ValueType; - for (const ValueType &dependencyName : dependencyNames) { - itr->second.insert(String(dependencyName.c_str(), m_allocator)); - } - - return *this; - } - - template - DependenciesConstraint & addSchemaDependency(const StringType &propertyName, const Subschema *schemaDependency) - { - if (m_schemaDependencies.insert(SchemaDependencies::value_type( - String(propertyName.c_str(), m_allocator), - schemaDependency)).second) { - return *this; - } - - throwRuntimeError("Dependencies constraint already contains a dependent " - "schema for the property '" + propertyName + "'"); - } - - template - void applyToPropertyDependencies(const FunctorType &fn) const - { - for (const PropertyDependencies::value_type &v : m_propertyDependencies) { - if (!fn(v.first, v.second)) { - return; - } - } - } - - template - void applyToSchemaDependencies(const FunctorType &fn) const - { - for (const SchemaDependencies::value_type &v : m_schemaDependencies) { - if (!fn(v.first, v.second)) { - return; - } - } - } - -private: - typedef std::set, internal::CustomAllocator> PropertySet; - - typedef std::map, - internal::CustomAllocator>> PropertyDependencies; - - typedef std::map, - internal::CustomAllocator>> SchemaDependencies; - - /// Mapping from property names to their property-based dependencies - PropertyDependencies m_propertyDependencies; - - /// Mapping from property names to their schema-based dependencies - SchemaDependencies m_schemaDependencies; -}; - -/** - * @brief Represents an 'enum' constraint - * - * An enum constraint provides a collection of permissible values for a JSON - * node. The node will only validate against this constraint if it matches one - * or more of the values in the collection. - */ -class EnumConstraint: public BasicConstraint -{ -public: - EnumConstraint() - : m_enumValues(Allocator::rebind::other(m_allocator)) { } - - EnumConstraint(CustomAlloc allocFn, CustomFree freeFn) - : BasicConstraint(allocFn, freeFn), - m_enumValues(Allocator::rebind::other(m_allocator)) { } - - EnumConstraint(const EnumConstraint &other) - : BasicConstraint(other), - m_enumValues(Allocator::rebind::other(m_allocator)) - { -#if VALIJSON_USE_EXCEPTIONS - try { -#endif - // Clone individual enum values - for (const EnumValue *otherValue : other.m_enumValues) { - const EnumValue *value = otherValue->clone(); -#if VALIJSON_USE_EXCEPTIONS - try { -#endif - m_enumValues.push_back(value); -#if VALIJSON_USE_EXCEPTIONS - } catch (...) { - delete value; - value = nullptr; - throw; - } - } - } catch (...) { - // Delete values already added to constraint - for (const EnumValue *value : m_enumValues) { - delete value; - } - throw; -#endif - } - } - - ~EnumConstraint() override - { - for (const EnumValue *value : m_enumValues) { - delete value; - } - } - - void addValue(const adapters::Adapter &value) - { - // TODO: Freeze value using custom alloc/free functions - m_enumValues.push_back(value.freeze()); - } - - void addValue(const adapters::FrozenValue &value) - { - // TODO: Clone using custom alloc/free functions - m_enumValues.push_back(value.clone()); - } - - template - void applyToValues(const FunctorType &fn) const - { - for (const EnumValue *value : m_enumValues) { - if (!fn(*value)) { - return; - } - } - } - -private: - typedef adapters::FrozenValue EnumValue; - - typedef std::vector> EnumValues; - - EnumValues m_enumValues; -}; - -/** - * @brief Represents non-singular 'items' and 'additionalItems' constraints - * - * Unlike the SingularItemsConstraint class, this class represents an 'items' - * constraint that specifies an array of sub-schemas, which should be used to - * validate each item in an array, in sequence. It also represents an optional - * 'additionalItems' sub-schema that should be used when an array contains - * more values than there are sub-schemas in the 'items' constraint. - * - * The prefix 'Linear' comes from the fact that this class contains a list of - * sub-schemas that corresponding array items must be validated against, and - * this validation is performed linearly (i.e. in sequence). - */ -class LinearItemsConstraint: public BasicConstraint -{ -public: - LinearItemsConstraint() - : m_itemSubschemas(Allocator::rebind::other(m_allocator)), - m_additionalItemsSubschema(nullptr) { } - - LinearItemsConstraint(CustomAlloc allocFn, CustomFree freeFn) - : BasicConstraint(allocFn, freeFn), - m_itemSubschemas(Allocator::rebind::other(m_allocator)), - m_additionalItemsSubschema(nullptr) { } - - void addItemSubschema(const Subschema *subschema) - { - m_itemSubschemas.push_back(subschema); - } - - template - void applyToItemSubschemas(const FunctorType &fn) const - { - unsigned int index = 0; - for (const Subschema *subschema : m_itemSubschemas) { - if (!fn(index, subschema)) { - return; - } - - index++; - } - } - - const Subschema * getAdditionalItemsSubschema() const - { - return m_additionalItemsSubschema; - } - - size_t getItemSubschemaCount() const - { - return m_itemSubschemas.size(); - } - - void setAdditionalItemsSubschema(const Subschema *subschema) - { - m_additionalItemsSubschema = subschema; - } - -private: - typedef std::vector> Subschemas; - - Subschemas m_itemSubschemas; - - const Subschema* m_additionalItemsSubschema; -}; - -/** - * @brief Represents 'maximum' and 'exclusiveMaximum' constraints - */ -class MaximumConstraint: public BasicConstraint -{ -public: - MaximumConstraint() - : m_maximum(std::numeric_limits::infinity()), - m_exclusiveMaximum(false) { } - - MaximumConstraint(CustomAlloc allocFn, CustomFree freeFn) - : BasicConstraint(allocFn, freeFn), - m_maximum(std::numeric_limits::infinity()), - m_exclusiveMaximum(false) { } - - bool getExclusiveMaximum() const - { - return m_exclusiveMaximum; - } - - void setExclusiveMaximum(bool newExclusiveMaximum) - { - m_exclusiveMaximum = newExclusiveMaximum; - } - - double getMaximum() const - { - return m_maximum; - } - - void setMaximum(double newMaximum) - { - m_maximum = newMaximum; - } - -private: - double m_maximum; - bool m_exclusiveMaximum; -}; - -/** - * @brief Represents a 'maxItems' constraint - */ -class MaxItemsConstraint: public BasicConstraint -{ -public: - MaxItemsConstraint() - : m_maxItems(std::numeric_limits::max()) { } - - MaxItemsConstraint(CustomAlloc allocFn, CustomFree freeFn) - : BasicConstraint(allocFn, freeFn), - m_maxItems(std::numeric_limits::max()) { } - - uint64_t getMaxItems() const - { - return m_maxItems; - } - - void setMaxItems(uint64_t newMaxItems) - { - m_maxItems = newMaxItems; - } - -private: - uint64_t m_maxItems; -}; - -/** - * @brief Represents a 'maxLength' constraint - */ -class MaxLengthConstraint: public BasicConstraint -{ -public: - MaxLengthConstraint() - : m_maxLength(std::numeric_limits::max()) { } - - MaxLengthConstraint(CustomAlloc allocFn, CustomFree freeFn) - : BasicConstraint(allocFn, freeFn), - m_maxLength(std::numeric_limits::max()) { } - - uint64_t getMaxLength() const - { - return m_maxLength; - } - - void setMaxLength(uint64_t newMaxLength) - { - m_maxLength = newMaxLength; - } - -private: - uint64_t m_maxLength; -}; - -/** - * @brief Represents a 'maxProperties' constraint - */ -class MaxPropertiesConstraint: public BasicConstraint -{ -public: - MaxPropertiesConstraint() - : m_maxProperties(std::numeric_limits::max()) { } - - MaxPropertiesConstraint(CustomAlloc allocFn, CustomFree freeFn) - : BasicConstraint(allocFn, freeFn), - m_maxProperties(std::numeric_limits::max()) { } - - uint64_t getMaxProperties() const - { - return m_maxProperties; - } - - void setMaxProperties(uint64_t newMaxProperties) - { - m_maxProperties = newMaxProperties; - } - -private: - uint64_t m_maxProperties; -}; - -/** - * @brief Represents 'minimum' and 'exclusiveMinimum' constraints - */ -class MinimumConstraint: public BasicConstraint -{ -public: - MinimumConstraint() - : m_minimum(-std::numeric_limits::infinity()), - m_exclusiveMinimum(false) { } - - MinimumConstraint(CustomAlloc allocFn, CustomFree freeFn) - : BasicConstraint(allocFn, freeFn), - m_minimum(-std::numeric_limits::infinity()), - m_exclusiveMinimum(false) { } - - bool getExclusiveMinimum() const - { - return m_exclusiveMinimum; - } - - void setExclusiveMinimum(bool newExclusiveMinimum) - { - m_exclusiveMinimum = newExclusiveMinimum; - } - - double getMinimum() const - { - return m_minimum; - } - - void setMinimum(double newMinimum) - { - m_minimum = newMinimum; - } - -private: - double m_minimum; - bool m_exclusiveMinimum; -}; - -/** - * @brief Represents a 'minItems' constraint - */ -class MinItemsConstraint: public BasicConstraint -{ -public: - MinItemsConstraint() - : m_minItems(0) { } - - MinItemsConstraint(CustomAlloc allocFn, CustomFree freeFn) - : BasicConstraint(allocFn, freeFn), - m_minItems(0) { } - - uint64_t getMinItems() const - { - return m_minItems; - } - - void setMinItems(uint64_t newMinItems) - { - m_minItems = newMinItems; - } - -private: - uint64_t m_minItems; -}; - -/** - * @brief Represents a 'minLength' constraint - */ -class MinLengthConstraint: public BasicConstraint -{ -public: - MinLengthConstraint() - : m_minLength(0) { } - - MinLengthConstraint(CustomAlloc allocFn, CustomFree freeFn) - : BasicConstraint(allocFn, freeFn), - m_minLength(0) { } - - uint64_t getMinLength() const - { - return m_minLength; - } - - void setMinLength(uint64_t newMinLength) - { - m_minLength = newMinLength; - } - -private: - uint64_t m_minLength; -}; - -/** - * @brief Represents a 'minProperties' constraint - */ -class MinPropertiesConstraint: public BasicConstraint -{ -public: - MinPropertiesConstraint() - : m_minProperties(0) { } - - MinPropertiesConstraint(CustomAlloc allocFn, CustomFree freeFn) - : BasicConstraint(allocFn, freeFn), - m_minProperties(0) { } - - uint64_t getMinProperties() const - { - return m_minProperties; - } - - void setMinProperties(uint64_t newMinProperties) - { - m_minProperties = newMinProperties; - } - -private: - uint64_t m_minProperties; -}; - -/** - * @brief Represents either 'multipleOf' or 'divisibleBy' constraints where - * the divisor is a floating point number - */ -class MultipleOfDoubleConstraint: - public BasicConstraint -{ -public: - MultipleOfDoubleConstraint() - : m_value(1.) { } - - MultipleOfDoubleConstraint(CustomAlloc allocFn, CustomFree freeFn) - : BasicConstraint(allocFn, freeFn), - m_value(1.) { } - - double getDivisor() const - { - return m_value; - } - - void setDivisor(double newValue) - { - m_value = newValue; - } - -private: - double m_value; -}; - -/** - * @brief Represents either 'multipleOf' or 'divisibleBy' constraints where - * the divisor is of integer type - */ -class MultipleOfIntConstraint: - public BasicConstraint -{ -public: - MultipleOfIntConstraint() - : m_value(1) { } - - MultipleOfIntConstraint(CustomAlloc allocFn, CustomFree freeFn) - : BasicConstraint(allocFn, freeFn), - m_value(1) { } - - int64_t getDivisor() const - { - return m_value; - } - - void setDivisor(int64_t newValue) - { - m_value = newValue; - } - -private: - int64_t m_value; -}; - -/** - * @brief Represents a 'not' constraint - */ -class NotConstraint: public BasicConstraint -{ -public: - NotConstraint() - : m_subschema(nullptr) { } - - NotConstraint(CustomAlloc allocFn, CustomFree freeFn) - : BasicConstraint(allocFn, freeFn), - m_subschema(nullptr) { } - - const Subschema * getSubschema() const - { - return m_subschema; - } - - void setSubschema(const Subschema *subschema) - { - m_subschema = subschema; - } - -private: - const Subschema *m_subschema; -}; - -/** - * @brief Represents a 'oneOf' constraint. - */ -class OneOfConstraint: public BasicConstraint -{ -public: - OneOfConstraint() - : m_subschemas(Allocator::rebind::other(m_allocator)) { } - - OneOfConstraint(CustomAlloc allocFn, CustomFree freeFn) - : BasicConstraint(allocFn, freeFn), - m_subschemas(Allocator::rebind::other(m_allocator)) { } - - void addSubschema(const Subschema *subschema) - { - m_subschemas.push_back(subschema); - } - - template - void applyToSubschemas(const FunctorType &fn) const - { - unsigned int index = 0; - for (const Subschema *subschema : m_subschemas) { - if (!fn(index, subschema)) { - return; - } - - index++; - } - } - -private: - typedef std::vector> Subschemas; - - /// Collection of sub-schemas, exactly one of which must be satisfied - Subschemas m_subschemas; -}; - -/** - * @brief Represents a 'pattern' constraint - */ -class PatternConstraint: public BasicConstraint -{ -public: - PatternConstraint() - : m_pattern(Allocator::rebind::other(m_allocator)) { } - - PatternConstraint(CustomAlloc allocFn, CustomFree freeFn) - : BasicConstraint(allocFn, freeFn), - m_pattern(Allocator::rebind::other(m_allocator)) { } - - template - bool getPattern(std::basic_string, AllocatorType> &result) const - { - result.assign(m_pattern.c_str()); - return true; - } - - template - std::basic_string, AllocatorType> getPattern( - const AllocatorType &alloc = AllocatorType()) const - { - return std::basic_string, AllocatorType>(m_pattern.c_str(), alloc); - } - - template - void setPattern(const std::basic_string, AllocatorType> &pattern) - { - m_pattern.assign(pattern.c_str()); - } - -private: - String m_pattern; -}; - -class PolyConstraint : public Constraint -{ -public: - bool accept(ConstraintVisitor &visitor) const override - { - return visitor.visit(*static_cast(this)); - } - - Constraint * clone(CustomAlloc allocFn, CustomFree freeFn) const override - { - void *ptr = allocFn(sizeOf()); - if (!ptr) { - throwRuntimeError("Failed to allocate memory for cloned constraint"); - } - -#if VALIJSON_USE_EXCEPTIONS - try { -#endif - return cloneInto(ptr); -#if VALIJSON_USE_EXCEPTIONS - } catch (...) { - freeFn(ptr); - throw; - } -#else - // pretend to use freeFn to avoid warning in GCC 8.3 - (void)freeFn; -#endif - } - - virtual bool validate(const adapters::Adapter &target, - const std::vector& context, - valijson::ValidationResults *results) const = 0; - -private: - virtual Constraint * cloneInto(void *) const = 0; - - virtual size_t sizeOf() const = 0; -}; - -/** - * @brief Represents a combination of 'properties', 'patternProperties' and - * 'additionalProperties' constraints - */ -class PropertiesConstraint: public BasicConstraint -{ -public: - PropertiesConstraint() - : m_properties(std::less(), m_allocator), - m_patternProperties(std::less(), m_allocator), - m_additionalProperties(nullptr) { } - - PropertiesConstraint(CustomAlloc allocFn, CustomFree freeFn) - : BasicConstraint(allocFn, freeFn), - m_properties(std::less(), m_allocator), - m_patternProperties(std::less(), m_allocator), - m_additionalProperties(nullptr) { } - - bool addPatternPropertySubschema(const char *patternProperty, const Subschema *subschema) - { - return m_patternProperties.insert(PropertySchemaMap::value_type( - String(patternProperty, m_allocator), subschema)).second; - } - - template - bool addPatternPropertySubschema(const std::basic_string, AllocatorType> &patternProperty, - const Subschema *subschema) - { - return addPatternPropertySubschema(patternProperty.c_str(), subschema); - } - - bool addPropertySubschema(const char *propertyName, - const Subschema *subschema) - { - return m_properties.insert(PropertySchemaMap::value_type( - String(propertyName, m_allocator), subschema)).second; - } - - template - bool addPropertySubschema(const std::basic_string, AllocatorType> &propertyName, - const Subschema *subschema) - { - return addPropertySubschema(propertyName.c_str(), subschema); - } - - template - void applyToPatternProperties(const FunctorType &fn) const - { - typedef typename PropertySchemaMap::value_type ValueType; - for (const ValueType &value : m_patternProperties) { - if (!fn(value.first, value.second)) { - return; - } - } - } - - template - void applyToProperties(const FunctorType &fn) const - { - typedef typename PropertySchemaMap::value_type ValueType; - for (const ValueType &value : m_properties) { - if (!fn(value.first, value.second)) { - return; - } - } - } - - const Subschema * getAdditionalPropertiesSubschema() const - { - return m_additionalProperties; - } - - void setAdditionalPropertiesSubschema(const Subschema *subschema) - { - m_additionalProperties = subschema; - } - -private: - typedef std::map< - String, - const Subschema *, - std::less, - internal::CustomAllocator> - > PropertySchemaMap; - - PropertySchemaMap m_properties; - PropertySchemaMap m_patternProperties; - - const Subschema *m_additionalProperties; -}; - -class PropertyNamesConstraint: public BasicConstraint -{ -public: - PropertyNamesConstraint() - : m_subschema(nullptr) { } - - PropertyNamesConstraint(CustomAlloc allocFn, CustomFree freeFn) - : BasicConstraint(allocFn, freeFn), - m_subschema(nullptr) { } - - const Subschema * getSubschema() const - { - return m_subschema; - } - - void setSubschema(const Subschema *subschema) - { - m_subschema = subschema; - } - -private: - const Subschema *m_subschema; -}; - -/** - * @brief Represents a 'required' constraint - */ -class RequiredConstraint: public BasicConstraint -{ -public: - RequiredConstraint() - : m_requiredProperties(std::less(), m_allocator) { } - - RequiredConstraint(CustomAlloc allocFn, CustomFree freeFn) - : BasicConstraint(allocFn, freeFn), - m_requiredProperties(std::less(), m_allocator) { } - - bool addRequiredProperty(const char *propertyName) - { - return m_requiredProperties.insert(String(propertyName, - Allocator::rebind::other(m_allocator))).second; - } - - template - bool addRequiredProperty(const std::basic_string, AllocatorType> &propertyName) - { - return addRequiredProperty(propertyName.c_str()); - } - - template - void applyToRequiredProperties(const FunctorType &fn) const - { - for (const String &propertyName : m_requiredProperties) { - if (!fn(propertyName)) { - return; - } - } - } - -private: - typedef std::set, - internal::CustomAllocator> RequiredProperties; - - RequiredProperties m_requiredProperties; -}; - -/** - * @brief Represents an 'items' constraint that specifies one sub-schema - * - * A value is considered valid against this constraint if it is an array, and - * each item in the array validates against the sub-schema specified by this - * constraint. - * - * The prefix 'Singular' comes from the fact that array items must validate - * against exactly one sub-schema. - */ -class SingularItemsConstraint: public BasicConstraint -{ -public: - SingularItemsConstraint() - : m_itemsSubschema(nullptr) { } - - SingularItemsConstraint(CustomAlloc allocFn, CustomFree freeFn) - : BasicConstraint(allocFn, freeFn), - m_itemsSubschema(nullptr) { } - - const Subschema * getItemsSubschema() const - { - return m_itemsSubschema; - } - - void setItemsSubschema(const Subschema *subschema) - { - m_itemsSubschema = subschema; - } - -private: - const Subschema *m_itemsSubschema; -}; - -/** - * @brief Represents a 'type' constraint. - */ -class TypeConstraint: public BasicConstraint -{ -public: - enum JsonType { - kAny, - kArray, - kBoolean, - kInteger, - kNull, - kNumber, - kObject, - kString - }; - - TypeConstraint() - : m_namedTypes(std::less(), m_allocator), - m_schemaTypes(Allocator::rebind::other(m_allocator)) { } - - TypeConstraint(CustomAlloc allocFn, CustomFree freeFn) - : BasicConstraint(allocFn, freeFn), - m_namedTypes(std::less(), m_allocator), - m_schemaTypes(Allocator::rebind::other(m_allocator)) { } - - void addNamedType(JsonType type) - { - m_namedTypes.insert(type); - } - - void addSchemaType(const Subschema *subschema) - { - m_schemaTypes.push_back(subschema); - } - - template - void applyToNamedTypes(const FunctorType &fn) const - { - for (const JsonType namedType : m_namedTypes) { - if (!fn(namedType)) { - return; - } - } - } - - template - void applyToSchemaTypes(const FunctorType &fn) const - { - unsigned int index = 0; - for (const Subschema *subschema : m_schemaTypes) { - if (!fn(index, subschema)) { - return; - } - - index++; - } - } - - template - static JsonType jsonTypeFromString(const std::basic_string, AllocatorType> &typeName) - { - if (typeName.compare("any") == 0) { - return kAny; - } else if (typeName.compare("array") == 0) { - return kArray; - } else if (typeName.compare("boolean") == 0) { - return kBoolean; - } else if (typeName.compare("integer") == 0) { - return kInteger; - } else if (typeName.compare("null") == 0) { - return kNull; - } else if (typeName.compare("number") == 0) { - return kNumber; - } else if (typeName.compare("object") == 0) { - return kObject; - } else if (typeName.compare("string") == 0) { - return kString; - } - - throwRuntimeError("Unrecognised JSON type name '" + - std::string(typeName.c_str()) + "'"); - abort(); - } - -private: - typedef std::set, internal::CustomAllocator> NamedTypes; - - typedef std::vector::other> SchemaTypes; - - /// Set of named JSON types that serve as valid types - NamedTypes m_namedTypes; - - /// Set of sub-schemas that serve as valid types - SchemaTypes m_schemaTypes; -}; - -/** - * @brief Represents a 'uniqueItems' constraint - */ -class UniqueItemsConstraint: public BasicConstraint -{ -public: - UniqueItemsConstraint() = default; - - UniqueItemsConstraint(CustomAlloc allocFn, CustomFree freeFn) - : BasicConstraint(allocFn, freeFn) { } -}; - -} // namespace constraints -} // namespace valijson - -#ifdef _MSC_VER -#pragma warning( pop ) -#endif diff --git a/subprojects/valijson/include/valijson/constraints/constraint.hpp b/subprojects/valijson/include/valijson/constraints/constraint.hpp deleted file mode 100644 index 03b6444cd..000000000 --- a/subprojects/valijson/include/valijson/constraints/constraint.hpp +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -namespace valijson { -namespace constraints { - -class ConstraintVisitor; - -/** - * @brief Interface that must be implemented by concrete constraint types. - * - * @todo Consider using something like the boost::cloneable concept here. - */ -struct Constraint -{ - /// Typedef for custom new-/malloc-like function - typedef void * (*CustomAlloc)(size_t size); - - /// Typedef for custom free-like function - typedef void (*CustomFree)(void *); - - /** - * @brief Virtual destructor. - */ - virtual ~Constraint() = default; - - /** - * @brief Perform an action on the constraint using the visitor pattern. - * - * Note that Constraints cannot be modified by visitors. - * - * @param visitor Reference to a ConstraintVisitor object. - * - * @returns the boolean value returned by one of the visitor's visit - * functions. - */ - virtual bool accept(ConstraintVisitor &visitor) const = 0; - - /** - * @brief Make a copy of a constraint. - * - * Note that this should be a deep copy of the constraint. - * - * @returns an owning-pointer to the new constraint. - */ - virtual Constraint * clone(CustomAlloc, CustomFree) const = 0; - -}; - -} // namespace constraints -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/constraints/constraint_visitor.hpp b/subprojects/valijson/include/valijson/constraints/constraint_visitor.hpp deleted file mode 100644 index da3f3d7cf..000000000 --- a/subprojects/valijson/include/valijson/constraints/constraint_visitor.hpp +++ /dev/null @@ -1,104 +0,0 @@ -#pragma once - -namespace valijson { -namespace constraints { - -class AllOfConstraint; -class AnyOfConstraint; -class ConditionalConstraint; -class ConstConstraint; -class ContainsConstraint; -class DependenciesConstraint; -class EnumConstraint; -class LinearItemsConstraint; -class MaxItemsConstraint; -class MaximumConstraint; -class MaxLengthConstraint; -class MaxPropertiesConstraint; -class MinItemsConstraint; -class MinimumConstraint; -class MinLengthConstraint; -class MinPropertiesConstraint; -class MultipleOfDoubleConstraint; -class MultipleOfIntConstraint; -class NotConstraint; -class OneOfConstraint; -class PatternConstraint; -class PolyConstraint; -class PropertiesConstraint; -class PropertyNamesConstraint; -class RequiredConstraint; -class SingularItemsConstraint; -class TypeConstraint; -class UniqueItemsConstraint; - -/// Interface to allow usage of the visitor pattern with Constraints -class ConstraintVisitor -{ -protected: - virtual ~ConstraintVisitor() = default; - - // Shorten type names for derived classes outside of this namespace - typedef constraints::AllOfConstraint AllOfConstraint; - typedef constraints::AnyOfConstraint AnyOfConstraint; - typedef constraints::ConditionalConstraint ConditionalConstraint; - typedef constraints::ConstConstraint ConstConstraint; - typedef constraints::ContainsConstraint ContainsConstraint; - typedef constraints::DependenciesConstraint DependenciesConstraint; - typedef constraints::EnumConstraint EnumConstraint; - typedef constraints::LinearItemsConstraint LinearItemsConstraint; - typedef constraints::MaximumConstraint MaximumConstraint; - typedef constraints::MaxItemsConstraint MaxItemsConstraint; - typedef constraints::MaxLengthConstraint MaxLengthConstraint; - typedef constraints::MaxPropertiesConstraint MaxPropertiesConstraint; - typedef constraints::MinimumConstraint MinimumConstraint; - typedef constraints::MinItemsConstraint MinItemsConstraint; - typedef constraints::MinLengthConstraint MinLengthConstraint; - typedef constraints::MinPropertiesConstraint MinPropertiesConstraint; - typedef constraints::MultipleOfDoubleConstraint MultipleOfDoubleConstraint; - typedef constraints::MultipleOfIntConstraint MultipleOfIntConstraint; - typedef constraints::NotConstraint NotConstraint; - typedef constraints::OneOfConstraint OneOfConstraint; - typedef constraints::PatternConstraint PatternConstraint; - typedef constraints::PolyConstraint PolyConstraint; - typedef constraints::PropertiesConstraint PropertiesConstraint; - typedef constraints::PropertyNamesConstraint PropertyNamesConstraint; - typedef constraints::RequiredConstraint RequiredConstraint; - typedef constraints::SingularItemsConstraint SingularItemsConstraint; - typedef constraints::TypeConstraint TypeConstraint; - typedef constraints::UniqueItemsConstraint UniqueItemsConstraint; - -public: - - virtual bool visit(const AllOfConstraint &) = 0; - virtual bool visit(const AnyOfConstraint &) = 0; - virtual bool visit(const ConditionalConstraint &) = 0; - virtual bool visit(const ConstConstraint &) = 0; - virtual bool visit(const ContainsConstraint &) = 0; - virtual bool visit(const DependenciesConstraint &) = 0; - virtual bool visit(const EnumConstraint &) = 0; - virtual bool visit(const LinearItemsConstraint &) = 0; - virtual bool visit(const MaximumConstraint &) = 0; - virtual bool visit(const MaxItemsConstraint &) = 0; - virtual bool visit(const MaxLengthConstraint &) = 0; - virtual bool visit(const MaxPropertiesConstraint &) = 0; - virtual bool visit(const MinimumConstraint &) = 0; - virtual bool visit(const MinItemsConstraint &) = 0; - virtual bool visit(const MinLengthConstraint &) = 0; - virtual bool visit(const MinPropertiesConstraint &) = 0; - virtual bool visit(const MultipleOfDoubleConstraint &) = 0; - virtual bool visit(const MultipleOfIntConstraint &) = 0; - virtual bool visit(const NotConstraint &) = 0; - virtual bool visit(const OneOfConstraint &) = 0; - virtual bool visit(const PatternConstraint &) = 0; - virtual bool visit(const PolyConstraint &) = 0; - virtual bool visit(const PropertiesConstraint &) = 0; - virtual bool visit(const PropertyNamesConstraint &) = 0; - virtual bool visit(const RequiredConstraint &) = 0; - virtual bool visit(const SingularItemsConstraint &) = 0; - virtual bool visit(const TypeConstraint &) = 0; - virtual bool visit(const UniqueItemsConstraint &) = 0; -}; - -} // namespace constraints -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/exceptions.hpp b/subprojects/valijson/include/valijson/exceptions.hpp deleted file mode 100644 index a4188259e..000000000 --- a/subprojects/valijson/include/valijson/exceptions.hpp +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once - -#include -#include - -namespace valijson { -#if defined(_MSC_VER) && _MSC_VER == 1800 -#define VALIJSON_NORETURN __declspec(noreturn) -#else -#define VALIJSON_NORETURN [[noreturn]] -#endif - -#if VALIJSON_USE_EXCEPTIONS -#include - -VALIJSON_NORETURN inline void throwRuntimeError(const std::string& msg) { - throw std::runtime_error(msg); -} - -VALIJSON_NORETURN inline void throwLogicError(const std::string& msg) { - throw std::logic_error(msg); -} -#else -VALIJSON_NORETURN inline void throwRuntimeError(const std::string& msg) { - std::cerr << msg << std::endl; - abort(); -} -VALIJSON_NORETURN inline void throwLogicError(const std::string& msg) { - std::cerr << msg << std::endl; - abort(); -} - -#endif - -VALIJSON_NORETURN inline void throwNotSupported() { - throwRuntimeError("Not supported"); \ -} - -} // namespace valijson - - diff --git a/subprojects/valijson/include/valijson/internal/custom_allocator.hpp b/subprojects/valijson/include/valijson/internal/custom_allocator.hpp deleted file mode 100644 index 07e1d6117..000000000 --- a/subprojects/valijson/include/valijson/internal/custom_allocator.hpp +++ /dev/null @@ -1,107 +0,0 @@ -#pragma once - -namespace valijson { -namespace internal { - -template -class CustomAllocator -{ -public: - /// Typedef for custom new-/malloc-like function - typedef void * (*CustomAlloc)(size_t size); - - /// Typedef for custom free-like function - typedef void (*CustomFree)(void *); - - // Standard allocator typedefs - typedef T value_type; - typedef T* pointer; - typedef const T* const_pointer; - typedef T& reference; - typedef const T& const_reference; - typedef std::size_t size_type; - typedef std::ptrdiff_t difference_type; - - template - struct rebind - { - typedef CustomAllocator other; - }; - - CustomAllocator() - : m_allocFn(::operator new), - m_freeFn(::operator delete) { } - - CustomAllocator(CustomAlloc allocFn, CustomFree freeFn) - : m_allocFn(allocFn), - m_freeFn(freeFn) { } - - CustomAllocator(const CustomAllocator &other) - : m_allocFn(other.m_allocFn), - m_freeFn(other.m_freeFn) { } - - template - CustomAllocator(CustomAllocator const &other) - : m_allocFn(other.m_allocFn), - m_freeFn(other.m_freeFn) { } - - CustomAllocator & operator=(const CustomAllocator &other) - { - m_allocFn = other.m_allocFn; - m_freeFn = other.m_freeFn; - - return *this; - } - - pointer address(reference r) - { - return &r; - } - - const_pointer address(const_reference r) - { - return &r; - } - - pointer allocate(size_type cnt, const void * = nullptr) - { - return reinterpret_cast(m_allocFn(cnt * sizeof(T))); - } - - void deallocate(pointer p, size_type) - { - m_freeFn(p); - } - - size_type max_size() const - { - return std::numeric_limits::max() / sizeof(T); - } - - void construct(pointer p, const T& t) - { - new(p) T(t); - } - - void destroy(pointer p) - { - p->~T(); - } - - bool operator==(const CustomAllocator &other) const - { - return other.m_allocFn == m_allocFn && other.m_freeFn == m_freeFn; - } - - bool operator!=(const CustomAllocator &other) const - { - return !operator==(other); - } - - CustomAlloc m_allocFn; - - CustomFree m_freeFn; -}; - -} // end namespace internal -} // end namespace valijson diff --git a/subprojects/valijson/include/valijson/internal/debug.hpp b/subprojects/valijson/include/valijson/internal/debug.hpp deleted file mode 100644 index 25c3dd770..000000000 --- a/subprojects/valijson/include/valijson/internal/debug.hpp +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include - -namespace valijson { -namespace internal { - -template -std::string nodeTypeAsString(const AdapterType &node) { - if (node.isArray()) { - return "array"; - } else if (node.isObject()) { - return "object"; - } else if (node.isString()) { - return "string"; - } else if (node.isNull()) { - return "null"; - } else if (node.isInteger()) { - return "integer"; - } else if (node.isDouble()) { - return "double"; - } else if (node.isBool()) { - return "bool"; - } - - return "unknown"; -} - -} // end namespace internal -} // end namespace valijson diff --git a/subprojects/valijson/include/valijson/internal/json_pointer.hpp b/subprojects/valijson/include/valijson/internal/json_pointer.hpp deleted file mode 100644 index b290c02a2..000000000 --- a/subprojects/valijson/include/valijson/internal/json_pointer.hpp +++ /dev/null @@ -1,275 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#ifdef _MSC_VER -#pragma warning( push ) -#pragma warning( disable : 4702 ) -#endif - -namespace valijson { -namespace internal { -namespace json_pointer { - -/** - * @brief Replace all occurrences of `search` with `replace`. Modifies `subject` in place. - * - * @param subject string to operate on - * @param search string to search - * @param replace replacement string - */ -inline void replaceAllInPlace(std::string& subject, const char* search, - const char* replace) -{ - size_t pos = 0; - - while((pos = subject.find(search, pos)) != std::string::npos) { - subject.replace(pos, strlen(search), replace); - pos += strlen(replace); - } -} - -/** - * @brief Return the char value corresponding to a 2-digit hexadecimal string - * - * @throws std::runtime_error for strings that are not exactly two characters - * in length and for strings that contain non-hexadecimal characters - * - * @return decoded char value corresponding to the hexadecimal string - */ -inline char decodePercentEncodedChar(const std::string &digits) -{ - if (digits.length() != 2) { - throwRuntimeError("Failed to decode %-encoded character '" + - digits + "' due to unexpected number of characters; " - "expected two characters"); - } - - errno = 0; - const char *begin = digits.c_str(); - char *end = nullptr; - const unsigned long value = strtoul(begin, &end, 16); - if (end != begin && *end != '\0') { - throwRuntimeError("Failed to decode %-encoded character '" + - digits + "'"); - } - - return char(value); -} - -/** - * @brief Extract and transform the token between two iterators - * - * This function is responsible for extracting a JSON Reference token from - * between two iterators, and performing any necessary transformations, before - * returning the resulting string. Its main purpose is to replace the escaped - * character sequences defined in the RFC-6901 (JSON Pointer), and to decode - * %-encoded character sequences defined in RFC-3986 (URI). - * - * The encoding used in RFC-3986 should be familiar to many developers, but - * the escaped character sequences used in JSON Pointers may be less so. From - * the JSON Pointer specification (RFC 6901, April 2013): - * - * Evaluation of each reference token begins by decoding any escaped - * character sequence. This is performed by first transforming any - * occurrence of the sequence '~1' to '/', and then transforming any - * occurrence of the sequence '~0' to '~'. By performing the - * substitutions in this order, an implementation avoids the error of - * turning '~01' first into '~1' and then into '/', which would be - * incorrect (the string '~01' correctly becomes '~1' after - * transformation). - * - * @param begin iterator pointing to beginning of a token - * @param end iterator pointing to one character past the end of the token - * - * @return string with escaped character sequences replaced - * - */ -inline std::string extractReferenceToken(std::string::const_iterator begin, - std::string::const_iterator end) -{ - std::string token(begin, end); - - // Replace JSON Pointer-specific escaped character sequences - replaceAllInPlace(token, "~1", "/"); - replaceAllInPlace(token, "~0", "~"); - - // Replace %-encoded character sequences with their actual characters - for (size_t n = token.find('%'); n != std::string::npos; - n = token.find('%', n + 1)) { - -#if VALIJSON_USE_EXCEPTIONS - try { -#endif - const char c = decodePercentEncodedChar(token.substr(n + 1, 2)); - token.replace(n, 3, &c, 1); -#if VALIJSON_USE_EXCEPTIONS - } catch (const std::runtime_error &e) { - throwRuntimeError( - std::string(e.what()) + "; in token: " + token); - } -#endif - } - - return token; -} - -/** - * @brief Recursively locate the value referenced by a JSON Pointer - * - * This function takes both a string reference and an iterator to the beginning - * of the substring that is being resolved. This iterator is expected to point - * to the beginning of a reference token, whose length will be determined by - * searching for the next delimiter ('/' or '\0'). A reference token must be - * at least one character in length to be considered valid. - * - * Once the next reference token has been identified, it will be used either as - * an array index or as an the name an object member. The validity of a - * reference token depends on the type of the node currently being traversed, - * and the applicability of the token to that node. For example, an array can - * only be dereferenced by a non-negative integral index. - * - * Once the next node has been identified, the length of the remaining portion - * of the JSON Pointer will be used to determine whether recursion should - * terminate. - * - * @param node current node in recursive evaluation of JSON Pointer - * @param jsonPointer string containing complete JSON Pointer - * @param jsonPointerItr string iterator pointing the beginning of the next - * reference token - * - * @return an instance of AdapterType that wraps the dereferenced node - */ -template -inline AdapterType resolveJsonPointer( - const AdapterType &node, - const std::string &jsonPointer, - const std::string::const_iterator jsonPointerItr) -{ - // TODO: This function will probably need to implement support for - // fetching documents referenced by JSON Pointers, similar to the - // populateSchema function. - - const std::string::const_iterator jsonPointerEnd = jsonPointer.end(); - - // Terminate recursion if all reference tokens have been consumed - if (jsonPointerItr == jsonPointerEnd) { - return node; - } - - // Reference tokens must begin with a leading slash - if (*jsonPointerItr != '/') { - throwRuntimeError("Expected reference token to begin with " - "leading slash; remaining tokens: " + - std::string(jsonPointerItr, jsonPointerEnd)); - } - - // Find iterator that points to next slash or newline character; this is - // one character past the end of the current reference token - std::string::const_iterator jsonPointerNext = - std::find(jsonPointerItr + 1, jsonPointerEnd, '/'); - - // Extract the next reference token - const std::string referenceToken = extractReferenceToken( - jsonPointerItr + 1, jsonPointerNext); - - // Empty reference tokens should be ignored - if (referenceToken.empty()) { - return resolveJsonPointer(node, jsonPointer, jsonPointerNext); - - } else if (node.isArray()) { - if (referenceToken == "-") { - throwRuntimeError("Hyphens cannot be used as array indices " - "since the requested array element does not yet exist"); - } - -#if VALIJSON_USE_EXCEPTIONS - try { -#endif - // Fragment must be non-negative integer - const uint64_t index = std::stoul(referenceToken); - typedef typename AdapterType::Array Array; - const Array arr = node.asArray(); - typename Array::const_iterator itr = arr.begin(); - const uint64_t arrSize = arr.size(); - - if (arrSize == 0 || index > arrSize - 1) { - throwRuntimeError("Expected reference token to identify " - "an element in the current array, but array index is " - "out of bounds; actual token: " + referenceToken); - } - - if (index > static_cast(std::numeric_limits::max())) { - throwRuntimeError("Array index out of bounds; hard " - "limit is " + std::to_string( - std::numeric_limits::max())); - } - - itr.advance(static_cast(index)); - - // Recursively process the remaining tokens - return resolveJsonPointer(*itr, jsonPointer, jsonPointerNext); - -#if VALIJSON_USE_EXCEPTIONS - } catch (std::invalid_argument &) { - throwRuntimeError("Expected reference token to contain a " - "non-negative integer to identify an element in the " - "current array; actual token: " + referenceToken); - } -#endif - } else if (node.maybeObject()) { - // Fragment must identify a member of the candidate object - typedef typename AdapterType::Object Object; - - const Object object = node.asObject(); - typename Object::const_iterator itr = object.find( - referenceToken); - if (itr == object.end()) { - throwRuntimeError("Expected reference token to identify an " - "element in the current object; " - "actual token: " + referenceToken); - abort(); - } - - // Recursively process the remaining tokens - return resolveJsonPointer(itr->second, jsonPointer, jsonPointerNext); - } - - throwRuntimeError("Expected end of JSON Pointer, but at least " - "one reference token has not been processed; remaining tokens: " + - std::string(jsonPointerNext, jsonPointerEnd)); - abort(); -} - -/** - * @brief Return the JSON Value referenced by a JSON Pointer - * - * @param rootNode node to use as root for JSON Pointer resolution - * @param jsonPointer string containing JSON Pointer - * - * @return an instance AdapterType in the specified document - */ -template -inline AdapterType resolveJsonPointer( - const AdapterType &rootNode, - const std::string &jsonPointer) -{ - return resolveJsonPointer(rootNode, jsonPointer, jsonPointer.begin()); -} - -} // namespace json_pointer -} // namespace internal -} // namespace valijson - -#ifdef _MSC_VER -#pragma warning( pop ) -#endif diff --git a/subprojects/valijson/include/valijson/internal/json_reference.hpp b/subprojects/valijson/include/valijson/internal/json_reference.hpp deleted file mode 100644 index fc67a3477..000000000 --- a/subprojects/valijson/include/valijson/internal/json_reference.hpp +++ /dev/null @@ -1,60 +0,0 @@ -#pragma once - -#include -#include - -#include - -namespace valijson { -namespace internal { -namespace json_reference { - -/** - * @brief Extract URI from JSON Reference relative to the current schema - * - * @param jsonRef JSON Reference to extract from - * @param schema Schema that JSON Reference URI is relative to - * - * @return Optional string containing URI - */ -inline opt::optional getJsonReferenceUri( - const std::string &jsonRef) -{ - const size_t ptrPos = jsonRef.find('#'); - if (ptrPos == 0) { - // The JSON Reference does not contain a URI, but might contain a - // JSON Pointer that refers to the current document - return opt::optional(); - } else if (ptrPos != std::string::npos) { - // The JSON Reference contains a URI and possibly a JSON Pointer - return jsonRef.substr(0, ptrPos); - } - - // The entire JSON Reference should be treated as a URI - return jsonRef; -} - -/** - * @brief Extract JSON Pointer portion of a JSON Reference - * - * @param jsonRef JSON Reference to extract from - * - * @return Optional string containing JSON Pointer - */ -inline opt::optional getJsonReferencePointer( - const std::string &jsonRef) -{ - // Attempt to extract JSON Pointer if '#' character is present. Note - // that a valid pointer would contain at least a leading forward - // slash character. - const size_t ptrPos = jsonRef.find('#'); - if (ptrPos != std::string::npos) { - return jsonRef.substr(ptrPos + 1); - } - - return opt::optional(); -} - -} // namespace json_reference -} // namespace internal -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/internal/optional.hpp b/subprojects/valijson/include/valijson/internal/optional.hpp deleted file mode 100644 index c9bc47b61..000000000 --- a/subprojects/valijson/include/valijson/internal/optional.hpp +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#if __cplusplus >= 201703 -// Visual C++ only supports __has_include in versions 14.12 and greater -# if !defined(_MSC_VER) || _MSC_VER >= 1912 -# if __has_include() -# include -namespace opt = std; -# endif -# endif -#else -# include -namespace opt = std::experimental; -#endif diff --git a/subprojects/valijson/include/valijson/internal/uri.hpp b/subprojects/valijson/include/valijson/internal/uri.hpp deleted file mode 100644 index d04a18b18..000000000 --- a/subprojects/valijson/include/valijson/internal/uri.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include - -namespace valijson { -namespace internal { -namespace uri { - -/** - * @brief Placeholder function to check whether a URI is absolute - * - * This function just checks for '://' - */ -inline bool isUriAbsolute(const std::string &documentUri) -{ - static const char * placeholderMarker = "://"; - - return documentUri.find(placeholderMarker) != std::string::npos; -} - -/** - * Placeholder function to resolve a relative URI within a given scope - */ -inline std::string resolveRelativeUri( - const std::string &resolutionScope, - const std::string &relativeUri) -{ - return resolutionScope + relativeUri; -} - -} // namespace uri -} // namespace internal -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/schema.hpp b/subprojects/valijson/include/valijson/schema.hpp deleted file mode 100644 index a3c3f24e4..000000000 --- a/subprojects/valijson/include/valijson/schema.hpp +++ /dev/null @@ -1,224 +0,0 @@ -#pragma once - -#include -#include - -#include -#include - -namespace valijson { - -/** - * Represents the root of a JSON Schema - * - * The root is distinct from other sub-schemas because it is the canonical - * starting point for validation of a document against a given a JSON Schema. - */ -class Schema: public Subschema -{ -public: - /** - * @brief Construct a new Schema instance with no constraints - */ - Schema() - : sharedEmptySubschema(newSubschema()) { } - - /** - * @brief Construct a new Schema using custom memory management - * functions - * - * @param allocFn malloc- or new-like function to allocate memory - * within Schema, such as for Subschema instances - * @param freeFn free-like function to free memory allocated with - * the `customAlloc` function - */ - Schema(CustomAlloc allocFn, CustomFree freeFn) - : Subschema(allocFn, freeFn), - sharedEmptySubschema(newSubschema()) { } - - // Disable copy construction - Schema(const Schema &) = delete; - - // Disable copy assignment - Schema & operator=(const Schema &) = delete; - - /** - * @brief Clean up and free all memory managed by the Schema - * - * Note that any Subschema pointers created and returned by this Schema - * should be considered invalid. - */ - ~Schema() override - { - sharedEmptySubschema->~Subschema(); - m_freeFn(const_cast(sharedEmptySubschema)); - sharedEmptySubschema = nullptr; - -#if VALIJSON_USE_EXCEPTIONS - try { -#endif - for (auto subschema : subschemaSet) { - subschema->~Subschema(); - m_freeFn(subschema); - } -#if VALIJSON_USE_EXCEPTIONS - } catch (const std::exception &e) { - fprintf(stderr, "Caught an exception while destroying Schema: %s", - e.what()); - } -#endif - } - - /** - * @brief Copy a constraint to a specific sub-schema - * - * @param constraint reference to a constraint that will be copied into - * the sub-schema - * @param subschema pointer to the sub-schema that will own the copied - * constraint - * - * @throws std::runtime_error if the sub-schema is not owned by this Schema - * instance - */ - void addConstraintToSubschema(const Constraint &constraint, - const Subschema *subschema) - { - // TODO: Check heirarchy for subschemas that do not belong... - - mutableSubschema(subschema)->addConstraint(constraint); - } - - /** - * @brief Create a new Subschema instance that is owned by this Schema - * - * @returns const pointer to the new Subschema instance - */ - const Subschema * createSubschema() - { - Subschema *subschema = newSubschema(); - -#if VALIJSON_USE_EXCEPTIONS - try { -#endif - if (!subschemaSet.insert(subschema).second) { - throwRuntimeError( - "Failed to store pointer for new sub-schema"); - } -#if VALIJSON_USE_EXCEPTIONS - } catch (...) { - subschema->~Subschema(); - m_freeFn(subschema); - throw; - } -#endif - return subschema; - } - - /** - * @brief Return a pointer to the shared empty schema - */ - const Subschema * emptySubschema() const - { - return sharedEmptySubschema; - } - - /** - * @brief Get a pointer to the root sub-schema of this Schema instance - */ - const Subschema * root() const - { - return this; - } - - void setAlwaysInvalid(const Subschema *subschema, bool value) - { - mutableSubschema(subschema)->setAlwaysInvalid(value); - } - - /** - * @brief Update the description for one of the sub-schemas owned by this - * Schema instance - * - * @param subschema sub-schema to update - * @param description new description - */ - void setSubschemaDescription(const Subschema *subschema, - const std::string &description) - { - mutableSubschema(subschema)->setDescription(description); - } - - /** - * @brief Update the ID for one of the sub-schemas owned by this Schema - * instance - * - * @param subschema sub-schema to update - * @param id new ID - */ - void setSubschemaId(const Subschema *subschema, const std::string &id) - { - mutableSubschema(subschema)->setId(id); - } - - /** - * @brief Update the title for one of the sub-schemas owned by this Schema - * instance - * - * @param subschema sub-schema to update - * @param title new title - */ - void setSubschemaTitle(const Subschema *subschema, const std::string &title) - { - mutableSubschema(subschema)->setTitle(title); - } - -private: - - Subschema *newSubschema() - { - void *ptr = m_allocFn(sizeof(Subschema)); - if (!ptr) { - throwRuntimeError( - "Failed to allocate memory for shared empty sub-schema"); - } - -#if VALIJSON_USE_EXCEPTIONS - try { -#endif - return new (ptr) Subschema(); -#if VALIJSON_USE_EXCEPTIONS - } catch (...) { - m_freeFn(ptr); - throw; - } -#endif - } - - Subschema * mutableSubschema(const Subschema *subschema) - { - if (subschema == this) { - return this; - } - - if (subschema == sharedEmptySubschema) { - throwRuntimeError( - "Cannot modify the shared empty sub-schema"); - } - - auto *noConst = const_cast(subschema); - if (subschemaSet.find(noConst) == subschemaSet.end()) { - throwRuntimeError( - "Subschema pointer is not owned by this Schema instance"); - } - - return noConst; - } - - /// Set of Subschema instances owned by this schema - std::set subschemaSet; - - /// Empty schema that can be reused by multiple constraints - const Subschema *sharedEmptySubschema; -}; - -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/schema_parser.hpp b/subprojects/valijson/include/valijson/schema_parser.hpp deleted file mode 100644 index 908cd182e..000000000 --- a/subprojects/valijson/include/valijson/schema_parser.hpp +++ /dev/null @@ -1,2282 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace valijson { - -/** - * @brief Parser for populating a Schema based on a JSON Schema document. - * - * The SchemaParser class supports Drafts 3 and 4 of JSON Schema, however - * Draft 3 support should be considered deprecated. - * - * The functions provided by this class have been templated so that they can - * be used with different Adapter types. - */ -class SchemaParser -{ -public: - /// Supported versions of JSON Schema - enum Version { - kDraft3, ///< @deprecated JSON Schema v3 has been superseded by v4 - kDraft4, - kDraft7 - }; - - /** - * @brief Construct a new SchemaParser for a given version of JSON Schema - * - * @param version Version of JSON Schema that will be expected - */ - explicit SchemaParser(const Version version = kDraft7) - : m_version(version) { } - - /** - * @brief Release memory associated with custom ConstraintBuilders - */ - virtual ~SchemaParser() - { - for (const auto& entry : constraintBuilders) { - delete entry.second; - } - } - - /** - * @brief Struct to contain templated function type for fetching documents - */ - template - struct FunctionPtrs - { - typedef typename adapters::AdapterTraits::DocumentType DocumentType; - - /// Templated function pointer type for fetching remote documents - typedef std::function FetchDoc; - - /// Templated function pointer type for freeing fetched documents - typedef std::function FreeDoc; - }; - - /** - * @brief Add a custom contraint to this SchemaParser - - * @param key name that will be used to identify relevant constraints - * while parsing a schema document - * @param builder pointer to a subclass of ConstraintBuilder that can - * parse custom constraints found in a schema document, - * and return an appropriate instance of Constraint; this - * class guarantees that it will take ownership of this - * pointer - unless this function throws an exception - * - * @todo consider accepting a list of custom ConstraintBuilders in - * constructor, so that this class remains immutable after - * construction - * - * @todo Add additional checks for key conflicts, empty keys, and - * potential restrictions relating to case sensitivity - */ - void addConstraintBuilder(const std::string &key, const ConstraintBuilder *builder) - { - constraintBuilders.push_back(std::make_pair(key, builder)); - } - - /** - * @brief Populate a Schema object from JSON Schema document - * - * When processing Draft 3 schemas, the parentSubschema and ownName pointers - * should be set in contexts where a 'required' constraint would be valid. - * These are used to add a RequiredConstraint object to the Schema that - * contains the required property. - * - * @param node Reference to node to parse - * @param schema Reference to Schema to populate - * @param fetchDoc Function to fetch remote JSON documents (optional) - */ - template - void populateSchema( - const AdapterType &node, - Schema &schema, - typename FunctionPtrs::FetchDoc fetchDoc = nullptr , - typename FunctionPtrs::FreeDoc freeDoc = nullptr ) - { - if ((fetchDoc == nullptr ) ^ (freeDoc == nullptr)) { - throwRuntimeError("Remote document fetching can't be enabled without both fetch and free functions"); - } - - typename DocumentCache::Type docCache; - SchemaCache schemaCache; -#if VALIJSON_USE_EXCEPTIONS - try { -#endif - resolveThenPopulateSchema(schema, node, node, schema, opt::optional(), "", fetchDoc, nullptr, - nullptr, docCache, schemaCache); -#if VALIJSON_USE_EXCEPTIONS - } catch (...) { - freeDocumentCache(docCache, freeDoc); - throw; - } -#endif - - freeDocumentCache(docCache, freeDoc); - } - -private: - - typedef std::vector> - ConstraintBuilders; - - ConstraintBuilders constraintBuilders; - - template - struct DocumentCache - { - typedef typename adapters::AdapterTraits::DocumentType DocumentType; - - typedef std::map Type; - }; - - typedef std::map SchemaCache; - - /** - * @brief Free memory used by fetched documents - * - * If a custom 'free' function has not been provided, then the default - * delete operator will be used. - * - * @param docCache collection of fetched documents to free - * @param freeDoc optional custom free function - */ - template - void freeDocumentCache(const typename DocumentCache::Type - &docCache, typename FunctionPtrs::FreeDoc freeDoc) - { - typedef typename DocumentCache::Type DocCacheType; - - for (const typename DocCacheType::value_type &v : docCache) { - freeDoc(v.second); - } - } - - /** - * @brief Find the absolute URI for a document, within a resolution scope - * - * This function captures five different cases that can occur when - * attempting to resolve a document URI within a particular resolution - * scope: - * - * - resolution scope not present, but absolute document URI is - * => document URI as-is - * - resolution scope not present, and document URI is relative or absent - * => no result - * - resolution scope is present, and document URI is a relative path - * => resolve document URI relative to resolution scope - * - resolution scope is present, and document URI is absolute - * => document URI as-is - * - resolution scope is present, but document URI is not - * => resolution scope as-is - * - * This function assumes that the resolution scope is absolute. - * - * When resolving a document URI relative to the resolution scope, the - * document URI should be used to replace the path, query and fragment - * portions of URI provided by the resolution scope. - */ - virtual opt::optional findAbsoluteDocumentUri( - const opt::optional& resolutionScope, - const opt::optional& documentUri) - { - if (resolutionScope) { - if (documentUri) { - if (internal::uri::isUriAbsolute(*documentUri)) { - return *documentUri; - } else { - return internal::uri::resolveRelativeUri(*resolutionScope, *documentUri); - } - } else { - return *resolutionScope; - } - } else if (documentUri && internal::uri::isUriAbsolute(*documentUri)) { - return *documentUri; - } else { - return opt::optional(); - } - } - - /** - * @brief Extract a JSON Reference string from a node - * - * @param node node to extract the JSON Reference from - * @param result reference to string to set with the result - * - * @throws std::invalid_argument if node is an object containing a `$ref` - * property but with a value that cannot be interpreted as a string - * - * @return \c true if a JSON Reference was extracted; \c false otherwise - */ - template - bool extractJsonReference(const AdapterType &node, std::string &result) - { - if (!node.isObject()) { - return false; - } - - const typename AdapterType::Object o = node.getObject(); - const typename AdapterType::Object::const_iterator itr = o.find("$ref"); - if (itr == o.end()) { - return false; - } else if (!itr->second.getString(result)) { - throwRuntimeError("$ref property expected to contain string value."); - } - - return true; - } - - /** - * Sanitise an optional JSON Pointer, trimming trailing slashes - */ - static std::string sanitiseJsonPointer(const opt::optional& input) - { - if (input) { - // Trim trailing slash(es) - std::string sanitised = *input; - sanitised.erase(sanitised.find_last_not_of('/') + 1, - std::string::npos); - - return sanitised; - } - - // If the JSON Pointer is not set, assume that the URI points to - // the root of the document - return ""; - } - - /** - * @brief Search the schema cache for a schema matching a given key - * - * If the key is not present in the query cache, a nullptr will be - * returned, and the contents of the cache will remain unchanged. This is - * in contrast to the behaviour of the std::map [] operator, which would - * add the nullptr to the cache. - * - * @param schemaCache schema cache to query - * @param queryKey key to search for - * - * @return shared pointer to Schema if found, nullptr otherwise - */ - static const Subschema * querySchemaCache(SchemaCache &schemaCache, - const std::string &queryKey) - { - const SchemaCache::iterator itr = schemaCache.find(queryKey); - if (itr == schemaCache.end()) { - return nullptr; - } - - return itr->second; - } - - /** - * @brief Add entries to the schema cache for a given list of keys - * - * @param schemaCache schema cache to update - * @param keysToCreate list of keys to create entries for - * @param schema shared pointer to schema that keys will map to - * - * @throws std::logic_error if any of the keys are already present in the - * schema cache. This behaviour is intended to help detect incorrect - * usage of the schema cache during development, and is not expected - * to occur otherwise, even for malformed schemas. - */ - static void updateSchemaCache(SchemaCache &schemaCache, - const std::vector &keysToCreate, - const Subschema *schema) - { - for (const std::string &keyToCreate : keysToCreate) { - const SchemaCache::value_type value(keyToCreate, schema); - if (!schemaCache.insert(value).second) { - throwLogicError("Key '" + keyToCreate + "' already in schema cache."); - } - } - } - - /** - * @brief Recursive helper function for retrieving or creating schemas - * - * This function will be applied recursively until a concrete node is found. - * A concrete node is a node that contains actual schema constraints rather - * than a JSON Reference. - * - * This termination condition may be trigged by visiting the concrete node - * at the end of a series of $ref nodes, or by finding a schema for one of - * those $ref nodes in the schema cache. An entry will be added to the - * schema cache for each node visited on the path to the concrete node. - * - * @param rootSchema The Schema instance, and root subschema, through - * which other subschemas can be created and - * modified - * @param rootNode Reference to the node from which JSON References - * will be resolved when they refer to the current - * document - * @param node Reference to the node to parse - * @param currentScope URI for current resolution scope - * @param nodePath JSON Pointer representing path to current node - * @param fetchDoc Function to fetch remote JSON documents (optional) - * @param parentSchema Optional pointer to the parent schema, used to - * support required keyword in Draft 3 - * @param ownName Optional pointer to a node name, used to support - * the 'required' keyword in Draft 3 - * @param docCache Cache of resolved and fetched remote documents - * @param schemaCache Cache of populated schemas - * @param newCacheKeys A list of keys that should be added to the cache - * when recursion terminates - */ - template - const Subschema * makeOrReuseSchema( - Schema &rootSchema, - const AdapterType &rootNode, - const AdapterType &node, - const opt::optional currentScope, - const std::string &nodePath, - const typename FunctionPtrs::FetchDoc fetchDoc, - const Subschema *parentSubschema, - const std::string *ownName, - typename DocumentCache::Type &docCache, - SchemaCache &schemaCache, - std::vector &newCacheKeys) - { - std::string jsonRef; - - // Check for the first termination condition (found a non-$ref node) - if (!extractJsonReference(node, jsonRef)) { - - // Construct a key that we can use to search the schema cache for - // a schema corresponding to the current node - const std::string schemaCacheKey = currentScope ? (*currentScope + nodePath) : nodePath; - - // Retrieve an existing schema from the cache if possible - const Subschema *cachedPtr = querySchemaCache(schemaCache, schemaCacheKey); - - // Create a new schema otherwise - const Subschema *subschema = cachedPtr ? cachedPtr : rootSchema.createSubschema(); - - // Add cache entries for keys belonging to any $ref nodes that were - // visited before arriving at the current node - updateSchemaCache(schemaCache, newCacheKeys, subschema); - - // Schema cache did not contain a pre-existing schema corresponding - // to the current node, so the schema that was returned will need - // to be populated - if (!cachedPtr) { - populateSchema(rootSchema, rootNode, node, *subschema, - currentScope, nodePath, fetchDoc, parentSubschema, - ownName, docCache, schemaCache); - } - - return subschema; - } - - // Returns a document URI if the reference points somewhere - // other than the current document - const opt::optional documentUri = internal::json_reference::getJsonReferenceUri(jsonRef); - - // Extract JSON Pointer from JSON Reference, with any trailing - // slashes removed so that keys in the schema cache end - // consistently - const std::string actualJsonPointer = sanitiseJsonPointer( - internal::json_reference::getJsonReferencePointer(jsonRef)); - - // Determine the actual document URI based on the resolution - // scope. An absolute document URI will take precedence when - // present, otherwise we need to resolve the URI relative to - // the current resolution scope - const opt::optional actualDocumentUri = findAbsoluteDocumentUri(currentScope, documentUri); - - // Construct a key to search the schema cache for an existing schema - const std::string queryKey = actualDocumentUri ? (*actualDocumentUri + actualJsonPointer) : actualJsonPointer; - - // Check for the second termination condition (found a $ref node that - // already has an entry in the schema cache) - const Subschema *cachedPtr = querySchemaCache(schemaCache, queryKey); - if (cachedPtr) { - updateSchemaCache(schemaCache, newCacheKeys, cachedPtr); - return cachedPtr; - } - - if (actualDocumentUri && (!currentScope || *actualDocumentUri != *currentScope)) { - const typename FunctionPtrs::DocumentType *newDoc = nullptr; - - // Have we seen this document before? - typename DocumentCache::Type::iterator docCacheItr = - docCache.find(*actualDocumentUri); - if (docCacheItr == docCache.end()) { - // Resolve reference against remote document - if (!fetchDoc) { - throwRuntimeError("Fetching of remote JSON References not enabled."); - } - - // Returns a pointer to the remote document that was - // retrieved, or null if retrieval failed. This class - // will take ownership of the pointer, and call freeDoc - // when it is no longer needed. - newDoc = fetchDoc(*actualDocumentUri); - - // Can't proceed without the remote document - if (!newDoc) { - throwRuntimeError("Failed to fetch referenced schema document: " + *actualDocumentUri); - } - - typedef typename DocumentCache::Type::value_type - DocCacheValueType; - - docCache.insert(DocCacheValueType(*actualDocumentUri, newDoc)); - - } else { - newDoc = docCacheItr->second; - } - - const AdapterType newRootNode(*newDoc); - - // Find where we need to be in the document - const AdapterType &referencedAdapter = - internal::json_pointer::resolveJsonPointer(newRootNode, - actualJsonPointer); - - newCacheKeys.push_back(queryKey); - - // Populate the schema, starting from the referenced node, with - // nested JSON References resolved relative to the new root node - return makeOrReuseSchema(rootSchema, newRootNode, referencedAdapter, - currentScope, actualJsonPointer, fetchDoc, parentSubschema, - ownName, docCache, schemaCache, newCacheKeys); - - } - - // JSON References in nested schema will be resolved relative to the - // current document - const AdapterType &referencedAdapter = - internal::json_pointer::resolveJsonPointer( - rootNode, actualJsonPointer); - - newCacheKeys.push_back(queryKey); - - // Populate the schema, starting from the referenced node, with - // nested JSON References resolved relative to the new root node - return makeOrReuseSchema(rootSchema, rootNode, referencedAdapter, - currentScope, actualJsonPointer, fetchDoc, parentSubschema, - ownName, docCache, schemaCache, newCacheKeys); - } - - /** - * @brief Return pointer for the schema corresponding to a given node - * - * This function makes use of a schema cache, so that if the path to the - * current node is the same as one that has already been parsed and - * populated, a pointer to the existing Subschema will be returned. - * - * Should a series of $ref, or reference, nodes be resolved before reaching - * a concrete node, an entry will be added to the schema cache for each of - * the nodes in that path. - * - * @param rootSchema The Schema instance, and root subschema, through - * which other subschemas can be created and - * modified - * @param rootNode Reference to the node from which JSON References - * will be resolved when they refer to the current - * document - * @param node Reference to the node to parse - * @param currentScope URI for current resolution scope - * @param nodePath JSON Pointer representing path to current node - * @param fetchDoc Function to fetch remote JSON documents (optional) - * @param parentSchema Optional pointer to the parent schema, used to - * support required keyword in Draft 3 - * @param ownName Optional pointer to a node name, used to support - * the 'required' keyword in Draft 3 - * @param docCache Cache of resolved and fetched remote documents - * @param schemaCache Cache of populated schemas - */ - template - const Subschema * makeOrReuseSchema( - Schema &rootSchema, - const AdapterType &rootNode, - const AdapterType &node, - const opt::optional currentScope, - const std::string &nodePath, - const typename FunctionPtrs::FetchDoc fetchDoc, - const Subschema *parentSubschema, - const std::string *ownName, - typename DocumentCache::Type &docCache, - SchemaCache &schemaCache) - { - std::vector schemaCacheKeysToCreate; - - return makeOrReuseSchema(rootSchema, rootNode, node, currentScope, - nodePath, fetchDoc, parentSubschema, ownName, docCache, - schemaCache, schemaCacheKeysToCreate); - } - - /** - * @brief Populate a Schema object from JSON Schema document - * - * When processing Draft 3 schemas, the parentSubschema and ownName pointers - * should be set in contexts where a 'required' constraint would be valid. - * These are used to add a RequiredConstraint object to the Schema that - * contains the required property. - * - * @param rootSchema The Schema instance, and root subschema, through - * which other subschemas can be created and - * modified - * @param rootNode Reference to the node from which JSON References - * will be resolved when they refer to the current - * document - * @param node Reference to node to parse - * @param schema Reference to Schema to populate - * @param currentScope URI for current resolution scope - * @param nodePath JSON Pointer representing path to current node - * @param fetchDoc Optional function to fetch remote JSON documents - * @param parentSubschema Optional pointer to the parent schema, used to - * support required keyword in Draft 3 - * @param ownName Optional pointer to a node name, used to support - * the 'required' keyword in Draft 3 - * @param docCache Cache of resolved and fetched remote documents - * @param schemaCache Cache of populated schemas - */ - template - void populateSchema( - Schema &rootSchema, - const AdapterType &rootNode, - const AdapterType &node, - const Subschema &subschema, - const opt::optional& currentScope, - const std::string &nodePath, - const typename FunctionPtrs::FetchDoc fetchDoc, - const Subschema *parentSubschema, - const std::string *ownName, - typename DocumentCache::Type &docCache, - SchemaCache &schemaCache) - { - static_assert((std::is_convertible::value), - "SchemaParser::populateSchema must be invoked with an " - "appropriate Adapter implementation"); - - if (!node.isObject()) { - if (m_version == kDraft7 && node.maybeBool()) { - // Boolean schema - if (!node.asBool()) { - rootSchema.setAlwaysInvalid(&subschema, true); - } - return; - } else { - std::string s; - s += "Expected node at "; - s += nodePath; - if (m_version == kDraft7) { - s += " to contain schema object or boolean value; actual node type is: "; - } else { - s += " to contain schema object; actual node type is: "; - } - s += internal::nodeTypeAsString(node); - throwRuntimeError(s); - } - } - - const typename AdapterType::Object object = node.asObject(); - typename AdapterType::Object::const_iterator itr(object.end()); - - // Check for 'id' attribute and update current scope - opt::optional updatedScope; - if ((itr = object.find("id")) != object.end() && itr->second.maybeString()) { - const std::string id = itr->second.asString(); - rootSchema.setSubschemaId(&subschema, itr->second.asString()); - if (!currentScope || internal::uri::isUriAbsolute(id)) { - updatedScope = id; - } else { - updatedScope = internal::uri::resolveRelativeUri(*currentScope, id); - } - } else { - updatedScope = currentScope; - } - - if ((itr = object.find("allOf")) != object.end()) { - rootSchema.addConstraintToSubschema( - makeAllOfConstraint(rootSchema, rootNode, itr->second, - updatedScope, nodePath + "/allOf", fetchDoc, - docCache, schemaCache), - &subschema); - } - - if ((itr = object.find("anyOf")) != object.end()) { - rootSchema.addConstraintToSubschema( - makeAnyOfConstraint(rootSchema, rootNode, itr->second, - updatedScope, nodePath + "/anyOf", fetchDoc, - docCache, schemaCache), - &subschema); - } - - if ((itr = object.find("const")) != object.end()) { - rootSchema.addConstraintToSubschema(makeConstConstraint(itr->second), &subschema); - } - - if ((itr = object.find("contains")) != object.end()) { - rootSchema.addConstraintToSubschema( - makeContainsConstraint(rootSchema, rootNode, itr->second, - updatedScope, nodePath + "/contains", fetchDoc, - docCache, schemaCache), &subschema); - } - - if ((itr = object.find("dependencies")) != object.end()) { - rootSchema.addConstraintToSubschema( - makeDependenciesConstraint(rootSchema, rootNode, - itr->second, updatedScope, - nodePath + "/dependencies", fetchDoc, docCache, - schemaCache), - &subschema); - } - - if ((itr = object.find("description")) != object.end()) { - if (itr->second.maybeString()) { - rootSchema.setSubschemaDescription(&subschema, - itr->second.asString()); - } else { - throwRuntimeError( - "'description' attribute should have a string value"); - } - } - - if ((itr = object.find("divisibleBy")) != object.end()) { - if (m_version == kDraft3) { - if (itr->second.maybeInteger()) { - rootSchema.addConstraintToSubschema( - makeMultipleOfIntConstraint(itr->second), - &subschema); - } else if (itr->second.maybeDouble()) { - rootSchema.addConstraintToSubschema( - makeMultipleOfDoubleConstraint(itr->second), - &subschema); - } else { - throwRuntimeError("Expected an numeric value for " - " 'divisibleBy' constraint."); - } - } else { - throwRuntimeError( - "'divisibleBy' constraint not valid after draft 3"); - } - } - - if ((itr = object.find("enum")) != object.end()) { - rootSchema.addConstraintToSubschema(makeEnumConstraint(itr->second), &subschema); - } - - { - const typename AdapterType::Object::const_iterator itemsItr = - object.find("items"); - - if (object.end() != itemsItr) { - if (!itemsItr->second.isArray()) { - rootSchema.addConstraintToSubschema( - makeSingularItemsConstraint(rootSchema, rootNode, - itemsItr->second, updatedScope, - nodePath + "/items", fetchDoc, docCache, - schemaCache), - &subschema); - - } else { - const typename AdapterType::Object::const_iterator - additionalItemsItr = object.find("additionalItems"); - rootSchema.addConstraintToSubschema( - makeLinearItemsConstraint(rootSchema, rootNode, - itemsItr != object.end() ? &itemsItr->second : nullptr, - additionalItemsItr != object.end() ? &additionalItemsItr->second : nullptr, - updatedScope, nodePath + "/items", - nodePath + "/additionalItems", fetchDoc, - docCache, schemaCache), - &subschema); - } - } - } - - { - const typename AdapterType::Object::const_iterator ifItr = object.find("if"); - const typename AdapterType::Object::const_iterator thenItr = object.find("then"); - const typename AdapterType::Object::const_iterator elseItr = object.find("else"); - - if (object.end() != ifItr) { - if (m_version == kDraft7) { - rootSchema.addConstraintToSubschema( - makeConditionalConstraint(rootSchema, rootNode, - ifItr->second, - thenItr == object.end() ? nullptr : &thenItr->second, - elseItr == object.end() ? nullptr : &elseItr->second, - updatedScope, nodePath, fetchDoc, docCache, schemaCache), - &subschema); - } else { - throwRuntimeError("Not supported"); - } - } - } - - if (m_version == kDraft7) { - if ((itr = object.find("exclusiveMaximum")) != object.end()) { - rootSchema.addConstraintToSubschema( - makeMaximumConstraintExclusive(itr->second), - &subschema); - } - - if ((itr = object.find("maximum")) != object.end()) { - rootSchema.addConstraintToSubschema( - makeMaximumConstraint(itr->second, nullptr), - &subschema); - } - } else if ((itr = object.find("maximum")) != object.end()) { - typename AdapterType::Object::const_iterator exclusiveMaximumItr = - object.find("exclusiveMaximum"); - if (exclusiveMaximumItr == object.end()) { - rootSchema.addConstraintToSubschema( - makeMaximumConstraint(itr->second, nullptr), - &subschema); - } else { - rootSchema.addConstraintToSubschema( - makeMaximumConstraint(itr->second, &exclusiveMaximumItr->second), - &subschema); - } - } else if (object.find("exclusiveMaximum") != object.end()) { - throwRuntimeError("'exclusiveMaximum' constraint only valid if a 'maximum' " - "constraint is also present"); - } - - if ((itr = object.find("maxItems")) != object.end()) { - rootSchema.addConstraintToSubschema( - makeMaxItemsConstraint(itr->second), &subschema); - } - - if ((itr = object.find("maxLength")) != object.end()) { - rootSchema.addConstraintToSubschema( - makeMaxLengthConstraint(itr->second), &subschema); - } - - if ((itr = object.find("maxProperties")) != object.end()) { - rootSchema.addConstraintToSubschema( - makeMaxPropertiesConstraint(itr->second), &subschema); - } - - if (m_version == kDraft7) { - if ((itr = object.find("exclusiveMinimum")) != object.end()) { - rootSchema.addConstraintToSubschema( - makeMinimumConstraintExclusive(itr->second), &subschema); - } - - if ((itr = object.find("minimum")) != object.end()) { - rootSchema.addConstraintToSubschema( - makeMinimumConstraint(itr->second, nullptr), - &subschema); - } - } else if ((itr = object.find("minimum")) != object.end()) { - typename AdapterType::Object::const_iterator exclusiveMinimumItr = object.find("exclusiveMinimum"); - if (exclusiveMinimumItr == object.end()) { - rootSchema.addConstraintToSubschema( - makeMinimumConstraint(itr->second, nullptr), - &subschema); - } else { - rootSchema.addConstraintToSubschema( - makeMinimumConstraint(itr->second, &exclusiveMinimumItr->second), - &subschema); - } - } else if (object.find("exclusiveMinimum") != object.end()) { - throwRuntimeError("'exclusiveMinimum' constraint only valid if a 'minimum' " - "constraint is also present"); - } - - if ((itr = object.find("minItems")) != object.end()) { - rootSchema.addConstraintToSubschema( - makeMinItemsConstraint(itr->second), &subschema); - } - - if ((itr = object.find("minLength")) != object.end()) { - rootSchema.addConstraintToSubschema( - makeMinLengthConstraint(itr->second), &subschema); - } - - if ((itr = object.find("minProperties")) != object.end()) { - rootSchema.addConstraintToSubschema( - makeMinPropertiesConstraint(itr->second), &subschema); - } - - if ((itr = object.find("multipleOf")) != object.end()) { - if (m_version == kDraft3) { - throwRuntimeError("'multipleOf' constraint not available in draft 3"); - } else if (itr->second.maybeInteger()) { - rootSchema.addConstraintToSubschema( - makeMultipleOfIntConstraint(itr->second), - &subschema); - } else if (itr->second.maybeDouble()) { - rootSchema.addConstraintToSubschema( - makeMultipleOfDoubleConstraint(itr->second), - &subschema); - } else { - throwRuntimeError("Expected an numeric value for 'divisibleBy' constraint."); - } - } - - if ((itr = object.find("not")) != object.end()) { - rootSchema.addConstraintToSubschema( - makeNotConstraint(rootSchema, rootNode, itr->second, updatedScope, nodePath + "/not", fetchDoc, - docCache, schemaCache), - &subschema); - } - - if ((itr = object.find("oneOf")) != object.end()) { - rootSchema.addConstraintToSubschema( - makeOneOfConstraint(rootSchema, rootNode, itr->second, updatedScope, nodePath + "/oneOf", fetchDoc, - docCache, schemaCache), - &subschema); - } - - if ((itr = object.find("pattern")) != object.end()) { - rootSchema.addConstraintToSubschema( - makePatternConstraint(itr->second), &subschema); - } - - { - // Check for schema keywords that require the creation of a - // PropertiesConstraint instance. - const typename AdapterType::Object::const_iterator - propertiesItr = object.find("properties"), - patternPropertiesItr = object.find("patternProperties"), - additionalPropertiesItr = object.find("additionalProperties"); - if (object.end() != propertiesItr || - object.end() != patternPropertiesItr || - object.end() != additionalPropertiesItr) { - rootSchema.addConstraintToSubschema( - makePropertiesConstraint(rootSchema, rootNode, - propertiesItr != object.end() ? &propertiesItr->second : nullptr, - patternPropertiesItr != object.end() ? &patternPropertiesItr->second : nullptr, - additionalPropertiesItr != object.end() ? &additionalPropertiesItr->second : nullptr, - updatedScope, nodePath + "/properties", - nodePath + "/patternProperties", - nodePath + "/additionalProperties", - fetchDoc, &subschema, docCache, schemaCache), - &subschema); - } - } - - if ((itr = object.find("propertyNames")) != object.end()) { - if (m_version == kDraft7) { - rootSchema.addConstraintToSubschema( - makePropertyNamesConstraint(rootSchema, rootNode, itr->second, updatedScope, - nodePath, fetchDoc, docCache, schemaCache), - &subschema); - } else { - throwRuntimeError("Not supported"); - } - } - - if ((itr = object.find("required")) != object.end()) { - if (m_version == kDraft3) { - if (parentSubschema && ownName) { - opt::optional constraint = - makeRequiredConstraintForSelf(itr->second, *ownName); - if (constraint) { - rootSchema.addConstraintToSubschema(*constraint, parentSubschema); - } - } else { - throwRuntimeError("'required' constraint not valid here"); - } - } else { - rootSchema.addConstraintToSubschema(makeRequiredConstraint(itr->second), &subschema); - } - } - - if ((itr = object.find("title")) != object.end()) { - if (itr->second.maybeString()) { - rootSchema.setSubschemaTitle(&subschema, itr->second.asString()); - } else { - throwRuntimeError("'title' attribute should have a string value"); - } - } - - if ((itr = object.find("type")) != object.end()) { - rootSchema.addConstraintToSubschema( - makeTypeConstraint(rootSchema, rootNode, itr->second, updatedScope, nodePath + "/type", fetchDoc, - docCache, schemaCache), - &subschema); - } - - if ((itr = object.find("uniqueItems")) != object.end()) { - opt::optional constraint = makeUniqueItemsConstraint(itr->second); - if (constraint) { - rootSchema.addConstraintToSubschema(*constraint, &subschema); - } - } - - for (const auto & constraintBuilder : constraintBuilders) { - if ((itr = object.find(constraintBuilder.first)) != object.end()) { - constraints::Constraint *constraint = nullptr; -#if VALIJSON_USE_EXCEPTIONS - try { -#endif - constraint = constraintBuilder.second->make(itr->second); - rootSchema.addConstraintToSubschema(*constraint, &subschema); - delete constraint; -#if VALIJSON_USE_EXCEPTIONS - } catch (...) { - delete constraint; - throw; - } -#endif - } - } - } - - /** - * @brief Resolves a chain of JSON References before populating a schema - * - * This helper function is used directly by the publicly visible - * populateSchema function. It ensures that the node being parsed is a - * concrete node, and not a JSON Reference. This function will call itself - * recursively to resolve references until a concrete node is found. - * - * @param rootSchema The Schema instance, and root subschema, through - * which other subschemas can be created and modified - * @param rootNode Reference to the node from which JSON References - * will be resolved when they refer to the current - * document - * @param node Reference to node to parse - * @param subschema Reference to Schema to populate - * @param currentScope URI for current resolution scope - * @param nodePath JSON Pointer representing path to current node - * @param fetchDoc Function to fetch remote JSON documents (optional) - * @param parentSchema Optional pointer to the parent schema, used to - * support required keyword in Draft 3 - * @param ownName Optional pointer to a node name, used to support - * the 'required' keyword in Draft 3 - * @param docCache Cache of resolved and fetched remote documents - * @param schemaCache Cache of populated schemas - */ - template - void resolveThenPopulateSchema( - Schema &rootSchema, - const AdapterType &rootNode, - const AdapterType &node, - const Subschema &subschema, - const opt::optional currentScope, - const std::string &nodePath, - const typename FunctionPtrs::FetchDoc fetchDoc, - const Subschema *parentSchema, - const std::string *ownName, - typename DocumentCache::Type &docCache, - SchemaCache &schemaCache) - { - std::string jsonRef; - if (!extractJsonReference(node, jsonRef)) { - populateSchema(rootSchema, rootNode, node, subschema, currentScope, nodePath, fetchDoc, parentSchema, - ownName, docCache, schemaCache); - return; - } - - // Returns a document URI if the reference points somewhere - // other than the current document - const opt::optional documentUri = internal::json_reference::getJsonReferenceUri(jsonRef); - - // Extract JSON Pointer from JSON Reference - const std::string actualJsonPointer = sanitiseJsonPointer( - internal::json_reference::getJsonReferencePointer(jsonRef)); - - if (documentUri && internal::uri::isUriAbsolute(*documentUri)) { - // Resolve reference against remote document - if (!fetchDoc) { - throwRuntimeError("Fetching of remote JSON References not enabled."); - } - - const typename DocumentCache::DocumentType *newDoc = fetchDoc(*documentUri); - - // Can't proceed without the remote document - if (!newDoc) { - throwRuntimeError("Failed to fetch referenced schema document: " + *documentUri); - } - - // Add to document cache - typedef typename DocumentCache::Type::value_type DocCacheValueType; - - docCache.insert(DocCacheValueType(*documentUri, newDoc)); - - const AdapterType newRootNode(*newDoc); - - const AdapterType &referencedAdapter = - internal::json_pointer::resolveJsonPointer(newRootNode, actualJsonPointer); - - // TODO: Need to detect degenerate circular references - resolveThenPopulateSchema(rootSchema, newRootNode, referencedAdapter, subschema, {}, actualJsonPointer, - fetchDoc, parentSchema, ownName, docCache, schemaCache); - - } else { - const AdapterType &referencedAdapter = - internal::json_pointer::resolveJsonPointer(rootNode, actualJsonPointer); - - // TODO: Need to detect degenerate circular references - resolveThenPopulateSchema(rootSchema, rootNode, referencedAdapter, subschema, {}, actualJsonPointer, - fetchDoc, parentSchema, ownName, docCache, schemaCache); - } - } - - /** - * @brief Make a new AllOfConstraint object - * - * @param rootSchema The Schema instance, and root subschema, through - * which other subschemas can be created and modified - * @param rootNode Reference to the node from which JSON References - * will be resolved when they refer to the current - * document; used for recursive parsing of schemas - * @param node JSON node containing an array of child schemas - * @param currentScope URI for current resolution scope - * @param nodePath JSON Pointer representing path to current node - * @param fetchDoc Function to fetch remote JSON documents (optional) - * @param docCache Cache of resolved and fetched remote documents - * @param schemaCache Cache of populated schemas - * - * @return pointer to a new AllOfConstraint object that belongs to the - * caller - */ - template - constraints::AllOfConstraint makeAllOfConstraint( - Schema &rootSchema, - const AdapterType &rootNode, - const AdapterType &node, - const opt::optional currentScope, - const std::string &nodePath, - const typename FunctionPtrs::FetchDoc fetchDoc, - typename DocumentCache::Type &docCache, - SchemaCache &schemaCache) - { - if (!node.maybeArray()) { - throwRuntimeError("Expected array value for 'allOf' constraint."); - } - - constraints::AllOfConstraint constraint; - - int index = 0; - for (const AdapterType schemaNode : node.asArray()) { - if (schemaNode.maybeObject() || (m_version == kDraft7 && schemaNode.isBool())) { - const std::string childPath = nodePath + "/" + std::to_string(index); - const Subschema *subschema = makeOrReuseSchema( - rootSchema, rootNode, schemaNode, currentScope, - childPath, fetchDoc, nullptr, nullptr, docCache, schemaCache); - constraint.addSubschema(subschema); - index++; - } else { - throwRuntimeError("Expected element to be a valid schema in 'allOf' constraint."); - } - } - - return constraint; - } - - /** - * @brief Make a new AnyOfConstraint object - * - * @param rootSchema The Schema instance, and root subschema, through - * which other subschemas can be created and modified - * @param rootNode Reference to the node from which JSON References - * will be resolved when they refer to the current - * document; used for recursive parsing of schemas - * @param node JSON node containing an array of child schemas - * @param currentScope URI for current resolution scope - * @param nodePath JSON Pointer representing path to current node - * @param fetchDoc Function to fetch remote JSON documents (optional) - * @param docCache Cache of resolved and fetched remote documents - * @param schemaCache Cache of populated schemas - * - * @return pointer to a new AnyOfConstraint object that belongs to the - * caller - */ - template - constraints::AnyOfConstraint makeAnyOfConstraint( - Schema &rootSchema, - const AdapterType &rootNode, - const AdapterType &node, - const opt::optional currentScope, - const std::string &nodePath, - const typename FunctionPtrs::FetchDoc fetchDoc, - typename DocumentCache::Type &docCache, - SchemaCache &schemaCache) - { - if (!node.maybeArray()) { - throwRuntimeError("Expected array value for 'anyOf' constraint."); - } - - constraints::AnyOfConstraint constraint; - - int index = 0; - for (const AdapterType schemaNode : node.asArray()) { - if (schemaNode.maybeObject() || (m_version == kDraft7 && schemaNode.isBool())) { - const std::string childPath = nodePath + "/" + std::to_string(index); - const Subschema *subschema = makeOrReuseSchema( - rootSchema, rootNode, schemaNode, currentScope, - childPath, fetchDoc, nullptr, nullptr, docCache, schemaCache); - constraint.addSubschema(subschema); - index++; - } else { - throwRuntimeError("Expected array element to be a valid schema in 'anyOf' constraint."); - } - } - - return constraint; - } - - /** - * @brief Make a new ConditionalConstraint object. - * - * @param rootSchema The Schema instance, and root subschema, - * through which other subschemas can be - * created and modified - * @param rootNode Reference to the node from which JSON - * References will be resolved when they refer - * to the current document; used for recursive - * parsing of schemas - * @param ifNode Schema that will be used to evaluate the - * conditional. - * @param thenNode Optional pointer to a JSON node containing - * a schema that will be used when the conditional - * evaluates to true. - * @param elseNode Optional pointer to a JSON node containing - * a schema that will be used when the conditional - * evaluates to false. - * @param currentScope URI for current resolution scope - * @param containsPath JSON Pointer representing the path to - * the 'contains' node - * @param fetchDoc Function to fetch remote JSON documents - * (optional) - * @param docCache Cache of resolved and fetched remote - * documents - * @param schemaCache Cache of populated schemas - * - * @return pointer to a new ContainsConstraint that belongs to the caller - */ - template - constraints::ConditionalConstraint makeConditionalConstraint( - Schema &rootSchema, - const AdapterType &rootNode, - const AdapterType &ifNode, - const AdapterType *thenNode, - const AdapterType *elseNode, - const opt::optional currentScope, - const std::string &nodePath, - const typename FunctionPtrs::FetchDoc fetchDoc, - typename DocumentCache::Type &docCache, - SchemaCache &schemaCache) - { - constraints::ConditionalConstraint constraint; - - const Subschema *ifSubschema = makeOrReuseSchema( - rootSchema, rootNode, ifNode, currentScope, - nodePath + "/if", fetchDoc, nullptr, nullptr, docCache, - schemaCache); - constraint.setIfSubschema(ifSubschema); - - if (thenNode) { - const Subschema *thenSubschema = makeOrReuseSchema( - rootSchema, rootNode, *thenNode, currentScope, nodePath + "/then", fetchDoc, nullptr, - nullptr, docCache, schemaCache); - constraint.setThenSubschema(thenSubschema); - } - - if (elseNode) { - const Subschema *elseSubschema = makeOrReuseSchema( - rootSchema, rootNode, *elseNode, currentScope, nodePath + "/else", fetchDoc, nullptr, - nullptr, docCache, schemaCache); - constraint.setElseSubschema(elseSubschema); - } - - return constraint; - } - - /** - * @brief Make a new ConstConstraint object. - * - * @param node JSON node containing an arbitrary value - * - * @return pointer to a new MinimumConstraint that belongs to the caller - */ - template - constraints::ConstConstraint makeConstConstraint(const AdapterType &node) - { - constraints::ConstConstraint constraint; - constraint.setValue(node); - return constraint; - } - - /** - * @brief Make a new ContainsConstraint object. - * - * @param rootSchema The Schema instance, and root subschema, - * through which other subschemas can be - * created and modified - * @param rootNode Reference to the node from which JSON - * References will be resolved when they refer - * to the current document; used for recursive - * parsing of schemas - * @param contains Optional pointer to a JSON node containing - * an object mapping property names to - * schemas. - * @param currentScope URI for current resolution scope - * @param containsPath JSON Pointer representing the path to - * the 'contains' node - * @param fetchDoc Function to fetch remote JSON documents - * (optional) - * @param docCache Cache of resolved and fetched remote - * documents - * @param schemaCache Cache of populated schemas - * - * @return pointer to a new ContainsConstraint that belongs to the caller - */ - template - constraints::ContainsConstraint makeContainsConstraint( - Schema &rootSchema, - const AdapterType &rootNode, - const AdapterType &contains, - const opt::optional currentScope, - const std::string &containsPath, - const typename FunctionPtrs::FetchDoc fetchDoc, - typename DocumentCache::Type &docCache, - SchemaCache &schemaCache) - { - constraints::ContainsConstraint constraint; - - if (contains.isObject() || (m_version == kDraft7 && contains.maybeBool())) { - const Subschema *subschema = makeOrReuseSchema( - rootSchema, rootNode, contains, currentScope, containsPath, - fetchDoc, nullptr, nullptr, docCache, schemaCache); - constraint.setSubschema(subschema); - - } else if (contains.maybeObject()) { - // If a loosely-typed Adapter type is being used, then we'll - // assume that an empty schema has been provided. - constraint.setSubschema(rootSchema.emptySubschema()); - - } else { - // All other formats will result in an exception being thrown. - throwRuntimeError("Expected valid schema for 'contains' constraint."); - } - - return constraint; - } - - /** - * @brief Make a new DependenciesConstraint object - * - * The dependencies for a property can be defined several ways. When parsing - * a Draft 4 schema, the following can be used: - * - an array that lists the name of each property that must be present - * if the dependent property is present - * - an object that specifies a schema which must be satisfied if the - * dependent property is present - * - * When parsing a Draft 3 schema, in addition to the formats above, the - * following format can be used: - * - a string that names a single property that must be present if the - * dependent property is presnet - * - * Multiple methods can be used in the same dependency constraint. - * - * If the format of any part of the the dependency node does not match one - * of these formats, an exception will be thrown. - * - * @param rootSchema The Schema instance, and root subschema, through - * which other subschemas can be created and modified - * @param rootNode Reference to the node from which JSON References - * will be resolved when they refer to the current - * document; used for recursive parsing of schemas - * @param node JSON node containing an object that defines a - * mapping of properties to their dependencies. - * @param currentScope URI for current resolution scope - * @param nodePath JSON Pointer representing path to current node - * @param fetchDoc Function to fetch remote JSON documents (optional) - * @param docCache Cache of resolved and fetched remote documents - * @param schemaCache Cache of populated schemas - * - * @return pointer to a new DependencyConstraint that belongs to the - * caller - */ - template - constraints::DependenciesConstraint makeDependenciesConstraint( - Schema &rootSchema, - const AdapterType &rootNode, - const AdapterType &node, - const opt::optional currentScope, - const std::string &nodePath, - const typename FunctionPtrs::FetchDoc fetchDoc, - typename DocumentCache::Type &docCache, - SchemaCache &schemaCache) - { - if (!node.maybeObject()) { - throwRuntimeError("Expected valid subschema for 'dependencies' constraint."); - } - - constraints::DependenciesConstraint dependenciesConstraint; - - // Process each of the dependency mappings defined by the object - for (const typename AdapterType::ObjectMember member : node.asObject()) { - - // First, we attempt to parse the value of the dependency mapping - // as an array of strings. If the Adapter type does not support - // strict types, then an empty string or empty object will be cast - // to an array, and the resulting dependency list will be empty. - // This is equivalent to using an empty object, but does mean that - // if the user provides an actual string then this error will not - // be detected. - if (member.second.maybeArray()) { - // Parse an array of dependency names - std::vector dependentPropertyNames; - for (const AdapterType dependencyName : member.second.asArray()) { - if (dependencyName.maybeString()) { - dependentPropertyNames.push_back(dependencyName.getString()); - } else { - throwRuntimeError("Expected string value in dependency list of property '" + - member.first + "' in 'dependencies' constraint."); - } - } - - dependenciesConstraint.addPropertyDependencies(member.first, - dependentPropertyNames); - - // If the value of dependency mapping could not be processed as an - // array, we'll try to process it as an object instead. Note that - // strict type comparison is used here, since we've already - // exercised the flexibility by loosely-typed Adapter types. If the - // value of the dependency mapping is an object, then we'll try to - // process it as a dependent schema. - } else if (member.second.isObject() || (m_version == kDraft7 && member.second.maybeBool())) { - // Parse dependent subschema - const Subschema *childSubschema = - makeOrReuseSchema(rootSchema, rootNode, - member.second, currentScope, nodePath, fetchDoc, - nullptr, nullptr, docCache, schemaCache); - dependenciesConstraint.addSchemaDependency(member.first, - childSubschema); - - // If we're supposed to be parsing a Draft3 schema, then the value - // of the dependency mapping can also be a string containing the - // name of a single dependency. - } else if (m_version == kDraft3 && member.second.isString()) { - dependenciesConstraint.addPropertyDependency(member.first, - member.second.getString()); - - // All other types result in an exception being thrown. - } else { - throwRuntimeError("Invalid dependencies definition."); - } - } - - return dependenciesConstraint; - } - - /** - * @brief Make a new EnumConstraint object. - * - * @param node JSON node containing an array of values permitted by the - * constraint. - * - * @return pointer to a new EnumConstraint that belongs to the caller - */ - template - constraints::EnumConstraint makeEnumConstraint( - const AdapterType &node) - { - // Make a copy of each value in the enum array - constraints::EnumConstraint constraint; - for (const AdapterType value : node.getArray()) { - constraint.addValue(value); - } - - /// @todo This will make another copy of the values while constructing - /// the EnumConstraint. Move semantics in C++11 should make it possible - /// to avoid these copies without complicating the implementation of the - /// EnumConstraint class. - return constraint; - } - - /** - * @brief Make a new ItemsConstraint object. - * - * @param rootSchema The Schema instance, and root subschema, - * through which other subschemas can be - * created and modified - * @param rootNode Reference to the node from which JSON - * References will be resolved when they refer - * to the current document; used for recursive - * parsing of schemas - * @param items Optional pointer to a JSON node containing - * an object mapping property names to - * schemas. - * @param additionalItems Optional pointer to a JSON node containing - * an additional properties schema or a - * boolean value. - * @param currentScope URI for current resolution scope - * @param itemsPath JSON Pointer representing the path to - * the 'items' node - * @param additionalItemsPath JSON Pointer representing the path to - * the 'additionalItems' node - * @param fetchDoc Function to fetch remote JSON documents - * (optional) - * @param docCache Cache of resolved and fetched remote - * documents - * @param schemaCache Cache of populated schemas - * - * @return pointer to a new ItemsConstraint that belongs to the caller - */ - template - constraints::LinearItemsConstraint makeLinearItemsConstraint( - Schema &rootSchema, - const AdapterType &rootNode, - const AdapterType *items, - const AdapterType *additionalItems, - const opt::optional currentScope, - const std::string &itemsPath, - const std::string &additionalItemsPath, - const typename FunctionPtrs::FetchDoc fetchDoc, - typename DocumentCache::Type &docCache, - SchemaCache &schemaCache) - { - constraints::LinearItemsConstraint constraint; - - // Construct a Schema object for the the additionalItems constraint, - // if the additionalItems property is present - if (additionalItems) { - if (additionalItems->maybeBool()) { - // If the value of the additionalItems property is a boolean - // and is set to true, then additional array items do not need - // to satisfy any constraints. - if (additionalItems->asBool()) { - constraint.setAdditionalItemsSubschema(rootSchema.emptySubschema()); - } - } else if (additionalItems->maybeObject()) { - // If the value of the additionalItems property is an object, - // then it should be parsed into a Schema object, which will be - // used to validate additional array items. - const Subschema *subschema = makeOrReuseSchema( - rootSchema, rootNode, *additionalItems, currentScope, - additionalItemsPath, fetchDoc, nullptr, nullptr, docCache, - schemaCache); - constraint.setAdditionalItemsSubschema(subschema); - } else { - // Any other format for the additionalItems property will result - // in an exception being thrown. - throwRuntimeError("Expected bool or object value for 'additionalItems'"); - } - } else { - // The default value for the additionalItems property is an empty - // object, which means that additional array items do not need to - // satisfy any constraints. - constraint.setAdditionalItemsSubschema(rootSchema.emptySubschema()); - } - - // Construct a Schema object for each item in the items array. - // If the items constraint is not provided, then array items - // will be validated against the additionalItems schema. - if (items) { - if (items->isArray()) { - // If the items constraint contains an array, then it should - // contain a list of child schemas which will be used to - // validate the values at the corresponding indexes in a target - // array. - int index = 0; - for (const AdapterType v : items->getArray()) { - const std::string childPath = itemsPath + "/" + - std::to_string(index); - const Subschema *subschema = makeOrReuseSchema( - rootSchema, rootNode, v, currentScope, childPath, - fetchDoc, nullptr, nullptr, docCache, schemaCache); - constraint.addItemSubschema(subschema); - index++; - } - } else { - throwRuntimeError("Expected array value for non-singular 'items' constraint."); - } - } - - return constraint; - } - - /** - * @brief Make a new ItemsConstraint object. - * - * @param rootSchema The Schema instance, and root subschema, - * through which other subschemas can be - * created and modified - * @param rootNode Reference to the node from which JSON - * References will be resolved when they refer - * to the current document; used for recursive - * parsing of schemas - * @param items Optional pointer to a JSON node containing - * an object mapping property names to - * schemas. - * @param additionalItems Optional pointer to a JSON node containing - * an additional properties schema or a - * boolean value. - * @param currentScope URI for current resolution scope - * @param itemsPath JSON Pointer representing the path to - * the 'items' node - * @param additionalItemsPath JSON Pointer representing the path to - * the 'additionalItems' node - * @param fetchDoc Function to fetch remote JSON documents - * (optional) - * @param docCache Cache of resolved and fetched remote - * documents - * @param schemaCache Cache of populated schemas - * - * @return pointer to a new ItemsConstraint that belongs to the caller - */ - template - constraints::SingularItemsConstraint makeSingularItemsConstraint( - Schema &rootSchema, - const AdapterType &rootNode, - const AdapterType &items, - const opt::optional currentScope, - const std::string &itemsPath, - const typename FunctionPtrs::FetchDoc fetchDoc, - typename DocumentCache::Type &docCache, - SchemaCache &schemaCache) - { - constraints::SingularItemsConstraint constraint; - - // Construct a Schema object for each item in the items array, if an - // array is provided, or a single Schema object, in an object value is - // provided. If the items constraint is not provided, then array items - // will be validated against the additionalItems schema. - if (items.isObject() || (m_version == kDraft7 && items.maybeBool())) { - // If the items constraint contains an object value, then it - // should contain a Schema that will be used to validate all - // items in a target array. Any schema defined by the - // additionalItems constraint will be ignored. - const Subschema *subschema = makeOrReuseSchema( - rootSchema, rootNode, items, currentScope, itemsPath, - fetchDoc, nullptr, nullptr, docCache, schemaCache); - constraint.setItemsSubschema(subschema); - - } else if (items.maybeObject()) { - // If a loosely-typed Adapter type is being used, then we'll - // assume that an empty schema has been provided. - constraint.setItemsSubschema(rootSchema.emptySubschema()); - - } else { - // All other formats will result in an exception being thrown. - throwRuntimeError("Expected valid schema for singular 'items' constraint."); - } - - return constraint; - } - - /** - * @brief Make a new MaximumConstraint object (draft 3 and 4). - * - * @param rootSchema The Schema instance, and root subschema, - * through which other subschemas can be - * created and modified - * @param rootNode Reference to the node from which JSON - * References will be resolved when they refer - * to the current document; used for recursive - * parsing of schemas - * @param node JSON node containing the maximum value. - * @param exclusiveMaximum Optional pointer to a JSON boolean value that - * indicates whether maximum value is excluded - * from the range of permitted values. - * - * @return pointer to a new MaximumConstraint that belongs to the caller - */ - template - constraints::MaximumConstraint makeMaximumConstraint( - const AdapterType &node, - const AdapterType *exclusiveMaximum) - { - if (!node.maybeDouble()) { - throwRuntimeError("Expected numeric value for maximum constraint."); - } - - constraints::MaximumConstraint constraint; - constraint.setMaximum(node.asDouble()); - - if (exclusiveMaximum) { - if (!exclusiveMaximum->maybeBool()) { - throwRuntimeError("Expected boolean value for exclusiveMaximum constraint."); - } - - constraint.setExclusiveMaximum(exclusiveMaximum->asBool()); - } - - return constraint; - } - - /** - * @brief Make a new MaximumConstraint object that is always exclusive (draft 7). - * - * @param node JSON node containing an integer, representing the maximum value. - * - * @param exclusive Optional pointer to a JSON boolean value that indicates whether the - * maximum value is excluded from the range of permitted values. - * - * @return pointer to a new Maximum that belongs to the caller - */ - template - constraints::MaximumConstraint makeMaximumConstraintExclusive(const AdapterType &node) - { - if (!node.maybeDouble()) { - throwRuntimeError("Expected numeric value for exclusiveMaximum constraint."); - } - - constraints::MaximumConstraint constraint; - constraint.setMaximum(node.asDouble()); - constraint.setExclusiveMaximum(true); - return constraint; - } - - /** - * @brief Make a new MaxItemsConstraint object. - * - * @param node JSON node containing an integer value representing the - * maximum number of items that may be contaned by an array. - * - * @return pointer to a new MaxItemsConstraint that belongs to the caller. - */ - template - constraints::MaxItemsConstraint makeMaxItemsConstraint( - const AdapterType &node) - { - if (node.maybeInteger()) { - const int64_t value = node.asInteger(); - if (value >= 0) { - constraints::MaxItemsConstraint constraint; - constraint.setMaxItems(value); - return constraint; - } - } - - throwRuntimeError("Expected non-negative integer value for 'maxItems' constraint."); - } - - /** - * @brief Make a new MaxLengthConstraint object. - * - * @param node JSON node containing an integer value representing the - * maximum length of a string. - * - * @return pointer to a new MaxLengthConstraint that belongs to the caller - */ - template - constraints::MaxLengthConstraint makeMaxLengthConstraint( - const AdapterType &node) - { - if (node.maybeInteger()) { - const int64_t value = node.asInteger(); - if (value >= 0) { - constraints::MaxLengthConstraint constraint; - constraint.setMaxLength(value); - return constraint; - } - } - - throwRuntimeError("Expected a non-negative integer value for 'maxLength' constraint."); - } - - /** - * @brief Make a new MaxPropertiesConstraint object. - * - * @param node JSON node containing an integer value representing the - * maximum number of properties that may be contained by an - * object. - * - * @return pointer to a new MaxPropertiesConstraint that belongs to the - * caller - */ - template - constraints::MaxPropertiesConstraint makeMaxPropertiesConstraint( - const AdapterType &node) - { - if (node.maybeInteger()) { - int64_t value = node.asInteger(); - if (value >= 0) { - constraints::MaxPropertiesConstraint constraint; - constraint.setMaxProperties(value); - return constraint; - } - } - - throwRuntimeError("Expected a non-negative integer for 'maxProperties' constraint."); - } - - /** - * @brief Make a new MinimumConstraint object (draft 3 and 4). - * - * @param node JSON node containing an integer, representing - * the minimum value. - * - * @param exclusiveMaximum Optional pointer to a JSON boolean value that - * indicates whether the minimum value is - * excluded from the range of permitted values. - * - * @return pointer to a new MinimumConstraint that belongs to the caller - */ - template - constraints::MinimumConstraint makeMinimumConstraint( - const AdapterType &node, - const AdapterType *exclusiveMinimum) - { - if (!node.maybeDouble()) { - throwRuntimeError("Expected numeric value for minimum constraint."); - } - - constraints::MinimumConstraint constraint; - constraint.setMinimum(node.asDouble()); - - if (exclusiveMinimum) { - if (!exclusiveMinimum->maybeBool()) { - throwRuntimeError("Expected boolean value for 'exclusiveMinimum' constraint."); - } - - constraint.setExclusiveMinimum(exclusiveMinimum->asBool()); - } - - return constraint; - } - - /** - * @brief Make a new MinimumConstraint object that is always exclusive (draft 7). - * - * @param node JSON node containing an integer, representing the minimum value. - * - * @param exclusive Optional pointer to a JSON boolean value that indicates whether the - * minimum value is excluded from the range of permitted values. - * - * @return pointer to a new MinimumConstraint that belongs to the caller - */ - template - constraints::MinimumConstraint makeMinimumConstraintExclusive(const AdapterType &node) - { - if (!node.maybeDouble()) { - throwRuntimeError("Expected numeric value for exclusiveMinimum constraint."); - } - - constraints::MinimumConstraint constraint; - constraint.setMinimum(node.asDouble()); - constraint.setExclusiveMinimum(true); - return constraint; - } - - /** - * @brief Make a new MinItemsConstraint object. - * - * @param node JSON node containing an integer value representing the - * minimum number of items that may be contained by an array. - * - * @return pointer to a new MinItemsConstraint that belongs to the caller - */ - template - constraints::MinItemsConstraint makeMinItemsConstraint(const AdapterType &node) - { - if (node.maybeInteger()) { - const int64_t value = node.asInteger(); - if (value >= 0) { - constraints::MinItemsConstraint constraint; - constraint.setMinItems(value); - return constraint; - } - } - - throwRuntimeError("Expected a non-negative integer value for 'minItems' constraint."); - } - - /** - * @brief Make a new MinLengthConstraint object. - * - * @param node JSON node containing an integer value representing the - * minimum length of a string. - * - * @return pointer to a new MinLengthConstraint that belongs to the caller - */ - template - constraints::MinLengthConstraint makeMinLengthConstraint(const AdapterType &node) - { - if (node.maybeInteger()) { - const int64_t value = node.asInteger(); - if (value >= 0) { - constraints::MinLengthConstraint constraint; - constraint.setMinLength(value); - return constraint; - } - } - - throwRuntimeError("Expected a non-negative integer value for 'minLength' constraint."); - } - - - /** - * @brief Make a new MaxPropertiesConstraint object. - * - * @param node JSON node containing an integer value representing the - * minimum number of properties that may be contained by an - * object. - * - * @return pointer to a new MinPropertiesConstraint that belongs to the - * caller - */ - template - constraints::MinPropertiesConstraint makeMinPropertiesConstraint(const AdapterType &node) - { - if (node.maybeInteger()) { - int64_t value = node.asInteger(); - if (value >= 0) { - constraints::MinPropertiesConstraint constraint; - constraint.setMinProperties(value); - return constraint; - } - } - - throwRuntimeError("Expected a non-negative integer for 'minProperties' constraint."); - } - - /** - * @brief Make a new MultipleOfDoubleConstraint object - * - * @param node JSON node containing an numeric value that a target value - * must divide by in order to satisfy this constraint - * - * @return a MultipleOfConstraint - */ - template - constraints::MultipleOfDoubleConstraint makeMultipleOfDoubleConstraint(const AdapterType &node) - { - constraints::MultipleOfDoubleConstraint constraint; - constraint.setDivisor(node.asDouble()); - return constraint; - } - - /** - * @brief Make a new MultipleOfIntConstraint object - * - * @param node JSON node containing a numeric value that a target value - * must divide by in order to satisfy this constraint - * - * @return a MultipleOfIntConstraint - */ - template - constraints::MultipleOfIntConstraint makeMultipleOfIntConstraint(const AdapterType &node) - { - constraints::MultipleOfIntConstraint constraint; - constraint.setDivisor(node.asInteger()); - return constraint; - } - - /** - * @brief Make a new NotConstraint object - * - * @param rootSchema The Schema instance, and root subschema, through - * which other subschemas can be created and modified - * @param rootNode Reference to the node from which JSON References - * will be resolved when they refer to the current - * document; used for recursive parsing of schemas - * @param node JSON node containing a schema - * @param currentScope URI for current resolution scope - * @param nodePath JSON Pointer representing path to current node - * @param fetchDoc Function to fetch remote JSON documents (optional) - * @param docCache Cache of resolved and fetched remote documents - * @param schemaCache Cache of populated schemas - * - * @return pointer to a new NotConstraint object that belongs to the caller - */ - template - constraints::NotConstraint makeNotConstraint( - Schema &rootSchema, - const AdapterType &rootNode, - const AdapterType &node, - const opt::optional currentScope, - const std::string &nodePath, - const typename FunctionPtrs::FetchDoc fetchDoc, - typename DocumentCache::Type &docCache, - SchemaCache &schemaCache) - { - if (node.maybeObject() || (m_version == kDraft7 && node.maybeBool())) { - const Subschema *subschema = makeOrReuseSchema( - rootSchema, rootNode, node, currentScope, nodePath, - fetchDoc, nullptr, nullptr, docCache, schemaCache); - constraints::NotConstraint constraint; - constraint.setSubschema(subschema); - return constraint; - } - - throwRuntimeError("Expected object value for 'not' constraint."); - } - - /** - * @brief Make a new OneOfConstraint object - * - * @param rootSchema The Schema instance, and root subschema, through - * which other subschemas can be created and modified - * @param rootNode Reference to the node from which JSON References - * will be resolved when they refer to the current - * document; used for recursive parsing of schemas - * @param node JSON node containing an array of child schemas - * @param currentScope URI for current resolution scope - * @param nodePath JSON Pointer representing path to current node - * @param fetchDoc Function to fetch remote JSON documents (optional) - * @param docCache Cache of resolved and fetched remote documents - * @param schemaCache Cache of populated schemas - * - * @return pointer to a new OneOfConstraint that belongs to the caller - */ - template - constraints::OneOfConstraint makeOneOfConstraint( - Schema &rootSchema, - const AdapterType &rootNode, - const AdapterType &node, - const opt::optional currentScope, - const std::string &nodePath, - const typename FunctionPtrs::FetchDoc fetchDoc, - typename DocumentCache::Type &docCache, - SchemaCache &schemaCache) - { - constraints::OneOfConstraint constraint; - - int index = 0; - for (const AdapterType schemaNode : node.getArray()) { - const std::string childPath = nodePath + "/" + std::to_string(index); - const Subschema *subschema = makeOrReuseSchema( - rootSchema, rootNode, schemaNode, currentScope, childPath, - fetchDoc, nullptr, nullptr, docCache, schemaCache); - constraint.addSubschema(subschema); - index++; - } - - return constraint; - } - - /** - * @brief Make a new PatternConstraint object. - * - * @param node JSON node containing a pattern string - * - * @return pointer to a new PatternConstraint object that belongs to the - * caller - */ - template - constraints::PatternConstraint makePatternConstraint( - const AdapterType &node) - { - constraints::PatternConstraint constraint; - constraint.setPattern(node.getString()); - return constraint; - } - - /** - * @brief Make a new Properties object. - * - * @param rootSchema The Schema instance, and root - * subschema, through which other - * subschemas can be created and modified - * @param rootNode Reference to the node from which JSON - * References will be resolved when they - * refer to the current document; used - * for recursive parsing of schemas - * @param properties Optional pointer to a JSON node - * containing an object mapping property - * names to schemas. - * @param patternProperties Optional pointer to a JSON node - * containing an object mapping pattern - * property names to schemas. - * @param additionalProperties Optional pointer to a JSON node - * containing an additional properties - * schema or a boolean value. - * @param currentScope URI for current resolution scope - * @param propertiesPath JSON Pointer representing the path to - * the 'properties' node - * @param patternPropertiesPath JSON Pointer representing the path to - * the 'patternProperties' node - * @param additionalPropertiesPath JSON Pointer representing the path to - * the 'additionalProperties' node - * @param fetchDoc Function to fetch remote JSON - * documents (optional) - * @param parentSubschema Optional pointer to the Schema of the - * parent object, needed to support the - * 'required' keyword in Draft 3 - * @param docCache Cache of resolved and fetched remote - * documents - * @param schemaCache Cache of populated schemas - * - * @return pointer to a new Properties that belongs to the caller - */ - template - constraints::PropertiesConstraint makePropertiesConstraint( - Schema &rootSchema, - const AdapterType &rootNode, - const AdapterType *properties, - const AdapterType *patternProperties, - const AdapterType *additionalProperties, - const opt::optional currentScope, - const std::string &propertiesPath, - const std::string &patternPropertiesPath, - const std::string &additionalPropertiesPath, - const typename FunctionPtrs::FetchDoc fetchDoc, - const Subschema *parentSubschema, - typename DocumentCache::Type &docCache, - SchemaCache &schemaCache) - { - typedef typename AdapterType::ObjectMember Member; - - constraints::PropertiesConstraint constraint; - - // Create subschemas for 'properties' constraint - if (properties) { - for (const Member m : properties->getObject()) { - const std::string &property = m.first; - const std::string childPath = propertiesPath + "/" + property; - const Subschema *subschema = makeOrReuseSchema( - rootSchema, rootNode, m.second, currentScope, childPath, - fetchDoc, parentSubschema, &property, docCache, - schemaCache); - constraint.addPropertySubschema(property, subschema); - } - } - - // Create subschemas for 'patternProperties' constraint - if (patternProperties) { - for (const Member m : patternProperties->getObject()) { - const std::string &pattern = m.first; - const std::string childPath = patternPropertiesPath + "/" + pattern; - const Subschema *subschema = makeOrReuseSchema( - rootSchema, rootNode, m.second, currentScope, childPath, - fetchDoc, parentSubschema, &pattern, docCache, - schemaCache); - constraint.addPatternPropertySubschema(pattern, subschema); - } - } - - // Create an additionalItems subschema if required - if (additionalProperties) { - // If additionalProperties has been set, check for a boolean value. - // Setting 'additionalProperties' to true allows the values of - // additional properties to take any form. Setting it false - // prohibits the use of additional properties. - // If additionalProperties is instead an object, it should be - // parsed as a schema. If additionalProperties has any other type, - // then the schema is not valid. - if (additionalProperties->isBool() || - additionalProperties->maybeBool()) { - // If it has a boolean value that is 'true', then an empty - // schema should be used. - if (additionalProperties->asBool()) { - constraint.setAdditionalPropertiesSubschema(rootSchema.emptySubschema()); - } - } else if (additionalProperties->isObject()) { - // If additionalProperties is an object, it should be used as - // a child schema. - const Subschema *subschema = makeOrReuseSchema( - rootSchema, rootNode, *additionalProperties, - currentScope, additionalPropertiesPath, fetchDoc, nullptr, - nullptr, docCache, schemaCache); - constraint.setAdditionalPropertiesSubschema(subschema); - } else { - // All other types are invalid - throwRuntimeError("Invalid type for 'additionalProperties' constraint."); - } - } else { - // If an additionalProperties constraint is not provided, then the - // default value is an empty schema. - constraint.setAdditionalPropertiesSubschema(rootSchema.emptySubschema()); - } - - return constraint; - } - - template - constraints::PropertyNamesConstraint makePropertyNamesConstraint( - Schema &rootSchema, - const AdapterType &rootNode, - const AdapterType ¤tNode, - const opt::optional currentScope, - const std::string &nodePath, - const typename FunctionPtrs::FetchDoc fetchDoc, - typename DocumentCache::Type &docCache, - SchemaCache &schemaCache) - { - const Subschema *subschema = makeOrReuseSchema(rootSchema, rootNode, currentNode, currentScope, - nodePath, fetchDoc, nullptr, nullptr, docCache, schemaCache); - constraints::PropertyNamesConstraint constraint; - constraint.setSubschema(subschema); - return constraint; - } - - /** - * @brief Make a new RequiredConstraint. - * - * This function is used to create new RequiredContraint objects for - * Draft 3 schemas. - * - * @param node Node containing a boolean value. - * @param name Name of the required attribute. - * - * @return pointer to a new RequiredConstraint object that belongs to the - * caller - */ - template - opt::optional - makeRequiredConstraintForSelf(const AdapterType &node, - const std::string &name) - { - if (!node.maybeBool()) { - throwRuntimeError("Expected boolean value for 'required' attribute."); - } - - if (node.asBool()) { - constraints::RequiredConstraint constraint; - constraint.addRequiredProperty(name); - return constraint; - } - - return opt::optional(); - } - - /** - * @brief Make a new RequiredConstraint. - * - * This function is used to create new RequiredContraint objects for - * Draft 4 schemas. - * - * @param node Node containing an array of strings. - * - * @return pointer to a new RequiredConstraint object that belongs to the - * caller - */ - template - constraints::RequiredConstraint makeRequiredConstraint( - const AdapterType &node) - { - constraints::RequiredConstraint constraint; - - for (const AdapterType v : node.getArray()) { - if (!v.maybeString()) { - throwRuntimeError("Expected required property name to be a string value"); - } - - constraint.addRequiredProperty(v.getString()); - } - - return constraint; - } - - /** - * @brief Make a new TypeConstraint object - * - * @param rootSchema The Schema instance, and root subschema, through - * which other subschemas can be created and modified - * @param rootNode Reference to the node from which JSON References - * will be resolved when they refer to the current - * document; used for recursive parsing of schemas - * @param node Node containing the name of a JSON type - * @param currentScope URI for current resolution scope - * @param nodePath JSON Pointer representing path to current node - * @param fetchDoc Function to fetch remote JSON documents (optional) - * @param docCache Cache of resolved and fetched remote documents - * @param schemaCache Cache of populated schemas - * - * @return pointer to a new TypeConstraint object. - */ - template - constraints::TypeConstraint makeTypeConstraint( - Schema &rootSchema, - const AdapterType &rootNode, - const AdapterType &node, - const opt::optional currentScope, - const std::string &nodePath, - const typename FunctionPtrs::FetchDoc fetchDoc, - typename DocumentCache::Type &docCache, - SchemaCache &schemaCache) - { - typedef constraints::TypeConstraint TypeConstraint; - - TypeConstraint constraint; - - if (node.maybeString()) { - const TypeConstraint::JsonType type = TypeConstraint::jsonTypeFromString(node.getString()); - if (type == TypeConstraint::kAny && m_version == kDraft4) { - throwRuntimeError("'any' type is not supported in version 4 schemas."); - } - - constraint.addNamedType(type); - - } else if (node.maybeArray()) { - int index = 0; - for (const AdapterType v : node.getArray()) { - if (v.maybeString()) { - const TypeConstraint::JsonType type = TypeConstraint::jsonTypeFromString(v.getString()); - if (type == TypeConstraint::kAny && m_version == kDraft4) { - throwRuntimeError("'any' type is not supported in version 4 schemas."); - } - - constraint.addNamedType(type); - - } else if (v.maybeObject() && m_version == kDraft3) { - const std::string childPath = nodePath + "/" + std::to_string(index); - const Subschema *subschema = makeOrReuseSchema(rootSchema, rootNode, v, currentScope, - childPath, fetchDoc, nullptr, nullptr, docCache, schemaCache); - constraint.addSchemaType(subschema); - - } else { - throwRuntimeError("Type name should be a string."); - } - - index++; - } - - } else if (node.maybeObject() && m_version == kDraft3) { - const Subschema *subschema = makeOrReuseSchema(rootSchema, rootNode, node, currentScope, - nodePath, fetchDoc, nullptr, nullptr, docCache, schemaCache); - constraint.addSchemaType(subschema); - - } else { - throwRuntimeError("Type name should be a string."); - } - - return constraint; - } - - /** - * @brief Make a new UniqueItemsConstraint object. - * - * @param node Node containing a boolean value. - * - * @return pointer to a new UniqueItemsConstraint object that belongs to - * the caller, or nullptr if the boolean value is false. - */ - template - opt::optional makeUniqueItemsConstraint(const AdapterType &node) - { - if (node.isBool() || node.maybeBool()) { - // If the boolean value is true, this function will return a pointer - // to a new UniqueItemsConstraint object. If it is value, then the - // constraint is redundant, so nullptr is returned instead. - if (node.asBool()) { - return constraints::UniqueItemsConstraint(); - } else { - return opt::optional(); - } - } - - throwRuntimeError("Expected boolean value for 'uniqueItems' constraint."); - } - -private: - - /// Version of JSON Schema that should be expected when parsing - const Version m_version; -}; - -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/subschema.hpp b/subprojects/valijson/include/valijson/subschema.hpp deleted file mode 100644 index abee6c42b..000000000 --- a/subprojects/valijson/include/valijson/subschema.hpp +++ /dev/null @@ -1,311 +0,0 @@ -#pragma once - -#include - -#include - -#include -#include -#include - -namespace valijson { - -/** - * Represents a sub-schema within a JSON Schema - * - * While all JSON Schemas have at least one sub-schema, the root, some will - * have additional sub-schemas that are defined as part of constraints that are - * included in the schema. For example, a 'oneOf' constraint maintains a set of - * references to one or more nested sub-schemas. As per the definition of a - * oneOf constraint, a document is valid within that constraint if it validates - * against one of the nested sub-schemas. - */ -class Subschema -{ -public: - - /// Typedef for custom new-/malloc-like function - typedef void * (*CustomAlloc)(size_t size); - - /// Typedef for custom free-like function - typedef void (*CustomFree)(void *); - - /// Typedef the Constraint class into the local namespace for convenience - typedef constraints::Constraint Constraint; - - /// Typedef for a function that can be applied to each of the Constraint - /// instances owned by a Schema. - typedef std::function ApplyFunction; - - // Disable copy construction - Subschema(const Subschema &) = delete; - - // Disable copy assignment - Subschema & operator=(const Subschema &) = delete; - - /** - * @brief Construct a new Subschema object - */ - Subschema() - : m_allocFn(::operator new) - , m_freeFn(::operator delete) - , m_alwaysInvalid(false) { } - - /** - * @brief Construct a new Subschema using custom memory management - * functions - * - * @param allocFn malloc- or new-like function to allocate memory - * within Schema, such as for Subschema instances - * @param freeFn free-like function to free memory allocated with - * the `customAlloc` function - */ - Subschema(CustomAlloc allocFn, CustomFree freeFn) - : m_allocFn(allocFn) - , m_freeFn(freeFn) - , m_alwaysInvalid(false) - { - // explicitly initialise optionals. See: https://github.com/tristanpenman/valijson/issues/124 - m_description = opt::nullopt; - m_id = opt::nullopt; - m_title = opt::nullopt; - } - - /** - * @brief Clean up and free all memory managed by the Subschema - */ - virtual ~Subschema() - { -#if VALIJSON_USE_EXCEPTIONS - try { -#endif - for (auto constConstraint : m_constraints) { - auto *constraint = const_cast(constConstraint); - constraint->~Constraint(); - m_freeFn(constraint); - } - m_constraints.clear(); -#if VALIJSON_USE_EXCEPTIONS - } catch (const std::exception &e) { - fprintf(stderr, "Caught an exception in Subschema destructor: %s", - e.what()); - } -#endif - } - - /** - * @brief Add a constraint to this sub-schema - * - * The constraint will be copied before being added to the list of - * constraints for this Subschema. Note that constraints will be copied - * only as deep as references to other Subschemas - e.g. copies of - * constraints that refer to sub-schemas, will continue to refer to the - * same Subschema instances. - * - * @param constraint Reference to the constraint to copy - */ - void addConstraint(const Constraint &constraint) - { - Constraint *newConstraint = constraint.clone(m_allocFn, m_freeFn); -#if VALIJSON_USE_EXCEPTIONS - try { -#endif - m_constraints.push_back(newConstraint); -#if VALIJSON_USE_EXCEPTIONS - } catch (...) { - newConstraint->~Constraint(); - m_freeFn(newConstraint); - throw; - } -#endif - } - - /** - * @brief Invoke a function on each child Constraint - * - * This function will apply the callback function to each constraint in - * the Subschema, even if one of the invokations returns \c false. However, - * if one or more invokations of the callback function return \c false, - * this function will also return \c false. - * - * @returns \c true if all invokations of the callback function are - * successful, \c false otherwise - */ - bool apply(ApplyFunction &applyFunction) const - { - bool allTrue = true; - for (const Constraint *constraint : m_constraints) { - allTrue = allTrue && applyFunction(*constraint); - } - - return allTrue; - } - - /** - * @brief Invoke a function on each child Constraint - * - * This is a stricter version of the apply() function that will return - * immediately if any of the invokations of the callback function return - * \c false. - * - * @returns \c true if all invokations of the callback function are - * successful, \c false otherwise - */ - bool applyStrict(ApplyFunction &applyFunction) const - { - for (const Constraint *constraint : m_constraints) { - if (!applyFunction(*constraint)) { - return false; - } - } - - return true; - } - - bool getAlwaysInvalid() const - { - return m_alwaysInvalid; - } - - /** - * @brief Get the description associated with this sub-schema - * - * @throws std::runtime_error if a description has not been set - * - * @returns string containing sub-schema description - */ - std::string getDescription() const - { - if (m_description) { - return *m_description; - } - - throwRuntimeError("Schema does not have a description"); - } - - /** - * @brief Get the ID associated with this sub-schema - * - * @throws std::runtime_error if an ID has not been set - * - * @returns string containing sub-schema ID - */ - std::string getId() const - { - if (m_id) { - return *m_id; - } - - throwRuntimeError("Schema does not have an ID"); - } - - /** - * @brief Get the title associated with this sub-schema - * - * @throws std::runtime_error if a title has not been set - * - * @returns string containing sub-schema title - */ - std::string getTitle() const - { - if (m_title) { - return *m_title; - } - - throwRuntimeError("Schema does not have a title"); - } - - /** - * @brief Check whether this sub-schema has a description - * - * @return boolean value - */ - bool hasDescription() const - { - return static_cast(m_description); - } - - /** - * @brief Check whether this sub-schema has an ID - * - * @return boolean value - */ - bool hasId() const - { - return static_cast(m_id); - } - - /** - * @brief Check whether this sub-schema has a title - * - * @return boolean value - */ - bool hasTitle() const - { - return static_cast(m_title); - } - - void setAlwaysInvalid(bool value) - { - m_alwaysInvalid = value; - } - - /** - * @brief Set the description for this sub-schema - * - * The description will not be used for validation, but may be used as part - * of the user interface for interacting with schemas and sub-schemas. As - * an example, it may be used as part of the validation error descriptions - * that are produced by the Validator and ValidationVisitor classes. - * - * @param description new description - */ - void setDescription(const std::string &description) - { - m_description = description; - } - - void setId(const std::string &id) - { - m_id = id; - } - - /** - * @brief Set the title for this sub-schema - * - * The title will not be used for validation, but may be used as part - * of the user interface for interacting with schemas and sub-schema. As an - * example, it may be used as part of the validation error descriptions - * that are produced by the Validator and ValidationVisitor classes. - * - * @param title new title - */ - void setTitle(const std::string &title) - { - m_title = title; - } - -protected: - - CustomAlloc m_allocFn; - - CustomFree m_freeFn; - -private: - - bool m_alwaysInvalid; - - /// List of pointers to constraints that apply to this schema. - std::vector m_constraints; - - /// Schema description (optional) - opt::optional m_description; - - /// Id to apply when resolving the schema URI - opt::optional m_id; - - /// Title string associated with the schema (optional) - opt::optional m_title; -}; - -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/utils/file_utils.hpp b/subprojects/valijson/include/valijson/utils/file_utils.hpp deleted file mode 100644 index 92757cf64..000000000 --- a/subprojects/valijson/include/valijson/utils/file_utils.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include -#include - -namespace valijson { -namespace utils { - -/** - * Load a file into a string - * - * @param path path to the file to be loaded - * @param dest string into which file should be loaded - * - * @return true if loaded, false otherwise - */ -inline bool loadFile(const std::string &path, std::string &dest) -{ - // Open file for reading - std::ifstream file(path.c_str()); - if (!file.is_open()) { - return false; - } - - // Allocate space for file contents - file.seekg(0, std::ios::end); - const std::streamoff offset = file.tellg(); - if (offset < 0 || offset > std::numeric_limits::max()) { - return false; - } - - dest.clear(); - dest.reserve(static_cast(offset)); - - // Assign file contents to destination string - file.seekg(0, std::ios::beg); - dest.assign(std::istreambuf_iterator(file), - std::istreambuf_iterator()); - - return true; -} - -} // namespace utils -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/utils/json11_utils.hpp b/subprojects/valijson/include/valijson/utils/json11_utils.hpp deleted file mode 100644 index b20b47854..000000000 --- a/subprojects/valijson/include/valijson/utils/json11_utils.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include - -#include - -#include - -namespace valijson { -namespace utils { - -inline bool loadDocument(const std::string &path, json11::Json &document) -{ - // Load schema JSON from file - std::string file; - if (!loadFile(path, file)) { - std::cerr << "Failed to load json from file '" << path << "'." << std::endl; - return false; - } - - // Parse schema - std::string err; - document = json11::Json::parse(file, err); - if (!err.empty()) { - std::cerr << "json11 failed to parse the document:" << std::endl - << "Parse error: " << err << std::endl; - return false; - } - - return true; -} - -} // namespace utils -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/utils/jsoncpp_utils.hpp b/subprojects/valijson/include/valijson/utils/jsoncpp_utils.hpp deleted file mode 100644 index 49a43b624..000000000 --- a/subprojects/valijson/include/valijson/utils/jsoncpp_utils.hpp +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include -#include -#include - -#include - -#include - -namespace valijson { -namespace utils { - -inline bool loadDocument(const std::string &path, Json::Value &document) -{ - // Load schema JSON from file - std::string file; - if (!loadFile(path, file)) { - std::cerr << "Failed to load json from file '" << path << "'." << std::endl; - return false; - } - - const auto fileLength = static_cast(file.length()); - Json::CharReaderBuilder builder; - const std::unique_ptr reader(builder.newCharReader()); - std::string err; - if (!reader->parse(file.c_str(), file.c_str() + fileLength, &document, &err)) { - std::cerr << "Jsoncpp parser failed to parse the document:" << std::endl << err; - return false; - } - return true; -} - -} // namespace utils -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/utils/nlohmann_json_utils.hpp b/subprojects/valijson/include/valijson/utils/nlohmann_json_utils.hpp deleted file mode 100644 index b3cbe205b..000000000 --- a/subprojects/valijson/include/valijson/utils/nlohmann_json_utils.hpp +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include - -#include -#include -#include - -namespace valijson { -namespace utils { - -inline bool loadDocument(const std::string &path, nlohmann::json &document) -{ - // Load schema JSON from file - std::string file; - if (!loadFile(path, file)) { - std::cerr << "Failed to load json from file '" << path << "'." - << std::endl; - return false; - } - - // Parse schema -#if VALIJSON_USE_EXCEPTION - try { - document = nlohmann::json::parse(file); - } catch (std::invalid_argument const& exception) { - std::cerr << "nlohmann::json failed to parse the document\n" - << "Parse error:" << exception.what() << "\n"; - return false; - } -#else - document = nlohmann::json::parse(file, nullptr, false); - if (document.is_discarded()) { - std::cerr << "nlohmann::json failed to parse the document."; - return false; - } -#endif - - return true; -} - -} // namespace utils -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/utils/picojson_utils.hpp b/subprojects/valijson/include/valijson/utils/picojson_utils.hpp deleted file mode 100644 index 36420d2e0..000000000 --- a/subprojects/valijson/include/valijson/utils/picojson_utils.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -#include - -#ifdef _MSC_VER -#pragma warning(disable: 4706) -#include -#pragma warning(default: 4706) -#else -#include -#endif - -#include - -namespace valijson { -namespace utils { - -inline bool loadDocument(const std::string &path, picojson::value &document) -{ - // Load schema JSON from file - std::string file; - if (!loadFile(path, file)) { - std::cerr << "Failed to load json from file '" << path << "'." << std::endl; - return false; - } - - // Parse schema - std::string err = picojson::parse(document, file); - if (!err.empty()) { - std::cerr << "PicoJson failed to parse the document:" << std::endl - << "Parse error: " << err << std::endl; - return false; - } - - return true; -} - -} // namespace utils -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/utils/poco_json_utils.hpp b/subprojects/valijson/include/valijson/utils/poco_json_utils.hpp deleted file mode 100644 index 145cec346..000000000 --- a/subprojects/valijson/include/valijson/utils/poco_json_utils.hpp +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include - -#include -#include -#include - -#include - -namespace valijson { -namespace utils { - -inline bool loadDocument(const std::string &path, Poco::Dynamic::Var &document) -{ - // Load schema JSON from file - std::string file; - if (!loadFile(path, file)) { - std::cerr << "Failed to load json from file '" << path << "'." - << std::endl; - return false; - } - - // Parse schema - try { - document = Poco::JSON::Parser().parse(file); - } catch (Poco::Exception const& exception) { - std::cerr << "Poco::JSON failed to parse the document\n" - << "Parse error:" << exception.what() << "\n"; - return false; - } - - return true; -} - -} // namespace utils -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/utils/property_tree_utils.hpp b/subprojects/valijson/include/valijson/utils/property_tree_utils.hpp deleted file mode 100644 index 2317f127c..000000000 --- a/subprojects/valijson/include/valijson/utils/property_tree_utils.hpp +++ /dev/null @@ -1,74 +0,0 @@ -#pragma once - -#include -#include - -#include -#include - -#if defined(__clang__) -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wshadow" -# include -# pragma clang diagnostic pop -#else -# include -#endif - -// Source locations were added in boost 1.73. -#include -#if (BOOST_VERSION > 107300) -#include -#endif - -#include -#include - -#if !VALIJSON_USE_EXCEPTION - -namespace boost { - -// Boost requires used-defined exception throwers when exceptions are -// disabled. -// NOTE: BOOST_NORETURN attribute was added in 1.71. -#if (BOOST_VERSION >= 107100) -BOOST_NORETURN -#endif -void throw_exception(std::exception const & e ) { - valijson::throwRuntimeError(e.what()); -} - -// Source location override was added in 1.73. -#if (BOOST_VERSION >= 107300) -BOOST_NORETURN -void throw_exception(std::exception const & e, boost::source_location const & loc ) { - valijson::throwRuntimeError(e.what()); -} -#endif - -} // namespace boost - -#endif - -namespace valijson { -namespace utils { - -inline bool loadDocument(const std::string &path, boost::property_tree::ptree &document) -{ -#if !defined(BOOST_NO_EXCEPTIONS) - try { -#endif - boost::property_tree::read_json(path, document); -#if !defined(BOOST_NO_EXCEPTIONS) - } catch (std::exception &e) { - std::cerr << "Boost Property Tree JSON parser failed to parse the document:" << std::endl; - std::cerr << e.what() << std::endl; - return false; - } -#endif - - return true; -} - -} // namespace utils -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/utils/qtjson_utils.hpp b/subprojects/valijson/include/valijson/utils/qtjson_utils.hpp deleted file mode 100644 index c05b0f0b6..000000000 --- a/subprojects/valijson/include/valijson/utils/qtjson_utils.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include - -#include -#include -#include - -#include - -namespace valijson { -namespace utils { - -inline bool loadDocument(const std::string &path, QJsonValue &root) -{ - // Load schema JSON from file - QFile file(QString::fromStdString(path)); - if (!file.open(QFile::ReadOnly)) { - std::cerr << "Failed to load json from file '" << path << "'." << std::endl; - return false; - } - - QByteArray data = file.readAll(); - - // Parse schema - QJsonParseError parseError; - QJsonDocument doc = QJsonDocument::fromJson(data); - if (doc.isNull()) { - std::cerr << "qt failed to parse the document:" << std::endl - << parseError.errorString().toStdString() << std::endl; - return false; - } else if (doc.isObject()) { - root = QJsonValue(doc.object()); - } else if (doc.isArray()) { - root = QJsonValue(doc.array()); - } else if (doc.isEmpty()) { - root = QJsonValue(); - } - - return true; -} - -} // namespace utils -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/utils/rapidjson_utils.hpp b/subprojects/valijson/include/valijson/utils/rapidjson_utils.hpp deleted file mode 100644 index 2f90ba933..000000000 --- a/subprojects/valijson/include/valijson/utils/rapidjson_utils.hpp +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#include -#include - -#include - -#include - -namespace valijson { -namespace utils { - -template -inline bool loadDocument(const std::string &path, rapidjson::GenericDocument &document) -{ - // Load schema JSON from file - std::string file; - if (!loadFile(path, file)) { - std::cerr << "Failed to load json from file '" << path << "'." << std::endl; - return false; - } - - // Parse schema -#if VALIJSON_USE_EXCEPTIONS - try { -#endif - document.template Parse(file.c_str()); - if (document.HasParseError()) { - std::cerr << "RapidJson failed to parse the document:" << std::endl; - std::cerr << "Parse error: " << document.GetParseError() << std::endl; - std::cerr << "Near: " << file.substr((std::max)(size_t(0), document.GetErrorOffset() - 20), 40) << std::endl; - return false; - } -#if VALIJSON_USE_EXCEPTIONS - } catch (const std::runtime_error &e) { - std::cerr << "RapidJson failed to parse the document:" << std::endl; - std::cerr << "Runtime error: " << e.what() << std::endl; - return false; - } -#endif - - return true; -} - -} // namespace utils -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/utils/utf8_utils.hpp b/subprojects/valijson/include/valijson/utils/utf8_utils.hpp deleted file mode 100644 index f1e01a547..000000000 --- a/subprojects/valijson/include/valijson/utils/utf8_utils.hpp +++ /dev/null @@ -1,63 +0,0 @@ -#pragma once - -#include -#include -#include - -#include - -/* - Basic UTF-8 manipulation routines, adapted from code that was released into - the public domain by Jeff Bezanson. -*/ - -namespace valijson { -namespace utils { - -static const uint32_t offsetsFromUTF8[6] = { - 0x00000000UL, 0x00003080UL, 0x000E2080UL, - 0x03C82080UL, 0xFA082080UL, 0x82082080UL -}; - -/* is c the start of a utf8 sequence? */ -inline bool isutf(char c) { - return ((c & 0xC0) != 0x80); -} - -/* reads the next utf-8 sequence out of a string, updating an index */ -inline uint64_t u8_nextchar(const char *s, uint64_t *i) -{ - uint64_t ch = 0; - int sz = 0; - - do { - ch <<= 6; - ch += static_cast(s[(*i)++]); - sz++; - } while (s[*i] && !isutf(s[*i])); - ch -= offsetsFromUTF8[sz-1]; - - return ch; -} - -/* number of characters */ -inline uint64_t u8_strlen(const char *s) -{ - constexpr auto maxLength = std::numeric_limits::max(); - uint64_t count = 0; - uint64_t i = 0; - - while (s[i] != 0 && u8_nextchar(s, &i) != 0) { - if (i == maxLength) { - throwRuntimeError( - "String exceeded maximum size of " + - std::to_string(maxLength) + " bytes."); - } - count++; - } - - return count; -} - -} // namespace utils -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/validation_results.hpp b/subprojects/valijson/include/valijson/validation_results.hpp deleted file mode 100644 index b82131793..000000000 --- a/subprojects/valijson/include/valijson/validation_results.hpp +++ /dev/null @@ -1,107 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace valijson { - -/** - * @brief Class that encapsulates the storage of validation errors. - * - * This class maintains an internal FIFO queue of errors that are reported - * during validation. Errors are pushed on to the back of an internal - * queue, and can retrieved by popping them from the front of the queue. - */ -class ValidationResults -{ -public: - - /** - * @brief Describes a validation error. - * - * This struct is used to pass around the context and description of a - * validation error. - */ - struct Error - { - /// Path to the node that failed validation. - std::vector context; - - /// A detailed description of the validation error. - std::string description; - }; - - /** - * @brief Return begin iterator for results in the queue. - */ - std::deque::const_iterator begin() const - { - return m_errors.begin(); - } - - /** - * @brief Return end iterator for results in the queue. - */ - std::deque::const_iterator end() const - { - return m_errors.end(); - } - - /** - * @brief Return the number of errors in the queue. - */ - size_t numErrors() const - { - return m_errors.size(); - } - - /** - * @brief Copy an Error and push it on to the back of the queue. - * - * @param error Reference to an Error object to be copied. - */ - void pushError(const Error &error) - { - m_errors.push_back(error); - } - - /** - * @brief Push an error onto the back of the queue. - * - * @param context Context of the validation error. - * @param description Description of the validation error. - */ - void - pushError(const std::vector &context, const std::string &description) - { - m_errors.push_back({context, description}); - } - - /** - * @brief Pop an error from the front of the queue. - * - * @param error Reference to an Error object to populate. - * - * @returns true if an Error was popped, false otherwise. - */ - bool - popError(Error &error) - { - if (m_errors.empty()) { - return false; - } - - error = m_errors.front(); - m_errors.pop_front(); - return true; - } - -private: - - /// FIFO queue of validation errors that have been reported - std::deque m_errors; -}; - -} // namespace valijson diff --git a/subprojects/valijson/include/valijson/validation_visitor.hpp b/subprojects/valijson/include/valijson/validation_visitor.hpp deleted file mode 100644 index cd4442d7c..000000000 --- a/subprojects/valijson/include/valijson/validation_visitor.hpp +++ /dev/null @@ -1,1792 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#ifdef _MSC_VER -#pragma warning( push ) -#pragma warning( disable : 4702 ) -#endif - -namespace valijson { - -class ValidationResults; - -/** - * @brief Implementation of the ConstraintVisitor interface that validates a - * target document - * - * @tparam AdapterType Adapter type for the target document. - */ -template -class ValidationVisitor: public constraints::ConstraintVisitor -{ -public: - - /** - * @brief Construct a new validator for a given target value and context. - * - * @param target Target value to be validated - * @param context Current context for validation error descriptions, - * only used if results is set. - * @param strictTypes Use strict type comparison - * @param results Optional pointer to ValidationResults object, for - * recording error descriptions. If this pointer is set - * to nullptr, validation errors will caused validation to - * stop immediately. - * @param regexesCache Cache of already created std::regex objects for pattern - * constraints. - */ - ValidationVisitor(const AdapterType &target, - std::vector context, - const bool strictTypes, - ValidationResults *results, - std::unordered_map& regexesCache) - : m_target(target), - m_context(std::move(context)), - m_results(results), - m_strictTypes(strictTypes), - m_regexesCache(regexesCache) { } - - /** - * @brief Validate the target against a schema. - * - * When a ValidationResults object has been set via the 'results' member - * variable, validation will proceed as long as no fatal errors occur, - * with error descriptions added to the ValidationResults object. - * - * If a pointer to a ValidationResults instance is not provided, validation - * will only continue for as long as the constraints are validated - * successfully. - * - * @param subschema Sub-schema that the target must validate against - * - * @return \c true if validation passes; \c false otherwise - */ - bool validateSchema(const Subschema &subschema) - { - if (subschema.getAlwaysInvalid()) { - return false; - } - - // Wrap the validationCallback() function below so that it will be - // passed a reference to a constraint (_1), and a reference to the - // visitor (*this). - Subschema::ApplyFunction fn(std::bind(validationCallback, std::placeholders::_1, std::ref(*this))); - - // Perform validation against each constraint defined in the schema - if (m_results == nullptr) { - // The applyStrict() function will return immediately if the - // callback function returns false - if (!subschema.applyStrict(fn)) { - return false; - } - } else { - // The apply() function will iterate over all constraints in the - // schema, even if the callback function returns false. Once - // iteration is complete, the apply() function will return true - // only if all invokations of the callback function returned true. - if (!subschema.apply(fn)) { - return false; - } - } - - return true; - } - - /** - * @brief Validate a value against an AllOfConstraint - * - * An allOf constraint provides a set of child schemas against which the - * target must be validated in order for the constraint to the satifisfied. - * - * When a ValidationResults object has been set via the 'results' member - * variable, validation will proceed as long as no fatal errors occur, - * with error descriptions added to the ValidationResults object. - * - * If a pointer to a ValidationResults instance is not provided, validation - * will only continue for as long as the child schemas are validated - * successfully. - * - * @param constraint Constraint that the target must validate against - * - * @return \c true if validation passes; \c false otherwise - */ - bool visit(const AllOfConstraint &constraint) override - { - bool validated = true; - constraint.applyToSubschemas( - ValidateSubschemas(m_target, m_context, true, false, *this, m_results, nullptr, &validated)); - - return validated; - } - - /** - * @brief Validate a value against an AnyOfConstraint - * - * An anyOf constraint provides a set of child schemas, any of which the - * target may be validated against in order for the constraint to the - * satifisfied. - * - * Because an anyOf constraint does not require the target to validate - * against all child schemas, if validation against a single schema fails, - * the results will not be added to a ValidationResults object. Only if - * validation fails for all child schemas will an error be added to the - * ValidationResults object. - * - * @param constraint Constraint that the target must validate against - * - * @return \c true if validation passes; \c false otherwise - */ - bool visit(const AnyOfConstraint &constraint) override - { - unsigned int numValidated = 0; - - ValidationResults newResults; - ValidationResults *childResults = (m_results) ? &newResults : nullptr; - - ValidationVisitor v(m_target, m_context, m_strictTypes, childResults, m_regexesCache); - constraint.applyToSubschemas( - ValidateSubschemas(m_target, m_context, false, true, v, childResults, &numValidated, nullptr)); - - if (numValidated == 0 && m_results) { - ValidationResults::Error childError; - while (childResults->popError(childError)) { - m_results->pushError( childError.context, childError.description); - } - m_results->pushError(m_context, "Failed to validate against any schemas allowed by anyOf constraint."); - } - - return numValidated > 0; - } - - /** - * @brief Validate current node using a set of 'if', 'then' and 'else' subschemas - * - * A conditional constraint allows a document to be validated against one of two additional - * subschemas (specified via 'then' or 'else' properties) depending on whether the document - * satifies an optional subschema (specified via the 'if' property). - * - * @param constraint ConditionalConstraint that the current node must validate against - * - * @return \c true if validation passes; \c false otherwise - */ - bool visit(const ConditionalConstraint &constraint) override - { - ValidationResults newResults; - ValidationResults* conditionalResults = (m_results) ? &newResults : nullptr; - - // Create a validator to evaluate the conditional - ValidationVisitor ifValidator(m_target, m_context, m_strictTypes, nullptr, m_regexesCache); - ValidationVisitor thenElseValidator(m_target, m_context, m_strictTypes, conditionalResults, m_regexesCache); - - bool validated = false; - if (ifValidator.validateSchema(*constraint.getIfSubschema())) { - const Subschema *thenSubschema = constraint.getThenSubschema(); - validated = thenSubschema == nullptr || thenElseValidator.validateSchema(*thenSubschema); - } else { - const Subschema *elseSubschema = constraint.getElseSubschema(); - validated = elseSubschema == nullptr || thenElseValidator.validateSchema(*elseSubschema); - } - - if (!validated && m_results) { - ValidationResults::Error conditionalError; - while (conditionalResults->popError(conditionalError)) { - m_results->pushError(conditionalError.context, conditionalError.description); - } - m_results->pushError(m_context, "Failed to validate against a conditional schema set by if-then-else constraints."); - } - - return validated; - } - - /** - * @brief Validate current node using a 'const' constraint - * - * A const constraint allows a document to be validated against a specific value. - * - * @param constraint ConstConstraint that the current node must validate against - * - * @return \c true if validation passes; \f false otherwise - */ - bool visit(const ConstConstraint &constraint) override - { - if (!constraint.getValue()->equalTo(m_target, m_strictTypes)) { - if (m_results) { - m_results->pushError(m_context, "Failed to match expected value set by 'const' constraint."); - } - return false; - } - - return true; - } - - /** - * @brief Validate current node using a 'contains' constraint - * - * A contains constraint is satisfied if the target is not an array, or if it is an array, - * only if it contains at least one value that matches the specified schema. - * - * @param constraint ContainsConstraint that the current node must validate against - * - * @return \c true if validation passes; \c false otherwise - */ - bool visit(const ContainsConstraint &constraint) override - { - if ((m_strictTypes && !m_target.isArray()) || !m_target.maybeArray()) { - return true; - } - - const Subschema *subschema = constraint.getSubschema(); - const typename AdapterType::Array arr = m_target.asArray(); - - bool validated = false; - for (const auto &el : arr) { - ValidationVisitor containsValidator(el, m_context, m_strictTypes, nullptr, m_regexesCache); - if (containsValidator.validateSchema(*subschema)) { - validated = true; - break; - } - } - - if (!validated) { - if (m_results) { - m_results->pushError(m_context, "Failed to any values against subschema in 'contains' constraint."); - } - - return false; - } - - return validated; - } - - /** - * @brief Validate current node against a 'dependencies' constraint - * - * A 'dependencies' constraint can be used to specify property-based or - * schema-based dependencies that must be fulfilled when a particular - * property is present in an object. - * - * Property-based dependencies define a set of properties that must be - * present in addition to a particular property, whereas a schema-based - * dependency defines an additional schema that the current document must - * validate against. - * - * @param constraint DependenciesConstraint that the current node - * must validate against - * - * @return \c true if validation passes; \c false otherwise - */ - bool visit(const DependenciesConstraint &constraint) override - { - // Ignore non-objects - if ((m_strictTypes && !m_target.isObject()) || (!m_target.maybeObject())) { - return true; - } - - // Object to be validated - const typename AdapterType::Object object = m_target.asObject(); - - // Cleared if validation fails - bool validated = true; - - // Iterate over all dependent properties defined by this constraint, - // invoking the DependentPropertyValidator functor once for each - // set of dependent properties - constraint.applyToPropertyDependencies(ValidatePropertyDependencies(object, m_context, m_results, &validated)); - if (!m_results && !validated) { - return false; - } - - // Iterate over all dependent schemas defined by this constraint, - // invoking the DependentSchemaValidator function once for each schema - // that must be validated if a given property is present - constraint.applyToSchemaDependencies(ValidateSchemaDependencies( - object, m_context, *this, m_results, &validated)); - if (!m_results && !validated) { - return false; - } - - return validated; - } - - /** - * @brief Validate current node against an EnumConstraint - * - * Validation succeeds if the target is equal to one of the values provided - * by the EnumConstraint. - * - * @param constraint Constraint that the target must validate against - * - * @return \c true if validation succeeds; \c false otherwise - */ - bool visit(const EnumConstraint &constraint) override - { - unsigned int numValidated = 0; - constraint.applyToValues( - ValidateEquality(m_target, m_context, false, true, m_strictTypes, nullptr, &numValidated)); - - if (numValidated == 0) { - if (m_results) { - m_results->pushError(m_context, "Failed to match against any enum values."); - } - - return false; - } - - return numValidated > 0; - } - - /** - * @brief Validate a value against a LinearItemsConstraint - * - * A LinearItemsConstraint represents an 'items' constraint that specifies, - * for each item in array, an individual sub-schema that the item must - * validate against. The LinearItemsConstraint class also captures the - * presence of an 'additionalItems' constraint, which specifies a default - * sub-schema that should be used if an array contains more items than - * there are sub-schemas in the 'items' constraint. - * - * If the current value is not an array, validation always succeeds. - * - * @param constraint SingularItemsConstraint to validate against - * - * @returns \c true if validation is successful; \c false otherwise - */ - bool visit(const LinearItemsConstraint &constraint) override - { - // Ignore values that are not arrays - if ((m_strictTypes && !m_target.isArray()) || (!m_target.maybeArray())) { - return true; - } - - // Sub-schema to validate against when number of items in array exceeds - // the number of sub-schemas provided by the 'items' constraint - const Subschema * const additionalItemsSubschema = constraint.getAdditionalItemsSubschema(); - - // Track how many items are validated using 'items' constraint - unsigned int numValidated = 0; - - // Array to validate - const typename AdapterType::Array arr = m_target.asArray(); - const size_t arrSize = arr.size(); - - // Track validation status - bool validated = true; - - // Validate as many items as possible using 'items' sub-schemas - const size_t itemSubschemaCount = constraint.getItemSubschemaCount(); - if (itemSubschemaCount > 0) { - if (!additionalItemsSubschema) { - if (arrSize > itemSubschemaCount) { - if (!m_results) { - return false; - } - m_results->pushError(m_context, "Array contains more items than allowed by items constraint."); - validated = false; - } - } - - constraint.applyToItemSubschemas( - ValidateItems(arr, m_context, true, m_results != nullptr, m_strictTypes, m_results, &numValidated, - &validated, m_regexesCache)); - - if (!m_results && !validated) { - return false; - } - } - - // Validate remaining items using 'additionalItems' sub-schema - if (numValidated < arrSize) { - if (additionalItemsSubschema) { - // Begin validation from the first item not validated against - // an sub-schema provided by the 'items' constraint - unsigned int index = numValidated; - typename AdapterType::Array::const_iterator begin = arr.begin(); - begin.advance(numValidated); - for (typename AdapterType::Array::const_iterator itr = begin; - itr != arr.end(); ++itr) { - - // Update context for current array item - std::vector newContext = m_context; - newContext.push_back("[" + std::to_string(index) + "]"); - - ValidationVisitor validator(*itr, newContext, m_strictTypes, m_results, m_regexesCache); - - if (!validator.validateSchema(*additionalItemsSubschema)) { - if (m_results) { - m_results->pushError(m_context, "Failed to validate item #" + std::to_string(index) + - " against additional items schema."); - validated = false; - } else { - return false; - } - } - - index++; - } - - } else if (m_results) { - m_results->pushError(m_context, "Cannot validate item #" + std::to_string(numValidated) + - " or greater using 'items' constraint or 'additionalItems' constraint."); - validated = false; - - } else { - return false; - } - } - - return validated; - } - - /** - * @brief Validate a value against a MaximumConstraint object - * - * @param constraint Constraint that the target must validate against - * - * @return \c true if constraints are satisfied; \c false otherwise - */ - bool visit(const MaximumConstraint &constraint) override - { - if ((m_strictTypes && !m_target.isNumber()) || !m_target.maybeDouble()) { - // Ignore values that are not numbers - return true; - } - - const double maximum = constraint.getMaximum(); - - if (constraint.getExclusiveMaximum()) { - if (m_target.asDouble() >= maximum) { - if (m_results) { - m_results->pushError(m_context, "Expected number less than " + std::to_string(maximum)); - } - - return false; - } - - } else if (m_target.asDouble() > maximum) { - if (m_results) { - m_results->pushError(m_context, "Expected number less than or equal to " + std::to_string(maximum)); - } - - return false; - } - - return true; - } - - /** - * @brief Validate a value against a MaxItemsConstraint - * - * @param constraint Constraint that the target must validate against - * - * @return \c true if constraint is satisfied; \c false otherwise - */ - bool visit(const MaxItemsConstraint &constraint) override - { - if ((m_strictTypes && !m_target.isArray()) || !m_target.maybeArray()) { - return true; - } - - const uint64_t maxItems = constraint.getMaxItems(); - if (m_target.asArray().size() <= maxItems) { - return true; - } - - if (m_results) { - m_results->pushError(m_context, "Array should contain no more than " + std::to_string(maxItems) + - " elements."); - } - - return false; - } - - /** - * @brief Validate a value against a MaxLengthConstraint - * - * @param constraint Constraint that the target must validate against - * - * @return \c true if constraint is satisfied; \c false otherwise - */ - bool visit(const MaxLengthConstraint &constraint) override - { - if ((m_strictTypes && !m_target.isString()) || !m_target.maybeString()) { - return true; - } - - const std::string s = m_target.asString(); - const uint64_t len = utils::u8_strlen(s.c_str()); - const uint64_t maxLength = constraint.getMaxLength(); - if (len <= maxLength) { - return true; - } - - if (m_results) { - m_results->pushError(m_context, "String should be no more than " + std::to_string(maxLength) + - " characters in length."); - } - - return false; - } - - /** - * @brief Validate a value against a MaxPropertiesConstraint - * - * @param constraint Constraint that the target must validate against - * - * @return \c true if the constraint is satisfied; \c false otherwise - */ - bool visit(const MaxPropertiesConstraint &constraint) override - { - if ((m_strictTypes && !m_target.isObject()) || !m_target.maybeObject()) { - return true; - } - - const uint64_t maxProperties = constraint.getMaxProperties(); - - if (m_target.asObject().size() <= maxProperties) { - return true; - } - - if (m_results) { - m_results->pushError(m_context, "Object should have no more than " + std::to_string(maxProperties) + - " properties."); - } - - return false; - } - - /** - * @brief Validate a value against a MinimumConstraint - * - * @param constraint Constraint that the target must validate against - * - * @return \c true if the constraint is satisfied; \c false otherwise - */ - bool visit(const MinimumConstraint &constraint) override - { - if ((m_strictTypes && !m_target.isNumber()) || !m_target.maybeDouble()) { - // Ignore values that are not numbers - return true; - } - - const double minimum = constraint.getMinimum(); - - if (constraint.getExclusiveMinimum()) { - if (m_target.asDouble() <= minimum) { - if (m_results) { - m_results->pushError(m_context, "Expected number greater than " + std::to_string(minimum)); - } - - return false; - } - } else if (m_target.asDouble() < minimum) { - if (m_results) { - m_results->pushError(m_context, "Expected number greater than or equal to " + std::to_string(minimum)); - } - - return false; - } - - return true; - } - - /** - * @brief Validate a value against a MinItemsConstraint - * - * @param constraint Constraint that the target must validate against - * - * @return \c true if the constraint is satisfied; \c false otherwise - */ - bool visit(const MinItemsConstraint &constraint) override - { - if ((m_strictTypes && !m_target.isArray()) || !m_target.maybeArray()) { - return true; - } - - const uint64_t minItems = constraint.getMinItems(); - if (m_target.asArray().size() >= minItems) { - return true; - } - - if (m_results) { - m_results->pushError(m_context, "Array should contain no fewer than " + std::to_string(minItems) + - " elements."); - } - - return false; - } - - /** - * @brief Validate a value against a MinLengthConstraint - * - * @param constraint Constraint that the target must validate against - * - * @return \c true if the constraint is satisfied; \c false otherwise - */ - bool visit(const MinLengthConstraint &constraint) override - { - if ((m_strictTypes && !m_target.isString()) || !m_target.maybeString()) { - return true; - } - - const std::string s = m_target.asString(); - const uint64_t len = utils::u8_strlen(s.c_str()); - const uint64_t minLength = constraint.getMinLength(); - if (len >= minLength) { - return true; - } - - if (m_results) { - m_results->pushError(m_context, "String should be no fewer than " + std::to_string(minLength) + - " characters in length."); - } - - return false; - } - - /** - * @brief Validate a value against a MinPropertiesConstraint - * - * @param constraint Constraint that the target must validate against - * - * @return \c true if the constraint is satisfied; \c false otherwise - */ - bool visit(const MinPropertiesConstraint &constraint) override - { - if ((m_strictTypes && !m_target.isObject()) || !m_target.maybeObject()) { - return true; - } - - const uint64_t minProperties = constraint.getMinProperties(); - - if (m_target.asObject().size() >= minProperties) { - return true; - } - - if (m_results) { - m_results->pushError(m_context, "Object should have no fewer than " + std::to_string(minProperties) + - " properties."); - } - - return false; - } - - /** - * @brief Validate a value against a MultipleOfDoubleConstraint - * - * @param constraint Constraint that the target must validate against - * - * @return \c true if the constraint is satisfied; \c false otherwise - */ - bool visit(const MultipleOfDoubleConstraint &constraint) override - { - const double divisor = constraint.getDivisor(); - - double d = 0.; - if (m_target.maybeDouble()) { - if (!m_target.asDouble(d)) { - if (m_results) { - m_results->pushError(m_context, "Value could not be converted " - "to a number to check if it is a multiple of " + std::to_string(divisor)); - } - return false; - } - } else if (m_target.maybeInteger()) { - int64_t i = 0; - if (!m_target.asInteger(i)) { - if (m_results) { - m_results->pushError(m_context, "Value could not be converted " - "to a number to check if it is a multiple of " + std::to_string(divisor)); - } - return false; - } - d = static_cast(i); - } else { - return true; - } - - if (d == 0) { - return true; - } - - const double r = remainder(d, divisor); - - if (fabs(r) > std::numeric_limits::epsilon()) { - if (m_results) { - m_results->pushError(m_context, "Value should be a multiple of " + std::to_string(divisor)); - } - return false; - } - - return true; - } - - /** - * @brief Validate a value against a MultipleOfIntConstraint - * - * @param constraint Constraint that the target must validate against - * - * @return \c true if the constraint is satisfied; \c false otherwise - */ - bool visit(const MultipleOfIntConstraint &constraint) override - { - const int64_t divisor = constraint.getDivisor(); - - int64_t i = 0; - if (m_target.maybeInteger()) { - if (!m_target.asInteger(i)) { - if (m_results) { - m_results->pushError(m_context, "Value could not be converted to an integer for multipleOf check"); - } - return false; - } - } else if (m_target.maybeDouble()) { - double d; - if (!m_target.asDouble(d)) { - if (m_results) { - m_results->pushError(m_context, "Value could not be converted to a double for multipleOf check"); - } - return false; - } - i = static_cast(d); - } else { - return true; - } - - if (i == 0) { - return true; - } - - if (i % divisor != 0) { - if (m_results) { - m_results->pushError(m_context, "Value should be a multiple of " + std::to_string(divisor)); - } - return false; - } - - return true; - } - - /** - * @brief Validate a value against a NotConstraint - * - * If the subschema NotConstraint currently holds a nullptr, the - * schema will be treated like the empty schema. Therefore validation - * will always fail. - * - * @param constraint Constraint that the target must validate against - * - * @return \c true if the constraint is satisfied; \c false otherwise - */ - bool visit(const NotConstraint &constraint) override - { - const Subschema *subschema = constraint.getSubschema(); - if (!subschema) { - // Treat nullptr like empty schema - return false; - } - - ValidationVisitor v(m_target, m_context, m_strictTypes, nullptr, m_regexesCache); - if (v.validateSchema(*subschema)) { - if (m_results) { - m_results->pushError(m_context, - "Target should not validate against schema specified in 'not' constraint."); - } - - return false; - } - - return true; - } - - /** - * @brief Validate a value against a OneOfConstraint - * - * @param constraint Constraint that the target must validate against - * - * @return \c true if the constraint is satisfied; \c false otherwise - */ - bool visit(const OneOfConstraint &constraint) override - { - unsigned int numValidated = 0; - - ValidationResults newResults; - ValidationResults *childResults = (m_results) ? &newResults : nullptr; - - ValidationVisitor v(m_target, m_context, m_strictTypes, childResults, m_regexesCache); - constraint.applyToSubschemas( - ValidateSubschemas(m_target, m_context, true, true, v, childResults, &numValidated, nullptr)); - - if (numValidated == 0) { - if (m_results) { - ValidationResults::Error childError; - while (childResults->popError(childError)) { - m_results->pushError( - childError.context, - childError.description); - } - m_results->pushError(m_context, "Failed to validate against any " - "child schemas allowed by oneOf constraint."); - } - return false; - } else if (numValidated != 1) { - if (m_results) { - m_results->pushError(m_context, "Failed to validate against exactly one child schema."); - } - return false; - } - - return true; - } - - /** - * @brief Validate a value against a PatternConstraint - * - * @param constraint Constraint that the target must validate against - * - * @return \c true if the constraint is satisfied; \c false otherwise - */ - bool visit(const PatternConstraint &constraint) override - { - if ((m_strictTypes && !m_target.isString()) || !m_target.maybeString()) { - return true; - } - - std::string pattern(constraint.getPattern()); - auto it = m_regexesCache.find(pattern); - if (it == m_regexesCache.end()) { - it = m_regexesCache.emplace(pattern, std::regex(pattern)).first; - } - - if (!std::regex_search(m_target.asString(), it->second)) { - if (m_results) { - m_results->pushError(m_context, "Failed to match regex specified by 'pattern' constraint."); - } - - return false; - } - - return true; - } - - /** - * @brief Validate a value against a PatternConstraint - * - * @param constraint Constraint that the target must validate against - * - * @return \c true if the constraint is satisfied; \c false otherwise - */ - bool visit(const constraints::PolyConstraint &constraint) override - { - return constraint.validate(m_target, m_context, m_results); - } - - /** - * @brief Validate a value against a PropertiesConstraint - * - * Validation of an object against a PropertiesConstraint proceeds in three - * stages. The first stage finds all properties in the object that have a - * corresponding subschema in the constraint, and validates those properties - * recursively. - * - * Next, the object's properties will be validated against the subschemas - * for any 'patternProperties' that match a given property name. A property - * is required to validate against the sub-schema for all patterns that it - * matches. - * - * Finally, any properties that have not yet been validated against at least - * one subschema will be validated against the 'additionalItems' subschema. - * If this subschema is not present, then all properties must have been - * validated at least once. - * - * Non-object values are always considered valid. - * - * @param constraint Constraint that the target must validate against - * - * @return \c true if the constraint is satisfied; \c false otherwise - */ - bool visit(const PropertiesConstraint &constraint) override - { - if ((m_strictTypes && !m_target.isObject()) || !m_target.maybeObject()) { - return true; - } - - bool validated = true; - - // Track which properties have already been validated - std::set propertiesMatched; - - // Validate properties against subschemas for matching 'properties' - // constraints - const typename AdapterType::Object object = m_target.asObject(); - constraint.applyToProperties( - ValidatePropertySubschemas( - object, m_context, true, m_results != nullptr, true, m_strictTypes, m_results, - &propertiesMatched, &validated, m_regexesCache)); - - // Exit early if validation failed, and we're not collecting exhaustive - // validation results - if (!validated && !m_results) { - return false; - } - - // Validate properties against subschemas for matching patternProperties - // constraints - constraint.applyToPatternProperties( - ValidatePatternPropertySubschemas( - object, m_context, true, false, true, m_strictTypes, m_results, &propertiesMatched, - &validated, m_regexesCache)); - - // Validate against additionalProperties subschema for any properties - // that have not yet been matched - const Subschema *additionalPropertiesSubschema = - constraint.getAdditionalPropertiesSubschema(); - if (!additionalPropertiesSubschema) { - if (propertiesMatched.size() != m_target.getObjectSize()) { - if (m_results) { - std::string unwanted; - for (const typename AdapterType::ObjectMember m : object) { - if (propertiesMatched.find(m.first) == propertiesMatched.end()) { - unwanted = m.first; - break; - } - } - m_results->pushError(m_context, "Object contains a property " - "that could not be validated using 'properties' " - "or 'additionalProperties' constraints: '" + unwanted + "'."); - } - - return false; - } - - return validated; - } - - for (const typename AdapterType::ObjectMember m : object) { - if (propertiesMatched.find(m.first) == propertiesMatched.end()) { - // Update context - std::vector newContext = m_context; - newContext.push_back("[" + m.first + "]"); - - // Create a validator to validate the property's value - ValidationVisitor validator(m.second, newContext, m_strictTypes, m_results, m_regexesCache); - if (!validator.validateSchema(*additionalPropertiesSubschema)) { - if (m_results) { - m_results->pushError(m_context, "Failed to validate against additional properties schema"); - } - - validated = false; - } - } - } - - return validated; - } - - /** - * @brief Validate a value against a PropertyNamesConstraint - * - * @param constraint Constraint that the target must validate against - * - * @return \c true if validation succeeds; \c false otherwise - */ - bool visit(const PropertyNamesConstraint &constraint) override - { - if ((m_strictTypes && !m_target.isObject()) || !m_target.maybeObject()) { - return true; - } - - for (const typename AdapterType::ObjectMember m : m_target.asObject()) { - adapters::StdStringAdapter stringAdapter(m.first); - ValidationVisitor validator(stringAdapter, m_context, m_strictTypes, nullptr, m_regexesCache); - if (!validator.validateSchema(*constraint.getSubschema())) { - return false; - } - } - - return true; - } - - /** - * @brief Validate a value against a RequiredConstraint - * - * A required constraint specifies a list of properties that must be present - * in the target. - * - * @param constraint Constraint that the target must validate against - * - * @return \c true if validation succeeds; \c false otherwise - */ - bool visit(const RequiredConstraint &constraint) override - { - if ((m_strictTypes && !m_target.isObject()) || !m_target.maybeObject()) { - return true; - } - - bool validated = true; - const typename AdapterType::Object object = m_target.asObject(); - constraint.applyToRequiredProperties( - ValidateProperties(object, m_context, true, m_results != nullptr, m_results, &validated)); - - return validated; - } - - /** - * @brief Validate a value against a SingularItemsConstraint - * - * A SingularItemsConstraint represents an 'items' constraint that specifies - * a sub-schema against which all items in an array must validate. If the - * current value is not an array, validation always succeeds. - * - * @param constraint SingularItemsConstraint to validate against - * - * @returns \c true if validation is successful; \c false otherwise - */ - bool visit(const SingularItemsConstraint &constraint) override - { - // Ignore values that are not arrays - if (!m_target.isArray()) { - return true; - } - - // Schema against which all items must validate - const Subschema *itemsSubschema = constraint.getItemsSubschema(); - - // Default items sub-schema accepts all values - if (!itemsSubschema) { - return true; - } - - // Track whether validation has failed - bool validated = true; - - unsigned int index = 0; - for (const AdapterType &item : m_target.getArray()) { - // Update context for current array item - std::vector newContext = m_context; - newContext.push_back("[" + std::to_string(index) + "]"); - - // Create a validator for the current array item - ValidationVisitor validationVisitor(item, newContext, m_strictTypes, m_results, m_regexesCache); - - // Perform validation - if (!validationVisitor.validateSchema(*itemsSubschema)) { - if (m_results) { - m_results->pushError(m_context, "Failed to validate item #" + std::to_string(index) + " in array."); - validated = false; - } else { - return false; - } - } - - index++; - } - - return validated; - } - - /** - * @brief Validate a value against a TypeConstraint - * - * Checks that the target is one of the valid named types, or matches one - * of a set of valid sub-schemas. - * - * @param constraint TypeConstraint to validate against - * - * @return \c true if validation is successful; \c false otherwise - */ - bool visit(const TypeConstraint &constraint) override - { - // Check named types - { - // ValidateNamedTypes functor assumes target is invalid - bool validated = false; - constraint.applyToNamedTypes(ValidateNamedTypes(m_target, false, true, m_strictTypes, &validated)); - if (validated) { - return true; - } - } - - // Check schema-based types - { - unsigned int numValidated = 0; - constraint.applyToSchemaTypes( - ValidateSubschemas(m_target, m_context, false, true, *this, nullptr, &numValidated, nullptr)); - if (numValidated > 0) { - return true; - } else if (m_results) { - m_results->pushError(m_context, "Value type not permitted by 'type' constraint."); - } - } - - return false; - } - - /** - * @brief Validate the uniqueItems constraint represented by a - * UniqueItems object. - * - * A uniqueItems constraint requires that each of the values in an array - * are unique. Comparison is performed recursively. - * - * @param constraint Constraint that the target must validate against - * - * @return true if validation succeeds, false otherwise - */ - bool visit(const UniqueItemsConstraint &) override - { - if ((m_strictTypes && !m_target.isArray()) || !m_target.maybeArray()) { - return true; - } - - // Empty arrays are always valid - if (m_target.getArraySize() == 0) { - return true; - } - - bool validated = true; - - const typename AdapterType::Array targetArray = m_target.asArray(); - const typename AdapterType::Array::const_iterator end = targetArray.end(); - const typename AdapterType::Array::const_iterator secondLast = --targetArray.end(); - unsigned int outerIndex = 0; - typename AdapterType::Array::const_iterator outerItr = targetArray.begin(); - for (; outerItr != secondLast; ++outerItr) { - unsigned int innerIndex = outerIndex + 1; - typename AdapterType::Array::const_iterator innerItr(outerItr); - for (++innerItr; innerItr != end; ++innerItr) { - if (outerItr->equalTo(*innerItr, true)) { - if (!m_results) { - return false; - } - m_results->pushError(m_context, "Elements at indexes #" + std::to_string(outerIndex) - + " and #" + std::to_string(innerIndex) + " violate uniqueness constraint."); - validated = false; - } - ++innerIndex; - } - ++outerIndex; - } - - return validated; - } - -private: - - /** - * @brief Functor to compare a node with a collection of values - */ - struct ValidateEquality - { - ValidateEquality( - const AdapterType &target, - const std::vector &context, - bool continueOnSuccess, - bool continueOnFailure, - bool strictTypes, - ValidationResults *results, - unsigned int *numValidated) - : m_target(target), - m_context(context), - m_continueOnSuccess(continueOnSuccess), - m_continueOnFailure(continueOnFailure), - m_strictTypes(strictTypes), - m_results(results), - m_numValidated(numValidated) { } - - template - bool operator()(const OtherValue &value) const - { - if (value.equalTo(m_target, m_strictTypes)) { - if (m_numValidated) { - (*m_numValidated)++; - } - - return m_continueOnSuccess; - } - - if (m_results) { - m_results->pushError(m_context, "Target value and comparison value are not equal"); - } - - return m_continueOnFailure; - } - - private: - const AdapterType &m_target; - const std::vector &m_context; - bool m_continueOnSuccess; - bool m_continueOnFailure; - bool m_strictTypes; - ValidationResults * const m_results; - unsigned int * const m_numValidated; - }; - - /** - * @brief Functor to validate the presence of a set of properties - */ - struct ValidateProperties - { - ValidateProperties( - const typename AdapterType::Object &object, - const std::vector &context, - bool continueOnSuccess, - bool continueOnFailure, - ValidationResults *results, - bool *validated) - : m_object(object), - m_context(context), - m_continueOnSuccess(continueOnSuccess), - m_continueOnFailure(continueOnFailure), - m_results(results), - m_validated(validated) { } - - template - bool operator()(const StringType &property) const - { - if (m_object.find(property.c_str()) == m_object.end()) { - if (m_validated) { - *m_validated = false; - } - - if (m_results) { - m_results->pushError(m_context, "Missing required property '" + - std::string(property.c_str()) + "'."); - } - - return m_continueOnFailure; - } - - return m_continueOnSuccess; - } - - private: - const typename AdapterType::Object &m_object; - const std::vector &m_context; - bool m_continueOnSuccess; - bool m_continueOnFailure; - ValidationResults * const m_results; - bool * const m_validated; - }; - - /** - * @brief Functor to validate property-based dependencies - */ - struct ValidatePropertyDependencies - { - ValidatePropertyDependencies( - const typename AdapterType::Object &object, - const std::vector &context, - ValidationResults *results, - bool *validated) - : m_object(object), - m_context(context), - m_results(results), - m_validated(validated) { } - - template - bool operator()(const StringType &propertyName, const ContainerType &dependencyNames) const - { - const std::string propertyNameKey(propertyName.c_str()); - if (m_object.find(propertyNameKey) == m_object.end()) { - return true; - } - - typedef typename ContainerType::value_type ValueType; - for (const ValueType &dependencyName : dependencyNames) { - const std::string dependencyNameKey(dependencyName.c_str()); - if (m_object.find(dependencyNameKey) == m_object.end()) { - if (m_validated) { - *m_validated = false; - } - if (m_results) { - m_results->pushError(m_context, "Missing dependency '" + dependencyNameKey + "'."); - } else { - return false; - } - } - } - - return true; - } - - private: - const typename AdapterType::Object &m_object; - const std::vector &m_context; - ValidationResults * const m_results; - bool * const m_validated; - }; - - /** - * @brief Functor to validate against sub-schemas in 'items' constraint - */ - struct ValidateItems - { - ValidateItems( - const typename AdapterType::Array &arr, - const std::vector &context, - bool continueOnSuccess, - bool continueOnFailure, - bool strictTypes, - ValidationResults *results, - unsigned int *numValidated, - bool *validated, - std::unordered_map& regexesCache) - : m_arr(arr), - m_context(context), - m_continueOnSuccess(continueOnSuccess), - m_continueOnFailure(continueOnFailure), - m_strictTypes(strictTypes), - m_results(results), - m_numValidated(numValidated), - m_validated(validated), - m_regexesCache(regexesCache) { } - - bool operator()(unsigned int index, const Subschema *subschema) const - { - // Check that there are more elements to validate - if (index >= m_arr.size()) { - return false; - } - - // Update context - std::vector newContext = m_context; - newContext.push_back("[" + std::to_string(index) + "]"); - - // Find array item - typename AdapterType::Array::const_iterator itr = m_arr.begin(); - itr.advance(index); - - // Validate current array item - ValidationVisitor validator(*itr, newContext, m_strictTypes, m_results, m_regexesCache); - if (validator.validateSchema(*subschema)) { - if (m_numValidated) { - (*m_numValidated)++; - } - - return m_continueOnSuccess; - } - - if (m_validated) { - *m_validated = false; - } - - if (m_results) { - m_results->pushError(newContext, "Failed to validate item #" + std::to_string(index) + - " against corresponding item schema."); - } - - return m_continueOnFailure; - } - - private: - const typename AdapterType::Array &m_arr; - const std::vector &m_context; - bool m_continueOnSuccess; - bool m_continueOnFailure; - bool m_strictTypes; - ValidationResults * const m_results; - unsigned int * const m_numValidated; - bool * const m_validated; - std::unordered_map& m_regexesCache; - }; - - /** - * @brief Functor to validate value against named JSON types - */ - struct ValidateNamedTypes - { - ValidateNamedTypes( - const AdapterType &target, - bool continueOnSuccess, - bool continueOnFailure, - bool strictTypes, - bool *validated) - : m_target(target), - m_continueOnSuccess(continueOnSuccess), - m_continueOnFailure(continueOnFailure), - m_strictTypes(strictTypes), - m_validated(validated) { } - - bool operator()(constraints::TypeConstraint::JsonType jsonType) const - { - typedef constraints::TypeConstraint TypeConstraint; - - bool valid = false; - - switch (jsonType) { - case TypeConstraint::kAny: - valid = true; - break; - case TypeConstraint::kArray: - valid = m_target.isArray(); - break; - case TypeConstraint::kBoolean: - valid = m_target.isBool() || (!m_strictTypes && m_target.maybeBool()); - break; - case TypeConstraint::kInteger: - valid = m_target.isInteger() || (!m_strictTypes && m_target.maybeInteger()); - break; - case TypeConstraint::kNull: - valid = m_target.isNull() || (!m_strictTypes && m_target.maybeNull()); - break; - case TypeConstraint::kNumber: - valid = m_target.isNumber() || (!m_strictTypes && m_target.maybeDouble()); - break; - case TypeConstraint::kObject: - valid = m_target.isObject(); - break; - case TypeConstraint::kString: - valid = m_target.isString(); - break; - default: - break; - } - - if (valid && m_validated) { - *m_validated = true; - } - - return (valid && m_continueOnSuccess) || m_continueOnFailure; - } - - private: - const AdapterType m_target; - const bool m_continueOnSuccess; - const bool m_continueOnFailure; - const bool m_strictTypes; - bool * const m_validated; - }; - - /** - * @brief Functor to validate object properties against sub-schemas - * defined by a 'patternProperties' constraint - */ - struct ValidatePatternPropertySubschemas - { - ValidatePatternPropertySubschemas( - const typename AdapterType::Object &object, - const std::vector &context, - bool continueOnSuccess, - bool continueOnFailure, - bool continueIfUnmatched, - bool strictTypes, - ValidationResults *results, - std::set *propertiesMatched, - bool *validated, - std::unordered_map& regexesCache) - : m_object(object), - m_context(context), - m_continueOnSuccess(continueOnSuccess), - m_continueOnFailure(continueOnFailure), - m_continueIfUnmatched(continueIfUnmatched), - m_strictTypes(strictTypes), - m_results(results), - m_propertiesMatched(propertiesMatched), - m_validated(validated), - m_regexesCache(regexesCache) { } - - template - bool operator()(const StringType &patternProperty, const Subschema *subschema) const - { - const std::string patternPropertyStr(patternProperty.c_str()); - - // It would be nice to store pre-allocated regex objects in the - // PropertiesConstraint. does std::regex currently support - // custom allocators? Anyway, this isn't an issue here, because Valijson's - // JSON Scheme validator does not yet support custom allocators. - const std::regex r(patternPropertyStr); - - bool matchFound = false; - - // Recursively validate all matching properties - typedef const typename AdapterType::ObjectMember ObjectMember; - for (const ObjectMember m : m_object) { - if (std::regex_search(m.first, r)) { - matchFound = true; - if (m_propertiesMatched) { - m_propertiesMatched->insert(m.first); - } - - // Update context - std::vector newContext = m_context; - newContext.push_back("[" + m.first + "]"); - - // Recursively validate property's value - ValidationVisitor validator(m.second, newContext, m_strictTypes, m_results, m_regexesCache); - if (validator.validateSchema(*subschema)) { - continue; - } - - if (m_results) { - m_results->pushError(m_context, "Failed to validate against schema associated with pattern '" + - patternPropertyStr + "'."); - } - - if (m_validated) { - *m_validated = false; - } - - if (!m_continueOnFailure) { - return false; - } - } - } - - // Allow iteration to terminate if there was not at least one match - if (!matchFound && !m_continueIfUnmatched) { - return false; - } - - return m_continueOnSuccess; - } - - private: - const typename AdapterType::Object &m_object; - const std::vector &m_context; - const bool m_continueOnSuccess; - const bool m_continueOnFailure; - const bool m_continueIfUnmatched; - const bool m_strictTypes; - ValidationResults * const m_results; - std::set * const m_propertiesMatched; - bool * const m_validated; - std::unordered_map& m_regexesCache; - }; - - /** - * @brief Functor to validate object properties against sub-schemas defined - * by a 'properties' constraint - */ - struct ValidatePropertySubschemas - { - ValidatePropertySubschemas( - const typename AdapterType::Object &object, - const std::vector &context, - bool continueOnSuccess, - bool continueOnFailure, - bool continueIfUnmatched, - bool strictTypes, - ValidationResults *results, - std::set *propertiesMatched, - bool *validated, - std::unordered_map& regexesCache) - : m_object(object), - m_context(context), - m_continueOnSuccess(continueOnSuccess), - m_continueOnFailure(continueOnFailure), - m_continueIfUnmatched(continueIfUnmatched), - m_strictTypes(strictTypes), - m_results(results), - m_propertiesMatched(propertiesMatched), - m_validated(validated), - m_regexesCache(regexesCache) { } - - template - bool operator()(const StringType &propertyName, const Subschema *subschema) const - { - const std::string propertyNameKey(propertyName.c_str()); - const typename AdapterType::Object::const_iterator itr = m_object.find(propertyNameKey); - if (itr == m_object.end()) { - return m_continueIfUnmatched; - } - - if (m_propertiesMatched) { - m_propertiesMatched->insert(propertyNameKey); - } - - // Update context - std::vector newContext = m_context; - newContext.push_back("[" + propertyNameKey + "]"); - - // Recursively validate property's value - ValidationVisitor validator(itr->second, newContext, m_strictTypes, m_results, m_regexesCache); - if (validator.validateSchema(*subschema)) { - return m_continueOnSuccess; - } - - if (m_results) { - m_results->pushError(m_context, "Failed to validate against schema associated with property name '" + - propertyNameKey + "'."); - } - - if (m_validated) { - *m_validated = false; - } - - return m_continueOnFailure; - } - - private: - const typename AdapterType::Object &m_object; - const std::vector &m_context; - const bool m_continueOnSuccess; - const bool m_continueOnFailure; - const bool m_continueIfUnmatched; - const bool m_strictTypes; - ValidationResults * const m_results; - std::set * const m_propertiesMatched; - bool * const m_validated; - std::unordered_map& m_regexesCache; - }; - - /** - * @brief Functor to validate schema-based dependencies - */ - struct ValidateSchemaDependencies - { - ValidateSchemaDependencies( - const typename AdapterType::Object &object, - const std::vector &context, - ValidationVisitor &validationVisitor, - ValidationResults *results, - bool *validated) - : m_object(object), - m_context(context), - m_validationVisitor(validationVisitor), - m_results(results), - m_validated(validated) { } - - template - bool operator()(const StringType &propertyName, const Subschema *schemaDependency) const - { - const std::string propertyNameKey(propertyName.c_str()); - if (m_object.find(propertyNameKey) == m_object.end()) { - return true; - } - - if (!m_validationVisitor.validateSchema(*schemaDependency)) { - if (m_validated) { - *m_validated = false; - } - if (m_results) { - m_results->pushError(m_context, "Failed to validate against dependent schema."); - } else { - return false; - } - } - - return true; - } - - private: - const typename AdapterType::Object &m_object; - const std::vector &m_context; - ValidationVisitor &m_validationVisitor; - ValidationResults * const m_results; - bool * const m_validated; - }; - - /** - * @brief Functor that can be used to validate one or more subschemas - * - * This functor is designed to be applied to collections of subschemas - * contained within 'allOf', 'anyOf' and 'oneOf' constraints. - * - * The return value depends on whether a given schema validates, with the - * actual return value for a given case being decided at construction time. - * The return value is used by the 'applyToSubschemas' functions in the - * AllOfConstraint, AnyOfConstraint and OneOfConstrant classes to decide - * whether to terminate early. - * - * The functor uses output parameters (provided at construction) to update - * validation state that may be needed by the caller. - */ - struct ValidateSubschemas - { - ValidateSubschemas( - const AdapterType &adapter, - const std::vector &context, - bool continueOnSuccess, - bool continueOnFailure, - ValidationVisitor &validationVisitor, - ValidationResults *results, - unsigned int *numValidated, - bool *validated) - : m_adapter(adapter), - m_context(context), - m_continueOnSuccess(continueOnSuccess), - m_continueOnFailure(continueOnFailure), - m_validationVisitor(validationVisitor), - m_results(results), - m_numValidated(numValidated), - m_validated(validated) { } - - bool operator()(unsigned int index, const Subschema *subschema) const - { - if (m_validationVisitor.validateSchema(*subschema)) { - if (m_numValidated) { - (*m_numValidated)++; - } - - return m_continueOnSuccess; - } - - if (m_validated) { - *m_validated = false; - } - - if (m_results) { - m_results->pushError(m_context, - "Failed to validate against child schema #" + std::to_string(index) + "."); - } - - return m_continueOnFailure; - } - - private: - const AdapterType &m_adapter; - const std::vector &m_context; - bool m_continueOnSuccess; - bool m_continueOnFailure; - ValidationVisitor &m_validationVisitor; - ValidationResults * const m_results; - unsigned int * const m_numValidated; - bool * const m_validated; - }; - - /** - * @brief Callback function that passes a visitor to a constraint. - * - * @param constraint Reference to constraint to be visited - * @param visitor Reference to visitor to be applied - * - * @return true if the visitor returns successfully, false otherwise. - */ - static bool validationCallback(const constraints::Constraint &constraint, ValidationVisitor &visitor) - { - return constraint.accept(visitor); - } - - /// The JSON value being validated - const AdapterType m_target; - - /// Vector of strings describing the current object context - const std::vector m_context; - - /// Optional pointer to a ValidationResults object to be populated - ValidationResults *m_results; - - /// Option to use strict type comparison - const bool m_strictTypes; - - /// Cached regex objects for pattern constraint - std::unordered_map& m_regexesCache; -}; - -} // namespace valijson - -#ifdef _MSC_VER -#pragma warning( pop ) -#endif diff --git a/subprojects/valijson/include/valijson/validator.hpp b/subprojects/valijson/include/valijson/validator.hpp deleted file mode 100644 index b26f625f2..000000000 --- a/subprojects/valijson/include/valijson/validator.hpp +++ /dev/null @@ -1,77 +0,0 @@ -#pragma once - -#include -#include - -namespace valijson { - -class Schema; -class ValidationResults; - -/** - * @brief Class that provides validation functionality. - */ -class Validator -{ -public: - enum TypeCheckingMode - { - kStrongTypes, - kWeakTypes - }; - - /** - * @brief Construct a Validator that uses strong type checking by default - */ - Validator() - : strictTypes(true) { } - - /** - * @brief Construct a Validator using a specific type checking mode - * - * @param typeCheckingMode choice of strong or weak type checking - */ - Validator(TypeCheckingMode typeCheckingMode) - : strictTypes(typeCheckingMode == kStrongTypes) { } - - /** - * @brief Validate a JSON document and optionally return the results. - * - * When a ValidationResults object is provided via the \c results parameter, - * validation will be performed against each constraint defined by the - * schema, even if validation fails for some or all constraints. - * - * If a pointer to a ValidationResults instance is not provided, validation - * will only continue for as long as the constraints are validated - * successfully. - * - * @param schema The schema to validate against - * @param target A rapidjson::Value to be validated - * - * @param results An optional pointer to a ValidationResults instance that - * will be used to report validation errors - * - * @returns true if validation succeeds, false otherwise - */ - template - bool validate(const Subschema &schema, const AdapterType &target, - ValidationResults *results) - { - // Construct a ValidationVisitor to perform validation at the root level - ValidationVisitor v(target, - std::vector(1, ""), strictTypes, results, regexesCache); - - return v.validateSchema(schema); - } - -private: - - /// Flag indicating that strict type comparisons should be used - const bool strictTypes; - - /// Cached regex objects for pattern constraint. Key - pattern. - std::unordered_map regexesCache; - -}; - -} // namespace valijson