Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
J
json
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
json
Commits
e24df7ec
Unverified
Commit
e24df7ec
authored
Apr 23, 2017
by
Niels Lohmann
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
📝
improved documentation
parent
2a211461
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
214 additions
and
36 deletions
+214
-36
src/json.hpp
src/json.hpp
+214
-36
No files found.
src/json.hpp
View file @
e24df7ec
...
...
@@ -6605,6 +6605,7 @@ class basic_json
// output adapters //
/////////////////////
/// abstract output adapter interface
template
<
typename
CharType
>
class
output_adapter
{
...
...
@@ -6629,9 +6630,11 @@ class basic_json
}
};
/// a type to simplify interfaces
template
<
typename
CharType
>
using
output_adapter_t
=
std
::
shared_ptr
<
output_adapter
<
CharType
>>
;
/// output adapter for byte vectors
template
<
typename
CharType
>
class
output_vector_adapter
:
public
output_adapter
<
CharType
>
{
...
...
@@ -6654,6 +6657,7 @@ class basic_json
std
::
vector
<
CharType
>&
v
;
};
/// putput adatpter for output streams
template
<
typename
CharType
>
class
output_stream_adapter
:
public
output_adapter
<
CharType
>
{
...
...
@@ -6676,6 +6680,7 @@ class basic_json
std
::
basic_ostream
<
CharType
>&
stream
;
};
/// output adapter for basic_string
template
<
typename
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
>
;
/// input adapter for cached stream input
...
...
@@ -8930,17 +8935,34 @@ class basic_json
/// @{
private:
/*!
@brief deserialization of CBOR and MessagePack values
*/
class
binary_reader
{
public:
/*!
@brief create a binary reader
@param[in] adapter input adapter to read from
*/
explicit
binary_reader
(
input_adapter_t
adapter
)
:
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
the input (true, default) or whether the last
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
)
{
...
...
@@ -9297,12 +9319,13 @@ class basic_json
check_eof
();
// code from RFC 7049, Appendix D, Figure 3:
// As half-precision floating-point numbers were only added to
// IEEE 754 in 2008, today's programming platforms often still
// only have limited support for them. It is very easy to
// include at least decoding support for them even without such
// support. An example of a small decoder for half-precision
// floating-point numbers in the C language is shown in Fig. 3.
// As half-precision floating-point numbers were only added
// to IEEE 754 in 2008, today's programming platforms often
// still only have limited support for them. It is very
// easy to include at least decoding support for them even
// without such support. An example of a small decoder for
// half-precision floating-point numbers in the C language
// is shown in Fig. 3.
const
int
half
=
(
byte1
<<
8
)
+
byte2
;
const
int
exp
=
(
half
>>
10
)
&
0x1f
;
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
()
{
switch
(
get
())
...
...
@@ -9745,23 +9776,52 @@ class basic_json
}
}
private:
// from http://stackoverflow.com/a/1001328/266378
static
bool
little_endianess
()
/*!
@brief determine system byte order
@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
;
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
()
{
++
chars_read
;
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
>
T
get_number
()
{
// step 1: read input into array with system's byte order
std
::
array
<
uint8_t
,
sizeof
(
T
)
>
vec
;
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
;
std
::
memcpy
(
&
result
,
vec
.
data
(),
sizeof
(
T
));
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
result
;
...
...
@@ -9796,6 +9866,18 @@ class basic_json
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
()
{
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
()
{
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
()))
{
...
...
@@ -9969,17 +10066,26 @@ class basic_json
const
bool
is_little_endian
=
true
;
};
/*!
@brief serialization to CBOR and MessagePack values
*/
class
binary_writer
{
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
)
:
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
)
{
switch
(
j
.
type
())
...
...
@@ -10100,6 +10206,7 @@ class basic_json
case
value_t
:
:
string
:
{
// step 1: write control byte and the string length
const
auto
N
=
j
.
m_value
.
string
->
size
();
if
(
N
<=
0x17
)
{
...
...
@@ -10128,7 +10235,7 @@ class basic_json
}
// LCOV_EXCL_STOP
//
append
string
//
step 2: write the
string
oa
->
write_characters
(
reinterpret_cast
<
const
uint8_t
*>
(
j
.
m_value
.
string
->
c_str
()),
j
.
m_value
.
string
->
size
());
break
;
...
...
@@ -10136,6 +10243,7 @@ class basic_json
case
value_t
:
:
array
:
{
// step 1: write control byte and the array size
const
auto
N
=
j
.
m_value
.
array
->
size
();
if
(
N
<=
0x17
)
{
...
...
@@ -10164,7 +10272,7 @@ class basic_json
}
// LCOV_EXCL_STOP
//
append
each element
//
step 2: write
each element
for
(
const
auto
&
el
:
*
j
.
m_value
.
array
)
{
write_cbor
(
el
);
...
...
@@ -10174,6 +10282,7 @@ class basic_json
case
value_t
:
:
object
:
{
// step 1: write control byte and the object size
const
auto
N
=
j
.
m_value
.
object
->
size
();
if
(
N
<=
0x17
)
{
...
...
@@ -10202,7 +10311,7 @@ class basic_json
}
// LCOV_EXCL_STOP
//
append
each element
//
step 2: write
each element
for
(
const
auto
&
el
:
*
j
.
m_value
.
object
)
{
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
)
{
switch
(
j
.
type
())
...
...
@@ -10353,6 +10465,7 @@ class basic_json
case
value_t
:
:
string
:
{
// step 1: write control byte and the string length
const
auto
N
=
j
.
m_value
.
string
->
size
();
if
(
N
<=
31
)
{
...
...
@@ -10378,7 +10491,7 @@ class basic_json
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
()),
j
.
m_value
.
string
->
size
());
break
;
...
...
@@ -10386,6 +10499,7 @@ class basic_json
case
value_t
:
:
array
:
{
// step 1: write control byte and the array size
const
auto
N
=
j
.
m_value
.
array
->
size
();
if
(
N
<=
15
)
{
...
...
@@ -10405,7 +10519,7 @@ class basic_json
write_number
(
static_cast
<
uint32_t
>
(
N
));
}
//
append
each element
//
step 2: write
each element
for
(
const
auto
&
el
:
*
j
.
m_value
.
array
)
{
write_msgpack
(
el
);
...
...
@@ -10415,6 +10529,7 @@ class basic_json
case
value_t
:
:
object
:
{
// step 1: write control byte and the object size
const
auto
N
=
j
.
m_value
.
object
->
size
();
if
(
N
<=
15
)
{
...
...
@@ -10434,7 +10549,7 @@ class basic_json
write_number
(
static_cast
<
uint32_t
>
(
N
));
}
//
append
each element
//
step 2: write
each element
for
(
const
auto
&
el
:
*
j
.
m_value
.
object
)
{
write_msgpack
(
el
.
first
);
...
...
@@ -10451,12 +10566,24 @@ class basic_json
}
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
>
void
write_number
(
T
n
)
{
// step 1: write number to array of length T
std
::
array
<
uint8_t
,
sizeof
(
T
)
>
vec
;
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
)
{
// 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:
/// whether we can assume little endianess
const
bool
is_little_endian
=
true
;
...
...
@@ -10928,12 +11048,19 @@ class basic_json
// 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
()
{
// this function only makes sense after reading `\u`
assert
(
current
==
'u'
);
int
codepoint
=
0
;
// byte 1: \uXxxx
switch
(
get
())
{
case
'0'
:
...
...
@@ -10993,6 +11120,7 @@ class basic_json
return
-
1
;
}
// byte 2: \uxXxx
switch
(
get
())
{
case
'0'
:
...
...
@@ -11052,6 +11180,7 @@ class basic_json
return
-
1
;
}
// byte 3: \uxxXx
switch
(
get
())
{
case
'0'
:
...
...
@@ -11111,6 +11240,7 @@ class basic_json
return
-
1
;
}
// byte 4: \uxxxX
switch
(
get
())
{
case
'0'
:
...
...
@@ -11173,6 +11303,10 @@ class basic_json
return
codepoint
;
}
/*!
@brief create diagnostic representation of a codepoint
@return string "U+XXXX" for codepoint XXXX
*/
static
std
::
string
codepoint_to_string
(
int
codepoint
)
{
std
::
stringstream
ss
;
...
...
@@ -11180,6 +11314,20 @@ class basic_json
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
()
{
// 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
---------|----------|----------|----------|---------|---------|----------|-----------
init | zero | any1 | [error] | [error] | minus | [error] | [error]
...
...
@@ -11725,13 +11884,31 @@ class basic_json
exponent | any2 | any2 | [error] | sign | sign | [error] | [error]
sign | any2 | any2 | [error] | [error] | [error] | [error] | [error]
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
()
{
// reset yytext to store the number's bytes
reset
();
// the type of the parsed number; initially set to unsigned; will
//
be
changed if minus sign, decimal point or exponent is read
// the type of the parsed number; initially set to unsigned; will
be
// changed if minus sign, decimal point or exponent is read
token_type
number_type
=
token_type
::
value_unsigned
;
// state (init): we just found out we need to scan a number
...
...
@@ -12008,7 +12185,8 @@ scan_number_any2:
}
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
;
next_unget
=
true
;
...
...
@@ -12155,7 +12333,7 @@ scan_number_done:
const
std
::
string
get_string
()
{
// yytext cannot be returned as char*, because it may contain a
// null byte
// null byte
(parsed as "\u0000")
return
std
::
string
(
yytext
.
data
(),
yylen
);
}
...
...
@@ -12302,7 +12480,7 @@ scan_number_done:
number_float_t
value_float
=
0
;
/// the decimal point
const
char
decimal_point_char
=
'
\0
'
;
const
char
decimal_point_char
=
'
.
'
;
};
/*!
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment