📝 improved documentation
This commit is contained in:
parent
2a21146160
commit
e24df7eca9
1 changed files with 214 additions and 36 deletions
250
src/json.hpp
250
src/json.hpp
|
@ -6605,6 +6605,7 @@ class basic_json
|
||||||
// output adapters //
|
// output adapters //
|
||||||
/////////////////////
|
/////////////////////
|
||||||
|
|
||||||
|
/// abstract output adapter interface
|
||||||
template<typename CharType>
|
template<typename CharType>
|
||||||
class output_adapter
|
class output_adapter
|
||||||
{
|
{
|
||||||
|
@ -6629,9 +6630,11 @@ class basic_json
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// a type to simplify interfaces
|
||||||
template<typename CharType>
|
template<typename CharType>
|
||||||
using output_adapter_t = std::shared_ptr<output_adapter<CharType>>;
|
using output_adapter_t = std::shared_ptr<output_adapter<CharType>>;
|
||||||
|
|
||||||
|
/// output adapter for byte vectors
|
||||||
template<typename CharType>
|
template<typename CharType>
|
||||||
class output_vector_adapter : public output_adapter<CharType>
|
class output_vector_adapter : public output_adapter<CharType>
|
||||||
{
|
{
|
||||||
|
@ -6654,6 +6657,7 @@ class basic_json
|
||||||
std::vector<CharType>& v;
|
std::vector<CharType>& v;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// putput adatpter for output streams
|
||||||
template<typename CharType>
|
template<typename CharType>
|
||||||
class output_stream_adapter : public output_adapter<CharType>
|
class output_stream_adapter : public output_adapter<CharType>
|
||||||
{
|
{
|
||||||
|
@ -6676,6 +6680,7 @@ class basic_json
|
||||||
std::basic_ostream<CharType>& stream;
|
std::basic_ostream<CharType>& stream;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// output adapter for basic_string
|
||||||
template<typename CharType>
|
template<typename CharType>
|
||||||
class output_string_adapter : public output_adapter<CharType>
|
class output_string_adapter : public output_adapter<CharType>
|
||||||
{
|
{
|
||||||
|
@ -8773,7 +8778,7 @@ class basic_json
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// a type to simplify interfaces
|
/// a type to simplify interfaces
|
||||||
using input_adapter_t = std::shared_ptr<input_adapter>;
|
using input_adapter_t = std::shared_ptr<input_adapter>;
|
||||||
|
|
||||||
/// input adapter for cached stream input
|
/// input adapter for cached stream input
|
||||||
|
@ -8930,17 +8935,34 @@ class basic_json
|
||||||
/// @{
|
/// @{
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/*!
|
||||||
|
@brief deserialization of CBOR and MessagePack values
|
||||||
|
*/
|
||||||
class binary_reader
|
class binary_reader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/*!
|
||||||
|
@brief create a binary reader
|
||||||
|
|
||||||
|
@param[in] adapter input adapter to read from
|
||||||
|
*/
|
||||||
explicit binary_reader(input_adapter_t adapter)
|
explicit binary_reader(input_adapter_t adapter)
|
||||||
: ia(adapter), is_little_endian(little_endianess())
|
: ia(adapter), is_little_endian(little_endianess())
|
||||||
{}
|
{
|
||||||
|
assert(ia);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@brief create a JSON value from CBOR input
|
||||||
|
|
||||||
@param[in] get_char whether a new character should be retrieved from
|
@param[in] get_char whether a new character should be retrieved from
|
||||||
the input (true, default) or whether the last
|
the input (true, default) or whether the last
|
||||||
read character should be considered instead
|
read character should be considered instead
|
||||||
|
|
||||||
|
@return JSON value created from CBOR input
|
||||||
|
|
||||||
|
@throw parse_error.110 if input ended unexpectedly
|
||||||
|
@throw parse_error.112 if unsupported byte was read
|
||||||
*/
|
*/
|
||||||
basic_json parse_cbor(const bool get_char = true)
|
basic_json parse_cbor(const bool get_char = true)
|
||||||
{
|
{
|
||||||
|
@ -9297,12 +9319,13 @@ class basic_json
|
||||||
check_eof();
|
check_eof();
|
||||||
|
|
||||||
// code from RFC 7049, Appendix D, Figure 3:
|
// code from RFC 7049, Appendix D, Figure 3:
|
||||||
// As half-precision floating-point numbers were only added to
|
// As half-precision floating-point numbers were only added
|
||||||
// IEEE 754 in 2008, today's programming platforms often still
|
// to IEEE 754 in 2008, today's programming platforms often
|
||||||
// only have limited support for them. It is very easy to
|
// still only have limited support for them. It is very
|
||||||
// include at least decoding support for them even without such
|
// easy to include at least decoding support for them even
|
||||||
// support. An example of a small decoder for half-precision
|
// without such support. An example of a small decoder for
|
||||||
// floating-point numbers in the C language is shown in Fig. 3.
|
// half-precision floating-point numbers in the C language
|
||||||
|
// is shown in Fig. 3.
|
||||||
const int half = (byte1 << 8) + byte2;
|
const int half = (byte1 << 8) + byte2;
|
||||||
const int exp = (half >> 10) & 0x1f;
|
const int exp = (half >> 10) & 0x1f;
|
||||||
const int mant = half & 0x3ff;
|
const int mant = half & 0x3ff;
|
||||||
|
@ -9343,6 +9366,14 @@ class basic_json
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief create a JSON value from MessagePack input
|
||||||
|
|
||||||
|
@return JSON value created from MessagePack input
|
||||||
|
|
||||||
|
@throw parse_error.110 if input ended unexpectedly
|
||||||
|
@throw parse_error.112 if unsupported byte was read
|
||||||
|
*/
|
||||||
basic_json parse_msgpack()
|
basic_json parse_msgpack()
|
||||||
{
|
{
|
||||||
switch (get())
|
switch (get())
|
||||||
|
@ -9745,23 +9776,52 @@ class basic_json
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
/*!
|
||||||
// from http://stackoverflow.com/a/1001328/266378
|
@brief determine system byte order
|
||||||
static bool little_endianess()
|
|
||||||
|
@return true iff system's byte order is little endian
|
||||||
|
|
||||||
|
@note from http://stackoverflow.com/a/1001328/266378
|
||||||
|
*/
|
||||||
|
static bool little_endianess() noexcept
|
||||||
{
|
{
|
||||||
int num = 1;
|
int num = 1;
|
||||||
return (*reinterpret_cast<char*>(&num) == 1);
|
return (*reinterpret_cast<char*>(&num) == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/*!
|
||||||
|
@brief get next character from the input
|
||||||
|
|
||||||
|
This function provides the interface to the used input adapter. It does
|
||||||
|
not throw in case the input reached EOF, but returns
|
||||||
|
`std::char_traits<char>::eof()` in that case.
|
||||||
|
|
||||||
|
@return character read from the input
|
||||||
|
*/
|
||||||
int get()
|
int get()
|
||||||
{
|
{
|
||||||
++chars_read;
|
++chars_read;
|
||||||
return (current = ia->get_character());
|
return (current = ia->get_character());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
@brief read a number from the input
|
||||||
|
|
||||||
|
@tparam T the type of the number
|
||||||
|
|
||||||
|
@return number of type @a T
|
||||||
|
|
||||||
|
@note This function needs to respect the system's endianess, because
|
||||||
|
bytes in CBOR and MessagePack are stored in network order (big
|
||||||
|
endian) and therefore need reordering on little endian systems.
|
||||||
|
|
||||||
|
@throw parse_error.110 if input has less than `sizeof(T)` bytes
|
||||||
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T get_number()
|
T get_number()
|
||||||
{
|
{
|
||||||
|
// step 1: read input into array with system's byte order
|
||||||
std::array<uint8_t, sizeof(T)> vec;
|
std::array<uint8_t, sizeof(T)> vec;
|
||||||
for (size_t i = 0; i < sizeof(T); ++i)
|
for (size_t i = 0; i < sizeof(T); ++i)
|
||||||
{
|
{
|
||||||
|
@ -9779,11 +9839,21 @@ class basic_json
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// step 2: convert array into number of type T and return
|
||||||
T result;
|
T result;
|
||||||
std::memcpy(&result, vec.data(), sizeof(T));
|
std::memcpy(&result, vec.data(), sizeof(T));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief create a string by reading characters from the input
|
||||||
|
|
||||||
|
@param[in] len number of bytes to read
|
||||||
|
|
||||||
|
@return string created by reading @a len bytes
|
||||||
|
|
||||||
|
@throw parse_error.110 if input has less than @a len bytes
|
||||||
|
*/
|
||||||
std::string get_string(const size_t len)
|
std::string get_string(const size_t len)
|
||||||
{
|
{
|
||||||
std::string result;
|
std::string result;
|
||||||
|
@ -9796,6 +9866,18 @@ class basic_json
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief reads a CBOR string
|
||||||
|
|
||||||
|
This function first reads starting bytes to determine the expected
|
||||||
|
string length and then copies this number of bytes into a string.
|
||||||
|
Additionally, CBOR's strings with indefinite lengths are supported.
|
||||||
|
|
||||||
|
@return string
|
||||||
|
|
||||||
|
@throw parse_error.110 if input ended
|
||||||
|
@throw parse_error.113 if an unexpexted byte is read
|
||||||
|
*/
|
||||||
std::string get_cbor_string()
|
std::string get_cbor_string()
|
||||||
{
|
{
|
||||||
check_eof();
|
check_eof();
|
||||||
|
@ -9876,6 +9958,17 @@ class basic_json
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief reads a MessagePack string
|
||||||
|
|
||||||
|
This function first reads starting bytes to determine the expected
|
||||||
|
string length and then copies this number of bytes into a string.
|
||||||
|
|
||||||
|
@return string
|
||||||
|
|
||||||
|
@throw parse_error.110 if input ended
|
||||||
|
@throw parse_error.113 if an unexpexted byte is read
|
||||||
|
*/
|
||||||
std::string get_msgpack_string()
|
std::string get_msgpack_string()
|
||||||
{
|
{
|
||||||
check_eof();
|
check_eof();
|
||||||
|
@ -9947,7 +10040,11 @@ class basic_json
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_eof()
|
/*!
|
||||||
|
@brief check if input ended
|
||||||
|
@throw parse_error.110 if input ended
|
||||||
|
*/
|
||||||
|
void check_eof() const
|
||||||
{
|
{
|
||||||
if (JSON_UNLIKELY(current == std::char_traits<char>::eof()))
|
if (JSON_UNLIKELY(current == std::char_traits<char>::eof()))
|
||||||
{
|
{
|
||||||
|
@ -9969,17 +10066,26 @@ class basic_json
|
||||||
const bool is_little_endian = true;
|
const bool is_little_endian = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief serialization to CBOR and MessagePack values
|
||||||
|
*/
|
||||||
class binary_writer
|
class binary_writer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
binary_writer()
|
/*!
|
||||||
: is_little_endian(little_endianess())
|
@brief create a binary writer
|
||||||
{}
|
|
||||||
|
|
||||||
|
@param[in] adapter output adapter to write to
|
||||||
|
*/
|
||||||
explicit binary_writer(output_adapter_t<uint8_t> adapter)
|
explicit binary_writer(output_adapter_t<uint8_t> adapter)
|
||||||
: is_little_endian(little_endianess()), oa(adapter)
|
: is_little_endian(binary_reader::little_endianess()), oa(adapter)
|
||||||
{}
|
{
|
||||||
|
assert(oa);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief[in] j JSON value to serialize
|
||||||
|
*/
|
||||||
void write_cbor(const basic_json& j)
|
void write_cbor(const basic_json& j)
|
||||||
{
|
{
|
||||||
switch (j.type())
|
switch (j.type())
|
||||||
|
@ -10100,6 +10206,7 @@ class basic_json
|
||||||
|
|
||||||
case value_t::string:
|
case value_t::string:
|
||||||
{
|
{
|
||||||
|
// step 1: write control byte and the string length
|
||||||
const auto N = j.m_value.string->size();
|
const auto N = j.m_value.string->size();
|
||||||
if (N <= 0x17)
|
if (N <= 0x17)
|
||||||
{
|
{
|
||||||
|
@ -10128,7 +10235,7 @@ class basic_json
|
||||||
}
|
}
|
||||||
// LCOV_EXCL_STOP
|
// LCOV_EXCL_STOP
|
||||||
|
|
||||||
// append string
|
// step 2: write the string
|
||||||
oa->write_characters(reinterpret_cast<const uint8_t*>(j.m_value.string->c_str()),
|
oa->write_characters(reinterpret_cast<const uint8_t*>(j.m_value.string->c_str()),
|
||||||
j.m_value.string->size());
|
j.m_value.string->size());
|
||||||
break;
|
break;
|
||||||
|
@ -10136,6 +10243,7 @@ class basic_json
|
||||||
|
|
||||||
case value_t::array:
|
case value_t::array:
|
||||||
{
|
{
|
||||||
|
// step 1: write control byte and the array size
|
||||||
const auto N = j.m_value.array->size();
|
const auto N = j.m_value.array->size();
|
||||||
if (N <= 0x17)
|
if (N <= 0x17)
|
||||||
{
|
{
|
||||||
|
@ -10164,7 +10272,7 @@ class basic_json
|
||||||
}
|
}
|
||||||
// LCOV_EXCL_STOP
|
// LCOV_EXCL_STOP
|
||||||
|
|
||||||
// append each element
|
// step 2: write each element
|
||||||
for (const auto& el : *j.m_value.array)
|
for (const auto& el : *j.m_value.array)
|
||||||
{
|
{
|
||||||
write_cbor(el);
|
write_cbor(el);
|
||||||
|
@ -10174,6 +10282,7 @@ class basic_json
|
||||||
|
|
||||||
case value_t::object:
|
case value_t::object:
|
||||||
{
|
{
|
||||||
|
// step 1: write control byte and the object size
|
||||||
const auto N = j.m_value.object->size();
|
const auto N = j.m_value.object->size();
|
||||||
if (N <= 0x17)
|
if (N <= 0x17)
|
||||||
{
|
{
|
||||||
|
@ -10202,7 +10311,7 @@ class basic_json
|
||||||
}
|
}
|
||||||
// LCOV_EXCL_STOP
|
// LCOV_EXCL_STOP
|
||||||
|
|
||||||
// append each element
|
// step 2: write each element
|
||||||
for (const auto& el : *j.m_value.object)
|
for (const auto& el : *j.m_value.object)
|
||||||
{
|
{
|
||||||
write_cbor(el.first);
|
write_cbor(el.first);
|
||||||
|
@ -10218,6 +10327,9 @@ class basic_json
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief[in] j JSON value to serialize
|
||||||
|
*/
|
||||||
void write_msgpack(const basic_json& j)
|
void write_msgpack(const basic_json& j)
|
||||||
{
|
{
|
||||||
switch (j.type())
|
switch (j.type())
|
||||||
|
@ -10353,6 +10465,7 @@ class basic_json
|
||||||
|
|
||||||
case value_t::string:
|
case value_t::string:
|
||||||
{
|
{
|
||||||
|
// step 1: write control byte and the string length
|
||||||
const auto N = j.m_value.string->size();
|
const auto N = j.m_value.string->size();
|
||||||
if (N <= 31)
|
if (N <= 31)
|
||||||
{
|
{
|
||||||
|
@ -10378,7 +10491,7 @@ class basic_json
|
||||||
write_number(static_cast<uint32_t>(N));
|
write_number(static_cast<uint32_t>(N));
|
||||||
}
|
}
|
||||||
|
|
||||||
// append string
|
// step 2: write the string
|
||||||
oa->write_characters(reinterpret_cast<const uint8_t*>(j.m_value.string->c_str()),
|
oa->write_characters(reinterpret_cast<const uint8_t*>(j.m_value.string->c_str()),
|
||||||
j.m_value.string->size());
|
j.m_value.string->size());
|
||||||
break;
|
break;
|
||||||
|
@ -10386,6 +10499,7 @@ class basic_json
|
||||||
|
|
||||||
case value_t::array:
|
case value_t::array:
|
||||||
{
|
{
|
||||||
|
// step 1: write control byte and the array size
|
||||||
const auto N = j.m_value.array->size();
|
const auto N = j.m_value.array->size();
|
||||||
if (N <= 15)
|
if (N <= 15)
|
||||||
{
|
{
|
||||||
|
@ -10405,7 +10519,7 @@ class basic_json
|
||||||
write_number(static_cast<uint32_t>(N));
|
write_number(static_cast<uint32_t>(N));
|
||||||
}
|
}
|
||||||
|
|
||||||
// append each element
|
// step 2: write each element
|
||||||
for (const auto& el : *j.m_value.array)
|
for (const auto& el : *j.m_value.array)
|
||||||
{
|
{
|
||||||
write_msgpack(el);
|
write_msgpack(el);
|
||||||
|
@ -10415,6 +10529,7 @@ class basic_json
|
||||||
|
|
||||||
case value_t::object:
|
case value_t::object:
|
||||||
{
|
{
|
||||||
|
// step 1: write control byte and the object size
|
||||||
const auto N = j.m_value.object->size();
|
const auto N = j.m_value.object->size();
|
||||||
if (N <= 15)
|
if (N <= 15)
|
||||||
{
|
{
|
||||||
|
@ -10434,7 +10549,7 @@ class basic_json
|
||||||
write_number(static_cast<uint32_t>(N));
|
write_number(static_cast<uint32_t>(N));
|
||||||
}
|
}
|
||||||
|
|
||||||
// append each element
|
// step 2: write each element
|
||||||
for (const auto& el : *j.m_value.object)
|
for (const auto& el : *j.m_value.object)
|
||||||
{
|
{
|
||||||
write_msgpack(el.first);
|
write_msgpack(el.first);
|
||||||
|
@ -10451,12 +10566,24 @@ class basic_json
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/*
|
||||||
|
@brief write a number to output input
|
||||||
|
|
||||||
|
@param[in] n number of type @a T
|
||||||
|
@tparam T the type of the number
|
||||||
|
|
||||||
|
@note This function needs to respect the system's endianess, because
|
||||||
|
bytes in CBOR and MessagePack are stored in network order (big
|
||||||
|
endian) and therefore need reordering on little endian systems.
|
||||||
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void write_number(T n)
|
void write_number(T n)
|
||||||
{
|
{
|
||||||
|
// step 1: write number to array of length T
|
||||||
std::array<uint8_t, sizeof(T)> vec;
|
std::array<uint8_t, sizeof(T)> vec;
|
||||||
std::memcpy(vec.data(), &n, sizeof(T));
|
std::memcpy(vec.data(), &n, sizeof(T));
|
||||||
|
|
||||||
|
// step 2: write array to output (with possible reordering)
|
||||||
for (size_t i = 0; i < sizeof(T); ++i)
|
for (size_t i = 0; i < sizeof(T); ++i)
|
||||||
{
|
{
|
||||||
// reverse byte order prior to conversion if necessary
|
// reverse byte order prior to conversion if necessary
|
||||||
|
@ -10471,13 +10598,6 @@ class basic_json
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// from http://stackoverflow.com/a/1001328/266378
|
|
||||||
static bool little_endianess()
|
|
||||||
{
|
|
||||||
int num = 1;
|
|
||||||
return (*reinterpret_cast<char*>(&num) == 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// whether we can assume little endianess
|
/// whether we can assume little endianess
|
||||||
const bool is_little_endian = true;
|
const bool is_little_endian = true;
|
||||||
|
@ -10928,12 +11048,19 @@ class basic_json
|
||||||
// scan functions
|
// scan functions
|
||||||
/////////////////////
|
/////////////////////
|
||||||
|
|
||||||
// must be called after \u was read; returns following xxxx as hex or -1 when error
|
/*!
|
||||||
|
@brief get codepoint from 4 hex characters following `\u`
|
||||||
|
|
||||||
|
@return codepoint or -1 in case of an error (e.g. EOF or non-hex
|
||||||
|
character)
|
||||||
|
*/
|
||||||
int get_codepoint()
|
int get_codepoint()
|
||||||
{
|
{
|
||||||
|
// this function only makes sense after reading `\u`
|
||||||
assert(current == 'u');
|
assert(current == 'u');
|
||||||
int codepoint = 0;
|
int codepoint = 0;
|
||||||
|
|
||||||
|
// byte 1: \uXxxx
|
||||||
switch (get())
|
switch (get())
|
||||||
{
|
{
|
||||||
case '0':
|
case '0':
|
||||||
|
@ -10993,6 +11120,7 @@ class basic_json
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// byte 2: \uxXxx
|
||||||
switch (get())
|
switch (get())
|
||||||
{
|
{
|
||||||
case '0':
|
case '0':
|
||||||
|
@ -11052,6 +11180,7 @@ class basic_json
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// byte 3: \uxxXx
|
||||||
switch (get())
|
switch (get())
|
||||||
{
|
{
|
||||||
case '0':
|
case '0':
|
||||||
|
@ -11111,6 +11240,7 @@ class basic_json
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// byte 4: \uxxxX
|
||||||
switch (get())
|
switch (get())
|
||||||
{
|
{
|
||||||
case '0':
|
case '0':
|
||||||
|
@ -11173,6 +11303,10 @@ class basic_json
|
||||||
return codepoint;
|
return codepoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief create diagnostic representation of a codepoint
|
||||||
|
@return string "U+XXXX" for codepoint XXXX
|
||||||
|
*/
|
||||||
static std::string codepoint_to_string(int codepoint)
|
static std::string codepoint_to_string(int codepoint)
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
@ -11180,6 +11314,20 @@ class basic_json
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@brief scan a string literal
|
||||||
|
|
||||||
|
This function scans a string according to Sect. 7 of RFC 7159. While
|
||||||
|
scanning, bytes are escaped and copied into buffer yytext. Then the
|
||||||
|
function returns successfully, yytext is null-terminated and yylen
|
||||||
|
contains the number of bytes in the string.
|
||||||
|
|
||||||
|
@return token_type::value_string if string could be successfully
|
||||||
|
scanned, token_type::parse_error otherwise
|
||||||
|
|
||||||
|
@note In case of errors, variable error_message contains a textual
|
||||||
|
description.
|
||||||
|
*/
|
||||||
token_type scan_string()
|
token_type scan_string()
|
||||||
{
|
{
|
||||||
// reset yytext (ignore opening quote)
|
// reset yytext (ignore opening quote)
|
||||||
|
@ -11714,6 +11862,17 @@ class basic_json
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@brief scan a number literal
|
||||||
|
|
||||||
|
This function scans a string according to Sect. 6 of RFC 7159.
|
||||||
|
|
||||||
|
The function is realized with a deterministic finite state machine
|
||||||
|
derived from the grammar described in RFC 7159. Starting in state
|
||||||
|
"init", the input is read and used to determined the next state. Only
|
||||||
|
state "done" accepts the number. State "error" is a trap state to model
|
||||||
|
errors. In the table below, "anything" means any character but the ones
|
||||||
|
listed before.
|
||||||
|
|
||||||
state | 0 | 1-9 | e E | + | - | . | anything
|
state | 0 | 1-9 | e E | + | - | . | anything
|
||||||
---------|----------|----------|----------|---------|---------|----------|-----------
|
---------|----------|----------|----------|---------|---------|----------|-----------
|
||||||
init | zero | any1 | [error] | [error] | minus | [error] | [error]
|
init | zero | any1 | [error] | [error] | minus | [error] | [error]
|
||||||
|
@ -11725,13 +11884,31 @@ class basic_json
|
||||||
exponent | any2 | any2 | [error] | sign | sign | [error] | [error]
|
exponent | any2 | any2 | [error] | sign | sign | [error] | [error]
|
||||||
sign | any2 | any2 | [error] | [error] | [error] | [error] | [error]
|
sign | any2 | any2 | [error] | [error] | [error] | [error] | [error]
|
||||||
any2 | any2 | any2 | done | done | done | done | done
|
any2 | any2 | any2 | done | done | done | done | done
|
||||||
|
|
||||||
|
The state machine is realized with one label per state (prefixed with
|
||||||
|
"scan_number_") and `goto` statements between them. The state machine
|
||||||
|
contains cycles, but any cycle can be left when EOF is read. Therefore,
|
||||||
|
the function is guaranteed to terminate.
|
||||||
|
|
||||||
|
During scanning, the read bytes are stored in yytext. This string is
|
||||||
|
then converted to a signed integer, an unsigned integer, or a
|
||||||
|
floating-point number.
|
||||||
|
|
||||||
|
@return token_type::value_unsigned, token_type::value_integer, or
|
||||||
|
token_type::value_float if number could be successfully scanned,
|
||||||
|
token_type::parse_error otherwise
|
||||||
|
|
||||||
|
@note The scanner is independent of the current locale. Internally, the
|
||||||
|
locale's decimal point is used instead of `.` to work with the
|
||||||
|
locale-dependent converters.
|
||||||
*/
|
*/
|
||||||
token_type scan_number()
|
token_type scan_number()
|
||||||
{
|
{
|
||||||
|
// reset yytext to store the number's bytes
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
// the type of the parsed number; initially set to unsigned; will
|
// the type of the parsed number; initially set to unsigned; will be
|
||||||
// be changed if minus sign, decimal point or exponent is read
|
// changed if minus sign, decimal point or exponent is read
|
||||||
token_type number_type = token_type::value_unsigned;
|
token_type number_type = token_type::value_unsigned;
|
||||||
|
|
||||||
// state (init): we just found out we need to scan a number
|
// state (init): we just found out we need to scan a number
|
||||||
|
@ -12008,7 +12185,8 @@ scan_number_any2:
|
||||||
}
|
}
|
||||||
|
|
||||||
scan_number_done:
|
scan_number_done:
|
||||||
// unget the character after the number
|
// unget the character after the number (we only read it to know
|
||||||
|
// that we are done scanning a number)
|
||||||
--chars_read;
|
--chars_read;
|
||||||
next_unget = true;
|
next_unget = true;
|
||||||
|
|
||||||
|
@ -12155,7 +12333,7 @@ scan_number_done:
|
||||||
const std::string get_string()
|
const std::string get_string()
|
||||||
{
|
{
|
||||||
// yytext cannot be returned as char*, because it may contain a
|
// yytext cannot be returned as char*, because it may contain a
|
||||||
// null byte
|
// null byte (parsed as "\u0000")
|
||||||
return std::string(yytext.data(), yylen);
|
return std::string(yytext.data(), yylen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12302,7 +12480,7 @@ scan_number_done:
|
||||||
number_float_t value_float = 0;
|
number_float_t value_float = 0;
|
||||||
|
|
||||||
/// the decimal point
|
/// the decimal point
|
||||||
const char decimal_point_char = '\0';
|
const char decimal_point_char = '.';
|
||||||
};
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
Loading…
Reference in a new issue