From 5684d9a498349ab76a02f98140932762d1bc029a Mon Sep 17 00:00:00 2001 From: Francois Chabot Date: Wed, 27 May 2020 12:40:04 -0400 Subject: [PATCH 01/16] unified input API --- .../nlohmann/detail/input/input_adapters.hpp | 245 ++++++++---------- include/nlohmann/json.hpp | 157 ++++------- single_include/nlohmann/json.hpp | 245 +++++++++--------- test/CMakeLists.txt | 1 + test/Makefile | 1 + test/src/unit-user_defined_input.cpp | 115 ++++++++ 6 files changed, 400 insertions(+), 364 deletions(-) create mode 100644 test/src/unit-user_defined_input.cpp diff --git a/include/nlohmann/detail/input/input_adapters.hpp b/include/nlohmann/detail/input/input_adapters.hpp index 7ad26d00c9..9d86820283 100644 --- a/include/nlohmann/detail/input/input_adapters.hpp +++ b/include/nlohmann/detail/input/input_adapters.hpp @@ -34,6 +34,8 @@ Input adapter for stdio file access. This adapter read only 1 byte and do not us class file_input_adapter { public: + using char_type = char; + JSON_HEDLEY_NON_NULL(2) explicit file_input_adapter(std::FILE* f) noexcept : m_file(f) @@ -68,6 +70,8 @@ subsequent call for input from the std::istream. class input_stream_adapter { public: + using char_type = char; + ~input_stream_adapter() { // clear stream flags; we use underlying streambuf I/O, do not @@ -113,51 +117,61 @@ class input_stream_adapter std::streambuf* sb = nullptr; }; -/// input adapter for buffer input -class input_buffer_adapter +// General-purpose iterator-based adapter. It might not be as fast as +// theoretically possible for some containers, but it is extremely versatile. +template +class iterator_input_adapter { public: - input_buffer_adapter(const char* b, const std::size_t l) noexcept - : cursor(b), limit(b == nullptr ? nullptr : (b + l)) - {} + using char_type = typename std::iterator_traits::value_type; - // delete because of pointer members - input_buffer_adapter(const input_buffer_adapter&) = delete; - input_buffer_adapter& operator=(input_buffer_adapter&) = delete; - input_buffer_adapter(input_buffer_adapter&&) = default; - input_buffer_adapter& operator=(input_buffer_adapter&&) = delete; + iterator_input_adapter(IteratorType first, IteratorType last) + : current(std::move(first)), end(std::move(last)) {} - std::char_traits::int_type get_character() noexcept + typename std::char_traits::int_type get_character() { - if (JSON_HEDLEY_LIKELY(cursor < limit)) + if (current != end) { - assert(cursor != nullptr and limit != nullptr); - return std::char_traits::to_int_type(*(cursor++)); + auto result = std::char_traits::to_int_type(*current); + std::advance(current, 1); + return result; + } + else + { + return std::char_traits::eof(); } - - return std::char_traits::eof(); } private: - /// pointer to the current character - const char* cursor; - /// pointer past the last character - const char* const limit; + IteratorType current; + IteratorType end; + + template + friend class wide_string_input_helper; + + bool empty() const + { + return current == end; + } + }; -template -struct wide_string_input_helper + +template +struct wide_string_input_helper; + +template +struct wide_string_input_helper { // UTF-32 - static void fill_buffer(const WideStringType& str, - size_t& current_wchar, + static void fill_buffer(BaseInputAdapter& input, std::array::int_type, 4>& utf8_bytes, size_t& utf8_bytes_index, size_t& utf8_bytes_filled) { utf8_bytes_index = 0; - if (current_wchar == str.size()) + if (input.empty()) { utf8_bytes[0] = std::char_traits::eof(); utf8_bytes_filled = 1; @@ -165,7 +179,7 @@ struct wide_string_input_helper else { // get the current character - const auto wc = static_cast(str[current_wchar++]); + const auto wc = input.get_character(); // UTF-32 to UTF-8 encoding if (wc < 0x80) @@ -204,19 +218,18 @@ struct wide_string_input_helper } }; -template -struct wide_string_input_helper +template +struct wide_string_input_helper { // UTF-16 - static void fill_buffer(const WideStringType& str, - size_t& current_wchar, + static void fill_buffer(BaseInputAdapter& input, std::array::int_type, 4>& utf8_bytes, size_t& utf8_bytes_index, size_t& utf8_bytes_filled) { utf8_bytes_index = 0; - if (current_wchar == str.size()) + if (input.empty()) { utf8_bytes[0] = std::char_traits::eof(); utf8_bytes_filled = 1; @@ -224,7 +237,7 @@ struct wide_string_input_helper else { // get the current character - const auto wc = static_cast(str[current_wchar++]); + const auto wc = input.get_character(); // UTF-16 to UTF-8 encoding if (wc < 0x80) @@ -247,9 +260,9 @@ struct wide_string_input_helper } else { - if (current_wchar < str.size()) + if (!input.empty()) { - const auto wc2 = static_cast(str[current_wchar++]); + const auto wc2 = static_cast(input.get_character()); const auto charcode = 0x10000u + (((wc & 0x3FFu) << 10u) | (wc2 & 0x3FFu)); utf8_bytes[0] = static_cast::int_type>(0xF0u | (charcode >> 18u)); utf8_bytes[1] = static_cast::int_type>(0x80u | ((charcode >> 12u) & 0x3Fu)); @@ -259,8 +272,6 @@ struct wide_string_input_helper } else { - // unknown character - ++current_wchar; utf8_bytes[0] = static_cast::int_type>(wc); utf8_bytes_filled = 1; } @@ -269,20 +280,20 @@ struct wide_string_input_helper } }; -template +// Wraps another input apdater to convert wide character types into individual bytes. +template class wide_string_input_adapter { public: - explicit wide_string_input_adapter(const WideStringType& w) noexcept - : str(w) - {} + wide_string_input_adapter(BaseInputAdapter base) + : base_adapter(base) {} - std::char_traits::int_type get_character() noexcept + typename std::char_traits::int_type get_character() noexcept { // check if buffer needs to be filled if (utf8_bytes_index == utf8_bytes_filled) { - fill_buffer(); + fill_buffer(); assert(utf8_bytes_filled > 0); assert(utf8_bytes_index == 0); @@ -295,18 +306,14 @@ class wide_string_input_adapter } private: + BaseInputAdapter base_adapter; + template void fill_buffer() { - wide_string_input_helper::fill_buffer(str, current_wchar, utf8_bytes, utf8_bytes_index, utf8_bytes_filled); + wide_string_input_helper::fill_buffer(base_adapter, utf8_bytes, utf8_bytes_index, utf8_bytes_filled); } - /// 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}}; @@ -316,113 +323,84 @@ class wide_string_input_adapter std::size_t utf8_bytes_filled = 0; }; -inline file_input_adapter input_adapter(std::FILE* file) -{ - return file_input_adapter(file); -} -inline input_stream_adapter input_adapter(std::istream& stream) +template +struct iterator_input_adapter_factory { - return input_stream_adapter(stream); -} + using iterator_type = IteratorType; + using char_type = typename std::iterator_traits::value_type; + using adapter_type = iterator_input_adapter; -inline input_stream_adapter input_adapter(std::istream&& stream) -{ - return input_stream_adapter(stream); -} + static adapter_type create(IteratorType begin, IteratorType end) + { + return adapter_type(std::move(begin), std::move(end)); + } +}; -template::value and - std::is_integral::type>::value and - sizeof(typename std::remove_pointer::type) == 1, - int>::type = 0> -input_buffer_adapter input_adapter(CharT b, std::size_t l) -{ - return input_buffer_adapter(reinterpret_cast(b), l); -} +template +struct iterator_input_adapter_factory::value_type)>1)>::type > + { -template::value and - std::is_integral::type>::value and - sizeof(typename std::remove_pointer::type) == 1, - int>::type = 0> -input_buffer_adapter input_adapter(CharT b) + using iterator_type = IteratorType; + using char_type = typename std::iterator_traits::value_type; + using base_adapter_type = iterator_input_adapter; + using adapter_type = wide_string_input_adapter; + + static adapter_type create(IteratorType begin, IteratorType end) { - return input_adapter(reinterpret_cast(b), - std::strlen(reinterpret_cast(b))); + return adapter_type(base_adapter_type(std::move(begin), std::move(end))); } + }; -template::iterator_category, std::random_access_iterator_tag>::value, - int>::type = 0> -input_buffer_adapter input_adapter(IteratorType first, IteratorType last) +// General purpose iterator-based input +template +typename iterator_input_adapter_factory::adapter_type input_adapter(IteratorType begin, IteratorType end) { -#ifndef NDEBUG - // assertion to check that the iterator range is indeed contiguous, - // see https://stackoverflow.com/a/35008842/266378 for more discussion - const auto is_contiguous = std::accumulate( - first, last, std::pair(true, 0), - [&first](std::pair res, decltype(*first) val) - { - res.first &= (val == *(std::next(std::addressof(*first), res.second++))); - return res; - }).first; - assert(is_contiguous); -#endif - - // assertion to check that each element is 1 byte long - static_assert( - sizeof(typename iterator_traits::value_type) == 1, - "each element in the iterator range must have the size of 1 byte"); - - const auto len = static_cast(std::distance(first, last)); - if (JSON_HEDLEY_LIKELY(len > 0)) - { - // there is at least one element: use the address of first - return input_buffer_adapter(reinterpret_cast(&(*first)), len); - } - else - { - // the address of first cannot be used: use nullptr - return input_buffer_adapter(nullptr, len); - } + using factory_type = iterator_input_adapter_factory; + return factory_type::create(begin, end); } -inline wide_string_input_adapter input_adapter(const std::wstring& ws) +// Convenience shorthand from container to iterator +template +auto input_adapter(const ContainerType& container) -> decltype(input_adapter(begin(container), end(container))) { - return wide_string_input_adapter(ws); + return input_adapter(begin(container), end(container)); } - -inline wide_string_input_adapter input_adapter(const std::u16string& ws) +// Special cases with fast paths +inline file_input_adapter input_adapter(std::FILE* file) { - return wide_string_input_adapter(ws); + return file_input_adapter(file); } -inline wide_string_input_adapter input_adapter(const std::u32string& ws) +inline input_stream_adapter input_adapter(std::istream& stream) { - return wide_string_input_adapter(ws); + return input_stream_adapter(stream); } -template::value and - std::is_base_of()))>::iterator_category>::value, - int>::type = 0> -input_buffer_adapter input_adapter(const ContiguousContainer& c) +inline input_stream_adapter input_adapter(std::istream&& stream) { - return input_adapter(std::begin(c), std::end(c)); + return input_stream_adapter(stream); } +using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval(), std::declval())); -template -input_buffer_adapter input_adapter(T (&array)[N]) +// Null-delimited strings, and the like. +template::value and + std::is_integral::type>::value and + sizeof(typename std::remove_pointer::type) == 1, + int>::type = 0> +contiguous_bytes_input_adapter input_adapter(CharT b) { - return input_adapter(std::begin(array), std::end(array)); + auto length = std::strlen(reinterpret_cast(b)); + auto ptr = reinterpret_cast(b); + return input_adapter(ptr, ptr + length); } + // This class only handles inputs of input_buffer_adapter type. // It's required so that expressions like {ptr, len} can be implicitely casted // to the correct adapter. @@ -436,7 +414,7 @@ class span_input_adapter sizeof(typename std::remove_pointer::type) == 1, int>::type = 0> span_input_adapter(CharT b, std::size_t l) - : ia(reinterpret_cast(b), l) {} + : ia(reinterpret_cast(b), reinterpret_cast(b) + l) {} template::type) == 1, int>::type = 0> span_input_adapter(CharT b) - : span_input_adapter(reinterpret_cast(b), - std::strlen(reinterpret_cast(b))) {} + : span_input_adapter(b, std::strlen(reinterpret_cast(b))) {} template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json parse(IteratorType begin, + IteratorType end, + const parser_callback_t cb = nullptr, + const bool allow_exceptions = true) + { + basic_json result; + parser(detail::input_adapter(std::move(begin), std::move(end)), cb, allow_exceptions).parse(true, result); + return result; + } JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json parse(detail::span_input_adapter&& i, @@ -6638,10 +6649,17 @@ class basic_json return parser(detail::input_adapter(std::forward(i))).accept(true); } + template + static bool accept(IteratorType begin, IteratorType end) + { + return parser(detail::input_adapter(std::move(begin), std::move(end))).accept(true); + } + static bool accept(detail::span_input_adapter&& i) { return parser(i.get()).accept(true); } + /*! @brief generate SAX events @@ -6695,7 +6713,7 @@ class basic_json @since version 3.2.0 */ - template + template JSON_HEDLEY_NON_NULL(2) static bool sax_parse(InputType&& i, SAX* sax, input_format_t format = input_format_t::json, @@ -6707,6 +6725,18 @@ class basic_json : detail::binary_reader(std::move(ia)).sax_parse(format, sax, strict); } + template + JSON_HEDLEY_NON_NULL(3) + static bool sax_parse(IteratorType first, IteratorType last, SAX* sax, + input_format_t format = input_format_t::json, + const bool strict = true) + { + auto ia = detail::input_adapter(std::move(first), std::move(last)); + return format == input_format_t::json + ? parser(std::move(ia)).sax_parse(sax, strict) + : detail::binary_reader(std::move(ia)).sax_parse(format, sax, strict); + } + template JSON_HEDLEY_NON_NULL(2) static bool sax_parse(detail::span_input_adapter&& i, SAX* sax, @@ -6720,86 +6750,7 @@ class basic_json } - /*! - @brief deserialize from an iterator range with contiguous storage - - This function reads from an iterator range of a container with contiguous - storage of 1-byte values. Compatible container types include - `std::vector`, `std::string`, `std::array`, `std::valarray`, and - `std::initializer_list`. Furthermore, C-style arrays can be used with - `std::begin()`/`std::end()`. User-defined containers can be used as long - as they implement random-access iterators and a contiguous storage. - - @pre The iterator range is contiguous. Violating this precondition yields - undefined behavior. **This precondition is enforced with an assertion.** - @pre Each element in the range has a size of 1 byte. Violating this - precondition yields undefined behavior. **This precondition is enforced - with a static assertion.** - - @warning There is no way to enforce all preconditions at compile-time. If - the function is called with noncompliant iterators and with - assertions switched off, the behavior is undefined and will most - likely yield segmentation violation. - - @tparam IteratorType iterator of container with contiguous storage - @param[in] first begin of the range to parse (included) - @param[in] last end of the range to parse (excluded) - @param[in] cb a parser callback function of type @ref parser_callback_t - which is used to control the deserialization by filtering unwanted values - (optional) - @param[in] allow_exceptions whether to throw exceptions in case of a - parse error (optional, true by default) - - @return deserialized JSON value; in case of a parse error and - @a allow_exceptions set to `false`, the return value will be - value_t::discarded. - - @throw parse_error.101 in case of an unexpected token - @throw parse_error.102 if to_unicode fails or surrogate error - @throw parse_error.103 if to_unicode fails - - @complexity Linear in the length of the input. The parser is a predictive - LL(1) parser. The complexity can be higher if the parser callback function - @a cb has a super-linear complexity. - - @note A UTF-8 byte order mark is silently ignored. - - @liveexample{The example below demonstrates the `parse()` function reading - from an iterator range.,parse__iteratortype__parser_callback_t} - - @since version 2.0.3 - */ - template::iterator_category>::value, int>::type = 0> - static basic_json parse(IteratorType first, IteratorType last, - const parser_callback_t cb = nullptr, - const bool allow_exceptions = true) - { - basic_json result; - parser(detail::input_adapter(first, last), cb, allow_exceptions).parse(true, result); - return result; - } - - template::iterator_category>::value, int>::type = 0> - static bool accept(IteratorType first, IteratorType last) - { - return parser(detail::input_adapter(first, last)).accept(true); - } - - template::iterator_category>::value, int>::type = 0> - JSON_HEDLEY_NON_NULL(3) - static bool sax_parse(IteratorType first, IteratorType last, SAX* sax) - { - return parser(detail::input_adapter(first, last)).sax_parse(sax); - } + /*! @brief deserialize from stream @@ -7449,16 +7400,16 @@ class basic_json /*! @copydoc from_cbor(detail::input_adapter&&, const bool, const bool) */ - template::value, int> = 0> + template JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json from_cbor(A1 && a1, A2 && a2, + static basic_json from_cbor(IteratorType first, IteratorType last, const bool strict = true, const bool allow_exceptions = true) { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); - const bool res = binary_reader(detail::span_input_adapter(std::forward(a1), std::forward(a2)).get()).sax_parse(input_format_t::cbor, &sdp, strict); + auto ia = detail::input_adapter(std::move(first), std::move(last)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict); return res ? result : basic_json(value_t::discarded); } @@ -7469,7 +7420,8 @@ class basic_json { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); - const bool res = binary_reader(i.get()).sax_parse(input_format_t::cbor, &sdp, strict); + auto ia = i.get(); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict); return res ? result : basic_json(value_t::discarded); } @@ -7575,16 +7527,16 @@ class basic_json /*! @copydoc from_msgpack(detail::input_adapter&&, const bool, const bool) */ - template::value, int> = 0> + template JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json from_msgpack(A1 && a1, A2 && a2, + static basic_json from_msgpack(IteratorType first, IteratorType last, const bool strict = true, const bool allow_exceptions = true) { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); - const bool res = binary_reader(detail::span_input_adapter(std::forward(a1), std::forward(a2)).get()).sax_parse(input_format_t::msgpack, &sdp, strict); + auto ia = detail::input_adapter(std::move(first), std::move(last)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::msgpack, &sdp, strict); return res ? result : basic_json(value_t::discarded); } @@ -7596,7 +7548,8 @@ class basic_json { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); - const bool res = binary_reader(i.get()).sax_parse(input_format_t::msgpack, &sdp, strict); + auto ia = i.get(); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::msgpack, &sdp, strict); return res ? result : basic_json(value_t::discarded); } @@ -7678,16 +7631,16 @@ class basic_json /*! @copydoc from_ubjson(detail::input_adapter&&, const bool, const bool) */ - template::value, int> = 0> + template JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json from_ubjson(A1 && a1, A2 && a2, + static basic_json from_ubjson(IteratorType first, IteratorType last, const bool strict = true, const bool allow_exceptions = true) { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); - const bool res = binary_reader(detail::span_input_adapter(std::forward(a1), std::forward(a2)).get()).sax_parse(input_format_t::ubjson, &sdp, strict); + auto ia = detail::input_adapter(std::move(first), std::move(last)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::ubjson, &sdp, strict); return res ? result : basic_json(value_t::discarded); } @@ -7698,7 +7651,8 @@ class basic_json { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); - const bool res = binary_reader(i.get()).sax_parse(input_format_t::ubjson, &sdp, strict); + auto ia = i.get(); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::ubjson, &sdp, strict); return res ? result : basic_json(value_t::discarded); } @@ -7779,16 +7733,16 @@ class basic_json /*! @copydoc from_bson(detail::input_adapter&&, const bool, const bool) */ - template::value, int> = 0> + template JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json from_bson(A1 && a1, A2 && a2, + static basic_json from_bson(IteratorType first, IteratorType last, const bool strict = true, const bool allow_exceptions = true) { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); - const bool res = binary_reader(detail::span_input_adapter(std::forward(a1), std::forward(a2)).get()).sax_parse(input_format_t::bson, &sdp, strict); + auto ia = detail::input_adapter(std::move(first), std::move(last)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::bson, &sdp, strict); return res ? result : basic_json(value_t::discarded); } @@ -7799,7 +7753,8 @@ class basic_json { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); - const bool res = binary_reader(i.get()).sax_parse(input_format_t::bson, &sdp, strict); + auto ia = i.get(); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::bson, &sdp, strict); return res ? result : basic_json(value_t::discarded); } /// @} diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 70ce011a8f..eeaa9d0a6a 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -4456,6 +4456,8 @@ Input adapter for stdio file access. This adapter read only 1 byte and do not us class file_input_adapter { public: + using char_type = char; + JSON_HEDLEY_NON_NULL(2) explicit file_input_adapter(std::FILE* f) noexcept : m_file(f) @@ -4490,6 +4492,8 @@ subsequent call for input from the std::istream. class input_stream_adapter { public: + using char_type = char; + ~input_stream_adapter() { // clear stream flags; we use underlying streambuf I/O, do not @@ -4535,51 +4539,55 @@ class input_stream_adapter std::streambuf* sb = nullptr; }; -/// input adapter for buffer input -class input_buffer_adapter +// General-purpose iterator-based adapter. It might not be as fast as +// theoretically possible for some containers, but it is extremely versatile. +template +class iterator_input_adapter { public: - input_buffer_adapter(const char* b, const std::size_t l) noexcept - : cursor(b), limit(b == nullptr ? nullptr : (b + l)) - {} + using char_type = typename std::iterator_traits::value_type; - // delete because of pointer members - input_buffer_adapter(const input_buffer_adapter&) = delete; - input_buffer_adapter& operator=(input_buffer_adapter&) = delete; - input_buffer_adapter(input_buffer_adapter&&) = default; - input_buffer_adapter& operator=(input_buffer_adapter&&) = delete; + iterator_input_adapter(IteratorType begin_ite, IteratorType end_ite) + : current(std::move(begin_ite)), end(std::move(end_ite)) {} - std::char_traits::int_type get_character() noexcept + typename std::char_traits::int_type get_character() { - if (JSON_HEDLEY_LIKELY(cursor < limit)) + if (current != end) { - assert(cursor != nullptr and limit != nullptr); - return std::char_traits::to_int_type(*(cursor++)); + return *current++; } + else + { + return std::char_traits::eof(); + } + } - return std::char_traits::eof(); + bool empty() const + { + return current == end; } private: - /// pointer to the current character - const char* cursor; - /// pointer past the last character - const char* const limit; + IteratorType current; + IteratorType end; }; -template -struct wide_string_input_helper + +template +struct wide_string_input_helper; + +template +struct wide_string_input_helper { // UTF-32 - static void fill_buffer(const WideStringType& str, - size_t& current_wchar, + static void fill_buffer(BaseInputAdapter& input, std::array::int_type, 4>& utf8_bytes, size_t& utf8_bytes_index, size_t& utf8_bytes_filled) { utf8_bytes_index = 0; - if (current_wchar == str.size()) + if (input.empty()) { utf8_bytes[0] = std::char_traits::eof(); utf8_bytes_filled = 1; @@ -4587,7 +4595,7 @@ struct wide_string_input_helper else { // get the current character - const auto wc = static_cast(str[current_wchar++]); + const auto wc = input.get_character(); // UTF-32 to UTF-8 encoding if (wc < 0x80) @@ -4626,19 +4634,18 @@ struct wide_string_input_helper } }; -template -struct wide_string_input_helper +template +struct wide_string_input_helper { // UTF-16 - static void fill_buffer(const WideStringType& str, - size_t& current_wchar, + static void fill_buffer(BaseInputAdapter& input, std::array::int_type, 4>& utf8_bytes, size_t& utf8_bytes_index, size_t& utf8_bytes_filled) { utf8_bytes_index = 0; - if (current_wchar == str.size()) + if (input.empty()) { utf8_bytes[0] = std::char_traits::eof(); utf8_bytes_filled = 1; @@ -4646,7 +4653,7 @@ struct wide_string_input_helper else { // get the current character - const auto wc = static_cast(str[current_wchar++]); + const auto wc = input.get_character(); // UTF-16 to UTF-8 encoding if (wc < 0x80) @@ -4669,9 +4676,9 @@ struct wide_string_input_helper } else { - if (current_wchar < str.size()) + if (!input.empty()) { - const auto wc2 = static_cast(str[current_wchar++]); + const auto wc2 = static_cast(input.get_character()); const auto charcode = 0x10000u + (((wc & 0x3FFu) << 10u) | (wc2 & 0x3FFu)); utf8_bytes[0] = static_cast::int_type>(0xF0u | (charcode >> 18u)); utf8_bytes[1] = static_cast::int_type>(0x80u | ((charcode >> 12u) & 0x3Fu)); @@ -4681,8 +4688,6 @@ struct wide_string_input_helper } else { - // unknown character - ++current_wchar; utf8_bytes[0] = static_cast::int_type>(wc); utf8_bytes_filled = 1; } @@ -4691,20 +4696,20 @@ struct wide_string_input_helper } }; -template +// Wraps another input apdater to convert wide character types into individual bytes. +template class wide_string_input_adapter { public: - explicit wide_string_input_adapter(const WideStringType& w) noexcept - : str(w) - {} + wide_string_input_adapter(BaseInputAdapter base) + : base_adapter(base) {} - std::char_traits::int_type get_character() noexcept + typename std::char_traits::int_type get_character() noexcept { // check if buffer needs to be filled if (utf8_bytes_index == utf8_bytes_filled) { - fill_buffer(); + fill_buffer(); assert(utf8_bytes_filled > 0); assert(utf8_bytes_index == 0); @@ -4717,18 +4722,14 @@ class wide_string_input_adapter } private: + BaseInputAdapter base_adapter; + template void fill_buffer() { - wide_string_input_helper::fill_buffer(str, current_wchar, utf8_bytes, utf8_bytes_index, utf8_bytes_filled); + wide_string_input_helper::fill_buffer(base_adapter, utf8_bytes, utf8_bytes_index, utf8_bytes_filled); } - /// 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}}; @@ -4736,8 +4737,53 @@ class wide_string_input_adapter std::size_t utf8_bytes_index = 0; /// number of valid bytes in the utf8_codes array std::size_t utf8_bytes_filled = 0; +} + + +template +struct iterator_input_adapter_factory +{ + using iterator_type = IteratorType; + using char_type = typename std::iterator_traits::value_type; + using adapter_type = iterator_input_adapter; + + adapter_type create(IteratorType begin, IteratorType end) + { + return adapter_type(std::move(begin), std::mve(end)); + } }; +template +struct iterator_input_adapter_factory::value_type)>1)>::type > + { + + using iterator_type = IteratorType; + using char_type = typename std::iterator_traits::value_type; + using base_adapter_type = iterator_input_adapter; + using adapter_type = wide_string_input_adapter; + + adapter_type create(IteratorType begin, IteratorType end) +{ + return adapter_type(base_adapter_type(std::move(begin), std::mve(end))); +} + }; + +// General purpose iterator-based input +template +typename iterator_input_adapter_factory::adapter_type input_adapter(IteratorType begin, IteratorType end) +{ + return iterator_input_adapter_factory::create(begin, end); +} + +// Convenience shorthand from container to iterator +template +decltype(input_adapter(begin(container), end(container))) input_adapter(const T& container) +{ + return input_adapter(begin(container), end(container)); +} + +// Special cases with fast paths inline file_input_adapter input_adapter(std::FILE* file) { return file_input_adapter(file); @@ -4753,17 +4799,7 @@ inline input_stream_adapter input_adapter(std::istream&& stream) return input_stream_adapter(stream); } -template::value and - std::is_integral::type>::value and - sizeof(typename std::remove_pointer::type) == 1, - int>::type = 0> -input_buffer_adapter input_adapter(CharT b, std::size_t l) -{ - return input_buffer_adapter(reinterpret_cast(b), l); -} - +// Null-delimited strings, and the like. template::value and @@ -4772,79 +4808,12 @@ template::type = 0> input_buffer_adapter input_adapter(CharT b) { - return input_adapter(reinterpret_cast(b), - std::strlen(reinterpret_cast(b))); -} - -template::iterator_category, std::random_access_iterator_tag>::value, - int>::type = 0> -input_buffer_adapter input_adapter(IteratorType first, IteratorType last) -{ -#ifndef NDEBUG - // assertion to check that the iterator range is indeed contiguous, - // see https://stackoverflow.com/a/35008842/266378 for more discussion - const auto is_contiguous = std::accumulate( - first, last, std::pair(true, 0), - [&first](std::pair res, decltype(*first) val) - { - res.first &= (val == *(std::next(std::addressof(*first), res.second++))); - return res; - }).first; - assert(is_contiguous); -#endif - - // assertion to check that each element is 1 byte long - static_assert( - sizeof(typename iterator_traits::value_type) == 1, - "each element in the iterator range must have the size of 1 byte"); - - const auto len = static_cast(std::distance(first, last)); - if (JSON_HEDLEY_LIKELY(len > 0)) - { - // there is at least one element: use the address of first - return input_buffer_adapter(reinterpret_cast(&(*first)), len); - } - else - { - // the address of first cannot be used: use nullptr - return input_buffer_adapter(nullptr, len); - } -} - -inline wide_string_input_adapter input_adapter(const std::wstring& ws) -{ - return wide_string_input_adapter(ws); + auto length = std::strlen(reinterpret_cast(b)); + auto ptr = reinterpret_cast(b); + return input_adapter(ptr, ptr + length); } -inline wide_string_input_adapter input_adapter(const std::u16string& ws) -{ - return wide_string_input_adapter(ws); -} - -inline wide_string_input_adapter input_adapter(const std::u32string& ws) -{ - return wide_string_input_adapter(ws); -} - -template::value and - std::is_base_of()))>::iterator_category>::value, - int>::type = 0> -input_buffer_adapter input_adapter(const ContiguousContainer& c) -{ - return input_adapter(std::begin(c), std::end(c)); -} - - -template -input_buffer_adapter input_adapter(T (&array)[N]) -{ - return input_adapter(std::begin(array), std::end(array)); -} - // This class only handles inputs of input_buffer_adapter type. // It's required so that expressions like {ptr, len} can be implicitely casted // to the correct adapter. @@ -22413,6 +22382,17 @@ class basic_json } + template + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json parse(IteratorType begin, + IteratorType end, + const parser_callback_t cb = nullptr, + const bool allow_exceptions = true) + { + basic_json result; + parser(detail::iterator_input_adapter(std::move(begin), std::move(end)), cb, allow_exceptions).parse(true, result); + return result; + } JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json parse(detail::span_input_adapter&& i, @@ -22430,10 +22410,17 @@ class basic_json return parser(detail::input_adapter(std::forward(i))).accept(true); } + template + static bool accept(IteratorType begin, IteratorType end) + { + return parser(detail::iterator_input_adapter(std::move(begin), std::move(end))).accept(true); + } + static bool accept(detail::span_input_adapter&& i) { return parser(i.get()).accept(true); } + /*! @brief generate SAX events diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 838cce535b..67377fc496 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -133,6 +133,7 @@ set(files src/unit-ubjson.cpp src/unit-udt.cpp src/unit-unicode.cpp + src/unit-user_defined_input.cpp src/unit-wstring.cpp) foreach(file ${files}) diff --git a/test/Makefile b/test/Makefile index 7bf0fef98b..bcf8de7dee 100644 --- a/test/Makefile +++ b/test/Makefile @@ -44,6 +44,7 @@ SOURCES = src/unit.cpp \ src/unit-testsuites.cpp \ src/unit-ubjson.cpp \ src/unit-unicode.cpp \ + src/unit-user_defined_input.cpp \ src/unit-wstring.cpp OBJECTS = $(SOURCES:.cpp=.o) diff --git a/test/src/unit-user_defined_input.cpp b/test/src/unit-user_defined_input.cpp new file mode 100644 index 0000000000..6948c61738 --- /dev/null +++ b/test/src/unit-user_defined_input.cpp @@ -0,0 +1,115 @@ +/* + __ _____ _____ _____ + __| | __| | | | JSON for Modern C++ (test suite) +| | |__ | | | | | | version 3.7.3 +|_____|_____|_____|_|___| https://github.com/nlohmann/json + +Licensed under the MIT License . +SPDX-License-Identifier: MIT +Copyright (c) 2013-2019 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. +*/ + +#include "doctest_compatibility.h" + +#include +using nlohmann::json; + +#include + +namespace +{ +TEST_CASE("Use arbitrary stdlib container") +{ + std::string raw_data = "[1,2,3,4]"; + std::list data(raw_data.begin(), raw_data.end()); + + json as_json = json::parse(data.begin(), data.end()); + CHECK(as_json.at(0) == 1); + CHECK(as_json.at(1) == 2); + CHECK(as_json.at(2) == 3); + CHECK(as_json.at(3) == 4); +} + +struct MyContainer +{ + const char* data; +}; + +const char* begin(const MyContainer& c) +{ + return c.data; +} + +const char* end(const MyContainer& c) +{ + return c.data + strlen(c.data); +} + +TEST_CASE("Custom container") +{ + + MyContainer data{"[1,2,3,4]"}; + json as_json = json::parse(data); + CHECK(as_json.at(0) == 1); + CHECK(as_json.at(1) == 2); + CHECK(as_json.at(2) == 3); + CHECK(as_json.at(3) == 4); + +} + +TEST_CASE("Custom iterator") +{ + const char* raw_data = "[1,2,3,4]"; + + struct MyIterator { + using difference_type = std::size_t; + using value_type = char; + using pointer = const char*; + using reference = const char&; + using iterator_category = std::input_iterator_tag; + + + MyIterator& operator++() { + ++ptr; + return *this; + } + + reference operator*() const {return *ptr;} + bool operator!=(const MyIterator& rhs) const { + return ptr != rhs.ptr; + } + + const char* ptr; + }; + + MyIterator begin{raw_data}; + MyIterator end{raw_data + strlen(raw_data)}; + + json as_json = json::parse(begin, end); + CHECK(as_json.at(0) == 1); + CHECK(as_json.at(1) == 2); + CHECK(as_json.at(2) == 3); + CHECK(as_json.at(3) == 4); +} + + + +} \ No newline at end of file From f1969e60a39fcf940bec96505934f2d59a587cc9 Mon Sep 17 00:00:00 2001 From: Francois Chabot Date: Wed, 27 May 2020 12:56:26 -0400 Subject: [PATCH 02/16] reamalgamate --- include/nlohmann/json.hpp | 2 +- single_include/nlohmann/json.hpp | 189 ++++++++++----------------- test/src/unit-user_defined_input.cpp | 14 +- 3 files changed, 78 insertions(+), 127 deletions(-) diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index af67365da8..145c4f4332 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -6750,7 +6750,7 @@ class basic_json } - + /*! @brief deserialize from stream diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index eeaa9d0a6a..8f9c103eb5 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -4547,14 +4547,16 @@ class iterator_input_adapter public: using char_type = typename std::iterator_traits::value_type; - iterator_input_adapter(IteratorType begin_ite, IteratorType end_ite) - : current(std::move(begin_ite)), end(std::move(end_ite)) {} + iterator_input_adapter(IteratorType first, IteratorType last) + : current(std::move(first)), end(std::move(last)) {} typename std::char_traits::int_type get_character() { if (current != end) { - return *current++; + auto result = std::char_traits::to_int_type(*current); + std::advance(current, 1); + return result; } else { @@ -4562,14 +4564,18 @@ class iterator_input_adapter } } + private: + IteratorType current; + IteratorType end; + + template + friend class wide_string_input_helper; + bool empty() const { return current == end; } - private: - IteratorType current; - IteratorType end; }; @@ -4737,7 +4743,7 @@ class wide_string_input_adapter std::size_t utf8_bytes_index = 0; /// number of valid bytes in the utf8_codes array std::size_t utf8_bytes_filled = 0; -} +}; template @@ -4747,15 +4753,15 @@ struct iterator_input_adapter_factory using char_type = typename std::iterator_traits::value_type; using adapter_type = iterator_input_adapter; - adapter_type create(IteratorType begin, IteratorType end) + static adapter_type create(IteratorType begin, IteratorType end) { - return adapter_type(std::move(begin), std::mve(end)); + return adapter_type(std::move(begin), std::move(end)); } }; template struct iterator_input_adapter_factory::value_type)>1)>::type > + typename std::enable_if<(sizeof(typename std::iterator_traits::value_type)>1)>::type > { using iterator_type = IteratorType; @@ -4763,9 +4769,9 @@ struct iterator_input_adapter_factory; using adapter_type = wide_string_input_adapter; - adapter_type create(IteratorType begin, IteratorType end) + static adapter_type create(IteratorType begin, IteratorType end) { - return adapter_type(base_adapter_type(std::move(begin), std::mve(end))); + return adapter_type(base_adapter_type(std::move(begin), std::move(end))); } }; @@ -4773,12 +4779,13 @@ struct iterator_input_adapter_factory typename iterator_input_adapter_factory::adapter_type input_adapter(IteratorType begin, IteratorType end) { - return iterator_input_adapter_factory::create(begin, end); + using factory_type = iterator_input_adapter_factory; + return factory_type::create(begin, end); } // Convenience shorthand from container to iterator template -decltype(input_adapter(begin(container), end(container))) input_adapter(const T& container) +auto input_adapter(const ContainerType& container) -> decltype(input_adapter(begin(container), end(container))) { return input_adapter(begin(container), end(container)); } @@ -4799,6 +4806,8 @@ inline input_stream_adapter input_adapter(std::istream&& stream) return input_stream_adapter(stream); } +using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval(), std::declval())); + // Null-delimited strings, and the like. template::type>::value and sizeof(typename std::remove_pointer::type) == 1, int>::type = 0> -input_buffer_adapter input_adapter(CharT b) +contiguous_bytes_input_adapter input_adapter(CharT b) { auto length = std::strlen(reinterpret_cast(b)); auto ptr = reinterpret_cast(b); @@ -4827,7 +4836,7 @@ class span_input_adapter sizeof(typename std::remove_pointer::type) == 1, int>::type = 0> span_input_adapter(CharT b, std::size_t l) - : ia(reinterpret_cast(b), l) {} + : ia(reinterpret_cast(b), reinterpret_cast(b) + l) {} template::type) == 1, int>::type = 0> span_input_adapter(CharT b) - : span_input_adapter(reinterpret_cast(b), - std::strlen(reinterpret_cast(b))) {} + : span_input_adapter(b, std::strlen(reinterpret_cast(b))) {} template static bool accept(IteratorType begin, IteratorType end) { - return parser(detail::iterator_input_adapter(std::move(begin), std::move(end))).accept(true); + return parser(detail::input_adapter(std::move(begin), std::move(end))).accept(true); } static bool accept(detail::span_input_adapter&& i) @@ -22474,7 +22482,7 @@ class basic_json @since version 3.2.0 */ - template + template JSON_HEDLEY_NON_NULL(2) static bool sax_parse(InputType&& i, SAX* sax, input_format_t format = input_format_t::json, @@ -22486,6 +22494,18 @@ class basic_json : detail::binary_reader(std::move(ia)).sax_parse(format, sax, strict); } + template + JSON_HEDLEY_NON_NULL(3) + static bool sax_parse(IteratorType first, IteratorType last, SAX* sax, + input_format_t format = input_format_t::json, + const bool strict = true) + { + auto ia = detail::input_adapter(std::move(first), std::move(last)); + return format == input_format_t::json + ? parser(std::move(ia)).sax_parse(sax, strict) + : detail::binary_reader(std::move(ia)).sax_parse(format, sax, strict); + } + template JSON_HEDLEY_NON_NULL(2) static bool sax_parse(detail::span_input_adapter&& i, SAX* sax, @@ -22499,86 +22519,7 @@ class basic_json } - /*! - @brief deserialize from an iterator range with contiguous storage - - This function reads from an iterator range of a container with contiguous - storage of 1-byte values. Compatible container types include - `std::vector`, `std::string`, `std::array`, `std::valarray`, and - `std::initializer_list`. Furthermore, C-style arrays can be used with - `std::begin()`/`std::end()`. User-defined containers can be used as long - as they implement random-access iterators and a contiguous storage. - - @pre The iterator range is contiguous. Violating this precondition yields - undefined behavior. **This precondition is enforced with an assertion.** - @pre Each element in the range has a size of 1 byte. Violating this - precondition yields undefined behavior. **This precondition is enforced - with a static assertion.** - - @warning There is no way to enforce all preconditions at compile-time. If - the function is called with noncompliant iterators and with - assertions switched off, the behavior is undefined and will most - likely yield segmentation violation. - - @tparam IteratorType iterator of container with contiguous storage - @param[in] first begin of the range to parse (included) - @param[in] last end of the range to parse (excluded) - @param[in] cb a parser callback function of type @ref parser_callback_t - which is used to control the deserialization by filtering unwanted values - (optional) - @param[in] allow_exceptions whether to throw exceptions in case of a - parse error (optional, true by default) - - @return deserialized JSON value; in case of a parse error and - @a allow_exceptions set to `false`, the return value will be - value_t::discarded. - - @throw parse_error.101 in case of an unexpected token - @throw parse_error.102 if to_unicode fails or surrogate error - @throw parse_error.103 if to_unicode fails - - @complexity Linear in the length of the input. The parser is a predictive - LL(1) parser. The complexity can be higher if the parser callback function - @a cb has a super-linear complexity. - - @note A UTF-8 byte order mark is silently ignored. - - @liveexample{The example below demonstrates the `parse()` function reading - from an iterator range.,parse__iteratortype__parser_callback_t} - - @since version 2.0.3 - */ - template::iterator_category>::value, int>::type = 0> - static basic_json parse(IteratorType first, IteratorType last, - const parser_callback_t cb = nullptr, - const bool allow_exceptions = true) - { - basic_json result; - parser(detail::input_adapter(first, last), cb, allow_exceptions).parse(true, result); - return result; - } - - template::iterator_category>::value, int>::type = 0> - static bool accept(IteratorType first, IteratorType last) - { - return parser(detail::input_adapter(first, last)).accept(true); - } - template::iterator_category>::value, int>::type = 0> - JSON_HEDLEY_NON_NULL(3) - static bool sax_parse(IteratorType first, IteratorType last, SAX* sax) - { - return parser(detail::input_adapter(first, last)).sax_parse(sax); - } /*! @brief deserialize from stream @@ -23228,16 +23169,16 @@ class basic_json /*! @copydoc from_cbor(detail::input_adapter&&, const bool, const bool) */ - template::value, int> = 0> + template JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json from_cbor(A1 && a1, A2 && a2, + static basic_json from_cbor(IteratorType first, IteratorType last, const bool strict = true, const bool allow_exceptions = true) { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); - const bool res = binary_reader(detail::span_input_adapter(std::forward(a1), std::forward(a2)).get()).sax_parse(input_format_t::cbor, &sdp, strict); + auto ia = detail::input_adapter(std::move(first), std::move(last)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict); return res ? result : basic_json(value_t::discarded); } @@ -23248,7 +23189,8 @@ class basic_json { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); - const bool res = binary_reader(i.get()).sax_parse(input_format_t::cbor, &sdp, strict); + auto ia = i.get(); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict); return res ? result : basic_json(value_t::discarded); } @@ -23354,16 +23296,16 @@ class basic_json /*! @copydoc from_msgpack(detail::input_adapter&&, const bool, const bool) */ - template::value, int> = 0> + template JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json from_msgpack(A1 && a1, A2 && a2, + static basic_json from_msgpack(IteratorType first, IteratorType last, const bool strict = true, const bool allow_exceptions = true) { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); - const bool res = binary_reader(detail::span_input_adapter(std::forward(a1), std::forward(a2)).get()).sax_parse(input_format_t::msgpack, &sdp, strict); + auto ia = detail::input_adapter(std::move(first), std::move(last)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::msgpack, &sdp, strict); return res ? result : basic_json(value_t::discarded); } @@ -23375,7 +23317,8 @@ class basic_json { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); - const bool res = binary_reader(i.get()).sax_parse(input_format_t::msgpack, &sdp, strict); + auto ia = i.get(); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::msgpack, &sdp, strict); return res ? result : basic_json(value_t::discarded); } @@ -23457,16 +23400,16 @@ class basic_json /*! @copydoc from_ubjson(detail::input_adapter&&, const bool, const bool) */ - template::value, int> = 0> + template JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json from_ubjson(A1 && a1, A2 && a2, + static basic_json from_ubjson(IteratorType first, IteratorType last, const bool strict = true, const bool allow_exceptions = true) { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); - const bool res = binary_reader(detail::span_input_adapter(std::forward(a1), std::forward(a2)).get()).sax_parse(input_format_t::ubjson, &sdp, strict); + auto ia = detail::input_adapter(std::move(first), std::move(last)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::ubjson, &sdp, strict); return res ? result : basic_json(value_t::discarded); } @@ -23477,7 +23420,8 @@ class basic_json { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); - const bool res = binary_reader(i.get()).sax_parse(input_format_t::ubjson, &sdp, strict); + auto ia = i.get(); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::ubjson, &sdp, strict); return res ? result : basic_json(value_t::discarded); } @@ -23558,16 +23502,16 @@ class basic_json /*! @copydoc from_bson(detail::input_adapter&&, const bool, const bool) */ - template::value, int> = 0> + template JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json from_bson(A1 && a1, A2 && a2, + static basic_json from_bson(IteratorType first, IteratorType last, const bool strict = true, const bool allow_exceptions = true) { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); - const bool res = binary_reader(detail::span_input_adapter(std::forward(a1), std::forward(a2)).get()).sax_parse(input_format_t::bson, &sdp, strict); + auto ia = detail::input_adapter(std::move(first), std::move(last)); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::bson, &sdp, strict); return res ? result : basic_json(value_t::discarded); } @@ -23578,7 +23522,8 @@ class basic_json { basic_json result; detail::json_sax_dom_parser sdp(result, allow_exceptions); - const bool res = binary_reader(i.get()).sax_parse(input_format_t::bson, &sdp, strict); + auto ia = i.get(); + const bool res = binary_reader(std::move(ia)).sax_parse(input_format_t::bson, &sdp, strict); return res ? result : basic_json(value_t::discarded); } /// @} diff --git a/test/src/unit-user_defined_input.cpp b/test/src/unit-user_defined_input.cpp index 6948c61738..d2685ec66f 100644 --- a/test/src/unit-user_defined_input.cpp +++ b/test/src/unit-user_defined_input.cpp @@ -79,7 +79,8 @@ TEST_CASE("Custom iterator") { const char* raw_data = "[1,2,3,4]"; - struct MyIterator { + struct MyIterator + { using difference_type = std::size_t; using value_type = char; using pointer = const char*; @@ -87,13 +88,18 @@ TEST_CASE("Custom iterator") using iterator_category = std::input_iterator_tag; - MyIterator& operator++() { + MyIterator& operator++() + { ++ptr; return *this; } - reference operator*() const {return *ptr;} - bool operator!=(const MyIterator& rhs) const { + reference operator*() const + { + return *ptr; + } + bool operator!=(const MyIterator& rhs) const + { return ptr != rhs.ptr; } From b9416a26aa42b0a967bda6b84b0ef5baa188c516 Mon Sep 17 00:00:00 2001 From: Francois Chabot Date: Wed, 27 May 2020 13:21:23 -0400 Subject: [PATCH 03/16] correct ADL lookup of arrays on Mac and Windows --- .../nlohmann/detail/input/input_adapters.hpp | 25 +++---------------- single_include/nlohmann/json.hpp | 25 +++---------------- 2 files changed, 8 insertions(+), 42 deletions(-) diff --git a/include/nlohmann/detail/input/input_adapters.hpp b/include/nlohmann/detail/input/input_adapters.hpp index 9d86820283..67a7f0d035 100644 --- a/include/nlohmann/detail/input/input_adapters.hpp +++ b/include/nlohmann/detail/input/input_adapters.hpp @@ -365,6 +365,10 @@ typename iterator_input_adapter_factory::adapter_type input_adapte template auto input_adapter(const ContainerType& container) -> decltype(input_adapter(begin(container), end(container))) { + // Enable ADL + using std::begin; + using std::end; + return input_adapter(begin(container), end(container)); } @@ -416,15 +420,6 @@ class span_input_adapter span_input_adapter(CharT b, std::size_t l) : ia(reinterpret_cast(b), reinterpret_cast(b) + l) {} - template::value and - std::is_integral::type>::value and - sizeof(typename std::remove_pointer::type) == 1, - int>::type = 0> - span_input_adapter(CharT b) - : span_input_adapter(b, std::strlen(reinterpret_cast(b))) {} - template::iterator_category, std::random_access_iterator_tag>::value, @@ -432,18 +427,6 @@ class span_input_adapter span_input_adapter(IteratorType first, IteratorType last) : ia(input_adapter(first, last)) {} - template - span_input_adapter(T (&array)[N]) - : span_input_adapter(std::begin(array), std::end(array)) {} - - /// input adapter for contiguous container - template::value and - std::is_base_of()))>::iterator_category>::value, - int>::type = 0> - span_input_adapter(const ContiguousContainer& c) - : span_input_adapter(std::begin(c), std::end(c)) {} - contiguous_bytes_input_adapter&& get() { return std::move(ia); diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 8f9c103eb5..5240aeddd5 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -4787,6 +4787,10 @@ typename iterator_input_adapter_factory::adapter_type input_adapte template auto input_adapter(const ContainerType& container) -> decltype(input_adapter(begin(container), end(container))) { + // Enable ADL + using std::begin; + using std::end; + return input_adapter(begin(container), end(container)); } @@ -4838,15 +4842,6 @@ class span_input_adapter span_input_adapter(CharT b, std::size_t l) : ia(reinterpret_cast(b), reinterpret_cast(b) + l) {} - template::value and - std::is_integral::type>::value and - sizeof(typename std::remove_pointer::type) == 1, - int>::type = 0> - span_input_adapter(CharT b) - : span_input_adapter(b, std::strlen(reinterpret_cast(b))) {} - template::iterator_category, std::random_access_iterator_tag>::value, @@ -4854,18 +4849,6 @@ class span_input_adapter span_input_adapter(IteratorType first, IteratorType last) : ia(input_adapter(first, last)) {} - template - span_input_adapter(T (&array)[N]) - : span_input_adapter(std::begin(array), std::end(array)) {} - - /// input adapter for contiguous container - template::value and - std::is_base_of()))>::iterator_category>::value, - int>::type = 0> - span_input_adapter(const ContiguousContainer& c) - : span_input_adapter(std::begin(c), std::end(c)) {} - contiguous_bytes_input_adapter&& get() { return std::move(ia); From 377995f4956f99c671bc97894eb0141182b08a56 Mon Sep 17 00:00:00 2001 From: Francois Chabot Date: Wed, 27 May 2020 18:21:38 -0400 Subject: [PATCH 04/16] forcefully exclude arrays from being interpreted as pointers --- .../nlohmann/detail/input/input_adapters.hpp | 18 ++++++++++++------ single_include/nlohmann/json.hpp | 18 ++++++++++++------ 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/include/nlohmann/detail/input/input_adapters.hpp b/include/nlohmann/detail/input/input_adapters.hpp index 67a7f0d035..0a52abaa65 100644 --- a/include/nlohmann/detail/input/input_adapters.hpp +++ b/include/nlohmann/detail/input/input_adapters.hpp @@ -391,12 +391,13 @@ inline input_stream_adapter input_adapter(std::istream&& stream) using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval(), std::declval())); // Null-delimited strings, and the like. -template::value and - std::is_integral::type>::value and - sizeof(typename std::remove_pointer::type) == 1, - int>::type = 0> +template < typename CharT, + typename std::enable_if < + std::is_pointer::value and + !std::is_array::value and + std::is_integral::type>::value and + sizeof(typename std::remove_pointer::type) == 1, + int >::type = 0 > contiguous_bytes_input_adapter input_adapter(CharT b) { auto length = std::strlen(reinterpret_cast(b)); @@ -404,6 +405,11 @@ contiguous_bytes_input_adapter input_adapter(CharT b) return input_adapter(ptr, ptr + length); } +template +auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) +{ + return input_adapter(array, array + N); +} // This class only handles inputs of input_buffer_adapter type. // It's required so that expressions like {ptr, len} can be implicitely casted diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 5240aeddd5..5e8e23fe77 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -4813,12 +4813,13 @@ inline input_stream_adapter input_adapter(std::istream&& stream) using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval(), std::declval())); // Null-delimited strings, and the like. -template::value and - std::is_integral::type>::value and - sizeof(typename std::remove_pointer::type) == 1, - int>::type = 0> +template < typename CharT, + typename std::enable_if < + std::is_pointer::value and + !std::is_array::value and + std::is_integral::type>::value and + sizeof(typename std::remove_pointer::type) == 1, + int >::type = 0 > contiguous_bytes_input_adapter input_adapter(CharT b) { auto length = std::strlen(reinterpret_cast(b)); @@ -4826,6 +4827,11 @@ contiguous_bytes_input_adapter input_adapter(CharT b) return input_adapter(ptr, ptr + length); } +template +auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) +{ + return input_adapter(array, array + N); +} // This class only handles inputs of input_buffer_adapter type. // It's required so that expressions like {ptr, len} can be implicitely casted From 76b49f9ee6d9c51cebc8abbb37ef326e08b2a9ea Mon Sep 17 00:00:00 2001 From: Francois Chabot Date: Thu, 28 May 2020 02:29:53 -0400 Subject: [PATCH 05/16] misc formatting fixes --- .clang-format | 137 ++++++++++++++++++ .../nlohmann/detail/input/input_adapters.hpp | 47 +++--- include/nlohmann/json.hpp | 10 +- single_include/nlohmann/json.hpp | 57 ++++---- 4 files changed, 199 insertions(+), 52 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000..ef5f80c131 --- /dev/null +++ b/.clang-format @@ -0,0 +1,137 @@ +--- +Language: Cpp +# BasedOnStyle: Mozilla +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignConsecutiveMacros: false +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Right +AlignOperands: true +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: false +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: None +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: TopLevel +AlwaysBreakAfterReturnType: TopLevel +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: false +BinPackParameters: false +BraceWrapping: + AfterCaseLabel: true + AfterClass: true + AfterControlStatement: true + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: false + AfterStruct: true + AfterUnion: true + AfterExternBlock: true + BeforeCatch: false + BeforeElse: true + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: false + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeComma +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeComma +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: false +ColumnLimit: 180 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: false +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + - Regex: '.*' + Priority: 1 + SortPriority: 0 +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentCaseLabels: true +IndentGotoLabels: false +IndentPPDirectives: None +IndentWidth: 4 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: true +ObjCSpaceBeforeProtocolList: false +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +ReflowComments: true +SortIncludes: false +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: true +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: false +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +Standard: Latest +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseCRLF: false +UseTab: Never +... + diff --git a/include/nlohmann/detail/input/input_adapters.hpp b/include/nlohmann/detail/input/input_adapters.hpp index 0a52abaa65..08954a2f73 100644 --- a/include/nlohmann/detail/input/input_adapters.hpp +++ b/include/nlohmann/detail/input/input_adapters.hpp @@ -104,7 +104,7 @@ class input_stream_adapter { auto res = sb->sbumpc(); // set eof manually, as we don't use the istream interface. - if (res == EOF) + if (JSON_HEDLEY_UNLIKELY(res == EOF)) { is->clear(is->rdstate() | std::ios::eofbit); } @@ -130,7 +130,7 @@ class iterator_input_adapter typename std::char_traits::int_type get_character() { - if (current != end) + if (JSON_HEDLEY_LIKELY(current != end)) { auto result = std::char_traits::to_int_type(*current); std::advance(current, 1); @@ -171,7 +171,7 @@ struct wide_string_input_helper { utf8_bytes_index = 0; - if (input.empty()) + if (JSON_HEDLEY_UNLIKELY(input.empty())) { utf8_bytes[0] = std::char_traits::eof(); utf8_bytes_filled = 1; @@ -229,7 +229,7 @@ struct wide_string_input_helper { utf8_bytes_index = 0; - if (input.empty()) + if (JSON_HEDLEY_UNLIKELY(input.empty())) { utf8_bytes[0] = std::char_traits::eof(); utf8_bytes_filled = 1; @@ -331,34 +331,39 @@ struct iterator_input_adapter_factory using char_type = typename std::iterator_traits::value_type; using adapter_type = iterator_input_adapter; - static adapter_type create(IteratorType begin, IteratorType end) + static adapter_type create(IteratorType first, IteratorType last) { - return adapter_type(std::move(begin), std::move(end)); + return adapter_type(std::move(first), std::move(last)); } }; -template -struct iterator_input_adapter_factory::value_type)>1)>::type > - { - - using iterator_type = IteratorType; - using char_type = typename std::iterator_traits::value_type; - using base_adapter_type = iterator_input_adapter; - using adapter_type = wide_string_input_adapter; - - static adapter_type create(IteratorType begin, IteratorType end) +// This test breaks astyle formatting when inlined in a template specialization. +template +inline constexpr bool is_iterator_of_multibyte() { - return adapter_type(base_adapter_type(std::move(begin), std::move(end))); + return sizeof(typename std::iterator_traits::value_type) > 1; } - }; + +template +struct iterator_input_adapter_factory()>> +{ + using iterator_type = IteratorType; + using char_type = typename std::iterator_traits::value_type; + using base_adapter_type = iterator_input_adapter; + using adapter_type = wide_string_input_adapter; + + static adapter_type create(IteratorType first, IteratorType last) + { + return adapter_type(base_adapter_type(std::move(first), std::move(last))); + } +}; // General purpose iterator-based input template -typename iterator_input_adapter_factory::adapter_type input_adapter(IteratorType begin, IteratorType end) +typename iterator_input_adapter_factory::adapter_type input_adapter(IteratorType first, IteratorType last) { using factory_type = iterator_input_adapter_factory; - return factory_type::create(begin, end); + return factory_type::create(first, last); } // Convenience shorthand from container to iterator diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 145c4f4332..1248c956e7 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -6623,13 +6623,13 @@ class basic_json template JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json parse(IteratorType begin, - IteratorType end, + static basic_json parse(IteratorType first, + IteratorType last, const parser_callback_t cb = nullptr, const bool allow_exceptions = true) { basic_json result; - parser(detail::input_adapter(std::move(begin), std::move(end)), cb, allow_exceptions).parse(true, result); + parser(detail::input_adapter(std::move(first), std::move(last)), cb, allow_exceptions).parse(true, result); return result; } @@ -6650,9 +6650,9 @@ class basic_json } template - static bool accept(IteratorType begin, IteratorType end) + static bool accept(IteratorType first, IteratorType last) { - return parser(detail::input_adapter(std::move(begin), std::move(end))).accept(true); + return parser(detail::input_adapter(std::move(first), std::move(last))).accept(true); } static bool accept(detail::span_input_adapter&& i) diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 5e8e23fe77..cb482bc282 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -4526,7 +4526,7 @@ class input_stream_adapter { auto res = sb->sbumpc(); // set eof manually, as we don't use the istream interface. - if (res == EOF) + if (JSON_HEDLEY_UNLIKELY(res == EOF)) { is->clear(is->rdstate() | std::ios::eofbit); } @@ -4552,7 +4552,7 @@ class iterator_input_adapter typename std::char_traits::int_type get_character() { - if (current != end) + if (JSON_HEDLEY_LIKELY(current != end)) { auto result = std::char_traits::to_int_type(*current); std::advance(current, 1); @@ -4593,7 +4593,7 @@ struct wide_string_input_helper { utf8_bytes_index = 0; - if (input.empty()) + if (JSON_HEDLEY_UNLIKELY(input.empty())) { utf8_bytes[0] = std::char_traits::eof(); utf8_bytes_filled = 1; @@ -4651,7 +4651,7 @@ struct wide_string_input_helper { utf8_bytes_index = 0; - if (input.empty()) + if (JSON_HEDLEY_UNLIKELY(input.empty())) { utf8_bytes[0] = std::char_traits::eof(); utf8_bytes_filled = 1; @@ -4753,34 +4753,39 @@ struct iterator_input_adapter_factory using char_type = typename std::iterator_traits::value_type; using adapter_type = iterator_input_adapter; - static adapter_type create(IteratorType begin, IteratorType end) + static adapter_type create(IteratorType first, IteratorType last) { - return adapter_type(std::move(begin), std::move(end)); + return adapter_type(std::move(first), std::move(last)); } }; -template -struct iterator_input_adapter_factory::value_type)>1)>::type > - { - - using iterator_type = IteratorType; - using char_type = typename std::iterator_traits::value_type; - using base_adapter_type = iterator_input_adapter; - using adapter_type = wide_string_input_adapter; - - static adapter_type create(IteratorType begin, IteratorType end) +// This test breaks astyle formatting when inlined in a template specialization. +template +inline constexpr bool is_iterator_of_multibyte() { - return adapter_type(base_adapter_type(std::move(begin), std::move(end))); + return sizeof(typename std::iterator_traits::value_type) > 1; } - }; + +template +struct iterator_input_adapter_factory()>> +{ + using iterator_type = IteratorType; + using char_type = typename std::iterator_traits::value_type; + using base_adapter_type = iterator_input_adapter; + using adapter_type = wide_string_input_adapter; + + static adapter_type create(IteratorType first, IteratorType last) + { + return adapter_type(base_adapter_type(std::move(first), std::move(last))); + } +}; // General purpose iterator-based input template -typename iterator_input_adapter_factory::adapter_type input_adapter(IteratorType begin, IteratorType end) +typename iterator_input_adapter_factory::adapter_type input_adapter(IteratorType first, IteratorType last) { using factory_type = iterator_input_adapter_factory; - return factory_type::create(begin, end); + return factory_type::create(first, last); } // Convenience shorthand from container to iterator @@ -22381,13 +22386,13 @@ class basic_json template JSON_HEDLEY_WARN_UNUSED_RESULT - static basic_json parse(IteratorType begin, - IteratorType end, + static basic_json parse(IteratorType first, + IteratorType last, const parser_callback_t cb = nullptr, const bool allow_exceptions = true) { basic_json result; - parser(detail::input_adapter(std::move(begin), std::move(end)), cb, allow_exceptions).parse(true, result); + parser(detail::input_adapter(std::move(first), std::move(last)), cb, allow_exceptions).parse(true, result); return result; } @@ -22408,9 +22413,9 @@ class basic_json } template - static bool accept(IteratorType begin, IteratorType end) + static bool accept(IteratorType first, IteratorType last) { - return parser(detail::input_adapter(std::move(begin), std::move(end))).accept(true); + return parser(detail::input_adapter(std::move(first), std::move(last))).accept(true); } static bool accept(detail::span_input_adapter&& i) From a4f1cf4d0053a6a39790768c3d847cc93d7e93fa Mon Sep 17 00:00:00 2001 From: Francois Chabot Date: Thu, 28 May 2020 02:50:58 -0400 Subject: [PATCH 06/16] better parse documentation --- include/nlohmann/json.hpp | 80 ++++++++++++++------------------ single_include/nlohmann/json.hpp | 80 ++++++++++++++------------------ 2 files changed, 70 insertions(+), 90 deletions(-) diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 1248c956e7..4cc329f9a2 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -6550,28 +6550,12 @@ class basic_json @brief deserialize from a compatible input This function reads from a compatible input. Examples are: - - an array of 1-byte values - - strings with character/literal type with size of 1 byte - - input streams - - container with contiguous storage of 1-byte values. Compatible container - types include `std::vector`, `std::string`, `std::array`, - `std::valarray`, and `std::initializer_list`. Furthermore, C-style - arrays can be used with `std::begin()`/`std::end()`. User-defined - containers can be used as long as they implement random-access iterators - and a contiguous storage. - - @pre Each element of the container has a size of 1 byte. Violating this - precondition yields undefined behavior. **This precondition is enforced - with a static assertion.** - - @pre The container storage is contiguous. Violating this precondition - yields undefined behavior. **This precondition is enforced with an - assertion.** - - @warning There is no way to enforce all preconditions at compile-time. If - the function is called with a noncompliant container and with - assertions switched off, the behavior is undefined and will most - likely yield segmentation violation. + - an std::istream object + - a FILE pointer + - a C-style array of characters + - a pointer to a null-terminated string of single byte characters + - an object obj for which begin(obj) and end(obj) produces a valid pair of + iterators. @param[in] i input to read from @param[in] cb a parser callback function of type @ref parser_callback_t @@ -6591,7 +6575,7 @@ class basic_json @complexity Linear in the length of the input. The parser is a predictive LL(1) parser. The complexity can be higher if the parser callback function - @a cb has a super-linear complexity. + @a cb or reading from the input @a i has a super-linear complexity. @note A UTF-8 byte order mark is silently ignored. @@ -6620,7 +6604,29 @@ class basic_json return result; } + /*! + @brief deserialize from a pair of character iterators + + The value_type of the iterator must be a integral type with size of 1, 2 or + 4 bytes, which will be interpreted respectively as UTF-8, UTF-16 and UTF-32. + @param[in] first iterator to start of character range + @param[in] last iterator to end of character range + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + @param[in] allow_exceptions whether to throw exceptions in case of a + parse error (optional, true by default) + + @return deserialized JSON value; in case of a parse error and + @a allow_exceptions set to `false`, the return value will be + value_t::discarded. + + @throw parse_error.101 if a parse error occurs; example: `""unexpected end + of input; expected string literal""` + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ template JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json parse(IteratorType first, @@ -6666,28 +6672,12 @@ class basic_json The SAX event lister must follow the interface of @ref json_sax. This function reads from a compatible input. Examples are: - - an array of 1-byte values - - strings with character/literal type with size of 1 byte - - input streams - - container with contiguous storage of 1-byte values. Compatible container - types include `std::vector`, `std::string`, `std::array`, - `std::valarray`, and `std::initializer_list`. Furthermore, C-style - arrays can be used with `std::begin()`/`std::end()`. User-defined - containers can be used as long as they implement random-access iterators - and a contiguous storage. - - @pre Each element of the container has a size of 1 byte. Violating this - precondition yields undefined behavior. **This precondition is enforced - with a static assertion.** - - @pre The container storage is contiguous. Violating this precondition - yields undefined behavior. **This precondition is enforced with an - assertion.** - - @warning There is no way to enforce all preconditions at compile-time. If - the function is called with a noncompliant container and with - assertions switched off, the behavior is undefined and will most - likely yield segmentation violation. + - an std::istream object + - a FILE pointer + - a C-style array of characters + - a pointer to a null-terminated string of single byte characters + - an object obj for which begin(obj) and end(obj) produces a valid pair of + iterators. @param[in] i input to read from @param[in,out] sax SAX event listener diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index cb482bc282..54b39ff56b 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -22313,28 +22313,12 @@ class basic_json @brief deserialize from a compatible input This function reads from a compatible input. Examples are: - - an array of 1-byte values - - strings with character/literal type with size of 1 byte - - input streams - - container with contiguous storage of 1-byte values. Compatible container - types include `std::vector`, `std::string`, `std::array`, - `std::valarray`, and `std::initializer_list`. Furthermore, C-style - arrays can be used with `std::begin()`/`std::end()`. User-defined - containers can be used as long as they implement random-access iterators - and a contiguous storage. - - @pre Each element of the container has a size of 1 byte. Violating this - precondition yields undefined behavior. **This precondition is enforced - with a static assertion.** - - @pre The container storage is contiguous. Violating this precondition - yields undefined behavior. **This precondition is enforced with an - assertion.** - - @warning There is no way to enforce all preconditions at compile-time. If - the function is called with a noncompliant container and with - assertions switched off, the behavior is undefined and will most - likely yield segmentation violation. + - an std::istream object + - a FILE pointer + - a C-style array of characters + - a pointer to a null-terminated string of single byte characters + - an object obj for which begin(obj) and end(obj) produces a valid pair of + iterators. @param[in] i input to read from @param[in] cb a parser callback function of type @ref parser_callback_t @@ -22354,7 +22338,7 @@ class basic_json @complexity Linear in the length of the input. The parser is a predictive LL(1) parser. The complexity can be higher if the parser callback function - @a cb has a super-linear complexity. + @a cb or reading from the input @a i has a super-linear complexity. @note A UTF-8 byte order mark is silently ignored. @@ -22383,7 +22367,29 @@ class basic_json return result; } + /*! + @brief deserialize from a pair of character iterators + + The value_type of the iterator must be a integral type with size of 1, 2 or + 4 bytes, which will be interpreted respectively as UTF-8, UTF-16 and UTF-32. + @param[in] first iterator to start of character range + @param[in] last iterator to end of character range + @param[in] cb a parser callback function of type @ref parser_callback_t + which is used to control the deserialization by filtering unwanted values + (optional) + @param[in] allow_exceptions whether to throw exceptions in case of a + parse error (optional, true by default) + + @return deserialized JSON value; in case of a parse error and + @a allow_exceptions set to `false`, the return value will be + value_t::discarded. + + @throw parse_error.101 if a parse error occurs; example: `""unexpected end + of input; expected string literal""` + @throw parse_error.102 if to_unicode fails or surrogate error + @throw parse_error.103 if to_unicode fails + */ template JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json parse(IteratorType first, @@ -22429,28 +22435,12 @@ class basic_json The SAX event lister must follow the interface of @ref json_sax. This function reads from a compatible input. Examples are: - - an array of 1-byte values - - strings with character/literal type with size of 1 byte - - input streams - - container with contiguous storage of 1-byte values. Compatible container - types include `std::vector`, `std::string`, `std::array`, - `std::valarray`, and `std::initializer_list`. Furthermore, C-style - arrays can be used with `std::begin()`/`std::end()`. User-defined - containers can be used as long as they implement random-access iterators - and a contiguous storage. - - @pre Each element of the container has a size of 1 byte. Violating this - precondition yields undefined behavior. **This precondition is enforced - with a static assertion.** - - @pre The container storage is contiguous. Violating this precondition - yields undefined behavior. **This precondition is enforced with an - assertion.** - - @warning There is no way to enforce all preconditions at compile-time. If - the function is called with a noncompliant container and with - assertions switched off, the behavior is undefined and will most - likely yield segmentation violation. + - an std::istream object + - a FILE pointer + - a C-style array of characters + - a pointer to a null-terminated string of single byte characters + - an object obj for which begin(obj) and end(obj) produces a valid pair of + iterators. @param[in] i input to read from @param[in,out] sax SAX event listener From 3a91a05db665cf7b462258c31de6e491939d4b07 Mon Sep 17 00:00:00 2001 From: Francois Chabot Date: Thu, 28 May 2020 03:13:39 -0400 Subject: [PATCH 07/16] added custom input to readme --- README.md | 51 +++++++++++++++++++++++++++- test/src/unit-user_defined_input.cpp | 1 + 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 077a60bc69..cf870973ac 100644 --- a/README.md +++ b/README.md @@ -416,7 +416,7 @@ Please note that setting the exception bit for `failbit` is inappropriate for th #### Read from iterator range -You can also parse JSON from an iterator range; that is, from any container accessible by iterators whose content is stored as contiguous byte sequence, for instance a `std::vector`: +You can also parse JSON from an iterator range; that is, from any container accessible by iterators whose `value_type` is an integral type of 1, 2 or 4 bytes, for instance a `std::vector`, or a `std::list`: ```cpp std::vector v = {'t', 'r', 'u', 'e'}; @@ -430,6 +430,55 @@ std::vector v = {'t', 'r', 'u', 'e'}; json j = json::parse(v); ``` +#### Custom data source + +Since the parse function accepts arbitrary iterator ranges, you can provide your own data sources by implementing the `LegacyInputIterator` concept. + +```cpp +struct MyContainer; + +struct MyContainer { + void advance(); + const char& get_current(); +}; + +struct MyIterator { + using difference_type = std::ptrdiff_t; + using value_type = char; + using pointer = const char*; + using reference = const char&; + using iterator_category = std::input_iterator_tag; + + MyIterator& operator++() { + MyContainer.advance(); + } + + bool operator!=(const MyIterator& rhs) const { + return rhs.pos != pos || rhs.target != target; + } + + reference operator*() const { + return target.get_current(); + } + + MyContainer* target = nullptr; + std::size_t pos = 0; +}; + +MyIterator begin(MyContainer& tgt) { + return MyIterator{&tgt, 0} +} + +MyIterator end(const MyContainer&) { + return MyIterator{nullptr, 0} +} + +void foo() { + MyContainer c; + json j = json::parse(c); +} +``` + #### SAX interface The library uses a SAX-like interface with the following functions: diff --git a/test/src/unit-user_defined_input.cpp b/test/src/unit-user_defined_input.cpp index d2685ec66f..06be4e1363 100644 --- a/test/src/unit-user_defined_input.cpp +++ b/test/src/unit-user_defined_input.cpp @@ -98,6 +98,7 @@ TEST_CASE("Custom iterator") { return *ptr; } + bool operator!=(const MyIterator& rhs) const { return ptr != rhs.ptr; From bfcd32c099479c785d9f74ba87dd5fa66d92b80c Mon Sep 17 00:00:00 2001 From: Francois Chabot Date: Thu, 28 May 2020 03:16:24 -0400 Subject: [PATCH 08/16] removed clang-format --- .clang-format | 137 -------------------------------------------------- 1 file changed, 137 deletions(-) delete mode 100644 .clang-format diff --git a/.clang-format b/.clang-format deleted file mode 100644 index ef5f80c131..0000000000 --- a/.clang-format +++ /dev/null @@ -1,137 +0,0 @@ ---- -Language: Cpp -# BasedOnStyle: Mozilla -AccessModifierOffset: -2 -AlignAfterOpenBracket: Align -AlignConsecutiveMacros: false -AlignConsecutiveAssignments: false -AlignConsecutiveDeclarations: false -AlignEscapedNewlines: Right -AlignOperands: true -AlignTrailingComments: true -AllowAllArgumentsOnNextLine: true -AllowAllConstructorInitializersOnNextLine: true -AllowAllParametersOfDeclarationOnNextLine: false -AllowShortBlocksOnASingleLine: Never -AllowShortCaseLabelsOnASingleLine: false -AllowShortFunctionsOnASingleLine: None -AllowShortLambdasOnASingleLine: All -AllowShortIfStatementsOnASingleLine: Never -AllowShortLoopsOnASingleLine: false -AlwaysBreakAfterDefinitionReturnType: TopLevel -AlwaysBreakAfterReturnType: TopLevel -AlwaysBreakBeforeMultilineStrings: false -AlwaysBreakTemplateDeclarations: Yes -BinPackArguments: false -BinPackParameters: false -BraceWrapping: - AfterCaseLabel: true - AfterClass: true - AfterControlStatement: true - AfterEnum: true - AfterFunction: true - AfterNamespace: true - AfterObjCDeclaration: false - AfterStruct: true - AfterUnion: true - AfterExternBlock: true - BeforeCatch: false - BeforeElse: true - IndentBraces: false - SplitEmptyFunction: true - SplitEmptyRecord: false - SplitEmptyNamespace: true -BreakBeforeBinaryOperators: None -BreakBeforeBraces: Custom -BreakBeforeInheritanceComma: false -BreakInheritanceList: BeforeComma -BreakBeforeTernaryOperators: true -BreakConstructorInitializersBeforeComma: false -BreakConstructorInitializers: BeforeComma -BreakAfterJavaFieldAnnotations: false -BreakStringLiterals: false -ColumnLimit: 180 -CommentPragmas: '^ IWYU pragma:' -CompactNamespaces: false -ConstructorInitializerAllOnOneLineOrOnePerLine: true -ConstructorInitializerIndentWidth: 4 -ContinuationIndentWidth: 4 -Cpp11BracedListStyle: true -DeriveLineEnding: true -DerivePointerAlignment: false -DisableFormat: false -ExperimentalAutoDetectBinPacking: false -FixNamespaceComments: false -ForEachMacros: - - foreach - - Q_FOREACH - - BOOST_FOREACH -IncludeBlocks: Preserve -IncludeCategories: - - Regex: '^"(llvm|llvm-c|clang|clang-c)/' - Priority: 2 - SortPriority: 0 - - Regex: '^(<|"(gtest|gmock|isl|json)/)' - Priority: 3 - SortPriority: 0 - - Regex: '.*' - Priority: 1 - SortPriority: 0 -IncludeIsMainRegex: '(Test)?$' -IncludeIsMainSourceRegex: '' -IndentCaseLabels: true -IndentGotoLabels: false -IndentPPDirectives: None -IndentWidth: 4 -IndentWrappedFunctionNames: false -JavaScriptQuotes: Leave -JavaScriptWrapImports: true -KeepEmptyLinesAtTheStartOfBlocks: true -MacroBlockBegin: '' -MacroBlockEnd: '' -MaxEmptyLinesToKeep: 1 -NamespaceIndentation: None -ObjCBinPackProtocolList: Auto -ObjCBlockIndentWidth: 2 -ObjCSpaceAfterProperty: true -ObjCSpaceBeforeProtocolList: false -PenaltyBreakAssignment: 2 -PenaltyBreakBeforeFirstCallParameter: 19 -PenaltyBreakComment: 300 -PenaltyBreakFirstLessLess: 120 -PenaltyBreakString: 1000 -PenaltyBreakTemplateDeclaration: 10 -PenaltyExcessCharacter: 1000000 -PenaltyReturnTypeOnItsOwnLine: 200 -PointerAlignment: Left -ReflowComments: true -SortIncludes: false -SortUsingDeclarations: true -SpaceAfterCStyleCast: false -SpaceAfterLogicalNot: false -SpaceAfterTemplateKeyword: false -SpaceBeforeAssignmentOperators: true -SpaceBeforeCpp11BracedList: true -SpaceBeforeCtorInitializerColon: true -SpaceBeforeInheritanceColon: true -SpaceBeforeParens: ControlStatements -SpaceBeforeRangeBasedForLoopColon: true -SpaceInEmptyBlock: false -SpaceInEmptyParentheses: false -SpacesBeforeTrailingComments: 1 -SpacesInAngles: false -SpacesInConditionalStatement: false -SpacesInContainerLiterals: true -SpacesInCStyleCastParentheses: false -SpacesInParentheses: false -SpacesInSquareBrackets: false -SpaceBeforeSquareBrackets: false -Standard: Latest -StatementMacros: - - Q_UNUSED - - QT_REQUIRE_VERSION -TabWidth: 8 -UseCRLF: false -UseTab: Never -... - From dcf6175978fa45e6e617b3879c7a98bc37dce80d Mon Sep 17 00:00:00 2001 From: Francois Chabot Date: Thu, 28 May 2020 09:29:38 -0400 Subject: [PATCH 09/16] use the correct convention for boolean operators --- include/nlohmann/detail/input/input_adapters.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/nlohmann/detail/input/input_adapters.hpp b/include/nlohmann/detail/input/input_adapters.hpp index 08954a2f73..3d90ac3e85 100644 --- a/include/nlohmann/detail/input/input_adapters.hpp +++ b/include/nlohmann/detail/input/input_adapters.hpp @@ -260,7 +260,7 @@ struct wide_string_input_helper } else { - if (!input.empty()) + if (JSON_HEDLEY_UNLIKELY(not input.empty())) { const auto wc2 = static_cast(input.get_character()); const auto charcode = 0x10000u + (((wc & 0x3FFu) << 10u) | (wc2 & 0x3FFu)); @@ -399,7 +399,7 @@ using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval::value and - !std::is_array::value and + not std::is_array::value and std::is_integral::type>::value and sizeof(typename std::remove_pointer::type) == 1, int >::type = 0 > From 897061c434563559bf9014f1e7e53962e928aec2 Mon Sep 17 00:00:00 2001 From: Francois Chabot Date: Thu, 28 May 2020 10:11:19 -0400 Subject: [PATCH 10/16] amalgamate --- single_include/nlohmann/json.hpp | 4 ++-- test/src/unit-user_defined_input.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 54b39ff56b..8c00758809 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -4682,7 +4682,7 @@ struct wide_string_input_helper } else { - if (!input.empty()) + if (JSON_HEDLEY_UNLIKELY(not input.empty())) { const auto wc2 = static_cast(input.get_character()); const auto charcode = 0x10000u + (((wc & 0x3FFu) << 10u) | (wc2 & 0x3FFu)); @@ -4821,7 +4821,7 @@ using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval::value and - !std::is_array::value and + not std::is_array::value and std::is_integral::type>::value and sizeof(typename std::remove_pointer::type) == 1, int >::type = 0 > diff --git a/test/src/unit-user_defined_input.cpp b/test/src/unit-user_defined_input.cpp index 06be4e1363..86f763d5a9 100644 --- a/test/src/unit-user_defined_input.cpp +++ b/test/src/unit-user_defined_input.cpp @@ -98,7 +98,7 @@ TEST_CASE("Custom iterator") { return *ptr; } - + bool operator!=(const MyIterator& rhs) const { return ptr != rhs.ptr; From 248f3102153a457d7f7058ef45405d8b1376bc1a Mon Sep 17 00:00:00 2001 From: Francois Chabot Date: Thu, 28 May 2020 10:14:55 -0400 Subject: [PATCH 11/16] cleaned up custom iterator example --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index fb793ab292..dfd5932eb1 100644 --- a/README.md +++ b/README.md @@ -454,7 +454,7 @@ struct MyIterator { } bool operator!=(const MyIterator& rhs) const { - return rhs.pos != pos || rhs.target != target; + return rhs.target != target; } reference operator*() const { @@ -462,15 +462,14 @@ struct MyIterator { } MyContainer* target = nullptr; - std::size_t pos = 0; }; MyIterator begin(MyContainer& tgt) { - return MyIterator{&tgt, 0} + return MyIterator{&tgt}; } MyIterator end(const MyContainer&) { - return MyIterator{nullptr, 0} + return {}; } void foo() { From d575534471044125256f1e03e150a8810aa304be Mon Sep 17 00:00:00 2001 From: Francois Chabot Date: Thu, 28 May 2020 12:13:43 -0400 Subject: [PATCH 12/16] brought back the from_*(ptr, len) syntax with a deprecation warning --- include/nlohmann/json.hpp | 49 ++++++++++++++++++++++++++++++++ single_include/nlohmann/json.hpp | 49 ++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 4cc329f9a2..bc0eda0079 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -6639,6 +6639,7 @@ class basic_json return result; } + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len)) JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json parse(detail::span_input_adapter&& i, const parser_callback_t cb = nullptr, @@ -6661,6 +6662,8 @@ class basic_json return parser(detail::input_adapter(std::move(first), std::move(last))).accept(true); } + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len)) + JSON_HEDLEY_WARN_UNUSED_RESULT static bool accept(detail::span_input_adapter&& i) { return parser(i.get()).accept(true); @@ -6728,6 +6731,7 @@ class basic_json } template + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, sax_parse(ptr, ptr + len, ...)) JSON_HEDLEY_NON_NULL(2) static bool sax_parse(detail::span_input_adapter&& i, SAX* sax, input_format_t format = input_format_t::json, @@ -7403,6 +7407,18 @@ class basic_json return res ? result : basic_json(value_t::discarded); } + template + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_cbor(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true) + { + return from_cbor(ptr, ptr + len, strict, allow_exceptions); + } + + + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json from_cbor(detail::span_input_adapter&& i, const bool strict = true, @@ -7531,6 +7547,17 @@ class basic_json } + template + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_msgpack(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true) + { + return from_msgpack(ptr, ptr + len, strict, allow_exceptions); + } + + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json from_msgpack(detail::span_input_adapter&& i, const bool strict = true, @@ -7634,7 +7661,18 @@ class basic_json return res ? result : basic_json(value_t::discarded); } + template + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_ubjson(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true) + { + return from_ubjson(ptr, ptr + len, strict, allow_exceptions); + } + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) + JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json from_ubjson(detail::span_input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) @@ -7736,6 +7774,17 @@ class basic_json return res ? result : basic_json(value_t::discarded); } + template + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_bson(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true) + { + return from_bson(ptr, ptr + len, strict, allow_exceptions); + } + + JSON_HEDLEY_DEPRECATED(3.8.0, from_bson(ptr, ptr + len)) JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json from_bson(detail::span_input_adapter&& i, const bool strict = true, diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 8c00758809..0421302ca3 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -22402,6 +22402,7 @@ class basic_json return result; } + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len)) JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json parse(detail::span_input_adapter&& i, const parser_callback_t cb = nullptr, @@ -22424,6 +22425,8 @@ class basic_json return parser(detail::input_adapter(std::move(first), std::move(last))).accept(true); } + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len)) + JSON_HEDLEY_WARN_UNUSED_RESULT static bool accept(detail::span_input_adapter&& i) { return parser(i.get()).accept(true); @@ -22491,6 +22494,7 @@ class basic_json } template + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, sax_parse(ptr, ptr + len, ...)) JSON_HEDLEY_NON_NULL(2) static bool sax_parse(detail::span_input_adapter&& i, SAX* sax, input_format_t format = input_format_t::json, @@ -23166,6 +23170,18 @@ class basic_json return res ? result : basic_json(value_t::discarded); } + template + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_cbor(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true) + { + return from_cbor(ptr, ptr + len, strict, allow_exceptions); + } + + + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json from_cbor(detail::span_input_adapter&& i, const bool strict = true, @@ -23294,6 +23310,17 @@ class basic_json } + template + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_msgpack(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true) + { + return from_msgpack(ptr, ptr + len, strict, allow_exceptions); + } + + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json from_msgpack(detail::span_input_adapter&& i, const bool strict = true, @@ -23397,7 +23424,18 @@ class basic_json return res ? result : basic_json(value_t::discarded); } + template + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_ubjson(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true) + { + return from_ubjson(ptr, ptr + len, strict, allow_exceptions); + } + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) + JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json from_ubjson(detail::span_input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) @@ -23499,6 +23537,17 @@ class basic_json return res ? result : basic_json(value_t::discarded); } + template + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) + JSON_HEDLEY_WARN_UNUSED_RESULT + static basic_json from_bson(const T* ptr, std::size_t len, + const bool strict = true, + const bool allow_exceptions = true) + { + return from_bson(ptr, ptr + len, strict, allow_exceptions); + } + + JSON_HEDLEY_DEPRECATED(3.8.0, from_bson(ptr, ptr + len)) JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json from_bson(detail::span_input_adapter&& i, const bool strict = true, From ce3143a038cd94387c733b6044ee21548c3df789 Mon Sep 17 00:00:00 2001 From: Francois Chabot Date: Thu, 28 May 2020 12:16:10 -0400 Subject: [PATCH 13/16] use correct deprecation macro --- include/nlohmann/json.hpp | 2 +- single_include/nlohmann/json.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index bc0eda0079..c3881cca69 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -7784,7 +7784,7 @@ class basic_json return from_bson(ptr, ptr + len, strict, allow_exceptions); } - JSON_HEDLEY_DEPRECATED(3.8.0, from_bson(ptr, ptr + len)) + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json from_bson(detail::span_input_adapter&& i, const bool strict = true, diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 0421302ca3..85e428781b 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -23547,7 +23547,7 @@ class basic_json return from_bson(ptr, ptr + len, strict, allow_exceptions); } - JSON_HEDLEY_DEPRECATED(3.8.0, from_bson(ptr, ptr + len)) + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) JSON_HEDLEY_WARN_UNUSED_RESULT static basic_json from_bson(detail::span_input_adapter&& i, const bool strict = true, From 7646253940bfa8a5d41e04b9a34b59135e033b0e Mon Sep 17 00:00:00 2001 From: Francois Chabot Date: Thu, 28 May 2020 12:20:02 -0400 Subject: [PATCH 14/16] fix inconsistent fwd declaration --- include/nlohmann/detail/input/input_adapters.hpp | 2 +- single_include/nlohmann/json.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/nlohmann/detail/input/input_adapters.hpp b/include/nlohmann/detail/input/input_adapters.hpp index 3d90ac3e85..725ff1fe49 100644 --- a/include/nlohmann/detail/input/input_adapters.hpp +++ b/include/nlohmann/detail/input/input_adapters.hpp @@ -147,7 +147,7 @@ class iterator_input_adapter IteratorType end; template - friend class wide_string_input_helper; + friend struct wide_string_input_helper; bool empty() const { diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 85e428781b..0b5b2a583e 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -4569,7 +4569,7 @@ class iterator_input_adapter IteratorType end; template - friend class wide_string_input_helper; + friend struct wide_string_input_helper; bool empty() const { From b715a706739deeaf2b14e098820f7fa0adba6087 Mon Sep 17 00:00:00 2001 From: Francois Chabot Date: Thu, 28 May 2020 12:26:29 -0400 Subject: [PATCH 15/16] changed macro order to satisfy clang --- include/nlohmann/json.hpp | 22 +++++++++++----------- single_include/nlohmann/json.hpp | 22 +++++++++++----------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index c3881cca69..592d19667b 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -6639,8 +6639,8 @@ class basic_json return result; } - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len)) JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len)) static basic_json parse(detail::span_input_adapter&& i, const parser_callback_t cb = nullptr, const bool allow_exceptions = true) @@ -6662,8 +6662,8 @@ class basic_json return parser(detail::input_adapter(std::move(first), std::move(last))).accept(true); } - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len)) JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len)) static bool accept(detail::span_input_adapter&& i) { return parser(i.get()).accept(true); @@ -6731,8 +6731,8 @@ class basic_json } template - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, sax_parse(ptr, ptr + len, ...)) JSON_HEDLEY_NON_NULL(2) + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, sax_parse(ptr, ptr + len, ...)) static bool sax_parse(detail::span_input_adapter&& i, SAX* sax, input_format_t format = input_format_t::json, const bool strict = true) @@ -7408,8 +7408,8 @@ class basic_json } template - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) static basic_json from_cbor(const T* ptr, std::size_t len, const bool strict = true, const bool allow_exceptions = true) @@ -7418,8 +7418,8 @@ class basic_json } - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) static basic_json from_cbor(detail::span_input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) @@ -7548,8 +7548,8 @@ class basic_json template - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) static basic_json from_msgpack(const T* ptr, std::size_t len, const bool strict = true, const bool allow_exceptions = true) @@ -7557,8 +7557,8 @@ class basic_json return from_msgpack(ptr, ptr + len, strict, allow_exceptions); } - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) static basic_json from_msgpack(detail::span_input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) @@ -7662,8 +7662,8 @@ class basic_json } template - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) static basic_json from_ubjson(const T* ptr, std::size_t len, const bool strict = true, const bool allow_exceptions = true) @@ -7671,8 +7671,8 @@ class basic_json return from_ubjson(ptr, ptr + len, strict, allow_exceptions); } - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) static basic_json from_ubjson(detail::span_input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) @@ -7775,8 +7775,8 @@ class basic_json } template - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) static basic_json from_bson(const T* ptr, std::size_t len, const bool strict = true, const bool allow_exceptions = true) @@ -7784,8 +7784,8 @@ class basic_json return from_bson(ptr, ptr + len, strict, allow_exceptions); } - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) static basic_json from_bson(detail::span_input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 0b5b2a583e..a684cdfa3a 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -22402,8 +22402,8 @@ class basic_json return result; } - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len)) JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, parse(ptr, ptr + len)) static basic_json parse(detail::span_input_adapter&& i, const parser_callback_t cb = nullptr, const bool allow_exceptions = true) @@ -22425,8 +22425,8 @@ class basic_json return parser(detail::input_adapter(std::move(first), std::move(last))).accept(true); } - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len)) JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, accept(ptr, ptr + len)) static bool accept(detail::span_input_adapter&& i) { return parser(i.get()).accept(true); @@ -22494,8 +22494,8 @@ class basic_json } template - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, sax_parse(ptr, ptr + len, ...)) JSON_HEDLEY_NON_NULL(2) + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, sax_parse(ptr, ptr + len, ...)) static bool sax_parse(detail::span_input_adapter&& i, SAX* sax, input_format_t format = input_format_t::json, const bool strict = true) @@ -23171,8 +23171,8 @@ class basic_json } template - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) static basic_json from_cbor(const T* ptr, std::size_t len, const bool strict = true, const bool allow_exceptions = true) @@ -23181,8 +23181,8 @@ class basic_json } - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_cbor(ptr, ptr + len)) static basic_json from_cbor(detail::span_input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) @@ -23311,8 +23311,8 @@ class basic_json template - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) static basic_json from_msgpack(const T* ptr, std::size_t len, const bool strict = true, const bool allow_exceptions = true) @@ -23320,8 +23320,8 @@ class basic_json return from_msgpack(ptr, ptr + len, strict, allow_exceptions); } - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_msgpack(ptr, ptr + len)) static basic_json from_msgpack(detail::span_input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) @@ -23425,8 +23425,8 @@ class basic_json } template - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) static basic_json from_ubjson(const T* ptr, std::size_t len, const bool strict = true, const bool allow_exceptions = true) @@ -23434,8 +23434,8 @@ class basic_json return from_ubjson(ptr, ptr + len, strict, allow_exceptions); } - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_ubjson(ptr, ptr + len)) static basic_json from_ubjson(detail::span_input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) @@ -23538,8 +23538,8 @@ class basic_json } template - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) static basic_json from_bson(const T* ptr, std::size_t len, const bool strict = true, const bool allow_exceptions = true) @@ -23547,8 +23547,8 @@ class basic_json return from_bson(ptr, ptr + len, strict, allow_exceptions); } - JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) JSON_HEDLEY_WARN_UNUSED_RESULT + JSON_HEDLEY_DEPRECATED_FOR(3.8.0, from_bson(ptr, ptr + len)) static basic_json from_bson(detail::span_input_adapter&& i, const bool strict = true, const bool allow_exceptions = true) From 0da131d717e90bcf96ba049a62a7cc6492e80427 Mon Sep 17 00:00:00 2001 From: Francois Chabot Date: Thu, 28 May 2020 17:12:26 -0400 Subject: [PATCH 16/16] minor readme correction --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index dfd5932eb1..68b6dae70e 100644 --- a/README.md +++ b/README.md @@ -416,7 +416,7 @@ Please note that setting the exception bit for `failbit` is inappropriate for th #### Read from iterator range -You can also parse JSON from an iterator range; that is, from any container accessible by iterators whose `value_type` is an integral type of 1, 2 or 4 bytes, for instance a `std::vector`, or a `std::list`: +You can also parse JSON from an iterator range; that is, from any container accessible by iterators whose `value_type` is an integral type of 1, 2 or 4 bytes, which will be interpreted as UTF-8, UTF-16 and UTF-32 respectively. For instance, a `std::vector`, or a `std::list`: ```cpp std::vector v = {'t', 'r', 'u', 'e'}; @@ -435,8 +435,6 @@ json j = json::parse(v); Since the parse function accepts arbitrary iterator ranges, you can provide your own data sources by implementing the `LegacyInputIterator` concept. ```cpp -struct MyContainer; - struct MyContainer { void advance(); const char& get_current(); @@ -451,6 +449,7 @@ struct MyIterator { MyIterator& operator++() { MyContainer.advance(); + return *this; } bool operator!=(const MyIterator& rhs) const {