Index: net/zerotier/Makefile =================================================================== --- net/zerotier/Makefile +++ net/zerotier/Makefile @@ -3,13 +3,14 @@ PORTNAME= zerotier DISTVERSION= 1.2.10 -PORTREVISION= 1 +PORTREVISION= 2 CATEGORIES= net MAINTAINER= dch@FreeBSD.org COMMENT= Network virtualization everywhere -LICENSE= GPLv3 +LICENSE= GPLv3 MIT PD BSD3CLAUSE APACHE20 +LICENSE_COMB= multi LICENSE_FILE= ${WRKSRC}/LICENSE.GPL-3 BROKEN_armv6= fails to link: Source object ext/arm32-neon-salsa2012-asm/salsa2012.o has EABI version 0, but target zerotier-one has EABI version 5 Index: net/zerotier/files/patch-ext_json_json.hpp =================================================================== --- /dev/null +++ net/zerotier/files/patch-ext_json_json.hpp @@ -0,0 +1,10678 @@ +--- ext/json/json.hpp.orig 2018-05-11 20:40:22 UTC ++++ ext/json/json.hpp +@@ -1,11 +1,12 @@ + /* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ +-| | |__ | | | | | | version 3.0.1 ++| | |__ | | | | | | version 3.2.0 + |_____|_____|_____|_|___| https://github.com/nlohmann/json + + Licensed under the MIT License . +-Copyright (c) 2013-2017 Niels Lohmann . ++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 +@@ -29,43 +30,105 @@ SOFTWARE. + #ifndef NLOHMANN_JSON_HPP + #define NLOHMANN_JSON_HPP + +-#include // all_of, copy, fill, find, for_each, generate_n, none_of, remove, reverse, transform +-#include // array ++#define NLOHMANN_JSON_VERSION_MAJOR 3 ++#define NLOHMANN_JSON_VERSION_MINOR 2 ++#define NLOHMANN_JSON_VERSION_PATCH 0 ++ ++#include // all_of, find, for_each + #include // assert + #include // and, not, or +-#include // lconv, localeconv +-#include // isfinite, labs, ldexp, signbit + #include // nullptr_t, ptrdiff_t, size_t +-#include // int64_t, uint64_t +-#include // abort, strtod, strtof, strtold, strtoul, strtoll, strtoull +-#include // memcpy, strlen +-#include // forward_list +-#include // function, hash, less ++#include // hash, less + #include // initializer_list +-#include // hex +-#include // istream, ostream +-#include // advance, begin, back_inserter, bidirectional_iterator_tag, distance, end, inserter, iterator, iterator_traits, next, random_access_iterator_tag, reverse_iterator +-#include // numeric_limits +-#include // locale +-#include // map +-#include // addressof, allocator, allocator_traits, unique_ptr ++#include // istream, ostream ++#include // iterator_traits, random_access_iterator_tag + #include // accumulate +-#include // stringstream +-#include // getline, stoi, string, to_string +-#include // add_pointer, conditional, decay, enable_if, false_type, integral_constant, is_arithmetic, is_base_of, is_const, is_constructible, is_convertible, is_default_constructible, is_enum, is_floating_point, is_integral, is_nothrow_move_assignable, is_nothrow_move_constructible, is_pointer, is_reference, is_same, is_scalar, is_signed, remove_const, remove_cv, remove_pointer, remove_reference, true_type, underlying_type +-#include // declval, forward, make_pair, move, pair, swap +-#include // valarray ++#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<>; ++} ++ ++#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(__clang__) +- #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 +- #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-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__) < 40900 ++ #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" ++ #endif + #endif +-#elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) +- #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 +- #error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" +- #endif + #endif + + // disable float-equal warnings on GCC/clang +@@ -90,16 +153,37 @@ SOFTWARE. + #endif + + // allow to disable exceptions +-#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && not defined(JSON_NOEXCEPTION) ++#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 ++ #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) +@@ -117,27 +201,6 @@ SOFTWARE. + #define JSON_HAS_CPP_14 + #endif + +-/*! +-@brief namespace for Niels Lohmann +-@see https://github.com/nlohmann +-@since version 1.0.0 +-*/ +-namespace nlohmann +-{ +-template +-struct adl_serializer; +- +-// forward declaration of basic_json (required to split the class) +-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; +- + // Ugly macros to avoid uglier copy-paste when specializing basic_json. They + // may be removed in the future once the class is split. + +@@ -154,17 +217,334 @@ class basic_json; + NumberIntegerType, NumberUnsignedType, NumberFloatType, \ + AllocatorType, JSONSerializer> + ++/*! ++@brief Helper to determine whether there's a key_type for T. + ++This helper is used to tell associative containers apart from other containers ++such as sequence containers. For instance, `std::map` passes the test as it ++contains a `mapped_type`, whereas `std::vector` fails the test. ++ ++@sa http://stackoverflow.com/a/7728728/266378 ++@since version 1.0.0, overworked in version 2.0.6 ++*/ ++#define NLOHMANN_JSON_HAS_HELPER(type) \ ++ template struct has_##type { \ ++ private: \ ++ template \ ++ static int detect(U &&); \ ++ static void detect(...); \ ++ public: \ ++ static constexpr bool value = \ ++ std::is_integral()))>::value; \ ++ } ++ ++// #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; ++ ++/* ++Implementation of two C++17 constructs: conjunction, negation. This is needed ++to avoid evaluating all the traits in a condition ++ ++For example: not std::is_same::value and has_value_type::value ++will not compile when T = void (on MSVC at least). Whereas ++conjunction>, has_value_type>::value will ++stop evaluating if negation<...>::value == false ++ ++Please note that those constructs must be used with caution, since symbols can ++become very long quickly (which can slow down compilation and cause MSVC ++internal compiler errors). Only use it when you have to (see example ahead). ++*/ ++template struct conjunction : std::true_type {}; ++template struct conjunction : B1 {}; ++template ++struct conjunction : std::conditional, B1>::type {}; ++ ++template struct negation : std::integral_constant {}; ++ ++// 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; ++} ++} ++ ++// #include ++ ++ ++#include // not ++#include // numeric_limits ++#include // false_type, is_constructible, is_integral, is_same, true_type ++#include // declval ++ ++// #include ++ ++// #include ++ ++// #include ++ ++ ++namespace nlohmann ++{ + /*! +-@brief unnamed namespace with internal helper functions ++@brief detail namespace with internal helper functions + +-This namespace collects some functions that could not be defined inside the +-@ref basic_json class. ++This namespace collects functions that should not be exposed, ++implementations of some @ref basic_json methods, and meta-programming helpers. + + @since version 2.1.0 + */ + namespace detail + { ++///////////// ++// helpers // ++///////////// ++ ++template struct is_basic_json : std::false_type {}; ++ ++NLOHMANN_BASIC_JSON_TPL_DECLARATION ++struct is_basic_json : std::true_type {}; ++ ++//////////////////////// ++// has_/is_ functions // ++//////////////////////// ++ ++// source: https://stackoverflow.com/a/37193089/4116453 ++ ++template ++struct is_complete_type : std::false_type {}; ++ ++template ++struct is_complete_type : std::true_type {}; ++ ++NLOHMANN_JSON_HAS_HELPER(mapped_type); ++NLOHMANN_JSON_HAS_HELPER(key_type); ++NLOHMANN_JSON_HAS_HELPER(value_type); ++NLOHMANN_JSON_HAS_HELPER(iterator); ++ ++template ++struct is_compatible_object_type_impl : std::false_type {}; ++ ++template ++struct is_compatible_object_type_impl ++{ ++ static constexpr auto value = ++ std::is_constructible::value and ++ std::is_constructible::value; ++}; ++ ++template ++struct is_compatible_string_type_impl : std::false_type {}; ++ ++template ++struct is_compatible_string_type_impl ++{ ++ static constexpr auto value = ++ std::is_same::value and ++ std::is_constructible::value; ++}; ++ ++template ++struct is_compatible_object_type ++{ ++ static auto constexpr value = is_compatible_object_type_impl < ++ conjunction>, ++ has_mapped_type, ++ has_key_type>::value, ++ typename BasicJsonType::object_t, CompatibleObjectType >::value; ++}; ++ ++template ++struct is_compatible_string_type ++{ ++ static auto constexpr value = is_compatible_string_type_impl < ++ conjunction>, ++ has_value_type>::value, ++ typename BasicJsonType::string_t, CompatibleStringType >::value; ++}; ++ ++template ++struct is_basic_json_nested_type ++{ ++ static auto constexpr value = std::is_same::value or ++ std::is_same::value or ++ std::is_same::value or ++ std::is_same::value; ++}; ++ ++template ++struct is_compatible_array_type ++{ ++ static auto constexpr value = ++ conjunction>, ++ negation>, ++ negation>, ++ negation>, ++ has_value_type, ++ has_iterator>::value; ++}; ++ ++template ++struct is_compatible_integer_type_impl : std::false_type {}; ++ ++template ++struct is_compatible_integer_type_impl ++{ ++ // is there an assert somewhere on overflows? ++ using RealLimits = std::numeric_limits; ++ using CompatibleLimits = std::numeric_limits; ++ ++ static constexpr auto value = ++ std::is_constructible::value and ++ CompatibleLimits::is_integer and ++ RealLimits::is_signed == CompatibleLimits::is_signed; ++}; ++ ++template ++struct is_compatible_integer_type ++{ ++ static constexpr auto value = ++ is_compatible_integer_type_impl < ++ std::is_integral::value and ++ not std::is_same::value, ++ RealIntegerType, CompatibleNumberIntegerType > ::value; ++}; ++ ++// trait checking if JSONSerializer::from_json(json const&, udt&) exists ++template ++struct has_from_json ++{ ++ private: ++ // also check the return type of from_json ++ template::from_json( ++ std::declval(), std::declval()))>::value>> ++ static int detect(U&&); ++ static void detect(...); ++ ++ public: ++ static constexpr bool value = std::is_integral>()))>::value; ++}; ++ ++// This trait checks if JSONSerializer::from_json(json const&) exists ++// this overload is used for non-default-constructible user-defined-types ++template ++struct has_non_default_from_json ++{ ++ private: ++ template < ++ typename U, ++ typename = enable_if_t::from_json(std::declval()))>::value >> ++ static int detect(U&&); ++ static void detect(...); ++ ++ public: ++ static constexpr bool value = std::is_integral>()))>::value; ++}; ++ ++// This trait checks if BasicJsonType::json_serializer::to_json exists ++template ++struct has_to_json ++{ ++ private: ++ template::to_json( ++ std::declval(), std::declval()))> ++ static int detect(U&&); ++ static void detect(...); ++ ++ public: ++ static constexpr bool value = std::is_integral>()))>::value; ++}; ++ ++template ++struct is_compatible_complete_type ++{ ++ static constexpr bool value = ++ not std::is_base_of::value and ++ not is_basic_json::value and ++ not is_basic_json_nested_type::value and ++ has_to_json::value; ++}; ++ ++template ++struct is_compatible_type ++ : conjunction, ++ is_compatible_complete_type> ++{ ++}; ++} ++} ++ ++// #include ++ ++ ++#include // exception ++#include // runtime_error ++#include // to_string ++ ++namespace nlohmann ++{ ++namespace detail ++{ + //////////////// + // exceptions // + //////////////// +@@ -419,6 +799,8 @@ json.exception.out_of_range.403 | key 'foo' not found + json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference token in a JSON Pointer could not be resolved. + json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. + json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. ++json.exception.out_of_range.407 | number overflow serializing '9223372036854775808' | UBJSON only supports integers numbers up to 9223372036854775807. | ++json.exception.out_of_range.408 | excessive array size: 8658170730974374167 | The size (following `#`) of an UBJSON array or object exceeds the maximal capacity. | + + @liveexample{The following code shows how an `out_of_range` exception can be + caught.,out_of_range} +@@ -481,9 +863,21 @@ class other_error : public exception + private: + other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} + }; ++} ++} + ++// #include + + ++#include // array ++#include // and ++#include // size_t ++#include // uint8_t ++ ++namespace nlohmann ++{ ++namespace detail ++{ + /////////////////////////// + // JSON type enumeration // + /////////////////////////// +@@ -512,7 +906,7 @@ value with the default value for a given type + + @since version 1.0.0 + */ +-enum class value_t : uint8_t ++enum class value_t : std::uint8_t + { + null, ///< null value + object, ///< object (unordered set of name/value pairs) +@@ -537,7 +931,7 @@ Returns an ordering that is similar to Python: + */ + inline bool operator<(const value_t lhs, const value_t rhs) noexcept + { +- static constexpr std::array order = {{ ++ static constexpr std::array order = {{ + 0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, + 1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */ + } +@@ -547,80 +941,558 @@ inline bool operator<(const value_t lhs, const value_t + const auto r_index = static_cast(rhs); + return l_index < order.size() and r_index < order.size() and order[l_index] < order[r_index]; + } ++} ++} + ++// #include + +-///////////// +-// helpers // +-///////////// + +-template struct is_basic_json : std::false_type {}; ++#include // transform ++#include // array ++#include // and, not ++#include // forward_list ++#include // inserter, front_inserter, end ++#include // map ++#include // string ++#include // tuple, make_tuple ++#include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible ++#include // unordered_map ++#include // pair, declval ++#include // valarray + +-NLOHMANN_BASIC_JSON_TPL_DECLARATION +-struct is_basic_json : std::true_type {}; ++// #include + +-// alias templates to reduce boilerplate +-template +-using enable_if_t = typename std::enable_if::type; ++// #include + +-template +-using uncvref_t = typename std::remove_cv::type>::type; ++// #include + +-// implementation of C++14 index_sequence and affiliates +-// source: https://stackoverflow.com/a/32223343 +-template +-struct index_sequence ++// #include ++ ++// #include ++ ++ ++namespace nlohmann + { +- using type = index_sequence; +- using value_type = std::size_t; +- static constexpr std::size_t size() noexcept ++namespace detail ++{ ++template ++void from_json(const BasicJsonType& j, typename std::nullptr_t& n) ++{ ++ if (JSON_UNLIKELY(not j.is_null())) + { +- return sizeof...(Ints); ++ JSON_THROW(type_error::create(302, "type must be null, but is " + std::string(j.type_name()))); + } ++ n = nullptr; ++} ++ ++// overloads for basic_json template parameters ++template::value and ++ not std::is_same::value, ++ int> = 0> ++void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) ++{ ++ switch (static_cast(j)) ++ { ++ case value_t::number_unsigned: ++ { ++ val = static_cast(*j.template get_ptr()); ++ break; ++ } ++ case value_t::number_integer: ++ { ++ val = static_cast(*j.template get_ptr()); ++ break; ++ } ++ case value_t::number_float: ++ { ++ val = static_cast(*j.template get_ptr()); ++ break; ++ } ++ ++ default: ++ JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); ++ } ++} ++ ++template ++void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) ++{ ++ if (JSON_UNLIKELY(not j.is_boolean())) ++ { ++ JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name()))); ++ } ++ b = *j.template get_ptr(); ++} ++ ++template ++void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) ++{ ++ if (JSON_UNLIKELY(not j.is_string())) ++ { ++ JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); ++ } ++ s = *j.template get_ptr(); ++} ++ ++template < ++ typename BasicJsonType, typename CompatibleStringType, ++ enable_if_t < ++ is_compatible_string_type::value and ++ not std::is_same::value, ++ int > = 0 > ++void from_json(const BasicJsonType& j, CompatibleStringType& s) ++{ ++ if (JSON_UNLIKELY(not j.is_string())) ++ { ++ JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); ++ } ++ ++ s = *j.template get_ptr(); ++} ++ ++template ++void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) ++{ ++ get_arithmetic_value(j, val); ++} ++ ++template ++void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val) ++{ ++ get_arithmetic_value(j, val); ++} ++ ++template ++void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val) ++{ ++ get_arithmetic_value(j, val); ++} ++ ++template::value, int> = 0> ++void from_json(const BasicJsonType& j, EnumType& e) ++{ ++ typename std::underlying_type::type val; ++ get_arithmetic_value(j, val); ++ e = static_cast(val); ++} ++ ++template ++void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr) ++{ ++ if (JSON_UNLIKELY(not j.is_array())) ++ { ++ JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); ++ } ++ arr = *j.template get_ptr(); ++} ++ ++// forward_list doesn't have an insert method ++template::value, int> = 0> ++void from_json(const BasicJsonType& j, std::forward_list& l) ++{ ++ if (JSON_UNLIKELY(not j.is_array())) ++ { ++ JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); ++ } ++ std::transform(j.rbegin(), j.rend(), ++ std::front_inserter(l), [](const BasicJsonType & i) ++ { ++ return i.template get(); ++ }); ++} ++ ++// valarray doesn't have an insert method ++template::value, int> = 0> ++void from_json(const BasicJsonType& j, std::valarray& l) ++{ ++ if (JSON_UNLIKELY(not j.is_array())) ++ { ++ JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); ++ } ++ l.resize(j.size()); ++ std::copy(j.m_value.array->begin(), j.m_value.array->end(), std::begin(l)); ++} ++ ++template ++void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<0> /*unused*/) ++{ ++ using std::end; ++ ++ std::transform(j.begin(), j.end(), ++ std::inserter(arr, end(arr)), [](const BasicJsonType & i) ++ { ++ // get() returns *this, this won't call a from_json ++ // method when value_type is BasicJsonType ++ return i.template get(); ++ }); ++} ++ ++template ++auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1> /*unused*/) ++-> decltype( ++ arr.reserve(std::declval()), ++ void()) ++{ ++ using std::end; ++ ++ arr.reserve(j.size()); ++ std::transform(j.begin(), j.end(), ++ std::inserter(arr, end(arr)), [](const BasicJsonType & i) ++ { ++ // get() returns *this, this won't call a from_json ++ // method when value_type is BasicJsonType ++ return i.template get(); ++ }); ++} ++ ++template ++void from_json_array_impl(const BasicJsonType& j, std::array& arr, priority_tag<2> /*unused*/) ++{ ++ for (std::size_t i = 0; i < N; ++i) ++ { ++ arr[i] = j.at(i).template get(); ++ } ++} ++ ++template < ++ typename BasicJsonType, typename CompatibleArrayType, ++ enable_if_t < ++ is_compatible_array_type::value and ++ not std::is_same::value and ++ std::is_constructible < ++ BasicJsonType, typename CompatibleArrayType::value_type >::value, ++ int > = 0 > ++void from_json(const BasicJsonType& j, CompatibleArrayType& arr) ++{ ++ if (JSON_UNLIKELY(not j.is_array())) ++ { ++ JSON_THROW(type_error::create(302, "type must be array, but is " + ++ std::string(j.type_name()))); ++ } ++ ++ from_json_array_impl(j, arr, priority_tag<2> {}); ++} ++ ++template::value, int> = 0> ++void from_json(const BasicJsonType& j, CompatibleObjectType& obj) ++{ ++ if (JSON_UNLIKELY(not j.is_object())) ++ { ++ JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name()))); ++ } ++ ++ auto inner_object = j.template get_ptr(); ++ using value_type = typename CompatibleObjectType::value_type; ++ std::transform( ++ inner_object->begin(), inner_object->end(), ++ std::inserter(obj, obj.begin()), ++ [](typename BasicJsonType::object_t::value_type const & p) ++ { ++ return value_type(p.first, p.second.template get()); ++ }); ++} ++ ++// overload for arithmetic types, not chosen for basic_json template arguments ++// (BooleanType, etc..); note: Is it really necessary to provide explicit ++// overloads for boolean_t etc. in case of a custom BooleanType which is not ++// an arithmetic type? ++template::value and ++ not std::is_same::value and ++ not std::is_same::value and ++ not std::is_same::value and ++ not std::is_same::value, ++ int> = 0> ++void from_json(const BasicJsonType& j, ArithmeticType& val) ++{ ++ switch (static_cast(j)) ++ { ++ case value_t::number_unsigned: ++ { ++ val = static_cast(*j.template get_ptr()); ++ break; ++ } ++ case value_t::number_integer: ++ { ++ val = static_cast(*j.template get_ptr()); ++ break; ++ } ++ case value_t::number_float: ++ { ++ val = static_cast(*j.template get_ptr()); ++ break; ++ } ++ case value_t::boolean: ++ { ++ val = static_cast(*j.template get_ptr()); ++ break; ++ } ++ ++ default: ++ JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); ++ } ++} ++ ++template ++void from_json(const BasicJsonType& j, std::pair& p) ++{ ++ p = {j.at(0).template get(), j.at(1).template get()}; ++} ++ ++template ++void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence) ++{ ++ t = std::make_tuple(j.at(Idx).template get::type>()...); ++} ++ ++template ++void from_json(const BasicJsonType& j, std::tuple& t) ++{ ++ from_json_tuple_impl(j, t, index_sequence_for {}); ++} ++ ++template ::value>> ++void from_json(const BasicJsonType& j, std::map& m) ++{ ++ if (JSON_UNLIKELY(not j.is_array())) ++ { ++ JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); ++ } ++ for (const auto& p : j) ++ { ++ if (JSON_UNLIKELY(not p.is_array())) ++ { ++ JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name()))); ++ } ++ m.emplace(p.at(0).template get(), p.at(1).template get()); ++ } ++} ++ ++template ::value>> ++void from_json(const BasicJsonType& j, std::unordered_map& m) ++{ ++ if (JSON_UNLIKELY(not j.is_array())) ++ { ++ JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); ++ } ++ for (const auto& p : j) ++ { ++ if (JSON_UNLIKELY(not p.is_array())) ++ { ++ JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name()))); ++ } ++ m.emplace(p.at(0).template get(), p.at(1).template get()); ++ } ++} ++ ++struct from_json_fn ++{ ++ private: ++ template ++ auto call(const BasicJsonType& j, T& val, priority_tag<1> /*unused*/) const ++ noexcept(noexcept(from_json(j, val))) ++ -> decltype(from_json(j, val), void()) ++ { ++ return from_json(j, val); ++ } ++ ++ template ++ void call(const BasicJsonType& /*unused*/, T& /*unused*/, priority_tag<0> /*unused*/) const noexcept ++ { ++ static_assert(sizeof(BasicJsonType) == 0, ++ "could not find from_json() method in T's namespace"); ++#ifdef _MSC_VER ++ // MSVC does not show a stacktrace for the above assert ++ using decayed = uncvref_t; ++ static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, ++ "forcing MSVC stacktrace to show which T we're talking about."); ++#endif ++ } ++ ++ public: ++ template ++ void operator()(const BasicJsonType& j, T& val) const ++ noexcept(noexcept(std::declval().call(j, val, priority_tag<1> {}))) ++ { ++ return call(j, val, priority_tag<1> {}); ++ } + }; ++} + +-template +-struct merge_and_renumber; ++/// namespace to hold default `from_json` function ++/// to see why this is required: ++/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html ++namespace ++{ ++constexpr const auto& from_json = detail::static_const::value; ++} ++} + +-template +-struct merge_and_renumber, index_sequence> +- : index_sequence < I1..., (sizeof...(I1) + I2)... > {}; ++// #include + +-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> {}; ++#include // or, and, not ++#include // begin, end ++#include // tuple, get ++#include // is_same, is_constructible, is_floating_point, is_enum, underlying_type ++#include // move, forward, declval, pair ++#include // valarray ++#include // vector + +-template +-using index_sequence_for = make_index_sequence; ++// #include + +-/* +-Implementation of two C++17 constructs: conjunction, negation. This is needed +-to avoid evaluating all the traits in a condition ++// #include + +-For example: not std::is_same::value and has_value_type::value +-will not compile when T = void (on MSVC at least). Whereas +-conjunction>, has_value_type>::value will +-stop evaluating if negation<...>::value == false ++// #include + +-Please note that those constructs must be used with caution, since symbols can +-become very long quickly (which can slow down compilation and cause MSVC +-internal compiler errors). Only use it when you have to (see example ahead). +-*/ +-template struct conjunction : std::true_type {}; +-template struct conjunction : B1 {}; +-template +-struct conjunction : std::conditional, B1>::type {}; ++// #include + +-template struct negation : std::integral_constant {}; + +-// dispatch utility (taken from ranges-v3) +-template struct priority_tag : priority_tag < N - 1 > {}; +-template<> struct priority_tag<0> {}; ++#include // size_t ++#include // string, to_string ++#include // input_iterator_tag + ++// #include + ++ ++namespace nlohmann ++{ ++namespace detail ++{ ++/// proxy class for the items() function ++template class iteration_proxy ++{ ++ private: ++ /// helper class for iteration ++ class iteration_proxy_internal ++ { ++ public: ++ using difference_type = std::ptrdiff_t; ++ using value_type = iteration_proxy_internal; ++ using pointer = iteration_proxy_internal*; ++ using reference = iteration_proxy_internal&; ++ using iterator_category = std::input_iterator_tag; ++ ++ private: ++ /// the iterator ++ IteratorType anchor; ++ /// an index for arrays (used to create key names) ++ std::size_t array_index = 0; ++ /// last stringified array index ++ mutable std::size_t array_index_last = 0; ++ /// a string representation of the array index ++ mutable std::string array_index_str = "0"; ++ /// an empty string (to return a reference for primitive values) ++ const std::string empty_str = ""; ++ ++ public: ++ explicit iteration_proxy_internal(IteratorType it) noexcept : anchor(it) {} ++ ++ iteration_proxy_internal(const iteration_proxy_internal&) = default; ++ iteration_proxy_internal& operator=(const iteration_proxy_internal&) = default; ++ ++ /// dereference operator (needed for range-based for) ++ iteration_proxy_internal& operator*() ++ { ++ return *this; ++ } ++ ++ /// increment operator (needed for range-based for) ++ iteration_proxy_internal& operator++() ++ { ++ ++anchor; ++ ++array_index; ++ ++ return *this; ++ } ++ ++ /// equality operator (needed for InputIterator) ++ bool operator==(const iteration_proxy_internal& o) const noexcept ++ { ++ return anchor == o.anchor; ++ } ++ ++ /// inequality operator (needed for range-based for) ++ bool operator!=(const iteration_proxy_internal& o) const noexcept ++ { ++ return anchor != o.anchor; ++ } ++ ++ /// return key of the iterator ++ const std::string& key() const ++ { ++ assert(anchor.m_object != nullptr); ++ ++ switch (anchor.m_object->type()) ++ { ++ // use integer array index as key ++ case value_t::array: ++ { ++ if (array_index != array_index_last) ++ { ++ array_index_str = std::to_string(array_index); ++ array_index_last = array_index; ++ } ++ return array_index_str; ++ } ++ ++ // use key from the object ++ case value_t::object: ++ return anchor.key(); ++ ++ // use an empty key for all primitive types ++ default: ++ return empty_str; ++ } ++ } ++ ++ /// return value of the iterator ++ typename IteratorType::reference value() const ++ { ++ return anchor.value(); ++ } ++ }; ++ ++ /// the container to iterate ++ typename IteratorType::reference container; ++ ++ public: ++ /// construct iteration proxy from a container ++ explicit iteration_proxy(typename IteratorType::reference cont) noexcept ++ : container(cont) {} ++ ++ /// return iterator begin (needed for range-based for) ++ iteration_proxy_internal begin() noexcept ++ { ++ return iteration_proxy_internal(container.begin()); ++ } ++ ++ /// return iterator end (needed for range-based for) ++ iteration_proxy_internal end() noexcept ++ { ++ return iteration_proxy_internal(container.end()); ++ } ++}; ++} ++} ++ ++ ++namespace nlohmann ++{ ++namespace detail ++{ + ////////////////// + // constructors // + ////////////////// +@@ -657,6 +1529,16 @@ struct external_constructor + j.m_value = std::move(s); + j.assert_invariant(); + } ++ ++ template::value, ++ int> = 0> ++ static void construct(BasicJsonType& j, const CompatibleStringType& str) ++ { ++ j.m_type = value_t::string; ++ j.m_value.string = j.template create(str); ++ j.assert_invariant(); ++ } + }; + + template<> +@@ -783,159 +1665,6 @@ struct external_constructor + } + }; + +- +-//////////////////////// +-// has_/is_ functions // +-//////////////////////// +- +-/*! +-@brief Helper to determine whether there's a key_type for T. +- +-This helper is used to tell associative containers apart from other containers +-such as sequence containers. For instance, `std::map` passes the test as it +-contains a `mapped_type`, whereas `std::vector` fails the test. +- +-@sa http://stackoverflow.com/a/7728728/266378 +-@since version 1.0.0, overworked in version 2.0.6 +-*/ +-#define NLOHMANN_JSON_HAS_HELPER(type) \ +- template struct has_##type { \ +- private: \ +- template \ +- static int detect(U &&); \ +- static void detect(...); \ +- public: \ +- static constexpr bool value = \ +- std::is_integral()))>::value; \ +- } +- +-NLOHMANN_JSON_HAS_HELPER(mapped_type); +-NLOHMANN_JSON_HAS_HELPER(key_type); +-NLOHMANN_JSON_HAS_HELPER(value_type); +-NLOHMANN_JSON_HAS_HELPER(iterator); +- +-#undef NLOHMANN_JSON_HAS_HELPER +- +- +-template +-struct is_compatible_object_type_impl : std::false_type {}; +- +-template +-struct is_compatible_object_type_impl +-{ +- static constexpr auto value = +- std::is_constructible::value and +- std::is_constructible::value; +-}; +- +-template +-struct is_compatible_object_type +-{ +- static auto constexpr value = is_compatible_object_type_impl < +- conjunction>, +- has_mapped_type, +- has_key_type>::value, +- typename BasicJsonType::object_t, CompatibleObjectType >::value; +-}; +- +-template +-struct is_basic_json_nested_type +-{ +- static auto constexpr value = std::is_same::value or +- std::is_same::value or +- std::is_same::value or +- std::is_same::value; +-}; +- +-template +-struct is_compatible_array_type +-{ +- static auto constexpr value = +- conjunction>, +- negation>, +- negation>, +- negation>, +- has_value_type, +- has_iterator>::value; +-}; +- +-template +-struct is_compatible_integer_type_impl : std::false_type {}; +- +-template +-struct is_compatible_integer_type_impl +-{ +- // is there an assert somewhere on overflows? +- using RealLimits = std::numeric_limits; +- using CompatibleLimits = std::numeric_limits; +- +- static constexpr auto value = +- std::is_constructible::value and +- CompatibleLimits::is_integer and +- RealLimits::is_signed == CompatibleLimits::is_signed; +-}; +- +-template +-struct is_compatible_integer_type +-{ +- static constexpr auto value = +- is_compatible_integer_type_impl < +- std::is_integral::value and +- not std::is_same::value, +- RealIntegerType, CompatibleNumberIntegerType >::value; +-}; +- +- +-// trait checking if JSONSerializer::from_json(json const&, udt&) exists +-template +-struct has_from_json +-{ +- private: +- // also check the return type of from_json +- template::from_json( +- std::declval(), std::declval()))>::value>> +- static int detect(U&&); +- static void detect(...); +- +- public: +- static constexpr bool value = std::is_integral>()))>::value; +-}; +- +-// This trait checks if JSONSerializer::from_json(json const&) exists +-// this overload is used for non-default-constructible user-defined-types +-template +-struct has_non_default_from_json +-{ +- private: +- template::from_json(std::declval()))>::value>> +- static int detect(U&&); +- static void detect(...); +- +- public: +- static constexpr bool value = std::is_integral>()))>::value; +-}; +- +-// This trait checks if BasicJsonType::json_serializer::to_json exists +-template +-struct has_to_json +-{ +- private: +- template::to_json( +- std::declval(), std::declval()))> +- static int detect(U&&); +- static void detect(...); +- +- public: +- static constexpr bool value = std::is_integral>()))>::value; +-}; +- +- + ///////////// + // to_json // + ///////////// +@@ -1006,7 +1735,7 @@ void to_json(BasicJsonType& j, const CompatibleArrayTy + + template::value, int> = 0> +-void to_json(BasicJsonType& j, std::valarray arr) ++void to_json(BasicJsonType& j, const std::valarray& arr) + { + external_constructor::construct(j, std::move(arr)); + } +@@ -1043,6 +1772,14 @@ void to_json(BasicJsonType& j, const std::pair::iteration_proxy_internal>::value, int> = 0> ++void to_json(BasicJsonType& j, T b) noexcept ++{ ++ j = {{b.key(), b.value()}}; ++} ++ + template + void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence) + { +@@ -1055,261 +1792,6 @@ void to_json(BasicJsonType& j, const std::tuple {}); + } + +-/////////////// +-// from_json // +-/////////////// +- +-// overloads for basic_json template parameters +-template::value and +- not std::is_same::value, +- int> = 0> +-void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) +-{ +- switch (static_cast(j)) +- { +- case value_t::number_unsigned: +- { +- val = static_cast(*j.template get_ptr()); +- break; +- } +- case value_t::number_integer: +- { +- val = static_cast(*j.template get_ptr()); +- break; +- } +- case value_t::number_float: +- { +- val = static_cast(*j.template get_ptr()); +- break; +- } +- +- default: +- JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); +- } +-} +- +-template +-void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b) +-{ +- if (JSON_UNLIKELY(not j.is_boolean())) +- { +- JSON_THROW(type_error::create(302, "type must be boolean, but is " + std::string(j.type_name()))); +- } +- b = *j.template get_ptr(); +-} +- +-template +-void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s) +-{ +- if (JSON_UNLIKELY(not j.is_string())) +- { +- JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name()))); +- } +- s = *j.template get_ptr(); +-} +- +-template +-void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) +-{ +- get_arithmetic_value(j, val); +-} +- +-template +-void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val) +-{ +- get_arithmetic_value(j, val); +-} +- +-template +-void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val) +-{ +- get_arithmetic_value(j, val); +-} +- +-template::value, int> = 0> +-void from_json(const BasicJsonType& j, EnumType& e) +-{ +- typename std::underlying_type::type val; +- get_arithmetic_value(j, val); +- e = static_cast(val); +-} +- +-template +-void from_json(const BasicJsonType& j, typename BasicJsonType::array_t& arr) +-{ +- if (JSON_UNLIKELY(not j.is_array())) +- { +- JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); +- } +- arr = *j.template get_ptr(); +-} +- +-// forward_list doesn't have an insert method +-template::value, int> = 0> +-void from_json(const BasicJsonType& j, std::forward_list& l) +-{ +- if (JSON_UNLIKELY(not j.is_array())) +- { +- JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); +- } +- std::transform(j.rbegin(), j.rend(), +- std::front_inserter(l), [](const BasicJsonType & i) +- { +- return i.template get(); +- }); +-} +- +-// valarray doesn't have an insert method +-template::value, int> = 0> +-void from_json(const BasicJsonType& j, std::valarray& l) +-{ +- if (JSON_UNLIKELY(not j.is_array())) +- { +- JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); +- } +- l.resize(j.size()); +- std::copy(j.m_value.array->begin(), j.m_value.array->end(), std::begin(l)); +-} +- +-template +-void from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<0> /*unused*/) +-{ +- using std::end; +- +- std::transform(j.begin(), j.end(), +- std::inserter(arr, end(arr)), [](const BasicJsonType & i) +- { +- // get() returns *this, this won't call a from_json +- // method when value_type is BasicJsonType +- return i.template get(); +- }); +-} +- +-template +-auto from_json_array_impl(const BasicJsonType& j, CompatibleArrayType& arr, priority_tag<1> /*unused*/) +--> decltype( +- arr.reserve(std::declval()), +- void()) +-{ +- using std::end; +- +- arr.reserve(j.size()); +- std::transform(j.begin(), j.end(), +- std::inserter(arr, end(arr)), [](const BasicJsonType & i) +- { +- // get() returns *this, this won't call a from_json +- // method when value_type is BasicJsonType +- return i.template get(); +- }); +-} +- +-template +-void from_json_array_impl(const BasicJsonType& j, std::array& arr, priority_tag<2> /*unused*/) +-{ +- for (std::size_t i = 0; i < N; ++i) +- { +- arr[i] = j.at(i).template get(); +- } +-} +- +-template::value and +- std::is_convertible::value and +- not std::is_same::value, int> = 0> +-void from_json(const BasicJsonType& j, CompatibleArrayType& arr) +-{ +- if (JSON_UNLIKELY(not j.is_array())) +- { +- JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); +- } +- +- from_json_array_impl(j, arr, priority_tag<2> {}); +-} +- +-template::value, int> = 0> +-void from_json(const BasicJsonType& j, CompatibleObjectType& obj) +-{ +- if (JSON_UNLIKELY(not j.is_object())) +- { +- JSON_THROW(type_error::create(302, "type must be object, but is " + std::string(j.type_name()))); +- } +- +- auto inner_object = j.template get_ptr(); +- using value_type = typename CompatibleObjectType::value_type; +- std::transform( +- inner_object->begin(), inner_object->end(), +- std::inserter(obj, obj.begin()), +- [](typename BasicJsonType::object_t::value_type const & p) +- { +- return value_type(p.first, p.second.template get()); +- }); +-} +- +-// overload for arithmetic types, not chosen for basic_json template arguments +-// (BooleanType, etc..); note: Is it really necessary to provide explicit +-// overloads for boolean_t etc. in case of a custom BooleanType which is not +-// an arithmetic type? +-template::value and +- not std::is_same::value and +- not std::is_same::value and +- not std::is_same::value and +- not std::is_same::value, +- int> = 0> +-void from_json(const BasicJsonType& j, ArithmeticType& val) +-{ +- switch (static_cast(j)) +- { +- case value_t::number_unsigned: +- { +- val = static_cast(*j.template get_ptr()); +- break; +- } +- case value_t::number_integer: +- { +- val = static_cast(*j.template get_ptr()); +- break; +- } +- case value_t::number_float: +- { +- val = static_cast(*j.template get_ptr()); +- break; +- } +- case value_t::boolean: +- { +- val = static_cast(*j.template get_ptr()); +- break; +- } +- +- default: +- JSON_THROW(type_error::create(302, "type must be number, but is " + std::string(j.type_name()))); +- } +-} +- +-template +-void from_json(const BasicJsonType& j, std::pair& p) +-{ +- p = {j.at(0).template get(), j.at(1).template get()}; +-} +- +-template +-void from_json_tuple_impl(const BasicJsonType& j, Tuple& t, index_sequence) +-{ +- t = std::make_tuple(j.at(Idx).template get::type>()...); +-} +- +-template +-void from_json(const BasicJsonType& j, std::tuple& t) +-{ +- from_json_tuple_impl(j, t, index_sequence_for {}); +-} +- + struct to_json_fn + { + private: +@@ -1342,50 +1824,39 @@ struct to_json_fn + return call(j, std::forward(val), priority_tag<1> {}); + } + }; ++} + +-struct from_json_fn ++/// namespace to hold default `to_json` function ++namespace + { +- private: +- template +- auto call(const BasicJsonType& j, T& val, priority_tag<1> /*unused*/) const +- noexcept(noexcept(from_json(j, val))) +- -> decltype(from_json(j, val), void()) +- { +- return from_json(j, val); +- } ++constexpr const auto& to_json = detail::static_const::value; ++} ++} + +- template +- void call(const BasicJsonType& /*unused*/, T& /*unused*/, priority_tag<0> /*unused*/) const noexcept +- { +- static_assert(sizeof(BasicJsonType) == 0, +- "could not find from_json() method in T's namespace"); +-#ifdef _MSC_VER +- // MSVC does not show a stacktrace for the above assert +- using decayed = uncvref_t; +- static_assert(sizeof(typename decayed::force_msvc_stacktrace) == 0, +- "forcing MSVC stacktrace to show which T we're talking about."); +-#endif +- } ++// #include + +- public: +- template +- void operator()(const BasicJsonType& j, T& val) const +- noexcept(noexcept(std::declval().call(j, val, priority_tag<1> {}))) +- { +- return call(j, val, priority_tag<1> {}); +- } +-}; + +-// taken from ranges-v3 +-template +-struct static_const +-{ +- static constexpr T value{}; +-}; ++#include // assert ++#include // size_t ++#include // strlen ++#include // istream ++#include // begin, end, iterator_traits, random_access_iterator_tag, distance, next ++#include // shared_ptr, make_shared, addressof ++#include // accumulate ++#include // string, char_traits ++#include // enable_if, is_base_of, is_pointer, is_integral, remove_pointer ++#include // pair, declval + +-template +-constexpr T static_const::value; ++// #include + ++ ++namespace nlohmann ++{ ++namespace detail ++{ ++/// the supported input formats ++enum class input_format_t { json, cbor, msgpack, ubjson }; ++ + //////////////////// + // input adapters // + //////////////////// +@@ -1394,19 +1865,17 @@ constexpr T static_const::value; + @brief abstract input adapter interface + + Produces a stream of std::char_traits::int_type characters from a +-std::istream, a buffer, or some other input type. Accepts the return of exactly +-one non-EOF character for future input. The int_type characters returned +-consist of all valid char values as positive values (typically unsigned char), +-plus an EOF value outside that range, specified by the value of the function +-std::char_traits::eof(). This value is typically -1, but could be any +-arbitrary value which is not a valid char value. ++std::istream, a buffer, or some other input type. Accepts the return of ++exactly one non-EOF character for future input. The int_type characters ++returned consist of all valid char values as positive values (typically ++unsigned char), plus an EOF value outside that range, specified by the value ++of the function std::char_traits::eof(). This value is typically -1, but ++could be any arbitrary value which is not a valid char value. + */ + struct input_adapter_protocol + { + /// get a character [0,255] or std::char_traits::eof(). + virtual std::char_traits::int_type get_character() = 0; +- /// restore the last non-eof() character to input +- virtual void unget_character() = 0; + virtual ~input_adapter_protocol() = default; + }; + +@@ -1434,34 +1903,7 @@ class input_stream_adapter : public input_adapter_prot + + explicit input_stream_adapter(std::istream& i) + : is(i), sb(*i.rdbuf()) +- { +- // skip byte order mark +- std::char_traits::int_type c; +- if ((c = get_character()) == 0xEF) +- { +- if ((c = get_character()) == 0xBB) +- { +- if ((c = get_character()) == 0xBF) +- { +- return; // Ignore BOM +- } +- else if (c != std::char_traits::eof()) +- { +- is.unget(); +- } +- is.putback('\xBB'); +- } +- else if (c != std::char_traits::eof()) +- { +- is.unget(); +- } +- is.putback('\xEF'); +- } +- else if (c != std::char_traits::eof()) +- { +- is.unget(); // no byte order mark; process as usual +- } +- } ++ {} + + // delete because of pointer members + input_stream_adapter(const input_stream_adapter&) = delete; +@@ -1475,11 +1917,6 @@ class input_stream_adapter : public input_adapter_prot + return sb.sbumpc(); + } + +- void unget_character() override +- { +- sb.sungetc(); // is.unget() avoided for performance +- } +- + private: + /// the associated input stream + std::istream& is; +@@ -1491,14 +1928,8 @@ class input_buffer_adapter : public input_adapter_prot + { + public: + input_buffer_adapter(const char* b, const std::size_t l) +- : cursor(b), limit(b + l), start(b) +- { +- // skip byte order mark +- if (l >= 3 and b[0] == '\xEF' and b[1] == '\xBB' and b[2] == '\xBF') +- { +- cursor += 3; +- } +- } ++ : cursor(b), limit(b + l) ++ {} + + // delete because of pointer members + input_buffer_adapter(const input_buffer_adapter&) = delete; +@@ -1514,21 +1945,164 @@ class input_buffer_adapter : public input_adapter_prot + return std::char_traits::eof(); + } + +- void unget_character() noexcept override ++ private: ++ /// pointer to the current character ++ const char* cursor; ++ /// pointer past the last character ++ const char* const limit; ++}; ++ ++template ++class wide_string_input_adapter : public input_adapter_protocol ++{ ++ public: ++ explicit wide_string_input_adapter(const WideStringType& w) : str(w) {} ++ ++ std::char_traits::int_type get_character() noexcept override + { +- if (JSON_LIKELY(cursor > start)) ++ // check if buffer needs to be filled ++ if (utf8_bytes_index == utf8_bytes_filled) + { +- --cursor; ++ if (sizeof(typename WideStringType::value_type) == 2) ++ { ++ fill_buffer_utf16(); ++ } ++ else ++ { ++ fill_buffer_utf32(); ++ } ++ ++ assert(utf8_bytes_filled > 0); ++ assert(utf8_bytes_index == 0); + } ++ ++ // use buffer ++ assert(utf8_bytes_filled > 0); ++ assert(utf8_bytes_index < utf8_bytes_filled); ++ return utf8_bytes[utf8_bytes_index++]; + } + + private: +- /// pointer to the current character +- const char* cursor; +- /// pointer past the last character +- const char* limit; +- /// pointer to the first character +- const char* start; ++ void fill_buffer_utf16() ++ { ++ utf8_bytes_index = 0; ++ ++ if (current_wchar == str.size()) ++ { ++ utf8_bytes[0] = std::char_traits::eof(); ++ utf8_bytes_filled = 1; ++ } ++ else ++ { ++ // get the current character ++ const int wc = static_cast(str[current_wchar++]); ++ ++ // UTF-16 to UTF-8 encoding ++ if (wc < 0x80) ++ { ++ utf8_bytes[0] = wc; ++ utf8_bytes_filled = 1; ++ } ++ else if (wc <= 0x7FF) ++ { ++ utf8_bytes[0] = 0xC0 | ((wc >> 6)); ++ utf8_bytes[1] = 0x80 | (wc & 0x3F); ++ utf8_bytes_filled = 2; ++ } ++ else if (0xD800 > wc or wc >= 0xE000) ++ { ++ utf8_bytes[0] = 0xE0 | ((wc >> 12)); ++ utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F); ++ utf8_bytes[2] = 0x80 | (wc & 0x3F); ++ utf8_bytes_filled = 3; ++ } ++ else ++ { ++ if (current_wchar < str.size()) ++ { ++ const int wc2 = static_cast(str[current_wchar++]); ++ const int charcode = 0x10000 + (((wc & 0x3FF) << 10) | (wc2 & 0x3FF)); ++ utf8_bytes[0] = 0xf0 | (charcode >> 18); ++ utf8_bytes[1] = 0x80 | ((charcode >> 12) & 0x3F); ++ utf8_bytes[2] = 0x80 | ((charcode >> 6) & 0x3F); ++ utf8_bytes[3] = 0x80 | (charcode & 0x3F); ++ utf8_bytes_filled = 4; ++ } ++ else ++ { ++ // unknown character ++ ++current_wchar; ++ utf8_bytes[0] = wc; ++ utf8_bytes_filled = 1; ++ } ++ } ++ } ++ } ++ ++ void fill_buffer_utf32() ++ { ++ utf8_bytes_index = 0; ++ ++ if (current_wchar == str.size()) ++ { ++ utf8_bytes[0] = std::char_traits::eof(); ++ utf8_bytes_filled = 1; ++ } ++ else ++ { ++ // get the current character ++ const int wc = static_cast(str[current_wchar++]); ++ ++ // UTF-32 to UTF-8 encoding ++ if (wc < 0x80) ++ { ++ utf8_bytes[0] = wc; ++ utf8_bytes_filled = 1; ++ } ++ else if (wc <= 0x7FF) ++ { ++ utf8_bytes[0] = 0xC0 | ((wc >> 6) & 0x1F); ++ utf8_bytes[1] = 0x80 | (wc & 0x3F); ++ utf8_bytes_filled = 2; ++ } ++ else if (wc <= 0xFFFF) ++ { ++ utf8_bytes[0] = 0xE0 | ((wc >> 12) & 0x0F); ++ utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F); ++ utf8_bytes[2] = 0x80 | (wc & 0x3F); ++ utf8_bytes_filled = 3; ++ } ++ else if (wc <= 0x10FFFF) ++ { ++ utf8_bytes[0] = 0xF0 | ((wc >> 18 ) & 0x07); ++ utf8_bytes[1] = 0x80 | ((wc >> 12) & 0x3F); ++ utf8_bytes[2] = 0x80 | ((wc >> 6) & 0x3F); ++ utf8_bytes[3] = 0x80 | (wc & 0x3F); ++ utf8_bytes_filled = 4; ++ } ++ else ++ { ++ // unknown character ++ utf8_bytes[0] = wc; ++ utf8_bytes_filled = 1; ++ } ++ } ++ } ++ ++ private: ++ /// the wstring to process ++ const WideStringType& str; ++ ++ /// index of the current wchar in str ++ std::size_t current_wchar = 0; ++ ++ /// a buffer for UTF-8 bytes ++ std::array::int_type, 4> utf8_bytes = {{0, 0, 0, 0}}; ++ ++ /// index to the utf8_codes array for the next valid byte ++ std::size_t utf8_bytes_index = 0; ++ /// number of valid bytes in the utf8_codes array ++ std::size_t utf8_bytes_filled = 0; + }; + + class input_adapter +@@ -1544,6 +2118,15 @@ class input_adapter + input_adapter(std::istream&& i) + : ia(std::make_shared(i)) {} + ++ input_adapter(const std::wstring& ws) ++ : ia(std::make_shared>(ws)) {} ++ ++ input_adapter(const std::u16string& ws) ++ : ia(std::make_shared>(ws)) {} ++ ++ input_adapter(const std::u32string& ws) ++ : ia(std::make_shared>(ws)) {} ++ + /// input adapter for buffer + template + ++ ++#include // localeconv ++#include // size_t ++#include // strtof, strtod, strtold, strtoll, strtoull ++#include // snprintf ++#include // initializer_list ++#include // char_traits, string ++#include // vector ++ ++// #include ++ ++// #include ++ ++ ++namespace nlohmann ++{ ++namespace detail ++{ ++/////////// ++// lexer // ++/////////// ++ + /*! + @brief lexical analysis + +@@ -1640,6 +2245,7 @@ class lexer + using number_integer_t = typename BasicJsonType::number_integer_t; + using number_unsigned_t = typename BasicJsonType::number_unsigned_t; + using number_float_t = typename BasicJsonType::number_float_t; ++ using string_t = typename BasicJsonType::string_t; + + public: + /// token types for the parser +@@ -1701,12 +2307,14 @@ class lexer + return "end of input"; + case token_type::literal_or_value: + return "'[', '{', or a literal"; ++ // LCOV_EXCL_START + default: // catch non-enum values +- return "unknown token"; // LCOV_EXCL_LINE ++ return "unknown token"; ++ // LCOV_EXCL_STOP + } + } + +- explicit lexer(detail::input_adapter_t adapter) ++ explicit lexer(detail::input_adapter_t&& adapter) + : ia(std::move(adapter)), decimal_point_char(get_decimal_point()) {} + + // delete because of pointer members +@@ -1819,9 +2427,10 @@ class lexer + @brief scan a string literal + + This function scans a string according to Sect. 7 of RFC 7159. While +- scanning, bytes are escaped and copied into buffer yytext. Then the function +- returns successfully, yytext is *not* null-terminated (as it may contain \0 +- bytes), and yytext.size() is the number of bytes in the string. ++ scanning, bytes are escaped and copied into buffer token_buffer. Then the ++ function returns successfully, token_buffer is *not* null-terminated (as it ++ may contain \0 bytes), and token_buffer.size() is the number of bytes in the ++ string. + + @return token_type::value_string if string could be successfully scanned, + token_type::parse_error otherwise +@@ -1831,7 +2440,7 @@ class lexer + */ + token_type scan_string() + { +- // reset yytext (ignore opening quote) ++ // reset token_buffer (ignore opening quote) + reset(); + + // we entered the function by reading an open quote +@@ -2303,7 +2912,7 @@ class lexer + contains cycles, but any cycle can be left when EOF is read. Therefore, + the function is guaranteed to terminate. + +- During scanning, the read bytes are stored in yytext. This string is ++ During scanning, the read bytes are stored in token_buffer. This string is + then converted to a signed integer, an unsigned integer, or a + floating-point number. + +@@ -2317,7 +2926,7 @@ class lexer + */ + token_type scan_number() + { +- // reset yytext to store the number's bytes ++ // reset token_buffer to store the number's bytes + reset(); + + // the type of the parsed number; initially set to unsigned; will be +@@ -2353,11 +2962,13 @@ class lexer + goto scan_number_any1; + } + ++ // LCOV_EXCL_START + default: + { + // all other characters are rejected outside scan_number() +- assert(false); // LCOV_EXCL_LINE ++ assert(false); + } ++ // LCOV_EXCL_STOP + } + + scan_number_minus: +@@ -2601,10 +3212,10 @@ scan_number_done: + // try to parse integers first and fall back to floats + if (number_type == token_type::value_unsigned) + { +- const auto x = std::strtoull(yytext.data(), &endptr, 10); ++ const auto x = std::strtoull(token_buffer.data(), &endptr, 10); + + // we checked the number format before +- assert(endptr == yytext.data() + yytext.size()); ++ assert(endptr == token_buffer.data() + token_buffer.size()); + + if (errno == 0) + { +@@ -2617,10 +3228,10 @@ scan_number_done: + } + else if (number_type == token_type::value_integer) + { +- const auto x = std::strtoll(yytext.data(), &endptr, 10); ++ const auto x = std::strtoll(token_buffer.data(), &endptr, 10); + + // we checked the number format before +- assert(endptr == yytext.data() + yytext.size()); ++ assert(endptr == token_buffer.data() + token_buffer.size()); + + if (errno == 0) + { +@@ -2634,10 +3245,10 @@ scan_number_done: + + // this code is reached if we parse a floating-point number or if an + // integer conversion above failed +- strtof(value_float, yytext.data(), &endptr); ++ strtof(value_float, token_buffer.data(), &endptr); + + // we checked the number format before +- assert(endptr == yytext.data() + yytext.size()); ++ assert(endptr == token_buffer.data() + token_buffer.size()); + + return token_type::value_float; + } +@@ -2666,10 +3277,10 @@ scan_number_done: + // input management + ///////////////////// + +- /// reset yytext; current character is beginning of token ++ /// reset token_buffer; current character is beginning of token + void reset() noexcept + { +- yytext.clear(); ++ token_buffer.clear(); + token_string.clear(); + token_string.push_back(std::char_traits::to_char_type(current)); + } +@@ -2687,7 +3298,16 @@ scan_number_done: + std::char_traits::int_type get() + { + ++chars_read; +- current = ia->get_character(); ++ if (next_unget) ++ { ++ // just reset the next_unget variable and work with current ++ next_unget = false; ++ } ++ else ++ { ++ current = ia->get_character(); ++ } ++ + if (JSON_LIKELY(current != std::char_traits::eof())) + { + token_string.push_back(std::char_traits::to_char_type(current)); +@@ -2695,22 +3315,29 @@ scan_number_done: + return current; + } + +- /// unget current character (return it again on next get) ++ /*! ++ @brief unget current character (read it again on next get) ++ ++ We implement unget by setting variable next_unget to true. The input is not ++ changed - we just simulate ungetting by modifying chars_read and ++ token_string. The next call to get() will behave as if the unget character ++ is read again. ++ */ + void unget() + { ++ next_unget = true; + --chars_read; + if (JSON_LIKELY(current != std::char_traits::eof())) + { +- ia->unget_character(); + assert(token_string.size() != 0); + token_string.pop_back(); + } + } + +- /// add a character to yytext ++ /// add a character to token_buffer + void add(int c) + { +- yytext.push_back(std::char_traits::to_char_type(c)); ++ token_buffer.push_back(std::char_traits::to_char_type(c)); + } + + public: +@@ -2737,9 +3364,9 @@ scan_number_done: + } + + /// return current string value (implicitly resets the token; useful only once) +- std::string move_string() ++ string_t& get_string() + { +- return std::move(yytext); ++ return token_buffer; + } + + ///////////////////// +@@ -2764,10 +3391,9 @@ scan_number_done: + if ('\x00' <= c and c <= '\x1F') + { + // escape control characters +- std::stringstream ss; +- ss << "(c) << ">"; +- result += ss.str(); ++ char cs[9]; ++ snprintf(cs, 9, "", static_cast(c)); ++ result += cs; + } + else + { +@@ -2789,8 +3415,43 @@ scan_number_done: + // actual scanner + ///////////////////// + ++ /*! ++ @brief skip the UTF-8 byte order mark ++ @return true iff there is no BOM or the correct BOM has been skipped ++ */ ++ bool skip_bom() ++ { ++ if (get() == 0xEF) ++ { ++ if (get() == 0xBB and get() == 0xBF) ++ { ++ // we completely parsed the BOM ++ return true; ++ } ++ else ++ { ++ // after reading 0xEF, an unexpected character followed ++ return false; ++ } ++ } ++ else ++ { ++ // the first character is not the beginning of the BOM; unget it to ++ // process is later ++ unget(); ++ return true; ++ } ++ } ++ + token_type scan() + { ++ // initially, skip the BOM ++ if (chars_read == 0 and not skip_bom()) ++ { ++ error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given"; ++ return token_type::parse_error; ++ } ++ + // read next character and ignore whitespace + do + { +@@ -2860,6 +3521,9 @@ scan_number_done: + /// the current character + std::char_traits::int_type current = std::char_traits::eof(); + ++ /// whether the next get() call should just return current ++ bool next_unget = false; ++ + /// the number of characters read + std::size_t chars_read = 0; + +@@ -2867,7 +3531,7 @@ scan_number_done: + std::vector token_string {}; + + /// buffer for variable-length tokens (numbers, strings) +- std::string yytext {}; ++ string_t token_buffer {}; + + /// a description of occurred lexer errors + const char* error_message = ""; +@@ -2880,8 +3544,957 @@ scan_number_done: + /// the decimal point + const char decimal_point_char = '.'; + }; ++} ++} + ++// #include ++ ++ ++#include // assert ++#include // isfinite ++#include // uint8_t ++#include // function ++#include // string ++#include // move ++ ++// #include ++ ++// #include ++ ++// #include ++ ++ ++#include // size_t ++#include // declval ++ ++// #include ++ ++ ++#include ++ ++// #include ++ ++ ++namespace nlohmann ++{ ++namespace detail ++{ ++template ++using void_t = void; ++} ++} ++ ++ ++// 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