13 #include <type_traits>
16 #include <nlohmann/detail/iterators/iterator_traits.hpp>
17 #include <nlohmann/detail/macro_scope.hpp>
41 struct input_adapter_protocol
58 JSON_HEDLEY_NON_NULL(2)
64 file_input_adapter(
const file_input_adapter&) =
delete;
65 file_input_adapter(file_input_adapter&&) =
default;
66 file_input_adapter& operator=(
const file_input_adapter&) =
delete;
67 file_input_adapter& operator=(file_input_adapter&&) =
default;
68 ~file_input_adapter()
override =
default;
72 return std::fgetc(m_file);
90 class input_stream_adapter :
public input_adapter_protocol
93 ~input_stream_adapter()
override
97 is.clear(is.rdstate() & std::ios::eofbit);
100 explicit input_stream_adapter(std::istream& i)
101 : is(i), sb(*i.rdbuf())
105 input_stream_adapter(
const input_stream_adapter&) =
delete;
106 input_stream_adapter& operator=(input_stream_adapter&) =
delete;
107 input_stream_adapter(input_stream_adapter&&) =
delete;
108 input_stream_adapter& operator=(input_stream_adapter&&) =
delete;
115 auto res = sb.sbumpc();
119 is.clear(is.rdstate() | std::ios::eofbit);
131 class input_buffer_adapter :
public input_adapter_protocol
134 input_buffer_adapter(
const char* b,
const std::size_t l) noexcept
135 : cursor(b), limit(b ==
nullptr ?
nullptr : (b + l))
139 input_buffer_adapter(
const input_buffer_adapter&) =
delete;
140 input_buffer_adapter& operator=(input_buffer_adapter&) =
delete;
141 input_buffer_adapter(input_buffer_adapter&&) =
delete;
142 input_buffer_adapter& operator=(input_buffer_adapter&&) =
delete;
143 ~input_buffer_adapter()
override =
default;
147 if (JSON_HEDLEY_LIKELY(cursor < limit))
149 assert(cursor !=
nullptr and limit !=
nullptr);
150 return std::char_traits<char>::to_int_type(*(cursor++));
153 return std::char_traits<char>::eof();
160 const char*
const limit;
163 template<
typename W
ideStringType,
size_t T>
164 struct wide_string_input_helper
167 static void fill_buffer(
const WideStringType& str,
168 size_t& current_wchar,
169 std::array<std::char_traits<char>::int_type, 4>& utf8_bytes,
170 size_t& utf8_bytes_index,
171 size_t& utf8_bytes_filled)
173 utf8_bytes_index = 0;
175 if (current_wchar == str.size())
177 utf8_bytes[0] = std::char_traits<char>::eof();
178 utf8_bytes_filled = 1;
183 const auto wc =
static_cast<unsigned int>(str[current_wchar++]);
188 utf8_bytes[0] =
static_cast<std::char_traits<char>::int_type
>(wc);
189 utf8_bytes_filled = 1;
191 else if (wc <= 0x7FF)
193 utf8_bytes[0] =
static_cast<std::char_traits<char>::int_type
>(0xC0u | ((wc >> 6u) & 0x1Fu));
194 utf8_bytes[1] =
static_cast<std::char_traits<char>::int_type
>(0x80u | (wc & 0x3Fu));
195 utf8_bytes_filled = 2;
197 else if (wc <= 0xFFFF)
199 utf8_bytes[0] =
static_cast<std::char_traits<char>::int_type
>(0xE0u | ((wc >> 12u) & 0x0Fu));
200 utf8_bytes[1] =
static_cast<std::char_traits<char>::int_type
>(0x80u | ((wc >> 6u) & 0x3Fu));
201 utf8_bytes[2] =
static_cast<std::char_traits<char>::int_type
>(0x80u | (wc & 0x3Fu));
202 utf8_bytes_filled = 3;
204 else if (wc <= 0x10FFFF)
206 utf8_bytes[0] =
static_cast<std::char_traits<char>::int_type
>(0xF0u | ((wc >> 18u) & 0x07u));
207 utf8_bytes[1] =
static_cast<std::char_traits<char>::int_type
>(0x80u | ((wc >> 12u) & 0x3Fu));
208 utf8_bytes[2] =
static_cast<std::char_traits<char>::int_type
>(0x80u | ((wc >> 6u) & 0x3Fu));
209 utf8_bytes[3] =
static_cast<std::char_traits<char>::int_type
>(0x80u | (wc & 0x3Fu));
210 utf8_bytes_filled = 4;
215 utf8_bytes[0] =
static_cast<std::char_traits<char>::int_type
>(wc);
216 utf8_bytes_filled = 1;
222 template<
typename W
ideStringType>
223 struct wide_string_input_helper<WideStringType, 2>
226 static void fill_buffer(
const WideStringType& str,
227 size_t& current_wchar,
228 std::array<std::char_traits<char>::int_type, 4>& utf8_bytes,
229 size_t& utf8_bytes_index,
230 size_t& utf8_bytes_filled)
232 utf8_bytes_index = 0;
234 if (current_wchar == str.size())
236 utf8_bytes[0] = std::char_traits<char>::eof();
237 utf8_bytes_filled = 1;
242 const auto wc =
static_cast<unsigned int>(str[current_wchar++]);
247 utf8_bytes[0] =
static_cast<std::char_traits<char>::int_type
>(wc);
248 utf8_bytes_filled = 1;
250 else if (wc <= 0x7FF)
252 utf8_bytes[0] =
static_cast<std::char_traits<char>::int_type
>(0xC0u | ((wc >> 6u)));
253 utf8_bytes[1] =
static_cast<std::char_traits<char>::int_type
>(0x80u | (wc & 0x3Fu));
254 utf8_bytes_filled = 2;
256 else if (0xD800 > wc or wc >= 0xE000)
258 utf8_bytes[0] =
static_cast<std::char_traits<char>::int_type
>(0xE0u | ((wc >> 12u)));
259 utf8_bytes[1] =
static_cast<std::char_traits<char>::int_type
>(0x80u | ((wc >> 6u) & 0x3Fu));
260 utf8_bytes[2] =
static_cast<std::char_traits<char>::int_type
>(0x80u | (wc & 0x3Fu));
261 utf8_bytes_filled = 3;
265 if (current_wchar < str.size())
267 const auto wc2 =
static_cast<unsigned int>(str[current_wchar++]);
268 const auto charcode = 0x10000u + (((wc & 0x3FFu) << 10u) | (wc2 & 0x3FFu));
269 utf8_bytes[0] =
static_cast<std::char_traits<char>::int_type
>(0xF0u | (charcode >> 18u));
270 utf8_bytes[1] =
static_cast<std::char_traits<char>::int_type
>(0x80u | ((charcode >> 12u) & 0x3Fu));
271 utf8_bytes[2] =
static_cast<std::char_traits<char>::int_type
>(0x80u | ((charcode >> 6u) & 0x3Fu));
272 utf8_bytes[3] =
static_cast<std::char_traits<char>::int_type
>(0x80u | (charcode & 0x3Fu));
273 utf8_bytes_filled = 4;
279 utf8_bytes[0] =
static_cast<std::char_traits<char>::int_type
>(wc);
280 utf8_bytes_filled = 1;
287 template<
typename W
ideStringType>
288 class wide_string_input_adapter :
public input_adapter_protocol
291 explicit wide_string_input_adapter(
const WideStringType& w) noexcept
298 if (utf8_bytes_index == utf8_bytes_filled)
300 fill_buffer<sizeof(typename WideStringType::value_type)>();
302 assert(utf8_bytes_filled > 0);
303 assert(utf8_bytes_index == 0);
307 assert(utf8_bytes_filled > 0);
308 assert(utf8_bytes_index < utf8_bytes_filled);
309 return utf8_bytes[utf8_bytes_index++];
320 const WideStringType& str;
323 std::size_t current_wchar = 0;
326 std::array<std::char_traits<char>::int_type, 4> utf8_bytes = {{0, 0, 0, 0}};
329 std::size_t utf8_bytes_index = 0;
331 std::size_t utf8_bytes_filled = 0;
338 JSON_HEDLEY_NON_NULL(2)
339 input_adapter(std::FILE* file)
340 : ia(std::make_shared<file_input_adapter>(file)) {}
352 input_adapter(
const std::u16string& ws)
353 : ia(std::make_shared<wide_string_input_adapter<std::u16string>>(ws)) {}
355 input_adapter(
const std::u32string& ws)
356 : ia(std::make_shared<wide_string_input_adapter<std::u32string>>(ws)) {}
359 template<
typename CharT,
360 typename std::enable_if<
361 std::is_pointer<CharT>::value and
362 std::is_integral<typename std::remove_pointer<CharT>::type>::value and
363 sizeof(
typename std::remove_pointer<CharT>::type) == 1,
366 : ia(std::make_shared<input_buffer_adapter>(
reinterpret_cast<const char*
>(b), l)) {}
371 template<
typename CharT,
372 typename std::enable_if<
373 std::is_pointer<CharT>::value and
374 std::is_integral<typename std::remove_pointer<CharT>::type>::value and
375 sizeof(
typename std::remove_pointer<CharT>::type) == 1,
379 std::strlen(
reinterpret_cast<const char*
>(b))) {}
382 template<
class IteratorType,
383 typename std::enable_if<
384 std::is_same<typename iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value,
391 const auto is_contiguous = std::accumulate(
392 first, last, std::pair<bool, int>(
true, 0),
393 [&first](std::pair<bool, int> res, decltype(*first) val)
395 res.first &= (val == *(std::next(std::addressof(*first), res.second++)));
398 assert(is_contiguous);
404 "each element in the iterator range must have the size of 1 byte");
406 const auto len =
static_cast<size_t>(std::distance(first, last));
407 if (JSON_HEDLEY_LIKELY(len > 0))
410 ia = std::make_shared<input_buffer_adapter>(
reinterpret_cast<const char*
>(&(*first)), len);
415 ia = std::make_shared<input_buffer_adapter>(
nullptr, len);
420 template<
class T, std::
size_t N>
425 template<
class ContiguousContainer,
typename
426 std::enable_if<not std::is_pointer<ContiguousContainer>::value and
427 std::is_base_of<std::random_access_iterator_tag, typename iterator_traits<decltype(std::begin(std::declval<ContiguousContainer const>()))>::iterator_category>::value,