diff --git a/Makefile b/Makefile index 1e12178804..36b01450de 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,10 @@ SRCS = include/nlohmann/json.hpp \ include/nlohmann/detail/json_ref.hpp \ include/nlohmann/detail/macro_scope.hpp \ include/nlohmann/detail/macro_unscope.hpp \ - include/nlohmann/detail/meta.hpp \ + include/nlohmann/detail/meta/cpp_future.hpp \ + include/nlohmann/detail/meta/detected.hpp \ + include/nlohmann/detail/meta/type_traits.hpp \ + include/nlohmann/detail/meta/void_t.hpp \ include/nlohmann/detail/output/binary_writer.hpp \ include/nlohmann/detail/output/output_adapters.hpp \ include/nlohmann/detail/output/serializer.hpp \ diff --git a/include/nlohmann/detail/conversions/from_json.hpp b/include/nlohmann/detail/conversions/from_json.hpp index b092c8cc32..5956352fb9 100644 --- a/include/nlohmann/detail/conversions/from_json.hpp +++ b/include/nlohmann/detail/conversions/from_json.hpp @@ -15,7 +15,8 @@ #include #include -#include +#include +#include #include namespace nlohmann diff --git a/include/nlohmann/detail/conversions/to_json.hpp b/include/nlohmann/detail/conversions/to_json.hpp index 07946f55ac..35be5de468 100644 --- a/include/nlohmann/detail/conversions/to_json.hpp +++ b/include/nlohmann/detail/conversions/to_json.hpp @@ -8,7 +8,8 @@ #include // valarray #include // vector -#include +#include +#include #include #include diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp index 726e552dd3..27c34edbc6 100644 --- a/include/nlohmann/detail/input/binary_reader.hpp +++ b/include/nlohmann/detail/input/binary_reader.hpp @@ -17,6 +17,7 @@ #include #include #include +#include #include namespace nlohmann @@ -30,14 +31,14 @@ namespace detail /*! @brief deserialization of CBOR, MessagePack, and UBJSON values */ -template +template> class binary_reader { 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; - using json_sax_t = json_sax; + using json_sax_t = SAX; public: /*! @@ -47,6 +48,7 @@ class binary_reader */ explicit binary_reader(input_adapter_t adapter) : ia(std::move(adapter)) { + (void)detail::is_sax_static_asserts {}; assert(ia); } @@ -321,7 +323,7 @@ class binary_reader } case 0x9F: // array (indefinite length) - return get_cbor_array(json_sax_t::no_limit); + return get_cbor_array(std::size_t(-1)); // map (0x00..0x17 pairs of data items follow) case 0xA0: @@ -375,7 +377,7 @@ class binary_reader } case 0xBF: // map (indefinite length) - return get_cbor_object(json_sax_t::no_limit); + return get_cbor_object(std::size_t(-1)); case 0xF4: // false return sax->boolean(false); @@ -1020,7 +1022,7 @@ class binary_reader } /*! - @param[in] len the length of the array or json_sax_t::no_limit for an + @param[in] len the length of the array or std::size_t(-1) for an array of indefinite size @return whether array creation completed */ @@ -1031,7 +1033,7 @@ class binary_reader return false; } - if (len != json_sax_t::no_limit) + if (len != std::size_t(-1)) for (std::size_t i = 0; i < len; ++i) { if (JSON_UNLIKELY(not parse_cbor_internal())) @@ -1054,7 +1056,7 @@ class binary_reader } /*! - @param[in] len the length of the object or json_sax_t::no_limit for an + @param[in] len the length of the object or std::size_t(-1) for an object of indefinite size @return whether object creation completed */ @@ -1066,7 +1068,7 @@ class binary_reader } string_t key; - if (len != json_sax_t::no_limit) + if (len != std::size_t(-1)) { for (std::size_t i = 0; i < len; ++i) { @@ -1558,7 +1560,7 @@ class binary_reader } else { - if (JSON_UNLIKELY(not sax->start_array())) + if (JSON_UNLIKELY(not sax->start_array(-1))) { return false; } @@ -1628,7 +1630,7 @@ class binary_reader } else { - if (JSON_UNLIKELY(not sax->start_object())) + if (JSON_UNLIKELY(not sax->start_object(-1))) { return false; } diff --git a/include/nlohmann/detail/input/json_sax.hpp b/include/nlohmann/detail/input/json_sax.hpp index 563eac312a..fe1cf7c5b6 100644 --- a/include/nlohmann/detail/input/json_sax.hpp +++ b/include/nlohmann/detail/input/json_sax.hpp @@ -25,9 +25,6 @@ struct json_sax /// type for strings using string_t = typename BasicJsonType::string_t; - /// constant to indicate that no size limit is given for array or object - static constexpr auto no_limit = std::size_t(-1); - /*! @brief a null value was read @return whether parsing should proceed @@ -72,11 +69,11 @@ struct json_sax /*! @brief the beginning of an object was read - @param[in] elements number of object elements or no_limit if unknown + @param[in] elements number of object elements or -1 if unknown @return whether parsing should proceed @note binary formats may report the number of elements */ - virtual bool start_object(std::size_t elements = no_limit) = 0; + virtual bool start_object(std::size_t elements) = 0; /*! @brief an object key was read @@ -93,11 +90,11 @@ struct json_sax /*! @brief the beginning of an array was read - @param[in] elements number of array elements or no_limit if unknown + @param[in] elements number of array elements or -1 if unknown @return whether parsing should proceed @note binary formats may report the number of elements */ - virtual bool start_array(std::size_t elements = no_limit) = 0; + virtual bool start_array(std::size_t elements) = 0; /*! @brief the end of an array was read @@ -136,7 +133,7 @@ constructor contains the parsed value. @tparam BasicJsonType the JSON type */ template -class json_sax_dom_parser : public json_sax +class json_sax_dom_parser { public: using number_integer_t = typename BasicJsonType::number_integer_t; @@ -153,47 +150,47 @@ class json_sax_dom_parser : public json_sax : root(r), allow_exceptions(allow_exceptions_) {} - bool null() override + bool null() { handle_value(nullptr); return true; } - bool boolean(bool val) override + bool boolean(bool val) { handle_value(val); return true; } - bool number_integer(number_integer_t val) override + bool number_integer(number_integer_t val) { handle_value(val); return true; } - bool number_unsigned(number_unsigned_t val) override + bool number_unsigned(number_unsigned_t val) { handle_value(val); return true; } - bool number_float(number_float_t val, const string_t&) override + bool number_float(number_float_t val, const string_t&) { handle_value(val); return true; } - bool string(string_t& val) override + bool string(string_t& val) { handle_value(val); return true; } - bool start_object(std::size_t len) override + bool start_object(std::size_t len) { ref_stack.push_back(handle_value(BasicJsonType::value_t::object)); - if (JSON_UNLIKELY(len != json_sax::no_limit and len > ref_stack.back()->max_size())) + if (JSON_UNLIKELY(len != -1 and len > ref_stack.back()->max_size())) { JSON_THROW(out_of_range::create(408, "excessive object size: " + std::to_string(len))); @@ -202,24 +199,24 @@ class json_sax_dom_parser : public json_sax return true; } - bool key(string_t& val) override + bool key(string_t& val) { // add null at given key and store the reference for later object_element = &(ref_stack.back()->m_value.object->operator[](val)); return true; } - bool end_object() override + bool end_object() { ref_stack.pop_back(); return true; } - bool start_array(std::size_t len) override + bool start_array(std::size_t len) { ref_stack.push_back(handle_value(BasicJsonType::value_t::array)); - if (JSON_UNLIKELY(len != json_sax::no_limit and len > ref_stack.back()->max_size())) + if (JSON_UNLIKELY(len != -1 and len > ref_stack.back()->max_size())) { JSON_THROW(out_of_range::create(408, "excessive array size: " + std::to_string(len))); @@ -228,14 +225,14 @@ class json_sax_dom_parser : public json_sax return true; } - bool end_array() override + bool end_array() { ref_stack.pop_back(); return true; } bool parse_error(std::size_t, const std::string&, - const detail::exception& ex) override + const detail::exception& ex) { errored = true; if (allow_exceptions) @@ -310,7 +307,7 @@ class json_sax_dom_parser : public json_sax }; template -class json_sax_dom_callback_parser : public json_sax +class json_sax_dom_callback_parser { public: using number_integer_t = typename BasicJsonType::number_integer_t; @@ -328,43 +325,43 @@ class json_sax_dom_callback_parser : public json_sax keep_stack.push_back(true); } - bool null() override + bool null() { handle_value(nullptr); return true; } - bool boolean(bool val) override + bool boolean(bool val) { handle_value(val); return true; } - bool number_integer(number_integer_t val) override + bool number_integer(number_integer_t val) { handle_value(val); return true; } - bool number_unsigned(number_unsigned_t val) override + bool number_unsigned(number_unsigned_t val) { handle_value(val); return true; } - bool number_float(number_float_t val, const string_t&) override + bool number_float(number_float_t val, const string_t&) { handle_value(val); return true; } - bool string(string_t& val) override + bool string(string_t& val) { handle_value(val); return true; } - bool start_object(std::size_t len) override + bool start_object(std::size_t len) { // check callback for object start const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::object_start, discarded); @@ -376,7 +373,7 @@ class json_sax_dom_callback_parser : public json_sax // check object limit if (ref_stack.back()) { - if (JSON_UNLIKELY(len != json_sax::no_limit and len > ref_stack.back()->max_size())) + if (JSON_UNLIKELY(len != -1 and len > ref_stack.back()->max_size())) { JSON_THROW(out_of_range::create(408, "excessive object size: " + std::to_string(len))); @@ -386,7 +383,7 @@ class json_sax_dom_callback_parser : public json_sax return true; } - bool key(string_t& val) override + bool key(string_t& val) { BasicJsonType k = BasicJsonType(val); @@ -403,7 +400,7 @@ class json_sax_dom_callback_parser : public json_sax return true; } - bool end_object() override + bool end_object() { if (ref_stack.back()) { @@ -438,7 +435,7 @@ class json_sax_dom_callback_parser : public json_sax return true; } - bool start_array(std::size_t len) override + bool start_array(std::size_t len) { const bool keep = callback(static_cast(ref_stack.size()), parse_event_t::array_start, discarded); keep_stack.push_back(keep); @@ -449,7 +446,7 @@ class json_sax_dom_callback_parser : public json_sax // check array limit if (ref_stack.back()) { - if (JSON_UNLIKELY(len != json_sax::no_limit and len > ref_stack.back()->max_size())) + if (JSON_UNLIKELY(len != -1 and len > ref_stack.back()->max_size())) { JSON_THROW(out_of_range::create(408, "excessive array size: " + std::to_string(len))); @@ -459,7 +456,7 @@ class json_sax_dom_callback_parser : public json_sax return true; } - bool end_array() override + bool end_array() { bool keep = true; @@ -491,7 +488,7 @@ class json_sax_dom_callback_parser : public json_sax } bool parse_error(std::size_t, const std::string&, - const detail::exception& ex) override + const detail::exception& ex) { errored = true; if (allow_exceptions) @@ -614,7 +611,7 @@ class json_sax_dom_callback_parser : public json_sax }; template -class json_sax_acceptor : public json_sax +class json_sax_acceptor { public: using number_integer_t = typename BasicJsonType::number_integer_t; @@ -622,62 +619,62 @@ class json_sax_acceptor : public json_sax using number_float_t = typename BasicJsonType::number_float_t; using string_t = typename BasicJsonType::string_t; - bool null() override + bool null() { return true; } - bool boolean(bool) override + bool boolean(bool) { return true; } - bool number_integer(number_integer_t) override + bool number_integer(number_integer_t) { return true; } - bool number_unsigned(number_unsigned_t) override + bool number_unsigned(number_unsigned_t) { return true; } - bool number_float(number_float_t, const string_t&) override + bool number_float(number_float_t, const string_t&) { return true; } - bool string(string_t&) override + bool string(string_t&) { return true; } - bool start_object(std::size_t) override + bool start_object(std::size_t = -1) { return true; } - bool key(string_t&) override + bool key(string_t&) { return true; } - bool end_object() override + bool end_object() { return true; } - bool start_array(std::size_t) override + bool start_array(std::size_t = -1) { return true; } - bool end_array() override + bool end_array() { return true; } - bool parse_error(std::size_t, const std::string&, const detail::exception&) override + bool parse_error(std::size_t, const std::string&, const detail::exception&) { return false; } diff --git a/include/nlohmann/detail/input/parser.hpp b/include/nlohmann/detail/input/parser.hpp index c3cfcd5325..cfb8b65e87 100644 --- a/include/nlohmann/detail/input/parser.hpp +++ b/include/nlohmann/detail/input/parser.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -54,8 +55,6 @@ class parser value }; - using json_sax_t = json_sax; - using parser_callback_t = std::function; @@ -144,8 +143,10 @@ class parser return sax_parse(&sax_acceptor, strict); } - bool sax_parse(json_sax_t* sax, const bool strict = true) + template + bool sax_parse(SAX* sax, const bool strict = true) { + (void)detail::is_sax_static_asserts{}; const bool result = sax_parse_internal(sax); // strict mode: next byte must be EOF @@ -160,7 +161,8 @@ class parser } private: - bool sax_parse_internal(json_sax_t* sax) + template + bool sax_parse_internal(SAX* sax) { // stack to remember the hieararchy of structured values we are parsing // true = array; false = object @@ -177,7 +179,7 @@ class parser { case token_type::begin_object: { - if (JSON_UNLIKELY(not sax->start_object())) + if (JSON_UNLIKELY(not sax->start_object(-1))) { return false; } @@ -225,7 +227,7 @@ class parser case token_type::begin_array: { - if (JSON_UNLIKELY(not sax->start_array())) + if (JSON_UNLIKELY(not sax->start_array(-1))) { return false; } diff --git a/include/nlohmann/detail/iterators/iter_impl.hpp b/include/nlohmann/detail/iterators/iter_impl.hpp index f34f7a5540..adcd8a37bb 100644 --- a/include/nlohmann/detail/iterators/iter_impl.hpp +++ b/include/nlohmann/detail/iterators/iter_impl.hpp @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include namespace nlohmann diff --git a/include/nlohmann/detail/meta/cpp_future.hpp b/include/nlohmann/detail/meta/cpp_future.hpp new file mode 100644 index 0000000000..d12d6bdb76 --- /dev/null +++ b/include/nlohmann/detail/meta/cpp_future.hpp @@ -0,0 +1,83 @@ +#pragma once + +#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; +} +} diff --git a/include/nlohmann/detail/meta/detected.hpp b/include/nlohmann/detail/meta/detected.hpp new file mode 100644 index 0000000000..ed1d6ac71d --- /dev/null +++ b/include/nlohmann/detail/meta/detected.hpp @@ -0,0 +1,56 @@ +#pragma once + +#include + +#include + +// 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