From def6549bcb14d5e01e7f0524d6694684c3b975be Mon Sep 17 00:00:00 2001 From: Joshua Scott Date: Sat, 15 Dec 2018 16:51:45 +0000 Subject: [PATCH] pclass: Implement casters between primitives and json object --- CMakeLists.txt | 5 +- include/ki/pclass/Casters.h | 337 + include/ki/pclass/StaticProperty.h | 32 +- include/ki/pclass/TypeSystem.h | 7 + include/ki/pclass/Value.h | 21 +- include/ki/pclass/VectorProperty.h | 40 +- include/ki/pclass/types/StringPrimitiveType.h | 4 + src/pclass/TypeSystem.cpp | 19 +- src/pclass/Value.cpp | 6 +- third_party/json.hpp | 20274 ++++++++++++++++ 10 files changed, 20730 insertions(+), 15 deletions(-) create mode 100644 include/ki/pclass/Casters.h create mode 100644 third_party/json.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b6650d..fb875d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,9 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake) set(RAPIDXML_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/third_party) add_library(RapidXML INTERFACE) target_include_directories(RapidXML INTERFACE ${RAPIDXML_INCLUDE_DIR}) +set(JSON_INCLUDE_DIR ${PROJECT_SOURCE_DIR}/third_party) +add_library(JSON INTERFACE) +target_include_directories(JSON INTERFACE ${JSON_INCLUDE_DIR}) find_package(ZLIB REQUIRED) include_directories(${ZLIB_INCLUDE_DIRS}) @@ -19,7 +22,7 @@ target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR}/include ) -target_link_libraries(${PROJECT_NAME} RapidXML ${ZLIB_LIBRARIES}) +target_link_libraries(${PROJECT_NAME} RapidXML JSON ${ZLIB_LIBRARIES}) add_subdirectory("src/dml") add_subdirectory("src/pclass") diff --git a/include/ki/pclass/Casters.h b/include/ki/pclass/Casters.h new file mode 100644 index 0000000..28cc6eb --- /dev/null +++ b/include/ki/pclass/Casters.h @@ -0,0 +1,337 @@ +#pragma once +#include +#include +#include +#include "ki/pclass/Value.h" +#include "ki/pclass/types/EnumType.h" + +namespace ki +{ +namespace pclass +{ +namespace detail +{ + /** + * A utility to call ValueCaster::declare with + * bi and bui as the destination type. + * + * N is automatically decremented until it reaches 0. + */ + template + struct bit_integer_declarer + { + static void declare() + { + bit_integer_declarer::declare(); + ValueCaster::declare>(); + ValueCaster::declare>(); + } + }; + + /** + * Specialization for bit_integer_declarer. + * Stop decrementing N when it reaches 0. + */ + template + struct bit_integer_declarer + { + static void declare() {} + }; + + /** + * Determines whether a type can be assigned to a + * nlohmann::json object. + */ + template + struct is_json_assignable : std::false_type {}; + + /** + * All fundamental types can be assigned to a json object. + */ + template + struct is_json_assignable< + SrcT, + typename std::enable_if::value>::type + > : std::true_type {}; + + /** + * std::string can be assigned to a json object. + */ + template <> + struct is_json_assignable : std::true_type {}; + + /** + * value_caster specialization for the generic case of casting + * any json-assignable value to a json object. + */ + template + struct value_caster< + SrcT, nlohmann::json, + typename std::enable_if::value>::type + > + : value_caster_impl + { + Value cast(const Value &value) const override + { + const nlohmann::json j = value.get(); + return Value::make_value(j); + } + }; + + /** + * value_caster specialization for casting bi and bui + * to a json object. + */ + template + struct value_caster< + BitInteger, nlohmann::json + > + : value_caster_impl, nlohmann::json> + { + using type = typename std::conditional< + Unsigned, + typename bits::uint_type, + typename bits::int_type + >::type; + + Value cast(const Value &value) const override + { + const nlohmann::json j = static_cast( + value.get>() + ); + return Value::make_value(j); + } + }; + + /** + * value_caster specialization for casting enums to a json object. + */ + template + struct value_caster< + SrcT, nlohmann::json, + typename std::enable_if::value>::type + > + : value_caster_impl + { + using underlying_type = typename std::underlying_type::type; + + Value cast(const Value &value) const override + { + const auto underlying_value = + static_cast(value.get()); + const nlohmann::json j = underlying_value; + return Value::make_value(j); + } + }; + + /** + * value_caster specialization for casting enums to bit integer types. + */ + template < + typename SrcT, + int N, bool Unsigned + > + struct value_caster< + SrcT, BitInteger, + typename std::enable_if::value>::type + > + : value_caster_impl + { + using underlying_type = typename std::underlying_type::type; + + Value cast(const Value &value) const override + { + const auto underlying_value = + static_cast(value.get()); + const auto bit_value = BitInteger(underlying_value); + return Value::make_value>(bit_value); + } + }; + + template + struct string_cast_t + { + using type = T; + }; + + /** + * Writing a int8_t or uint8_t value to a stream will + * write a ASCII character, rather than an integer, so + * we cast to int16_t/uint16_t before writing. + */ + template <> + struct string_cast_t + { + using type = int16_t; + }; + template <> + struct string_cast_t + { + using type = uint16_t; + }; + + /** + * Enums should be written as 32-bit integers. + */ + template + struct string_cast_t< + T, + typename std::enable_if::value>::type + > + { + using type = enum_value_t; + }; + + /** + * Caster implementation for casting any type to string + * via std::ostringstream. + */ + template + struct value_caster + : value_caster_impl + { + Value cast(const Value &value) const override + { + std::ostringstream oss; + auto casted_value = static_cast< + typename string_cast_t::type + >(value.get()); + oss << casted_value; + return Value::make_value(oss.str()); + } + }; + + /** + * Utility class used by TypeSystem to declare casters for each + * primitive type. + */ + template + struct caster_declarer + { + static void declare() {} + }; + + /** + * caster_declarer specialization for all integral types. + * Integers can cast to other integer types, as well as floating point + * integers, std::string and nlohmann::json. + */ + template + struct caster_declarer< + T, + typename std::enable_if::value>::type + > + { + static void declare() + { + ValueCaster::declare(); + bit_integer_declarer::declare(); + ValueCaster::declare(); + ValueCaster::declare(); + ValueCaster::declare>(); + ValueCaster::declare(); + ValueCaster::declare(); + ValueCaster::declare(); + ValueCaster::declare(); + ValueCaster::declare>(); + ValueCaster::declare(); + ValueCaster::declare(); + ValueCaster::declare(); + ValueCaster::declare(); + ValueCaster::declare(); + ValueCaster::declare(); + } + }; + + /** + * caster_declarer specialization for all floating point types. + * Floating point integers can cast to all integer types, as well as + * std::string and nlohmann::json. + */ + template + struct caster_declarer< + T, + typename std::enable_if::value>::type + > + { + static void declare() + { + ValueCaster::declare(); + bit_integer_declarer::declare(); + ValueCaster::declare(); + ValueCaster::declare(); + ValueCaster::declare>(); + ValueCaster::declare(); + ValueCaster::declare(); + ValueCaster::declare(); + ValueCaster::declare(); + ValueCaster::declare>(); + ValueCaster::declare(); + ValueCaster::declare(); + ValueCaster::declare(); + ValueCaster::declare(); + ValueCaster::declare(); + ValueCaster::declare(); + } + }; + + /** + * caster_declarer specialization for enum types. + * Enums can be cast to any integer type, as well as std::string, + * and nlohmann::json. + */ + template + struct caster_declarer< + T, + typename std::enable_if::value>::type + > + { + static void declare() + { + ValueCaster::declare(); + bit_integer_declarer::declare(); + ValueCaster::declare(); + ValueCaster::declare(); + ValueCaster::declare>(); + ValueCaster::declare(); + ValueCaster::declare(); + ValueCaster::declare(); + ValueCaster::declare(); + ValueCaster::declare>(); + ValueCaster::declare(); + ValueCaster::declare(); + ValueCaster::declare(); + ValueCaster::declare(); + } + }; + + /** + * caster_declarer specialization for string. + * Strings can be cast to UTF-16 strings, and json objects. + */ + template <> + struct caster_declarer + { + static void declare() + { + // TODO: Casting string to u16string + ValueCaster::declare(); + } + }; + + /** + * caster_declarer specialization for UTF-16 strings. + * UTF-16 strings can be cast to strings, and json objects. + */ + template <> + struct caster_declarer + { + static void declare() + { + // TODO: Casting u16string to string + ValueCaster::declare(); + } + }; +} +} +} diff --git a/include/ki/pclass/StaticProperty.h b/include/ki/pclass/StaticProperty.h index 2981cbb..4b1f78d 100644 --- a/include/ki/pclass/StaticProperty.h +++ b/include/ki/pclass/StaticProperty.h @@ -36,6 +36,12 @@ namespace pclass return ValueT(prop.m_value); } + static Value get_value(const StaticProperty &prop) + { + // Return a reference to the property's value + return Value::make_reference(prop.m_value); + } + static const PropertyClass *get_object(const StaticProperty &prop) { // ValueT does not derive from PropertyClass, and so, this property is not @@ -80,6 +86,8 @@ namespace pclass >::type > { + using nonpointer_type = typename std::remove_pointer::type; + static ValueT construct(const Type &type) { // The default value of pointers is null @@ -93,6 +101,11 @@ namespace pclass return prop.m_value; } + static Value get_value(const StaticProperty &prop) + { + return Value::make_reference(*prop.m_value); + } + static const PropertyClass *get_object(const StaticProperty &prop) { // ValueT does not derive from PropertyClass, and so, this property is not @@ -140,6 +153,8 @@ namespace pclass >::type > { + using nonpointer_type = typename std::remove_pointer::type; + static ValueT construct(const Type &type) { // The default value of pointers is null @@ -153,6 +168,11 @@ namespace pclass return prop.m_value; } + static Value get_value(const StaticProperty &prop) + { + return Value::make_reference(*prop.m_value); + } + static const PropertyClass *get_object(const StaticProperty &prop) { // ValueT does derive from PropertyClass, and we have a pointer to an instance @@ -215,6 +235,11 @@ namespace pclass delete value_ptr; return value; } + + static Value get_value(const StaticProperty &prop) + { + return Value::make_reference(prop.m_value); + } static const PropertyClass *get_object(const StaticProperty &prop) { @@ -313,6 +338,11 @@ namespace pclass return value_object_helper::copy(prop); } + static Value get_value(const StaticProperty &prop) + { + return value_object_helper::get_value(prop); + } + static const PropertyClass *get_object(const StaticProperty &prop) { return value_object_helper::get_object(prop); @@ -381,7 +411,7 @@ namespace pclass Value get_value() const override { - return Value::make_reference(m_value); + return value_helper::get_value(*this); } const PropertyClass *get_object() const override diff --git a/include/ki/pclass/TypeSystem.h b/include/ki/pclass/TypeSystem.h index c1f60f3..5608335 100644 --- a/include/ki/pclass/TypeSystem.h +++ b/include/ki/pclass/TypeSystem.h @@ -6,6 +6,7 @@ #include "ki/pclass/types/PrimitiveType.h" #include "ki/pclass/types/ClassType.h" #include "ki/pclass/types/EnumType.h" +#include "ki/pclass/Casters.h" namespace ki { @@ -30,6 +31,7 @@ namespace pclass template PrimitiveType &define_primitive(const std::string &name) { + detail::caster_declarer::declare(); auto *type = new PrimitiveType(name, *this); define_type(std::unique_ptr( dynamic_cast(type) @@ -50,9 +52,12 @@ namespace pclass return define_class(name, &base_class); } + EnumType &define_enum(const std::string &name); + template CppEnumType &define_enum(const std::string &name) { + detail::caster_declarer::declare(); auto *type = new CppEnumType(name, *this); define_type(std::unique_ptr( dynamic_cast(type) @@ -83,6 +88,8 @@ namespace pclass ClassType &define_class( const std::string &name, const Type *base_class) { + detail::caster_declarer::declare(); + // If the caller does not specify a base class, automatically make // ki::pclass::PropertyClass the base class (if it has been defined) if (base_class == nullptr && has_type("class PropertyClass")) diff --git a/include/ki/pclass/Value.h b/include/ki/pclass/Value.h index be1c2ff..7351303 100644 --- a/include/ki/pclass/Value.h +++ b/include/ki/pclass/Value.h @@ -15,7 +15,10 @@ namespace pclass namespace detail { - template + template < + typename SrcT, typename DestT, + typename SrcEnable = void, typename DestEnable = void + > struct value_caster; /** @@ -160,7 +163,7 @@ namespace pclass * A static lookup used to find appropriate casters at runtime. * Contains SrcT -> Caster elements. */ - static std::unordered_map s_caster_lookup; + static std::unordered_map *s_caster_lookup; const std::type_info *m_src_type; std::unordered_map m_casts; @@ -175,11 +178,14 @@ namespace pclass template static ValueCaster &get() { + if (!s_caster_lookup) + s_caster_lookup = new std::unordered_map(); + const auto &src_type = typeid(SrcT); const auto src_type_hash = src_type.hash_code(); - if (s_caster_lookup.find(src_type_hash) == s_caster_lookup.end()) - s_caster_lookup[src_type_hash] = new ValueCaster(src_type); - return *s_caster_lookup[src_type_hash]; + if (s_caster_lookup->find(src_type_hash) == s_caster_lookup->end()) + (*s_caster_lookup)[src_type_hash] = new ValueCaster(src_type); + return *s_caster_lookup->at(src_type_hash); } template @@ -388,7 +394,10 @@ namespace pclass /** * TODO: Documentation */ - template + template < + typename SrcT, typename DestT, + typename SrcEnable, typename DestEnable + > struct value_caster : value_caster_impl { Value cast(const Value &value) const override diff --git a/include/ki/pclass/VectorProperty.h b/include/ki/pclass/VectorProperty.h index 14373f8..5d69b41 100644 --- a/include/ki/pclass/VectorProperty.h +++ b/include/ki/pclass/VectorProperty.h @@ -34,6 +34,14 @@ namespace pclass return ValueT(prop.at(index)); } + static Value get_value(const VectorProperty &prop, const int index) + { + // Ensure index is within bounds + if (index < 0 || index >= prop.size()) + throw runtime_error("Index out of bounds."); + return Value::make_reference(prop.at(index)); + } + static const PropertyClass *get_object(const VectorProperty &prop, const int index) { // ValueT does not derive from PropertyClass, and so, this property is not @@ -82,6 +90,14 @@ namespace pclass return prop.at(index); } + static Value get_value(const VectorProperty &prop, const int index) + { + // Ensure index is within bounds + if (index < 0 || index >= prop.size()) + throw runtime_error("Index out of bounds."); + return Value::make_reference(*prop.at(index)); + } + static const PropertyClass *get_object(const VectorProperty &prop, const int index) { // ValueT does not derive from PropertyClass, and so, this property is not @@ -126,6 +142,14 @@ namespace pclass return prop.at(index); } + static Value get_value(const VectorProperty &prop, const int index) + { + // Ensure index is within bounds + if (index < 0 || index >= prop.size()) + throw runtime_error("Index out of bounds."); + return Value::make_reference(*prop.at(index)); + } + static const PropertyClass *get_object(const VectorProperty &prop, const int index) { // Ensure index is within bounds @@ -185,6 +209,14 @@ namespace pclass return value; } + static Value get_value(const VectorProperty &prop, const int index) + { + // Ensure index is within bounds + if (index < 0 || index >= prop.size()) + throw runtime_error("Index out of bounds."); + return Value::make_reference(prop.at(index)); + } + static const PropertyClass *get_object(const VectorProperty &prop, const int index) { // Ensure index is within bounds @@ -300,6 +332,12 @@ namespace pclass return vector_value_object_helper::get_object(prop, index); } + static Value get_value(const VectorProperty &prop, + const int index) + { + return vector_value_object_helper::get_value(prop, index); + } + static void set_object(VectorProperty &prop, std::unique_ptr &object, const int index) { @@ -364,7 +402,7 @@ namespace pclass { if (index < 0 || index >= this->size()) throw runtime_error("Index out of bounds."); - return Value::make_reference(this->at(index)); + return vector_value_helper::get_value(*this, index); } const PropertyClass *get_object(const int index) const override diff --git a/include/ki/pclass/types/StringPrimitiveType.h b/include/ki/pclass/types/StringPrimitiveType.h index a220009..1ff952b 100644 --- a/include/ki/pclass/types/StringPrimitiveType.h +++ b/include/ki/pclass/types/StringPrimitiveType.h @@ -1,4 +1,5 @@ #pragma once +#include #include namespace ki @@ -7,6 +8,9 @@ namespace pclass { namespace detail { + /** + * primitive_type_helper specialization for string types. + */ template < typename _Elem, typename _Traits, diff --git a/src/pclass/TypeSystem.cpp b/src/pclass/TypeSystem.cpp index 25fa154..751c122 100644 --- a/src/pclass/TypeSystem.cpp +++ b/src/pclass/TypeSystem.cpp @@ -13,8 +13,8 @@ namespace ki { namespace pclass { - template - void define_bit_integer_primitive(pclass::TypeSystem &type_system) + template + void define_bit_integer_primitive(TypeSystem &type_system) { define_bit_integer_primitive(type_system); @@ -29,6 +29,10 @@ namespace pclass type_system.define_primitive>(oss.str()); } + /** + * Specialization for define_bit_integer_primitive. + * Stop decrementing N when it reaches 0. + */ template <> void define_bit_integer_primitive<0>(TypeSystem &type_system) {} @@ -58,7 +62,7 @@ namespace pclass define_primitive("gid"); // Define bit-integer types - define_bit_integer_primitive<7>(*this); + define_bit_integer_primitive(*this); define_primitive>("s24"); define_primitive>("u24"); @@ -118,6 +122,15 @@ namespace pclass return *it->second; } + EnumType &TypeSystem::define_enum(const std::string& name) + { + auto *type = new EnumType(name, *this); + define_type(std::unique_ptr( + dynamic_cast(type) + )); + return *type; + } + void TypeSystem::define_type(std::unique_ptr type) { // Does a type with this name already exist? diff --git a/src/pclass/Value.cpp b/src/pclass/Value.cpp index 4171986..a134d00 100644 --- a/src/pclass/Value.cpp +++ b/src/pclass/Value.cpp @@ -4,6 +4,9 @@ namespace ki { namespace pclass { + // Initialize the static lookup map + std::unordered_map *ValueCaster::s_caster_lookup = nullptr; + namespace detail { Value value_caster_base::cast(const Value &v) const @@ -109,8 +112,5 @@ namespace pclass m_deallocator.deallocate(m_value_ptr); m_value_ptr = nullptr; } - - // Initialize the static lookup map - std::unordered_map ValueCaster::s_caster_lookup = {}; } } diff --git a/third_party/json.hpp b/third_party/json.hpp new file mode 100644 index 0000000..1e7cf51 --- /dev/null +++ b/third_party/json.hpp @@ -0,0 +1,20274 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ +| | |__ | | | | | | version 3.4.0 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +SPDX-License-Identifier: MIT +Copyright (c) 2013-2018 Niels Lohmann . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef NLOHMANN_JSON_HPP +#define NLOHMANN_JSON_HPP + +#define NLOHMANN_JSON_VERSION_MAJOR 3 +#define NLOHMANN_JSON_VERSION_MINOR 4 +#define NLOHMANN_JSON_VERSION_PATCH 0 + +#include // all_of, find, for_each +#include // assert +#include // and, not, or +#include // nullptr_t, ptrdiff_t, size_t +#include // hash, less +#include // initializer_list +#include // istream, ostream +#include // iterator_traits, random_access_iterator_tag +#include // accumulate +#include // string, stoi, to_string +#include // declval, forward, move, pair, swap + +// #include +#ifndef NLOHMANN_JSON_FWD_HPP +#define NLOHMANN_JSON_FWD_HPP + +#include // int64_t, uint64_t +#include // map +#include // allocator +#include // string +#include // vector + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +@since version 1.0.0 +*/ +namespace nlohmann +{ +/*! +@brief default JSONSerializer template argument + +This serializer ignores the template arguments and uses ADL +([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl)) +for serialization. +*/ +template +struct adl_serializer; + +template class ObjectType = + std::map, + template class ArrayType = std::vector, + class StringType = std::string, class BooleanType = bool, + class NumberIntegerType = std::int64_t, + class NumberUnsignedType = std::uint64_t, + class NumberFloatType = double, + template class AllocatorType = std::allocator, + template class JSONSerializer = + adl_serializer> +class basic_json; + +/*! +@brief JSON Pointer + +A JSON pointer defines a string syntax for identifying a specific value +within a JSON document. It can be used with functions `at` and +`operator[]`. Furthermore, JSON pointers are the base for JSON patches. + +@sa [RFC 6901](https://tools.ietf.org/html/rfc6901) + +@since version 2.0.0 +*/ +template +class json_pointer; + +/*! +@brief default JSON class + +This type is the default specialization of the @ref basic_json class which +uses the standard template types. + +@since version 1.0.0 +*/ +using json = basic_json<>; +} // namespace nlohmann + +#endif + +// #include + + +// This file contains all internal macro definitions +// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them + +// exclude unsupported compilers +#if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK) + #if defined(__clang__) + #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 + #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) + #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40800 + #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" + #endif + #endif +#endif + +// disable float-equal warnings on GCC/clang +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + +// disable documentation warnings on clang +#if defined(__clang__) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wdocumentation" +#endif + +// allow for portable deprecation warnings +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) + #define JSON_DEPRECATED __declspec(deprecated) +#else + #define JSON_DEPRECATED +#endif + +// allow to disable exceptions +#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) + #define JSON_THROW(exception) throw exception + #define JSON_TRY try + #define JSON_CATCH(exception) catch(exception) + #define JSON_INTERNAL_CATCH(exception) catch(exception) +#else + #define JSON_THROW(exception) std::abort() + #define JSON_TRY if(true) + #define JSON_CATCH(exception) if(false) + #define JSON_INTERNAL_CATCH(exception) if(false) +#endif + +// override exception macros +#if defined(JSON_THROW_USER) + #undef JSON_THROW + #define JSON_THROW JSON_THROW_USER +#endif +#if defined(JSON_TRY_USER) + #undef JSON_TRY + #define JSON_TRY JSON_TRY_USER +#endif +#if defined(JSON_CATCH_USER) + #undef JSON_CATCH + #define JSON_CATCH JSON_CATCH_USER + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_CATCH_USER +#endif +#if defined(JSON_INTERNAL_CATCH_USER) + #undef JSON_INTERNAL_CATCH + #define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER +#endif + +// manual branch prediction +#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) + #define JSON_LIKELY(x) __builtin_expect(!!(x), 1) + #define JSON_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else + #define JSON_LIKELY(x) x + #define JSON_UNLIKELY(x) x +#endif + +// C++ language standard detection +#if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 + #define JSON_HAS_CPP_17 + #define JSON_HAS_CPP_14 +#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) + #define JSON_HAS_CPP_14 +#endif + +/*! +@brief macro to briefly define a mapping between an enum and JSON +@def NLOHMANN_JSON_SERIALIZE_ENUM +@since version 3.4.0 +*/ +#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ + template \ + inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [e](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.first == e; \ + }); \ + j = ((it != std::end(m)) ? it : std::begin(m))->second; \ + } \ + template \ + inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ + { \ + static_assert(std::is_enum::value, #ENUM_TYPE " must be an enum!"); \ + static const std::pair m[] = __VA_ARGS__; \ + auto it = std::find_if(std::begin(m), std::end(m), \ + [j](const std::pair& ej_pair) -> bool \ + { \ + return ej_pair.second == j; \ + }); \ + e = ((it != std::end(m)) ? it : std::begin(m))->first; \ + } + +// Ugly macros to avoid uglier copy-paste when specializing basic_json. They +// may be removed in the future once the class is split. + +#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ + template class ObjectType, \ + template class ArrayType, \ + class StringType, class BooleanType, class NumberIntegerType, \ + class NumberUnsignedType, class NumberFloatType, \ + template class AllocatorType, \ + template class JSONSerializer> + +#define NLOHMANN_BASIC_JSON_TPL \ + basic_json + +// #include + + +#include // not +#include // size_t +#include // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type + +namespace nlohmann +{ +namespace detail +{ +// alias templates to reduce boilerplate +template +using enable_if_t = typename std::enable_if::type; + +template +using uncvref_t = typename std::remove_cv::type>::type; + +// implementation of C++14 index_sequence and affiliates +// source: https://stackoverflow.com/a/32223343 +template +struct index_sequence +{ + using type = index_sequence; + using value_type = std::size_t; + static constexpr std::size_t size() noexcept + { + return sizeof...(Ints); + } +}; + +template +struct merge_and_renumber; + +template +struct merge_and_renumber, index_sequence> + : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; + +template +struct make_index_sequence + : merge_and_renumber < typename make_index_sequence < N / 2 >::type, + typename make_index_sequence < N - N / 2 >::type > {}; + +template<> struct make_index_sequence<0> : index_sequence<> {}; +template<> struct make_index_sequence<1> : index_sequence<0> {}; + +template +using index_sequence_for = make_index_sequence; + +// dispatch utility (taken from ranges-v3) +template struct priority_tag : priority_tag < N - 1 > {}; +template<> struct priority_tag<0> {}; + +// taken from ranges-v3 +template +struct static_const +{ + static constexpr T value{}; +}; + +template +constexpr T static_const::value; +} // namespace detail +} // namespace nlohmann + +// #include + + +#include // not +#include // numeric_limits +#include // false_type, is_constructible, is_integral, is_same, true_type +#include // declval + +// #include + +// #include + +// #include + + +#include + +// #include + + +namespace nlohmann +{ +namespace detail +{ +template struct make_void +{ + using type = void; +}; +template using void_t = typename make_void::type; +} // namespace detail +} // namespace nlohmann + + +// http://en.cppreference.com/w/cpp/experimental/is_detected +namespace nlohmann +{ +namespace detail +{ +struct nonesuch +{ + nonesuch() = delete; + ~nonesuch() = delete; + nonesuch(nonesuch const&) = delete; + void operator=(nonesuch const&) = delete; +}; + +template class Op, + class... Args> +struct detector +{ + using value_t = std::false_type; + using type = Default; +}; + +template class Op, class... Args> +struct detector>, Op, Args...> +{ + using value_t = std::true_type; + using type = Op; +}; + +template