valijson from package managers

This commit is contained in:
briaguya
2025-09-27 13:04:41 -04:00
parent 9090e80507
commit 2a84d0a032
46 changed files with 30 additions and 16283 deletions

View File

@@ -113,8 +113,8 @@ jobs:
echo "MacPorts already installed"
else
echo "Installing MacPorts"
wget https://github.com/macports/macports-base/releases/download/v2.9.3/MacPorts-2.9.3-14-Sonoma.pkg
sudo installer -pkg ./MacPorts-2.9.3-14-Sonoma.pkg -target /
wget https://github.com/macports/macports-base/releases/download/v2.11.5/MacPorts-2.11.5-14-Sonoma.pkg
sudo installer -pkg ./MacPorts-2.11.5-14-Sonoma.pkg -target /
fi
echo "/opt/local/bin:/opt/local/sbin" >> "$GITHUB_PATH"
- name: Install dependencies
@@ -233,6 +233,19 @@ jobs:
make
sudo make install
sudo cp -av /usr/local/lib/libzip* /lib/x86_64-linux-gnu/
# this is available in 24.04 but not in 22.04, manually install it
- name: Install valijson
run: |
export PATH="/usr/lib/ccache:/usr/local/opt/ccache/libexec:$PATH"
if [ ! -d "deps/valijson-1.0.6" ]; then
wget https://github.com/tristanpenman/valijson/archive/refs/tags/v1.0.6.tar.gz
tar -xzf v1.0.6.tar.gz -C deps
fi
cd deps/valijson-1.0.6
mkdir -p build
cd build
cmake ..
sudo cmake --install .
- name: Download soh.o2r
uses: actions/download-artifact@v4
with:

View File

@@ -83,7 +83,7 @@ if (CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(VCPKG_TARGET_TRIPLET x64-windows-static)
vcpkg_bootstrap()
vcpkg_install_packages(zlib bzip2 libzip libpng sdl2 sdl2-net glew glfw3 nlohmann-json tinyxml2 spdlog libogg libvorbis opus opusfile openssl)
vcpkg_install_packages(zlib bzip2 libzip libpng sdl2 sdl2-net glew glfw3 nlohmann-json tinyxml2 spdlog libogg libvorbis opus opusfile openssl valijson)
if (CMAKE_C_COMPILER_LAUNCHER MATCHES "ccache|sccache")
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT Embedded)
endif()

View File

@@ -289,11 +289,24 @@ endif()
################################################################################
add_compile_definitions(ASIO_STANDALONE)
if(BUILD_REMOTE_CONTROL)
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
FetchContent_Declare(
valijson
GIT_REPOSITORY https://github.com/tristanpenman/valijson.git
GIT_TAG v1.0.6
)
FetchContent_MakeAvailable(valijson)
target_include_directories(${PROJECT_NAME} PRIVATE ${valijson_SOURCE_DIR}/include)
else()
find_package(valijson REQUIRED)
endif()
endif()
target_include_directories(${PROJECT_NAME} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/../subprojects/asio/include
${CMAKE_CURRENT_SOURCE_DIR}/../subprojects/websocketpp
${CMAKE_CURRENT_SOURCE_DIR}/../subprojects/wswrap/include
${CMAKE_CURRENT_SOURCE_DIR}/../subprojects/valijson/include
${CMAKE_CURRENT_SOURCE_DIR}/../subprojects/apclientpp
)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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