valijson from package managers
This commit is contained in:
17
.github/workflows/generate-builds.yml
vendored
17
.github/workflows/generate-builds.yml
vendored
@@ -113,8 +113,8 @@ jobs:
|
|||||||
echo "MacPorts already installed"
|
echo "MacPorts already installed"
|
||||||
else
|
else
|
||||||
echo "Installing MacPorts"
|
echo "Installing MacPorts"
|
||||||
wget https://github.com/macports/macports-base/releases/download/v2.9.3/MacPorts-2.9.3-14-Sonoma.pkg
|
wget https://github.com/macports/macports-base/releases/download/v2.11.5/MacPorts-2.11.5-14-Sonoma.pkg
|
||||||
sudo installer -pkg ./MacPorts-2.9.3-14-Sonoma.pkg -target /
|
sudo installer -pkg ./MacPorts-2.11.5-14-Sonoma.pkg -target /
|
||||||
fi
|
fi
|
||||||
echo "/opt/local/bin:/opt/local/sbin" >> "$GITHUB_PATH"
|
echo "/opt/local/bin:/opt/local/sbin" >> "$GITHUB_PATH"
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
@@ -233,6 +233,19 @@ jobs:
|
|||||||
make
|
make
|
||||||
sudo make install
|
sudo make install
|
||||||
sudo cp -av /usr/local/lib/libzip* /lib/x86_64-linux-gnu/
|
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
|
- name: Download soh.o2r
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
|
|||||||
set(VCPKG_TARGET_TRIPLET x64-windows-static)
|
set(VCPKG_TARGET_TRIPLET x64-windows-static)
|
||||||
|
|
||||||
vcpkg_bootstrap()
|
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")
|
if (CMAKE_C_COMPILER_LAUNCHER MATCHES "ccache|sccache")
|
||||||
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT Embedded)
|
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT Embedded)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -289,11 +289,24 @@ endif()
|
|||||||
################################################################################
|
################################################################################
|
||||||
add_compile_definitions(ASIO_STANDALONE)
|
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
|
target_include_directories(${PROJECT_NAME} PRIVATE
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/../subprojects/asio/include
|
${CMAKE_CURRENT_SOURCE_DIR}/../subprojects/asio/include
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/../subprojects/websocketpp
|
${CMAKE_CURRENT_SOURCE_DIR}/../subprojects/websocketpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/../subprojects/wswrap/include
|
${CMAKE_CURRENT_SOURCE_DIR}/../subprojects/wswrap/include
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/../subprojects/valijson/include
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/../subprojects/apclientpp
|
${CMAKE_CURRENT_SOURCE_DIR}/../subprojects/apclientpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -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), <email address unknown>
|
|
||||||
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
|
|
||||||
@@ -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.
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,472 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
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<bool (const Adapter &)>
|
|
||||||
ArrayValueCallback;
|
|
||||||
|
|
||||||
/// Typedef for callback function supplied to applyToObject.
|
|
||||||
typedef std::function<bool (const std::string &, const Adapter &)>
|
|
||||||
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<typename T>
|
|
||||||
struct AdapterTraits
|
|
||||||
{
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace adapters
|
|
||||||
} // namespace valijson
|
|
||||||
@@ -1,859 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
#include <valijson/adapters/adapter.hpp>
|
|
||||||
#include <valijson/internal/optional.hpp>
|
|
||||||
#include <valijson/exceptions.hpp>
|
|
||||||
|
|
||||||
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<class Value>
|
|
||||||
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> 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> 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<ArrayType> 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<ObjectType> 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<ArrayType> 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<double>(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<ObjectType> 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
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <valijson/adapters/adapter.hpp>
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -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 <string>
|
|
||||||
#include <json11.hpp>
|
|
||||||
|
|
||||||
#include <valijson/adapters/adapter.hpp>
|
|
||||||
#include <valijson/adapters/basic_adapter.hpp>
|
|
||||||
#include <valijson/adapters/frozen_value.hpp>
|
|
||||||
#include <valijson/exceptions.hpp>
|
|
||||||
|
|
||||||
namespace valijson {
|
|
||||||
namespace adapters {
|
|
||||||
|
|
||||||
class Json11Adapter;
|
|
||||||
class Json11ArrayValueIterator;
|
|
||||||
class Json11ObjectMemberIterator;
|
|
||||||
|
|
||||||
typedef std::pair<std::string, Json11Adapter> 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<Json11Array> 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<Json11Object> 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<Json11Adapter,
|
|
||||||
Json11Array,
|
|
||||||
Json11ObjectMember,
|
|
||||||
Json11Object,
|
|
||||||
Json11Value>
|
|
||||||
{
|
|
||||||
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<Json11Adapter> operator->() const
|
|
||||||
{
|
|
||||||
return DerefProxy<Json11Adapter>(**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<Json11ObjectMember> operator->() const
|
|
||||||
{
|
|
||||||
return DerefProxy<Json11ObjectMember>(**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<valijson::adapters::Json11Adapter>
|
|
||||||
{
|
|
||||||
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
|
|
||||||
@@ -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 <cstdint>
|
|
||||||
#include <string>
|
|
||||||
#include <iterator>
|
|
||||||
|
|
||||||
#include <json/json.h>
|
|
||||||
|
|
||||||
#include <valijson/adapters/adapter.hpp>
|
|
||||||
#include <valijson/adapters/basic_adapter.hpp>
|
|
||||||
#include <valijson/adapters/frozen_value.hpp>
|
|
||||||
#include <valijson/exceptions.hpp>
|
|
||||||
|
|
||||||
namespace valijson {
|
|
||||||
namespace adapters {
|
|
||||||
|
|
||||||
class JsonCppAdapter;
|
|
||||||
class JsonCppArrayValueIterator;
|
|
||||||
class JsonCppObjectMemberIterator;
|
|
||||||
|
|
||||||
typedef std::pair<std::string, JsonCppAdapter> 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<JsonCppArray> 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<int64_t>(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<JsonCppObject> 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<JsonCppAdapter,
|
|
||||||
JsonCppArray,
|
|
||||||
JsonCppObjectMember,
|
|
||||||
JsonCppObject,
|
|
||||||
JsonCppValue>
|
|
||||||
{
|
|
||||||
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<JsonCppAdapter> operator->() const
|
|
||||||
{
|
|
||||||
return DerefProxy<JsonCppAdapter>(**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<JsonCppObjectMember> operator->() const
|
|
||||||
{
|
|
||||||
return DerefProxy<JsonCppObjectMember>(**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<valijson::adapters::JsonCppAdapter>
|
|
||||||
{
|
|
||||||
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
|
|
||||||
@@ -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 <string>
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
|
|
||||||
#include <valijson/adapters/adapter.hpp>
|
|
||||||
#include <valijson/adapters/basic_adapter.hpp>
|
|
||||||
#include <valijson/adapters/frozen_value.hpp>
|
|
||||||
#include <valijson/exceptions.hpp>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
namespace valijson {
|
|
||||||
namespace adapters {
|
|
||||||
|
|
||||||
class NlohmannJsonAdapter;
|
|
||||||
class NlohmannJsonArrayValueIterator;
|
|
||||||
class NlohmannJsonObjectMemberIterator;
|
|
||||||
|
|
||||||
typedef std::pair<std::string, NlohmannJsonAdapter> 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<NlohmannJsonArray> 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<bool>();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool getDouble(double &result) const
|
|
||||||
{
|
|
||||||
if (m_value.is_number_float()) {
|
|
||||||
result = m_value.get<double>();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool getInteger(int64_t &result) const
|
|
||||||
{
|
|
||||||
if(m_value.is_number_integer()) {
|
|
||||||
result = m_value.get<int64_t>();
|
|
||||||
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<NlohmannJsonObject> 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<std::string>();
|
|
||||||
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<NlohmannJsonAdapter,
|
|
||||||
NlohmannJsonArray,
|
|
||||||
NlohmannJsonObjectMember,
|
|
||||||
NlohmannJsonObject,
|
|
||||||
NlohmannJsonValue>
|
|
||||||
{
|
|
||||||
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<NlohmannJsonAdapter> operator->() const
|
|
||||||
{
|
|
||||||
return DerefProxy<NlohmannJsonAdapter>(**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<NlohmannJsonObjectMember> operator->() const
|
|
||||||
{
|
|
||||||
return DerefProxy<NlohmannJsonObjectMember>(**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<valijson::adapters::NlohmannJsonAdapter>
|
|
||||||
{
|
|
||||||
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
|
|
||||||
@@ -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 <string>
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#pragma warning(disable: 4706)
|
|
||||||
#include <picojson.h>
|
|
||||||
#pragma warning(default: 4706)
|
|
||||||
#else
|
|
||||||
#include <picojson.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <valijson/adapters/adapter.hpp>
|
|
||||||
#include <valijson/adapters/basic_adapter.hpp>
|
|
||||||
#include <valijson/adapters/frozen_value.hpp>
|
|
||||||
#include <valijson/exceptions.hpp>
|
|
||||||
|
|
||||||
namespace valijson {
|
|
||||||
namespace adapters {
|
|
||||||
|
|
||||||
class PicoJsonAdapter;
|
|
||||||
class PicoJsonArrayValueIterator;
|
|
||||||
class PicoJsonObjectMemberIterator;
|
|
||||||
|
|
||||||
typedef std::pair<std::string, PicoJsonAdapter> 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<picojson::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 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<picojson::array>();
|
|
||||||
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<picojson::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 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<picojson::object>();
|
|
||||||
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<PicoJsonArray> getArrayOptional() const
|
|
||||||
{
|
|
||||||
if (m_value.is<picojson::array>()) {
|
|
||||||
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<picojson::array>()) {
|
|
||||||
const picojson::array& array = m_value.get<picojson::array>();
|
|
||||||
result = array.size();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool getBool(bool &result) const
|
|
||||||
{
|
|
||||||
if (m_value.is<bool>()) {
|
|
||||||
result = m_value.get<bool>();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool getDouble(double &result) const
|
|
||||||
{
|
|
||||||
if (m_value.is<double>()) {
|
|
||||||
result = m_value.get<double>();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool getInteger(int64_t &result) const
|
|
||||||
{
|
|
||||||
if (m_value.is<int64_t>()) {
|
|
||||||
result = m_value.get<int64_t>();
|
|
||||||
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<PicoJsonObject> getObjectOptional() const
|
|
||||||
{
|
|
||||||
if (m_value.is<picojson::object>()) {
|
|
||||||
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<picojson::object>()) {
|
|
||||||
const picojson::object &object = m_value.get<picojson::object>();
|
|
||||||
result = object.size();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool getString(std::string &result) const
|
|
||||||
{
|
|
||||||
if (m_value.is<std::string>()) {
|
|
||||||
result = m_value.get<std::string>();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool hasStrictTypes()
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isArray() const
|
|
||||||
{
|
|
||||||
return m_value.is<picojson::array>();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isBool() const
|
|
||||||
{
|
|
||||||
return m_value.is<bool>();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isDouble() const
|
|
||||||
{
|
|
||||||
if (m_value.is<int64_t>()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_value.is<double>();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isInteger() const
|
|
||||||
{
|
|
||||||
return m_value.is<int64_t>();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isNull() const
|
|
||||||
{
|
|
||||||
return m_value.is<picojson::null>();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isNumber() const
|
|
||||||
{
|
|
||||||
return m_value.is<double>();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isObject() const
|
|
||||||
{
|
|
||||||
return m_value.is<picojson::object>();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isString() const
|
|
||||||
{
|
|
||||||
return m_value.is<std::string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
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<PicoJsonAdapter,
|
|
||||||
PicoJsonArray,
|
|
||||||
PicoJsonObjectMember,
|
|
||||||
PicoJsonObject,
|
|
||||||
PicoJsonValue>
|
|
||||||
{
|
|
||||||
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<PicoJsonAdapter> operator->() const
|
|
||||||
{
|
|
||||||
return DerefProxy<PicoJsonAdapter>(**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<PicoJsonObjectMember> operator->() const
|
|
||||||
{
|
|
||||||
return DerefProxy<PicoJsonObjectMember>(**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<valijson::adapters::PicoJsonAdapter>
|
|
||||||
{
|
|
||||||
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<picojson::array>();
|
|
||||||
return array.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline PicoJsonArrayValueIterator PicoJsonArray::end() const
|
|
||||||
{
|
|
||||||
const picojson::array &array = m_value.get<picojson::array>();
|
|
||||||
return array.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline PicoJsonObjectMemberIterator PicoJsonObject::begin() const
|
|
||||||
{
|
|
||||||
const picojson::object &object = m_value.get<picojson::object>();
|
|
||||||
return object.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline PicoJsonObjectMemberIterator PicoJsonObject::end() const
|
|
||||||
{
|
|
||||||
const picojson::object &object = m_value.get<picojson::object>();
|
|
||||||
return object.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline PicoJsonObjectMemberIterator PicoJsonObject::find(
|
|
||||||
const std::string &propertyName) const
|
|
||||||
{
|
|
||||||
const picojson::object &object = m_value.get<picojson::object>();
|
|
||||||
return object.find(propertyName);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace adapters
|
|
||||||
} // namespace valijson
|
|
||||||
@@ -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 <string>
|
|
||||||
#include <Poco/JSON/Object.h>
|
|
||||||
|
|
||||||
#include <valijson/adapters/adapter.hpp>
|
|
||||||
#include <valijson/adapters/basic_adapter.hpp>
|
|
||||||
#include <valijson/adapters/frozen_value.hpp>
|
|
||||||
#include <valijson/exceptions.hpp>
|
|
||||||
|
|
||||||
namespace valijson {
|
|
||||||
namespace adapters {
|
|
||||||
|
|
||||||
class PocoJsonAdapter;
|
|
||||||
class PocoJsonArrayValueIterator;
|
|
||||||
class PocoJsonObjectMemberIterator;
|
|
||||||
|
|
||||||
typedef std::pair<std::string, PocoJsonAdapter> 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<Poco::JSON::Array::Ptr>()->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<Poco::JSON::Object::Ptr>()->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<PocoJsonArray> getArrayOptional() const
|
|
||||||
{
|
|
||||||
if (m_value.type() == typeid(Poco::JSON::Array::Ptr)) {
|
|
||||||
return opt::make_optional(PocoJsonArray(m_value));
|
|
||||||
}
|
|
||||||
|
|
||||||
return opt::optional<PocoJsonArray>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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<Poco::JSON::Array::Ptr>()->size();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool getBool(bool &result) const
|
|
||||||
{
|
|
||||||
if (m_value.isBoolean()) {
|
|
||||||
result = m_value.convert<bool>();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool getDouble(double &result) const
|
|
||||||
{
|
|
||||||
if (m_value.isNumeric() && !m_value.isInteger()) {
|
|
||||||
result = m_value.convert<double>();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool getInteger(int64_t &result) const
|
|
||||||
{
|
|
||||||
if (m_value.isInteger()) {
|
|
||||||
result = m_value.convert<int>();
|
|
||||||
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<PocoJsonObject> getObjectOptional() const
|
|
||||||
{
|
|
||||||
if (m_value.type() == typeid(Poco::JSON::Object::Ptr)) {
|
|
||||||
return opt::make_optional(PocoJsonObject(m_value));
|
|
||||||
}
|
|
||||||
|
|
||||||
return opt::optional<PocoJsonObject>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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<Poco::JSON::Object::Ptr>()->size();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool getString(std::string &result) const
|
|
||||||
{
|
|
||||||
if (m_value.isString()) {
|
|
||||||
result = m_value.convert<std::string>();
|
|
||||||
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<PocoJsonAdapter,
|
|
||||||
PocoJsonArray,
|
|
||||||
PocoJsonObjectMember,
|
|
||||||
PocoJsonObject,
|
|
||||||
PocoJsonValue>
|
|
||||||
{
|
|
||||||
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<PocoJsonAdapter> operator->() const
|
|
||||||
{
|
|
||||||
return DerefProxy<PocoJsonAdapter>(**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<PocoJsonObjectMember> operator->() const
|
|
||||||
{
|
|
||||||
return DerefProxy<PocoJsonObjectMember>(**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<valijson::adapters::PocoJsonAdapter>
|
|
||||||
{
|
|
||||||
typedef Poco::Dynamic::Var DocumentType;
|
|
||||||
|
|
||||||
static std::string adapterName()
|
|
||||||
{
|
|
||||||
return "PocoJsonAdapter";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
inline PocoJsonArrayValueIterator PocoJsonArray::begin() const
|
|
||||||
{
|
|
||||||
return m_value.extract<Poco::JSON::Array::Ptr>()->begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline PocoJsonArrayValueIterator PocoJsonArray::end() const
|
|
||||||
{
|
|
||||||
return m_value.extract<Poco::JSON::Array::Ptr>()->end();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline PocoJsonObjectMemberIterator PocoJsonObject::begin() const
|
|
||||||
{
|
|
||||||
return m_value.extract<Poco::JSON::Object::Ptr>()->begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline PocoJsonObjectMemberIterator PocoJsonObject::end() const
|
|
||||||
{
|
|
||||||
return m_value.extract<Poco::JSON::Object::Ptr>()->end();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline PocoJsonObjectMemberIterator PocoJsonObject::find(const std::string &propertyName) const
|
|
||||||
{
|
|
||||||
auto& ptr = m_value.extract<Poco::JSON::Object::Ptr>();
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -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 <string>
|
|
||||||
|
|
||||||
#include <boost/property_tree/ptree.hpp>
|
|
||||||
|
|
||||||
#include <valijson/adapters/adapter.hpp>
|
|
||||||
#include <valijson/adapters/basic_adapter.hpp>
|
|
||||||
#include <valijson/adapters/frozen_value.hpp>
|
|
||||||
|
|
||||||
namespace valijson {
|
|
||||||
namespace adapters {
|
|
||||||
|
|
||||||
class PropertyTreeAdapter;
|
|
||||||
class PropertyTreeArrayValueIterator;
|
|
||||||
class PropertyTreeObjectMemberIterator;
|
|
||||||
|
|
||||||
typedef std::pair<std::string, PropertyTreeAdapter> 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<PropertyTreeArray> 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<PropertyTreeObject> 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<bool>(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<bool>(m_object);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isString() const
|
|
||||||
{
|
|
||||||
return static_cast<bool>(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<const boost::property_tree::ptree &> m_array;
|
|
||||||
|
|
||||||
/// Reference used if the value is known to be an object
|
|
||||||
opt::optional<const boost::property_tree::ptree &> m_object;
|
|
||||||
|
|
||||||
/// Reference used if the value is known to be a POD type
|
|
||||||
opt::optional<std::string> 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<PropertyTreeAdapter,
|
|
||||||
PropertyTreeArray,
|
|
||||||
PropertyTreeObjectMember,
|
|
||||||
PropertyTreeObject,
|
|
||||||
PropertyTreeValue>
|
|
||||||
{
|
|
||||||
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<PropertyTreeAdapter> operator->() const
|
|
||||||
{
|
|
||||||
return DerefProxy<PropertyTreeAdapter>(**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<PropertyTreeObjectMember> operator->() const
|
|
||||||
{
|
|
||||||
return DerefProxy<PropertyTreeObjectMember>(**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<valijson::adapters::PropertyTreeAdapter>
|
|
||||||
{
|
|
||||||
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
|
|
||||||
@@ -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 <string>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QJsonValue>
|
|
||||||
#include <QJsonArray>
|
|
||||||
|
|
||||||
#include <valijson/adapters/adapter.hpp>
|
|
||||||
#include <valijson/adapters/basic_adapter.hpp>
|
|
||||||
#include <valijson/adapters/frozen_value.hpp>
|
|
||||||
#include <valijson/exceptions.hpp>
|
|
||||||
|
|
||||||
namespace valijson {
|
|
||||||
namespace adapters {
|
|
||||||
|
|
||||||
class QtJsonAdapter;
|
|
||||||
class QtJsonArrayValueIterator;
|
|
||||||
class QtJsonObjectMemberIterator;
|
|
||||||
|
|
||||||
typedef std::pair<std::string, QtJsonAdapter> 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<QtJsonArray> getArrayOptional() const
|
|
||||||
{
|
|
||||||
if (m_value.isArray()) {
|
|
||||||
return opt::make_optional(QtJsonArray(m_value));
|
|
||||||
}
|
|
||||||
|
|
||||||
return opt::optional<QtJsonArray>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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<QtJsonObject> getObjectOptional() const
|
|
||||||
{
|
|
||||||
if (m_value.isObject()) {
|
|
||||||
return opt::make_optional(QtJsonObject(m_value));
|
|
||||||
}
|
|
||||||
|
|
||||||
return opt::optional<QtJsonObject>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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<QtJsonAdapter,
|
|
||||||
QtJsonArray,
|
|
||||||
QtJsonObjectMember,
|
|
||||||
QtJsonObject,
|
|
||||||
QtJsonValue>
|
|
||||||
{
|
|
||||||
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<QtJsonAdapter> operator->() const
|
|
||||||
{
|
|
||||||
return DerefProxy<QtJsonAdapter>(**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<QtJsonObjectMember> operator->() const
|
|
||||||
{
|
|
||||||
return DerefProxy<QtJsonObjectMember>(**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<valijson::adapters::QtJsonAdapter>
|
|
||||||
{
|
|
||||||
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
|
|
||||||
@@ -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 <string>
|
|
||||||
#include <iterator>
|
|
||||||
|
|
||||||
#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<typename T>
|
|
||||||
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 <rapidjson/document.h>
|
|
||||||
|
|
||||||
#include <valijson/adapters/adapter.hpp>
|
|
||||||
#include <valijson/adapters/basic_adapter.hpp>
|
|
||||||
#include <valijson/adapters/frozen_value.hpp>
|
|
||||||
#include <valijson/exceptions.hpp>
|
|
||||||
|
|
||||||
namespace valijson {
|
|
||||||
namespace adapters {
|
|
||||||
|
|
||||||
template<class ValueType = rapidjson::Value>
|
|
||||||
class GenericRapidJsonAdapter;
|
|
||||||
|
|
||||||
template<class ValueType = rapidjson::Value>
|
|
||||||
class GenericRapidJsonArrayValueIterator;
|
|
||||||
|
|
||||||
template<class ValueType = rapidjson::Value>
|
|
||||||
class GenericRapidJsonObjectMemberIterator;
|
|
||||||
|
|
||||||
/// Container for a property name and an associated RapidJson value
|
|
||||||
template<class ValueType = rapidjson::Value>
|
|
||||||
class GenericRapidJsonObjectMember :
|
|
||||||
public std::pair<std::string, GenericRapidJsonAdapter<ValueType>>
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
typedef std::pair<std::string, GenericRapidJsonAdapter<ValueType>> Super;
|
|
||||||
|
|
||||||
public:
|
|
||||||
GenericRapidJsonObjectMember(
|
|
||||||
const std::string &name,
|
|
||||||
const GenericRapidJsonAdapter<ValueType> &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 ValueType = rapidjson::Value>
|
|
||||||
class GenericRapidJsonArray
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
typedef GenericRapidJsonArrayValueIterator<ValueType> const_iterator;
|
|
||||||
typedef GenericRapidJsonArrayValueIterator<ValueType> 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 ValueType = rapidjson::Value>
|
|
||||||
class GenericRapidJsonObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
typedef GenericRapidJsonObjectMemberIterator<ValueType> const_iterator;
|
|
||||||
typedef GenericRapidJsonObjectMemberIterator<ValueType> 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 ValueType = rapidjson::Value>
|
|
||||||
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<typename Allocator>
|
|
||||||
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 ValueType = rapidjson::Value>
|
|
||||||
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<ValueType>(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<GenericRapidJsonArray<ValueType>> getArrayOptional() const
|
|
||||||
{
|
|
||||||
if (m_value.IsArray()) {
|
|
||||||
return opt::make_optional(GenericRapidJsonArray<ValueType>(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<int64_t>(m_value.GetUint());
|
|
||||||
return true;
|
|
||||||
} else if (m_value.IsUint64()) {
|
|
||||||
result = static_cast<int64_t>(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<GenericRapidJsonObject<ValueType>> getObjectOptional() const
|
|
||||||
{
|
|
||||||
if (m_value.IsObject()) {
|
|
||||||
return opt::make_optional(GenericRapidJsonObject<ValueType>(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 ValueType>
|
|
||||||
class GenericRapidJsonAdapter:
|
|
||||||
public BasicAdapter<GenericRapidJsonAdapter<ValueType>,
|
|
||||||
GenericRapidJsonArray<ValueType>,
|
|
||||||
GenericRapidJsonObjectMember<ValueType>,
|
|
||||||
GenericRapidJsonObject<ValueType>,
|
|
||||||
GenericRapidJsonValue<ValueType>>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
|
|
||||||
/// Construct a RapidJsonAdapter that contains an empty object
|
|
||||||
GenericRapidJsonAdapter()
|
|
||||||
: BasicAdapter<GenericRapidJsonAdapter<ValueType>,
|
|
||||||
GenericRapidJsonArray<ValueType>,
|
|
||||||
GenericRapidJsonObjectMember<ValueType>,
|
|
||||||
GenericRapidJsonObject<ValueType>,
|
|
||||||
GenericRapidJsonValue<ValueType>>() { }
|
|
||||||
|
|
||||||
/// Construct a RapidJsonAdapter containing a specific RapidJson value
|
|
||||||
GenericRapidJsonAdapter(const ValueType &value)
|
|
||||||
: BasicAdapter<GenericRapidJsonAdapter<ValueType>,
|
|
||||||
GenericRapidJsonArray<ValueType>,
|
|
||||||
GenericRapidJsonObjectMember<ValueType>,
|
|
||||||
GenericRapidJsonObject<ValueType>,
|
|
||||||
GenericRapidJsonValue<ValueType>>(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 ValueType>
|
|
||||||
class GenericRapidJsonArrayValueIterator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using iterator_category = std::bidirectional_iterator_tag;
|
|
||||||
using value_type = GenericRapidJsonAdapter<ValueType>;
|
|
||||||
using difference_type = GenericRapidJsonAdapter<ValueType>;
|
|
||||||
using pointer = GenericRapidJsonAdapter<ValueType>*;
|
|
||||||
using reference = GenericRapidJsonAdapter<ValueType>&;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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<ValueType> operator*() const
|
|
||||||
{
|
|
||||||
return GenericRapidJsonAdapter<ValueType>(*m_itr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a proxy for the value of the current element
|
|
||||||
DerefProxy<GenericRapidJsonAdapter<ValueType>> operator->() const
|
|
||||||
{
|
|
||||||
return DerefProxy<GenericRapidJsonAdapter<ValueType>>(**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<ValueType> &other) const
|
|
||||||
{
|
|
||||||
return m_itr == other.m_itr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator!=(const GenericRapidJsonArrayValueIterator<ValueType>& other) const
|
|
||||||
{
|
|
||||||
return m_itr != other.m_itr;
|
|
||||||
}
|
|
||||||
|
|
||||||
GenericRapidJsonArrayValueIterator<ValueType>& operator++()
|
|
||||||
{
|
|
||||||
m_itr++;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
GenericRapidJsonArrayValueIterator<ValueType> operator++(int) {
|
|
||||||
GenericRapidJsonArrayValueIterator<ValueType> iterator_pre(m_itr);
|
|
||||||
++(*this);
|
|
||||||
return iterator_pre;
|
|
||||||
}
|
|
||||||
|
|
||||||
GenericRapidJsonArrayValueIterator<ValueType>& operator--()
|
|
||||||
{
|
|
||||||
m_itr--;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void advance(std::ptrdiff_t n)
|
|
||||||
{
|
|
||||||
m_itr += n;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ptrdiff_t difference(const GenericRapidJsonArrayValueIterator<ValueType> &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 ValueType>
|
|
||||||
class GenericRapidJsonObjectMemberIterator
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using iterator_category = std::bidirectional_iterator_tag;
|
|
||||||
using value_type = GenericRapidJsonObjectMember<ValueType>;
|
|
||||||
using difference_type = GenericRapidJsonObjectMember<ValueType>;
|
|
||||||
using pointer = GenericRapidJsonObjectMember<ValueType>*;
|
|
||||||
using reference = GenericRapidJsonObjectMember<ValueType>&;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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<ValueType> operator*() const
|
|
||||||
{
|
|
||||||
return GenericRapidJsonObjectMember<ValueType>(
|
|
||||||
std::string(m_itr->name.GetString(), m_itr->name.GetStringLength()),
|
|
||||||
m_itr->value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a proxy for the value of the current element
|
|
||||||
DerefProxy<GenericRapidJsonObjectMember<ValueType>> operator->() const
|
|
||||||
{
|
|
||||||
return DerefProxy<GenericRapidJsonObjectMember<ValueType>>(**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<ValueType> &other) const
|
|
||||||
{
|
|
||||||
return m_itr == other.m_itr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator!=(const GenericRapidJsonObjectMemberIterator<ValueType> &other) const
|
|
||||||
{
|
|
||||||
return m_itr != other.m_itr;
|
|
||||||
}
|
|
||||||
|
|
||||||
GenericRapidJsonObjectMemberIterator<ValueType>& operator++()
|
|
||||||
{
|
|
||||||
m_itr++;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
GenericRapidJsonObjectMemberIterator<ValueType> operator++(int)
|
|
||||||
{
|
|
||||||
GenericRapidJsonObjectMemberIterator<ValueType> iterator_pre(m_itr);
|
|
||||||
++(*this);
|
|
||||||
return iterator_pre;
|
|
||||||
}
|
|
||||||
|
|
||||||
GenericRapidJsonObjectMemberIterator<ValueType>& 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<class ValueType>
|
|
||||||
inline bool GenericRapidJsonFrozenValue<ValueType>::equalTo(const Adapter &other, bool strict) const
|
|
||||||
{
|
|
||||||
return GenericRapidJsonAdapter<ValueType>(m_value).equalTo(other, strict);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ValueType>
|
|
||||||
inline typename GenericRapidJsonArray<ValueType>::iterator GenericRapidJsonArray<ValueType>::begin() const
|
|
||||||
{
|
|
||||||
return m_value.Begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ValueType>
|
|
||||||
inline typename GenericRapidJsonArray<ValueType>::iterator GenericRapidJsonArray<ValueType>::end() const
|
|
||||||
{
|
|
||||||
return m_value.End();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ValueType>
|
|
||||||
inline typename GenericRapidJsonObject<ValueType>::iterator GenericRapidJsonObject<ValueType>::begin() const
|
|
||||||
{
|
|
||||||
return m_value.MemberBegin();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ValueType>
|
|
||||||
inline typename GenericRapidJsonObject<ValueType>::iterator GenericRapidJsonObject<ValueType>::end() const
|
|
||||||
{
|
|
||||||
return m_value.MemberEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class ValueType>
|
|
||||||
inline typename GenericRapidJsonObject<ValueType>::iterator
|
|
||||||
GenericRapidJsonObject<ValueType>::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<valijson::adapters::RapidJsonAdapter>
|
|
||||||
{
|
|
||||||
typedef rapidjson::Document DocumentType;
|
|
||||||
|
|
||||||
static std::string adapterName()
|
|
||||||
{
|
|
||||||
return "RapidJsonAdapter";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef rapidjson::GenericValue<rapidjson::UTF8<>, rapidjson::CrtAllocator> RapidJsonCrt;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Specialisation of the AdapterTraits template struct for a
|
|
||||||
* RapidJsonAdapter that uses the default CRT allocator
|
|
||||||
*/
|
|
||||||
template<>
|
|
||||||
struct AdapterTraits<valijson::adapters::GenericRapidJsonAdapter<RapidJsonCrt>>
|
|
||||||
{
|
|
||||||
typedef rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::CrtAllocator> DocumentType;
|
|
||||||
|
|
||||||
static std::string adapterName()
|
|
||||||
{
|
|
||||||
return "GenericRapidJsonAdapter (using CrtAllocator)";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace adapters
|
|
||||||
} // namespace valijson
|
|
||||||
@@ -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 <string>
|
|
||||||
|
|
||||||
#include <valijson/adapters/adapter.hpp>
|
|
||||||
#include <valijson/adapters/frozen_value.hpp>
|
|
||||||
#include <valijson/adapters/basic_adapter.hpp>
|
|
||||||
#include <valijson/exceptions.hpp>
|
|
||||||
|
|
||||||
namespace valijson {
|
|
||||||
namespace adapters {
|
|
||||||
|
|
||||||
class StdStringAdapter;
|
|
||||||
class StdStringArrayValueIterator;
|
|
||||||
class StdStringObjectMemberIterator;
|
|
||||||
|
|
||||||
typedef std::pair<std::string, StdStringAdapter> 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<StdStringAdapter> 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<StdStringObjectMember> 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<valijson::adapters::StdStringAdapter>
|
|
||||||
{
|
|
||||||
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
|
|
||||||
@@ -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
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <valijson/constraints/constraint.hpp>
|
|
||||||
#include <valijson/constraints/constraint_visitor.hpp>
|
|
||||||
#include <valijson/internal/custom_allocator.hpp>
|
|
||||||
#include <valijson/exceptions.hpp>
|
|
||||||
|
|
||||||
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<typename ConstraintType>
|
|
||||||
struct BasicConstraint: Constraint
|
|
||||||
{
|
|
||||||
typedef internal::CustomAllocator<void *> Allocator;
|
|
||||||
|
|
||||||
typedef std::basic_string<char, std::char_traits<char>, internal::CustomAllocator<char>> 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<const ConstraintType*>(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<const ConstraintType*>(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
Allocator m_allocator;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace constraints
|
|
||||||
} // namespace valijson
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
|
||||||
@@ -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
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <exception>
|
|
||||||
|
|
||||||
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 <stdexcept>
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
namespace valijson {
|
|
||||||
namespace internal {
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
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<typename U>
|
|
||||||
struct rebind
|
|
||||||
{
|
|
||||||
typedef CustomAllocator<U> 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<typename U>
|
|
||||||
CustomAllocator(CustomAllocator<U> 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<pointer>(m_allocFn(cnt * sizeof(T)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void deallocate(pointer p, size_type)
|
|
||||||
{
|
|
||||||
m_freeFn(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_type max_size() const
|
|
||||||
{
|
|
||||||
return std::numeric_limits<size_type>::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
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace valijson {
|
|
||||||
namespace internal {
|
|
||||||
|
|
||||||
template<typename AdapterType>
|
|
||||||
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
|
|
||||||
@@ -1,275 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cerrno>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstring>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include <valijson/adapters/adapter.hpp>
|
|
||||||
#include <valijson/internal/optional.hpp>
|
|
||||||
#include <valijson/exceptions.hpp>
|
|
||||||
|
|
||||||
#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<typename AdapterType>
|
|
||||||
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<uint64_t>(std::numeric_limits<std::ptrdiff_t>::max())) {
|
|
||||||
throwRuntimeError("Array index out of bounds; hard "
|
|
||||||
"limit is " + std::to_string(
|
|
||||||
std::numeric_limits<std::ptrdiff_t>::max()));
|
|
||||||
}
|
|
||||||
|
|
||||||
itr.advance(static_cast<std::ptrdiff_t>(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<typename AdapterType>
|
|
||||||
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
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include <valijson/internal/optional.hpp>
|
|
||||||
|
|
||||||
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<std::string> 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<std::string>();
|
|
||||||
} 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<std::string> 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<std::string>();
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace json_reference
|
|
||||||
} // namespace internal
|
|
||||||
} // namespace valijson
|
|
||||||
@@ -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(<optional>)
|
|
||||||
# include <optional>
|
|
||||||
namespace opt = std;
|
|
||||||
# endif
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
# include <compat/optional.hpp>
|
|
||||||
namespace opt = std::experimental;
|
|
||||||
#endif
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -1,224 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstdio>
|
|
||||||
#include <set>
|
|
||||||
|
|
||||||
#include <valijson/subschema.hpp>
|
|
||||||
#include <valijson/exceptions.hpp>
|
|
||||||
|
|
||||||
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<Subschema *>(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*>(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<Subschema*> subschemaSet;
|
|
||||||
|
|
||||||
/// Empty schema that can be reused by multiple constraints
|
|
||||||
const Subschema *sharedEmptySubschema;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace valijson
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,311 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include <valijson/constraints/constraint.hpp>
|
|
||||||
#include <valijson/internal/optional.hpp>
|
|
||||||
#include <valijson/exceptions.hpp>
|
|
||||||
|
|
||||||
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<bool (const Constraint &)> 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<Constraint *>(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<bool>(m_description);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Check whether this sub-schema has an ID
|
|
||||||
*
|
|
||||||
* @return boolean value
|
|
||||||
*/
|
|
||||||
bool hasId() const
|
|
||||||
{
|
|
||||||
return static_cast<bool>(m_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Check whether this sub-schema has a title
|
|
||||||
*
|
|
||||||
* @return boolean value
|
|
||||||
*/
|
|
||||||
bool hasTitle() const
|
|
||||||
{
|
|
||||||
return static_cast<bool>(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<const Constraint *> m_constraints;
|
|
||||||
|
|
||||||
/// Schema description (optional)
|
|
||||||
opt::optional<std::string> m_description;
|
|
||||||
|
|
||||||
/// Id to apply when resolving the schema URI
|
|
||||||
opt::optional<std::string> m_id;
|
|
||||||
|
|
||||||
/// Title string associated with the schema (optional)
|
|
||||||
opt::optional<std::string> m_title;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace valijson
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
#include <limits>
|
|
||||||
|
|
||||||
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<unsigned int>::max()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
dest.clear();
|
|
||||||
dest.reserve(static_cast<unsigned int>(offset));
|
|
||||||
|
|
||||||
// Assign file contents to destination string
|
|
||||||
file.seekg(0, std::ios::beg);
|
|
||||||
dest.assign(std::istreambuf_iterator<char>(file),
|
|
||||||
std::istreambuf_iterator<char>());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace utils
|
|
||||||
} // namespace valijson
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include <json11.hpp>
|
|
||||||
|
|
||||||
#include <valijson/utils/file_utils.hpp>
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include <json/json.h>
|
|
||||||
|
|
||||||
#include <valijson/utils/file_utils.hpp>
|
|
||||||
|
|
||||||
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<int>(file.length());
|
|
||||||
Json::CharReaderBuilder builder;
|
|
||||||
const std::unique_ptr<Json::CharReader> 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
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
|
||||||
#include <valijson/utils/file_utils.hpp>
|
|
||||||
#include <valijson/exceptions.hpp>
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
#pragma warning(disable: 4706)
|
|
||||||
#include <picojson.h>
|
|
||||||
#pragma warning(default: 4706)
|
|
||||||
#else
|
|
||||||
#include <picojson.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <valijson/utils/file_utils.hpp>
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include <Poco/JSON/JSONException.h>
|
|
||||||
#include <Poco/JSON/Object.h>
|
|
||||||
#include <Poco/JSON/Parser.h>
|
|
||||||
|
|
||||||
#include <valijson/utils/file_utils.hpp>
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
#include <boost/property_tree/ptree.hpp>
|
|
||||||
#include <boost/throw_exception.hpp>
|
|
||||||
|
|
||||||
#if defined(__clang__)
|
|
||||||
# pragma clang diagnostic push
|
|
||||||
# pragma clang diagnostic ignored "-Wshadow"
|
|
||||||
# include <boost/property_tree/json_parser.hpp>
|
|
||||||
# pragma clang diagnostic pop
|
|
||||||
#else
|
|
||||||
# include <boost/property_tree/json_parser.hpp>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Source locations were added in boost 1.73.
|
|
||||||
#include <boost/version.hpp>
|
|
||||||
#if (BOOST_VERSION > 107300)
|
|
||||||
#include <boost/assert/source_location.hpp>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <valijson/utils/file_utils.hpp>
|
|
||||||
#include <valijson/exceptions.hpp>
|
|
||||||
|
|
||||||
#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
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <QFile>
|
|
||||||
|
|
||||||
#include <QJsonDocument>
|
|
||||||
#include <QJsonObject>
|
|
||||||
#include <QJsonArray>
|
|
||||||
|
|
||||||
#include <valijson/utils/file_utils.hpp>
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
#include <rapidjson/document.h>
|
|
||||||
|
|
||||||
#include <valijson/utils/file_utils.hpp>
|
|
||||||
|
|
||||||
namespace valijson {
|
|
||||||
namespace utils {
|
|
||||||
|
|
||||||
template<typename Encoding, typename Allocator>
|
|
||||||
inline bool loadDocument(const std::string &path, rapidjson::GenericDocument<Encoding, Allocator> &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<rapidjson::kParseIterativeFlag>(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
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include <valijson/exceptions.hpp>
|
|
||||||
|
|
||||||
/*
|
|
||||||
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<unsigned char>(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<uint64_t>::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
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <deque>
|
|
||||||
#include <string>
|
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
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<std::string> context;
|
|
||||||
|
|
||||||
/// A detailed description of the validation error.
|
|
||||||
std::string description;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return begin iterator for results in the queue.
|
|
||||||
*/
|
|
||||||
std::deque<Error>::const_iterator begin() const
|
|
||||||
{
|
|
||||||
return m_errors.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Return end iterator for results in the queue.
|
|
||||||
*/
|
|
||||||
std::deque<Error>::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<std::string> &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<Error> m_errors;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace valijson
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,77 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <valijson/schema.hpp>
|
|
||||||
#include <valijson/validation_visitor.hpp>
|
|
||||||
|
|
||||||
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<typename AdapterType>
|
|
||||||
bool validate(const Subschema &schema, const AdapterType &target,
|
|
||||||
ValidationResults *results)
|
|
||||||
{
|
|
||||||
// Construct a ValidationVisitor to perform validation at the root level
|
|
||||||
ValidationVisitor<AdapterType> v(target,
|
|
||||||
std::vector<std::string>(1, "<root>"), 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<std::string, std::regex> regexesCache;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace valijson
|
|
||||||
Reference in New Issue
Block a user