Merge pull request #2145 from FrancoisChabot/1813-user-input
Fix Issue#1813: user defined input adapters
This commit is contained in:
		
						commit
						7444c7fa25
					
				
					 7 changed files with 714 additions and 615 deletions
				
			
		|  | @ -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
 | ||||
|  | @ -100,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); | ||||
|         } | ||||
|  | @ -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<typename IteratorType> | ||||
| 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<IteratorType>::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<char>::int_type get_character() noexcept | ||||
|     typename std::char_traits<char_type>::int_type get_character() | ||||
|     { | ||||
|         if (JSON_HEDLEY_LIKELY(cursor < limit)) | ||||
|         if (JSON_HEDLEY_LIKELY(current != end)) | ||||
|         { | ||||
|             assert(cursor != nullptr and limit != nullptr); | ||||
|             return std::char_traits<char>::to_int_type(*(cursor++)); | ||||
|             auto result = std::char_traits<char_type>::to_int_type(*current); | ||||
|             std::advance(current, 1); | ||||
|             return result; | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return std::char_traits<char_type>::eof(); | ||||
|         } | ||||
| 
 | ||||
|         return std::char_traits<char>::eof(); | ||||
|     } | ||||
| 
 | ||||
|   private: | ||||
|     /// pointer to the current character
 | ||||
|     const char* cursor; | ||||
|     /// pointer past the last character
 | ||||
|     const char* const limit; | ||||
|     IteratorType current; | ||||
|     IteratorType end; | ||||
| 
 | ||||
|     template<typename BaseInputAdapter, size_t T> | ||||
|     friend struct wide_string_input_helper; | ||||
| 
 | ||||
|     bool empty() const | ||||
|     { | ||||
|         return current == end; | ||||
|     } | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| template<typename WideStringType, size_t T> | ||||
| struct wide_string_input_helper | ||||
| 
 | ||||
| template<typename BaseInputAdapter, size_t T> | ||||
| struct wide_string_input_helper; | ||||
| 
 | ||||
| template<typename BaseInputAdapter> | ||||
| struct wide_string_input_helper<BaseInputAdapter, 4> | ||||
| { | ||||
|     // UTF-32
 | ||||
|     static void fill_buffer(const WideStringType& str, | ||||
|                             size_t& current_wchar, | ||||
|     static void fill_buffer(BaseInputAdapter& input, | ||||
|                             std::array<std::char_traits<char>::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 (JSON_HEDLEY_UNLIKELY(input.empty())) | ||||
|         { | ||||
|             utf8_bytes[0] = std::char_traits<char>::eof(); | ||||
|             utf8_bytes_filled = 1; | ||||
|  | @ -165,7 +179,7 @@ struct wide_string_input_helper | |||
|         else | ||||
|         { | ||||
|             // get the current character
 | ||||
|             const auto wc = static_cast<unsigned int>(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<typename WideStringType> | ||||
| struct wide_string_input_helper<WideStringType, 2> | ||||
| template<typename BaseInputAdapter> | ||||
| struct wide_string_input_helper<BaseInputAdapter, 2> | ||||
| { | ||||
|     // UTF-16
 | ||||
|     static void fill_buffer(const WideStringType& str, | ||||
|                             size_t& current_wchar, | ||||
|     static void fill_buffer(BaseInputAdapter& input, | ||||
|                             std::array<std::char_traits<char>::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 (JSON_HEDLEY_UNLIKELY(input.empty())) | ||||
|         { | ||||
|             utf8_bytes[0] = std::char_traits<char>::eof(); | ||||
|             utf8_bytes_filled = 1; | ||||
|  | @ -224,7 +237,7 @@ struct wide_string_input_helper<WideStringType, 2> | |||
|         else | ||||
|         { | ||||
|             // get the current character
 | ||||
|             const auto wc = static_cast<unsigned int>(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<WideStringType, 2> | |||
|             } | ||||
|             else | ||||
|             { | ||||
|                 if (current_wchar < str.size()) | ||||
|                 if (JSON_HEDLEY_UNLIKELY(not input.empty())) | ||||
|                 { | ||||
|                     const auto wc2 = static_cast<unsigned int>(str[current_wchar++]); | ||||
|                     const auto wc2 = static_cast<unsigned int>(input.get_character()); | ||||
|                     const auto charcode = 0x10000u + (((wc & 0x3FFu) << 10u) | (wc2 & 0x3FFu)); | ||||
|                     utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | (charcode >> 18u)); | ||||
|                     utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 12u) & 0x3Fu)); | ||||
|  | @ -259,8 +272,6 @@ struct wide_string_input_helper<WideStringType, 2> | |||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     // unknown character
 | ||||
|                     ++current_wchar; | ||||
|                     utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc); | ||||
|                     utf8_bytes_filled = 1; | ||||
|                 } | ||||
|  | @ -269,20 +280,20 @@ struct wide_string_input_helper<WideStringType, 2> | |||
|     } | ||||
| }; | ||||
| 
 | ||||
| template<typename WideStringType> | ||||
| // Wraps another input apdater to convert wide character types into individual bytes.
 | ||||
| template<typename BaseInputAdapter, typename WideCharType> | ||||
| 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<char>::int_type get_character() noexcept | ||||
|     typename std::char_traits<char>::int_type get_character() noexcept | ||||
|     { | ||||
|         // check if buffer needs to be filled
 | ||||
|         if (utf8_bytes_index == utf8_bytes_filled) | ||||
|         { | ||||
|             fill_buffer<sizeof(typename WideStringType::value_type)>(); | ||||
|             fill_buffer<sizeof(WideCharType)>(); | ||||
| 
 | ||||
|             assert(utf8_bytes_filled > 0); | ||||
|             assert(utf8_bytes_index == 0); | ||||
|  | @ -295,18 +306,14 @@ class wide_string_input_adapter | |||
|     } | ||||
| 
 | ||||
|   private: | ||||
|     BaseInputAdapter base_adapter; | ||||
| 
 | ||||
|     template<size_t T> | ||||
|     void fill_buffer() | ||||
|     { | ||||
|         wide_string_input_helper<WideStringType, T>::fill_buffer(str, current_wchar, utf8_bytes, utf8_bytes_index, utf8_bytes_filled); | ||||
|         wide_string_input_helper<BaseInputAdapter, T>::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<std::char_traits<char>::int_type, 4> utf8_bytes = {{0, 0, 0, 0}}; | ||||
| 
 | ||||
|  | @ -316,6 +323,61 @@ class wide_string_input_adapter | |||
|     std::size_t utf8_bytes_filled = 0; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| template<typename IteratorType, typename Enable = void> | ||||
| struct iterator_input_adapter_factory | ||||
| { | ||||
|     using iterator_type = IteratorType; | ||||
|     using char_type = typename std::iterator_traits<iterator_type>::value_type; | ||||
|     using adapter_type = iterator_input_adapter<iterator_type>; | ||||
| 
 | ||||
|     static adapter_type create(IteratorType first, IteratorType last) | ||||
|     { | ||||
|         return adapter_type(std::move(first), std::move(last)); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| // This test breaks astyle formatting when inlined in a template specialization.
 | ||||
| template<typename T> | ||||
| inline constexpr bool is_iterator_of_multibyte() | ||||
| { | ||||
|     return sizeof(typename std::iterator_traits<T>::value_type) > 1; | ||||
| } | ||||
| 
 | ||||
| template<typename IteratorType> | ||||
| struct iterator_input_adapter_factory<IteratorType, enable_if_t<is_iterator_of_multibyte<IteratorType>()>> | ||||
| { | ||||
|     using iterator_type = IteratorType; | ||||
|     using char_type = typename std::iterator_traits<iterator_type>::value_type; | ||||
|     using base_adapter_type = iterator_input_adapter<iterator_type>; | ||||
|     using adapter_type = wide_string_input_adapter<base_adapter_type, char_type>; | ||||
| 
 | ||||
|     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 IteratorType> | ||||
| typename iterator_input_adapter_factory<IteratorType>::adapter_type input_adapter(IteratorType first, IteratorType last) | ||||
| { | ||||
|     using factory_type = iterator_input_adapter_factory<IteratorType>; | ||||
|     return factory_type::create(first, last); | ||||
| } | ||||
| 
 | ||||
| // Convenience shorthand from container to iterator
 | ||||
| template<typename ContainerType> | ||||
| 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)); | ||||
| } | ||||
| 
 | ||||
| // Special cases with fast paths
 | ||||
| inline file_input_adapter input_adapter(std::FILE* file) | ||||
| { | ||||
|     return file_input_adapter(file); | ||||
|  | @ -331,97 +393,27 @@ inline input_stream_adapter input_adapter(std::istream&& stream) | |||
|     return input_stream_adapter(stream); | ||||
| } | ||||
| 
 | ||||
| template<typename CharT, typename SizeT, | ||||
|          typename std::enable_if< | ||||
|              std::is_pointer<CharT>::value and | ||||
|              std::is_integral<typename std::remove_pointer<CharT>::type>::value and | ||||
|              not std::is_same<SizeT, bool>::value and | ||||
|              sizeof(typename std::remove_pointer<CharT>::type) == 1, | ||||
|              int>::type = 0> | ||||
| input_buffer_adapter input_adapter(CharT b, SizeT l) | ||||
| using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval<const char*>(), std::declval<const char*>())); | ||||
| 
 | ||||
| // Null-delimited strings, and the like.
 | ||||
| template < typename CharT, | ||||
|            typename std::enable_if < | ||||
|                std::is_pointer<CharT>::value and | ||||
|                not std::is_array<CharT>::value and | ||||
|                std::is_integral<typename std::remove_pointer<CharT>::type>::value and | ||||
|                sizeof(typename std::remove_pointer<CharT>::type) == 1, | ||||
|                int >::type = 0 > | ||||
| contiguous_bytes_input_adapter input_adapter(CharT b) | ||||
| { | ||||
|     return input_buffer_adapter(reinterpret_cast<const char*>(b), l); | ||||
|     auto length = std::strlen(reinterpret_cast<const char*>(b)); | ||||
|     auto ptr = reinterpret_cast<const char*>(b); | ||||
|     return input_adapter(ptr, ptr + length); | ||||
| } | ||||
| 
 | ||||
| template<typename CharT, | ||||
|          typename std::enable_if< | ||||
|              std::is_pointer<CharT>::value and | ||||
|              std::is_integral<typename std::remove_pointer<CharT>::type>::value and | ||||
|              sizeof(typename std::remove_pointer<CharT>::type) == 1, | ||||
|              int>::type = 0> | ||||
| input_buffer_adapter input_adapter(CharT b) | ||||
| template<typename T, std::size_t N> | ||||
| auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) | ||||
| { | ||||
|     return input_adapter(reinterpret_cast<const char*>(b), | ||||
|                          std::strlen(reinterpret_cast<const char*>(b))); | ||||
| } | ||||
| 
 | ||||
| template<class IteratorType, | ||||
|          typename std::enable_if< | ||||
|              std::is_same<typename iterator_traits<IteratorType>::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<bool, int>(true, 0), | ||||
|                                    [&first](std::pair<bool, int> 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<IteratorType>::value_type) == 1, | ||||
|         "each element in the iterator range must have the size of 1 byte"); | ||||
| 
 | ||||
|     const auto len = static_cast<size_t>(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<const char*>(&(*first)), len); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         // the address of first cannot be used: use nullptr
 | ||||
|         return input_buffer_adapter(nullptr, len); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| inline wide_string_input_adapter<std::wstring> input_adapter(const std::wstring& ws) | ||||
| { | ||||
|     return wide_string_input_adapter<std::wstring>(ws); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| inline wide_string_input_adapter<std::u16string> input_adapter(const std::u16string& ws) | ||||
| { | ||||
|     return wide_string_input_adapter<std::u16string>(ws); | ||||
| } | ||||
| 
 | ||||
| inline wide_string_input_adapter<std::u32string> input_adapter(const std::u32string& ws) | ||||
| { | ||||
|     return wide_string_input_adapter<std::u32string>(ws); | ||||
| } | ||||
| 
 | ||||
| template<class ContiguousContainer, typename | ||||
|          std::enable_if<not std::is_pointer<ContiguousContainer>::value and | ||||
|                         std::is_base_of<std::random_access_iterator_tag, typename iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value, | ||||
|                         int>::type = 0> | ||||
| input_buffer_adapter input_adapter(const ContiguousContainer& c) | ||||
| { | ||||
|     return input_adapter(std::begin(c), std::end(c)); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| template<class T, std::size_t N> | ||||
| input_buffer_adapter input_adapter(T (&array)[N]) | ||||
| { | ||||
|     return input_adapter(std::begin(array), std::end(array)); | ||||
|     return input_adapter(array, array + N); | ||||
| } | ||||
| 
 | ||||
| // This class only handles inputs of input_buffer_adapter type.
 | ||||
|  | @ -437,17 +429,7 @@ class span_input_adapter | |||
|                  sizeof(typename std::remove_pointer<CharT>::type) == 1, | ||||
|                  int>::type = 0> | ||||
|     span_input_adapter(CharT b, std::size_t l) | ||||
|         : ia(reinterpret_cast<const char*>(b), l) {} | ||||
| 
 | ||||
|     template<typename CharT, | ||||
|              typename std::enable_if< | ||||
|                  std::is_pointer<CharT>::value and | ||||
|                  std::is_integral<typename std::remove_pointer<CharT>::type>::value and | ||||
|                  sizeof(typename std::remove_pointer<CharT>::type) == 1, | ||||
|                  int>::type = 0> | ||||
|     span_input_adapter(CharT b) | ||||
|         : span_input_adapter(reinterpret_cast<const char*>(b), | ||||
|                              std::strlen(reinterpret_cast<const char*>(b))) {} | ||||
|         : ia(reinterpret_cast<const char*>(b), reinterpret_cast<const char*>(b) + l) {} | ||||
| 
 | ||||
|     template<class IteratorType, | ||||
|              typename std::enable_if< | ||||
|  | @ -456,25 +438,13 @@ class span_input_adapter | |||
|     span_input_adapter(IteratorType first, IteratorType last) | ||||
|         : ia(input_adapter(first, last)) {} | ||||
| 
 | ||||
|     template<class T, std::size_t N> | ||||
|     span_input_adapter(T (&array)[N]) | ||||
|         : span_input_adapter(std::begin(array), std::end(array)) {} | ||||
| 
 | ||||
|     /// input adapter for contiguous container
 | ||||
|     template<class ContiguousContainer, typename | ||||
|              std::enable_if<not std::is_pointer<ContiguousContainer>::value and | ||||
|                             std::is_base_of<std::random_access_iterator_tag, typename iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value, | ||||
|                             int>::type = 0> | ||||
|     span_input_adapter(const ContiguousContainer& c) | ||||
|         : span_input_adapter(std::begin(c), std::end(c)) {} | ||||
| 
 | ||||
|     input_buffer_adapter&& get() | ||||
|     contiguous_bytes_input_adapter&& get() | ||||
|     { | ||||
|         return std::move(ia); | ||||
|     } | ||||
| 
 | ||||
|   private: | ||||
|     input_buffer_adapter ia; | ||||
|     contiguous_bytes_input_adapter ia; | ||||
| }; | ||||
| }  // namespace detail
 | ||||
| }  // namespace nlohmann
 | ||||
|  |  | |||
|  | @ -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,9 +6604,43 @@ 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<typename IteratorType> | ||||
|     JSON_HEDLEY_WARN_UNUSED_RESULT | ||||
|     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(first), std::move(last)), cb, allow_exceptions).parse(true, result); | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     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) | ||||
|  | @ -6638,38 +6656,31 @@ class basic_json | |||
|         return parser(detail::input_adapter(std::forward<InputType>(i))).accept(true); | ||||
|     } | ||||
| 
 | ||||
|     template<typename IteratorType> | ||||
|     static bool accept(IteratorType first, IteratorType last) | ||||
|     { | ||||
|         return parser(detail::input_adapter(std::move(first), std::move(last))).accept(true); | ||||
|     } | ||||
| 
 | ||||
|     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); | ||||
|     } | ||||
| 
 | ||||
|     /*!
 | ||||
|     @brief generate SAX events | ||||
| 
 | ||||
|     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 | ||||
|  | @ -6695,7 +6706,7 @@ class basic_json | |||
| 
 | ||||
|     @since version 3.2.0 | ||||
|     */ | ||||
|     template <typename SAX, typename InputType> | ||||
|     template <typename InputType, typename SAX> | ||||
|     JSON_HEDLEY_NON_NULL(2) | ||||
|     static bool sax_parse(InputType&& i, SAX* sax, | ||||
|                           input_format_t format = input_format_t::json, | ||||
|  | @ -6707,8 +6718,21 @@ class basic_json | |||
|                : detail::binary_reader<basic_json, decltype(ia), SAX>(std::move(ia)).sax_parse(format, sax, strict); | ||||
|     } | ||||
| 
 | ||||
|     template<class IteratorType, class SAX> | ||||
|     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<basic_json, decltype(ia), SAX>(std::move(ia)).sax_parse(format, sax, strict); | ||||
|     } | ||||
| 
 | ||||
|     template <typename SAX> | ||||
|     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) | ||||
|  | @ -6720,86 +6744,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<class IteratorType, typename std::enable_if< | ||||
|                  std::is_base_of< | ||||
|                      std::random_access_iterator_tag, | ||||
|                      typename std::iterator_traits<IteratorType>::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<class IteratorType, typename std::enable_if< | ||||
|                  std::is_base_of< | ||||
|                      std::random_access_iterator_tag, | ||||
|                      typename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0> | ||||
|     static bool accept(IteratorType first, IteratorType last) | ||||
|     { | ||||
|         return parser(detail::input_adapter(first, last)).accept(true); | ||||
|     } | ||||
| 
 | ||||
|     template<class IteratorType, class SAX, typename std::enable_if< | ||||
|                  std::is_base_of< | ||||
|                      std::random_access_iterator_tag, | ||||
|                      typename std::iterator_traits<IteratorType>::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,27 +7394,40 @@ class basic_json | |||
|     /*!
 | ||||
|     @copydoc from_cbor(detail::input_adapter&&, const bool, const bool) | ||||
|     */ | ||||
|     template<typename A1, typename A2, | ||||
|              detail::enable_if_t<std::is_constructible<detail::span_input_adapter, A1, A2>::value, int> = 0> | ||||
|     template<typename IteratorType> | ||||
|     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<basic_json> sdp(result, allow_exceptions); | ||||
|         const bool res = binary_reader<detail::input_buffer_adapter>(detail::span_input_adapter(std::forward<A1>(a1), std::forward<A2>(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<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict); | ||||
|         return res ? result : basic_json(value_t::discarded); | ||||
|     } | ||||
| 
 | ||||
|     template<typename T> | ||||
|     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) | ||||
|     { | ||||
|         return from_cbor(ptr, ptr + len, strict, allow_exceptions); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     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) | ||||
|     { | ||||
|         basic_json result; | ||||
|         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); | ||||
|         const bool res = binary_reader<detail::input_buffer_adapter>(i.get()).sax_parse(input_format_t::cbor, &sdp, strict); | ||||
|         auto ia = i.get(); | ||||
|         const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::cbor, &sdp, strict); | ||||
|         return res ? result : basic_json(value_t::discarded); | ||||
|     } | ||||
| 
 | ||||
|  | @ -7575,28 +7533,40 @@ class basic_json | |||
|     /*!
 | ||||
|     @copydoc from_msgpack(detail::input_adapter&&, const bool, const bool) | ||||
|     */ | ||||
|     template<typename A1, typename A2, | ||||
|              detail::enable_if_t<std::is_constructible<detail::span_input_adapter, A1, A2>::value, int> = 0> | ||||
|     template<typename IteratorType> | ||||
|     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<basic_json> sdp(result, allow_exceptions); | ||||
|         const bool res = binary_reader<detail::input_buffer_adapter>(detail::span_input_adapter(std::forward<A1>(a1), std::forward<A2>(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<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::msgpack, &sdp, strict); | ||||
|         return res ? result : basic_json(value_t::discarded); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     template<typename T> | ||||
|     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) | ||||
|     { | ||||
|         return from_msgpack(ptr, ptr + len, strict, allow_exceptions); | ||||
|     } | ||||
| 
 | ||||
|     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) | ||||
|     { | ||||
|         basic_json result; | ||||
|         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); | ||||
|         const bool res = binary_reader<detail::input_buffer_adapter>(i.get()).sax_parse(input_format_t::msgpack, &sdp, strict); | ||||
|         auto ia = i.get(); | ||||
|         const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::msgpack, &sdp, strict); | ||||
|         return res ? result : basic_json(value_t::discarded); | ||||
|     } | ||||
| 
 | ||||
|  | @ -7678,27 +7648,39 @@ class basic_json | |||
|     /*!
 | ||||
|     @copydoc from_ubjson(detail::input_adapter&&, const bool, const bool) | ||||
|     */ | ||||
|     template<typename A1, typename A2, | ||||
|              detail::enable_if_t<std::is_constructible<detail::span_input_adapter, A1, A2>::value, int> = 0> | ||||
|     template<typename IteratorType> | ||||
|     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<basic_json> sdp(result, allow_exceptions); | ||||
|         const bool res = binary_reader<detail::input_buffer_adapter>(detail::span_input_adapter(std::forward<A1>(a1), std::forward<A2>(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<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::ubjson, &sdp, strict); | ||||
|         return res ? result : basic_json(value_t::discarded); | ||||
|     } | ||||
| 
 | ||||
|     template<typename T> | ||||
|     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) | ||||
|     { | ||||
|         return from_ubjson(ptr, ptr + len, strict, allow_exceptions); | ||||
|     } | ||||
| 
 | ||||
|     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) | ||||
|     { | ||||
|         basic_json result; | ||||
|         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); | ||||
|         const bool res = binary_reader<detail::input_buffer_adapter>(i.get()).sax_parse(input_format_t::ubjson, &sdp, strict); | ||||
|         auto ia = i.get(); | ||||
|         const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::ubjson, &sdp, strict); | ||||
|         return res ? result : basic_json(value_t::discarded); | ||||
|     } | ||||
| 
 | ||||
|  | @ -7779,27 +7761,39 @@ class basic_json | |||
|     /*!
 | ||||
|     @copydoc from_bson(detail::input_adapter&&, const bool, const bool) | ||||
|     */ | ||||
|     template<typename A1, typename A2, | ||||
|              detail::enable_if_t<std::is_constructible<detail::span_input_adapter, A1, A2>::value, int> = 0> | ||||
|     template<typename IteratorType> | ||||
|     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<basic_json> sdp(result, allow_exceptions); | ||||
|         const bool res = binary_reader<detail::input_buffer_adapter>(detail::span_input_adapter(std::forward<A1>(a1), std::forward<A2>(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<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::bson, &sdp, strict); | ||||
|         return res ? result : basic_json(value_t::discarded); | ||||
|     } | ||||
| 
 | ||||
|     template<typename T> | ||||
|     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) | ||||
|     { | ||||
|         return from_bson(ptr, ptr + len, strict, allow_exceptions); | ||||
|     } | ||||
| 
 | ||||
|     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) | ||||
|     { | ||||
|         basic_json result; | ||||
|         detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions); | ||||
|         const bool res = binary_reader<detail::input_buffer_adapter>(i.get()).sax_parse(input_format_t::bson, &sdp, strict); | ||||
|         auto ia = i.get(); | ||||
|         const bool res = binary_reader<decltype(ia)>(std::move(ia)).sax_parse(input_format_t::bson, &sdp, strict); | ||||
|         return res ? result : basic_json(value_t::discarded); | ||||
|     } | ||||
|     /// @}
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue