Skip to content

Commit 2362b3f

Browse files
committed
Update json.hpp
1 parent 83dd7db commit 2362b3f

File tree

1 file changed

+105
-21
lines changed

1 file changed

+105
-21
lines changed

single_include/nlohmann/json.hpp

Lines changed: 105 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6220,6 +6220,9 @@ NLOHMANN_JSON_NAMESPACE_END
62206220
#include <string> // char_traits, string
62216221
#include <utility> // make_pair, move
62226222
#include <vector> // vector
6223+
#ifdef __cpp_lib_byteswap
6224+
#include <bit> //byteswap
6225+
#endif
62236226

62246227
// #include <nlohmann/detail/exceptions.hpp>
62256228

@@ -6298,6 +6301,13 @@ class file_input_adapter
62986301
return std::fgetc(m_file);
62996302
}
63006303

6304+
// returns the number of characters successfully read
6305+
template<class T>
6306+
std::size_t get_elements(T* dest, std::size_t count = 1)
6307+
{
6308+
return fread(dest, 1, sizeof(T) * count, m_file);
6309+
}
6310+
63016311
private:
63026312
/// the file pointer to read from
63036313
std::FILE* m_file;
@@ -6357,6 +6367,17 @@ class input_stream_adapter
63576367
return res;
63586368
}
63596369

6370+
template<class T>
6371+
std::size_t get_elements(T* dest, std::size_t count = 1)
6372+
{
6373+
auto res = sb->sgetn(reinterpret_cast<char*>(dest), static_cast<std::streamsize>(count * sizeof(T)));
6374+
if (JSON_HEDLEY_UNLIKELY(res < count * sizeof(T)))
6375+
{
6376+
is->clear(is->rdstate() | std::ios::eofbit);
6377+
}
6378+
return static_cast<std::size_t>(res);
6379+
}
6380+
63606381
private:
63616382
/// the associated input stream
63626383
std::istream* is = nullptr;
@@ -6388,6 +6409,26 @@ class iterator_input_adapter
63886409
return char_traits<char_type>::eof();
63896410
}
63906411

6412+
// for general iterators, we cannot really do something better than falling back to processing the range one-by-one
6413+
template<class T>
6414+
std::size_t get_elements(T* dest, std::size_t count = 1)
6415+
{
6416+
auto ptr = reinterpret_cast<char*>(dest);
6417+
for (std::size_t read_index = 0; read_index < count * sizeof(T); ++read_index)
6418+
{
6419+
if (JSON_HEDLEY_LIKELY(current != end))
6420+
{
6421+
ptr[read_index] = *current;
6422+
std::advance(current, 1);
6423+
}
6424+
else
6425+
{
6426+
return read_index;
6427+
}
6428+
}
6429+
return count * sizeof(T);
6430+
}
6431+
63916432
private:
63926433
IteratorType current;
63936434
IteratorType end;
@@ -6551,6 +6592,17 @@ class wide_string_input_adapter
65516592
return utf8_bytes[utf8_bytes_index++];
65526593
}
65536594

6595+
template<class T>
6596+
std::size_t get_elements(T* dest, std::size_t count = 1)
6597+
{
6598+
auto ptr = reinterpret_cast<char*>(dest);
6599+
for (std::size_t read_index = 0; read_index < count * sizeof(T); ++read_index)
6600+
{
6601+
ptr[read_index] = get_character();
6602+
}
6603+
return count * sizeof(T);
6604+
}
6605+
65546606
private:
65556607
BaseInputAdapter base_adapter;
65566608

@@ -12007,6 +12059,29 @@ class binary_reader
1200712059
return current = ia.get_character();
1200812060
}
1200912061

12062+
/*!
12063+
@brief get_to read into a primitive type
12064+
12065+
This function provides the interface to the used input adapter. It does
12066+
not throw in case the input reached EOF, but returns false instead
12067+
12068+
@return bool, whether the read was successful
12069+
*/
12070+
template<class T>
12071+
bool get_to(T& dest, const input_format_t format, const char* context)
12072+
{
12073+
auto new_chars_read = ia.get_elements(&dest);
12074+
chars_read += new_chars_read;
12075+
if (JSON_HEDLEY_UNLIKELY(new_chars_read < sizeof(T)))
12076+
{
12077+
// in case of failure, advance position by 1 to report failing location
12078+
++chars_read;
12079+
sax->parse_error(chars_read, "<end of file>", parse_error::create(110, chars_read, exception_message(format, "unexpected end of input", context), nullptr));
12080+
return false;
12081+
}
12082+
return true;
12083+
}
12084+
1201012085
/*!
1201112086
@return character read from the input after ignoring all 'N' entries
1201212087
*/
@@ -12021,6 +12096,28 @@ class binary_reader
1202112096
return current;
1202212097
}
1202312098

12099+
template<class NumberType>
12100+
static void byte_swap(NumberType& number)
12101+
{
12102+
constexpr std::size_t sz = sizeof(number);
12103+
#ifdef __cpp_lib_byteswap
12104+
if constexpr (sz == 1)
12105+
{
12106+
return;
12107+
}
12108+
// convert float types to int types of the same size
12109+
using swap_t = std::conditional<sz == 2, std::uint16_t, typename std::conditional<sz == 4, std::uint32_t, std::uint64_t>::type>::type;
12110+
swap_t& number_ref = reinterpret_cast<swap_t&>(number);
12111+
number_ref = std::byteswap(number_ref);
12112+
#else
12113+
auto ptr = reinterpret_cast<std::uint8_t*>(&number);
12114+
for (std::size_t i = 0; i < sz / 2; ++i)
12115+
{
12116+
std::swap(ptr[i], ptr[sz - i - 1]);
12117+
}
12118+
#endif
12119+
}
12120+
1202412121
/*
1202512122
@brief read a number from the input
1202612123

@@ -12039,29 +12136,16 @@ class binary_reader
1203912136
template<typename NumberType, bool InputIsLittleEndian = false>
1204012137
bool get_number(const input_format_t format, NumberType& result)
1204112138
{
12042-
// step 1: read input into array with system's byte order
12043-
std::array<std::uint8_t, sizeof(NumberType)> vec{};
12044-
for (std::size_t i = 0; i < sizeof(NumberType); ++i)
12045-
{
12046-
get();
12047-
if (JSON_HEDLEY_UNLIKELY(!unexpect_eof(format, "number")))
12048-
{
12049-
return false;
12050-
}
12139+
// read in the original format
1205112140

12052-
// reverse byte order prior to conversion if necessary
12053-
if (is_little_endian != (InputIsLittleEndian || format == input_format_t::bjdata))
12054-
{
12055-
vec[sizeof(NumberType) - i - 1] = static_cast<std::uint8_t>(current);
12056-
}
12057-
else
12058-
{
12059-
vec[i] = static_cast<std::uint8_t>(current); // LCOV_EXCL_LINE
12060-
}
12141+
if (JSON_HEDLEY_UNLIKELY(!get_to(result, format, "number")))
12142+
{
12143+
return false;
12144+
}
12145+
if (is_little_endian != (InputIsLittleEndian || format == input_format_t::bjdata))
12146+
{
12147+
byte_swap(result);
1206112148
}
12062-
12063-
// step 2: convert array into number of type T and return
12064-
std::memcpy(&result, vec.data(), sizeof(NumberType));
1206512149
return true;
1206612150
}
1206712151

0 commit comments

Comments
 (0)