Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
J
json
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Chen Yisong
json
Commits
5684d9a4
Commit
5684d9a4
authored
May 27, 2020
by
Francois Chabot
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
unified input API
parent
d70d06ae
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
401 additions
and
364 deletions
+401
-364
input_adapters.hpp
include/nlohmann/detail/input/input_adapters.hpp
+111
-134
json.hpp
include/nlohmann/json.hpp
+56
-101
json.hpp
single_include/nlohmann/json.hpp
+116
-129
CMakeLists.txt
test/CMakeLists.txt
+1
-0
Makefile
test/Makefile
+1
-0
unit-user_defined_input.cpp
test/src/unit-user_defined_input.cpp
+116
-0
No files found.
include/nlohmann/detail/input/input_adapters.hpp
View file @
5684d9a4
...
...
@@ -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
...
...
@@ -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
(
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
class
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
(
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
(
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
(
!
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_t
ype
)
>
();
fill_buffer
<
sizeof
(
WideCharT
ype
)
>
();
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_wcha
r
,
utf8_bytes
,
utf8_bytes_index
,
utf8_bytes_filled
);
wide_string_input_helper
<
BaseInputAdapter
,
T
>::
fill_buffer
(
base_adapte
r
,
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,113 +323,84 @@ class wide_string_input_adapter
std
::
size_t
utf8_bytes_filled
=
0
;
};
inline
file_input_adapter
input_adapter
(
std
::
FILE
*
file
)
{
return
file_input_adapter
(
file
);
}
inline
input_stream_adapter
input_adapter
(
std
::
istream
&
stream
)
template
<
typename
IteratorType
,
typename
Enable
=
void
>
struct
iterator_input_adapter_factory
{
return
input_stream_adapter
(
stream
);
}
using
iterator_type
=
IteratorType
;
using
char_type
=
typename
std
::
iterator_traits
<
iterator_type
>::
value_type
;
using
adapter_type
=
iterator_input_adapter
<
iterator_type
>
;
inline
input_stream_adapter
input_adapter
(
std
::
istream
&&
stream
)
{
return
input_stream_adapter
(
stream
);
}
static
adapter_type
create
(
IteratorType
begin
,
IteratorType
end
)
{
return
adapter_type
(
std
::
move
(
begin
),
std
::
move
(
end
));
}
};
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
,
std
::
size_t
l
)
{
return
input_buffer_adapter
(
reinterpret_cast
<
const
char
*>
(
b
),
l
);
}
template
<
typename
IteratorType
>
struct
iterator_input_adapter_factory
<
IteratorType
,
typename
std
::
enable_if
<
(
sizeof
(
typename
std
::
iterator_traits
<
IteratorType
>::
value_type
)
>
1
)
>::
type
>
{
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
)
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
begin
,
IteratorType
end
)
{
return
input_adapter
(
reinterpret_cast
<
const
char
*>
(
b
),
std
::
strlen
(
reinterpret_cast
<
const
char
*>
(
b
)));
return
adapter_type
(
base_adapter_type
(
std
::
move
(
begin
),
std
::
move
(
end
)));
}
};
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
)
// General purpose iterator-based input
template
<
typename
IteratorType
>
typename
iterator_input_adapter_factory
<
IteratorType
>::
adapter_type
input_adapter
(
IteratorType
begin
,
IteratorType
end
)
{
#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
);
}
using
factory_type
=
iterator_input_adapter_factory
<
IteratorType
>
;
return
factory_type
::
create
(
begin
,
end
);
}
inline
wide_string_input_adapter
<
std
::
wstring
>
input_adapter
(
const
std
::
wstring
&
ws
)
// Convenience shorthand from container to iterator
template
<
typename
ContainerType
>
auto
input_adapter
(
const
ContainerType
&
container
)
->
decltype
(
input_adapter
(
begin
(
container
),
end
(
container
)))
{
return
wide_string_input_adapter
<
std
::
wstring
>
(
ws
);
return
input_adapter
(
begin
(
container
),
end
(
container
)
);
}
inline
wide_string_input_adapter
<
std
::
u16string
>
input_adapter
(
const
std
::
u16string
&
ws
)
// Special cases with fast paths
inline
file_input_adapter
input_adapter
(
std
::
FILE
*
file
)
{
return
wide_string_input_adapter
<
std
::
u16string
>
(
ws
);
return
file_input_adapter
(
file
);
}
inline
wide_string_input_adapter
<
std
::
u32string
>
input_adapter
(
const
std
::
u32string
&
ws
)
inline
input_stream_adapter
input_adapter
(
std
::
istream
&
stream
)
{
return
wide_string_input_adapter
<
std
::
u32string
>
(
ws
);
return
input_stream_adapter
(
stream
);
}
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
)
inline
input_stream_adapter
input_adapter
(
std
::
istream
&&
stream
)
{
return
input_
adapter
(
std
::
begin
(
c
),
std
::
end
(
c
)
);
return
input_
stream_adapter
(
stream
);
}
using
contiguous_bytes_input_adapter
=
decltype
(
input_adapter
(
std
::
declval
<
const
char
*>
(),
std
::
declval
<
const
char
*>
()));
template
<
class
T
,
std
::
size_t
N
>
input_buffer_adapter
input_adapter
(
T
(
&
array
)[
N
])
// Null-delimited strings, and the like.
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
>
contiguous_bytes_input_adapter
input_adapter
(
CharT
b
)
{
return
input_adapter
(
std
::
begin
(
array
),
std
::
end
(
array
));
auto
length
=
std
::
strlen
(
reinterpret_cast
<
const
char
*>
(
b
));
auto
ptr
=
reinterpret_cast
<
const
char
*>
(
b
);
return
input_adapter
(
ptr
,
ptr
+
length
);
}
// This class only handles inputs of input_buffer_adapter type.
// It's required so that expressions like {ptr, len} can be implicitely casted
// to the correct adapter.
...
...
@@ -436,7 +414,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
)
{}
:
ia
(
reinterpret_cast
<
const
char
*>
(
b
),
reinterpret_cast
<
const
char
*>
(
b
)
+
l
)
{}
template
<
typename
CharT
,
typename
std
::
enable_if
<
...
...
@@ -445,8 +423,7 @@ class span_input_adapter
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
)))
{}
:
span_input_adapter
(
b
,
std
::
strlen
(
reinterpret_cast
<
const
char
*>
(
b
)))
{}
template
<
class
IteratorType
,
typename
std
::
enable_if
<
...
...
@@ -467,13 +444,13 @@ class span_input_adapter
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
include/nlohmann/json.hpp
View file @
5684d9a4
...
...
@@ -6621,6 +6621,17 @@ class basic_json
}
template
<
typename
IteratorType
>
JSON_HEDLEY_WARN_UNUSED_RESULT
static
basic_json
parse
(
IteratorType
begin
,
IteratorType
end
,
const
parser_callback_t
cb
=
nullptr
,
const
bool
allow_exceptions
=
true
)
{
basic_json
result
;
parser
(
detail
::
input_adapter
(
std
::
move
(
begin
),
std
::
move
(
end
)),
cb
,
allow_exceptions
).
parse
(
true
,
result
);
return
result
;
}
JSON_HEDLEY_WARN_UNUSED_RESULT
static
basic_json
parse
(
detail
::
span_input_adapter
&&
i
,
...
...
@@ -6638,10 +6649,17 @@ class basic_json
return
parser
(
detail
::
input_adapter
(
std
::
forward
<
InputType
>
(
i
))).
accept
(
true
);
}
template
<
typename
IteratorType
>
static
bool
accept
(
IteratorType
begin
,
IteratorType
end
)
{
return
parser
(
detail
::
input_adapter
(
std
::
move
(
begin
),
std
::
move
(
end
))).
accept
(
true
);
}
static
bool
accept
(
detail
::
span_input_adapter
&&
i
)
{
return
parser
(
i
.
get
()).
accept
(
true
);
}
/*!
@brief generate SAX events
...
...
@@ -6695,7 +6713,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,6 +6725,18 @@ 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
)
static
bool
sax_parse
(
detail
::
span_input_adapter
&&
i
,
SAX
*
sax
,
...
...
@@ -6720,86 +6750,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,16 +7400,16 @@ 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
);
}
...
...
@@ -7469,7 +7420,8 @@ class basic_json
{
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,16 +7527,16 @@ 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
);
}
...
...
@@ -7596,7 +7548,8 @@ class basic_json
{
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,16 +7631,16 @@ 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
);
}
...
...
@@ -7698,7 +7651,8 @@ class basic_json
{
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,16 +7733,16 @@ 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
);
}
...
...
@@ -7799,7 +7753,8 @@ class basic_json
{
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
);
}
/// @}
...
...
single_include/nlohmann/json.hpp
View file @
5684d9a4
...
...
@@ -4456,6 +4456,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
)
...
...
@@ -4490,6 +4492,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
...
...
@@ -4535,51 +4539,55 @@ 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
begin_ite
,
IteratorType
end_ite
)
:
current
(
std
::
move
(
begin_ite
)),
end
(
std
::
move
(
end_ite
))
{}
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
(
current
!=
end
)
{
assert
(
cursor
!=
nullptr
and
limit
!=
nullptr
);
return
std
::
char_traits
<
char
>::
to_int_type
(
*
(
cursor
++
));
return
*
current
++
;
}
else
{
return
std
::
char_traits
<
char_type
>::
eof
();
}
}
return
std
::
char_traits
<
char
>::
eof
();
bool
empty
()
const
{
return
current
==
end
;
}
private
:
/// pointer to the current character
const
char
*
cursor
;
/// pointer past the last character
const
char
*
const
limit
;
IteratorType
current
;
IteratorType
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
(
input
.
empty
())
{
utf8_bytes
[
0
]
=
std
::
char_traits
<
char
>::
eof
();
utf8_bytes_filled
=
1
;
...
...
@@ -4587,7 +4595,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
)
...
...
@@ -4626,19 +4634,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
(
input
.
empty
())
{
utf8_bytes
[
0
]
=
std
::
char_traits
<
char
>::
eof
();
utf8_bytes_filled
=
1
;
...
...
@@ -4646,7 +4653,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
)
...
...
@@ -4669,9 +4676,9 @@ struct wide_string_input_helper<WideStringType, 2>
}
else
{
if
(
current_wchar
<
str
.
size
())
if
(
!
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
));
...
...
@@ -4681,8 +4688,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
;
}
...
...
@@ -4691,20 +4696,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_t
ype
)
>
();
fill_buffer
<
sizeof
(
WideCharT
ype
)
>
();
assert
(
utf8_bytes_filled
>
0
);
assert
(
utf8_bytes_index
==
0
);
...
...
@@ -4717,18 +4722,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_wcha
r
,
utf8_bytes
,
utf8_bytes_index
,
utf8_bytes_filled
);
wide_string_input_helper
<
BaseInputAdapter
,
T
>::
fill_buffer
(
base_adapte
r
,
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
}};
...
...
@@ -4736,8 +4737,53 @@ class wide_string_input_adapter
std
::
size_t
utf8_bytes_index
=
0
;
/// number of valid bytes in the utf8_codes array
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
>
;
adapter_type
create
(
IteratorType
begin
,
IteratorType
end
)
{
return
adapter_type
(
std
::
move
(
begin
),
std
::
mve
(
end
));
}
};
template
<
typename
IteratorType
>
struct
iterator_input_adapter_factory
<
IteratorType
,
typename
std
::
enable_if
<
(
sizeof
(
typename
std
::
iterator_traits
<
iterator_type
>::
value_type
)
>
1
)
>::
type
>
{
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
>
;
adapter_type
create
(
IteratorType
begin
,
IteratorType
end
)
{
return
adapter_type
(
base_adapter_type
(
std
::
move
(
begin
),
std
::
mve
(
end
)));
}
};
// General purpose iterator-based input
template
<
typename
IteratorType
>
typename
iterator_input_adapter_factory
<
IteratorType
>::
adapter_type
input_adapter
(
IteratorType
begin
,
IteratorType
end
)
{
return
iterator_input_adapter_factory
<
IteratorType
>::
create
(
begin
,
end
);
}
// Convenience shorthand from container to iterator
template
<
typename
ContainerType
>
decltype
(
input_adapter
(
begin
(
container
),
end
(
container
)))
input_adapter
(
const
T
&
container
)
{
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
);
...
...
@@ -4753,17 +4799,7 @@ inline input_stream_adapter input_adapter(std::istream&& stream)
return
input_stream_adapter
(
stream
);
}
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
,
std
::
size_t
l
)
{
return
input_buffer_adapter
(
reinterpret_cast
<
const
char
*>
(
b
),
l
);
}
// Null-delimited strings, and the like.
template
<
typename
CharT
,
typename
std
::
enable_if
<
std
::
is_pointer
<
CharT
>::
value
and
...
...
@@ -4772,79 +4808,12 @@ template<typename CharT,
int
>::
type
=
0
>
input_buffer_adapter
input_adapter
(
CharT
b
)
{
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
);
auto
length
=
std
::
strlen
(
reinterpret_cast
<
const
char
*>
(
b
));
auto
ptr
=
reinterpret_cast
<
const
char
*>
(
b
);
return
input_adapter
(
ptr
,
ptr
+
length
);
}
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
));
}
// This class only handles inputs of input_buffer_adapter type.
// It's required so that expressions like {ptr, len} can be implicitely casted
// to the correct adapter.
...
...
@@ -22413,6 +22382,17 @@ class basic_json
}
template
<
typename
IteratorType
>
JSON_HEDLEY_WARN_UNUSED_RESULT
static
basic_json
parse
(
IteratorType
begin
,
IteratorType
end
,
const
parser_callback_t
cb
=
nullptr
,
const
bool
allow_exceptions
=
true
)
{
basic_json
result
;
parser
(
detail
::
iterator_input_adapter
(
std
::
move
(
begin
),
std
::
move
(
end
)),
cb
,
allow_exceptions
).
parse
(
true
,
result
);
return
result
;
}
JSON_HEDLEY_WARN_UNUSED_RESULT
static
basic_json
parse
(
detail
::
span_input_adapter
&&
i
,
...
...
@@ -22430,10 +22410,17 @@ class basic_json
return
parser
(
detail
::
input_adapter
(
std
::
forward
<
InputType
>
(
i
))).
accept
(
true
);
}
template
<
typename
IteratorType
>
static
bool
accept
(
IteratorType
begin
,
IteratorType
end
)
{
return
parser
(
detail
::
iterator_input_adapter
(
std
::
move
(
begin
),
std
::
move
(
end
))).
accept
(
true
);
}
static
bool
accept
(
detail
::
span_input_adapter
&&
i
)
{
return
parser
(
i
.
get
()).
accept
(
true
);
}
/*!
@brief generate SAX events
...
...
test/CMakeLists.txt
View file @
5684d9a4
...
...
@@ -133,6 +133,7 @@ set(files
src/unit-ubjson.cpp
src/unit-udt.cpp
src/unit-unicode.cpp
src/unit-user_defined_input.cpp
src/unit-wstring.cpp
)
foreach
(
file
${
files
}
)
...
...
test/Makefile
View file @
5684d9a4
...
...
@@ -44,6 +44,7 @@ SOURCES = src/unit.cpp \
src/unit-testsuites.cpp
\
src/unit-ubjson.cpp
\
src/unit-unicode.cpp
\
src/unit-user_defined_input.cpp
\
src/unit-wstring.cpp
OBJECTS
=
$
(
SOURCES:.cpp
=
.o
)
...
...
test/src/unit-user_defined_input.cpp
0 → 100644
View file @
5684d9a4
/*
__ _____ _____ _____
__| | __| | | | JSON for Modern C++ (test suite)
| | |__ | | | | | | version 3.7.3
|_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
SPDX-License-Identifier: MIT
Copyright (c) 2013-2019 Niels Lohmann <http://nlohmann.me>.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#include "doctest_compatibility.h"
#include <nlohmann/json.hpp>
using
nlohmann
::
json
;
#include <list>
namespace
{
TEST_CASE
(
"Use arbitrary stdlib container"
)
{
std
::
string
raw_data
=
"[1,2,3,4]"
;
std
::
list
<
char
>
data
(
raw_data
.
begin
(),
raw_data
.
end
());
json
as_json
=
json
::
parse
(
data
.
begin
(),
data
.
end
());
CHECK
(
as_json
.
at
(
0
)
==
1
);
CHECK
(
as_json
.
at
(
1
)
==
2
);
CHECK
(
as_json
.
at
(
2
)
==
3
);
CHECK
(
as_json
.
at
(
3
)
==
4
);
}
struct
MyContainer
{
const
char
*
data
;
};
const
char
*
begin
(
const
MyContainer
&
c
)
{
return
c
.
data
;
}
const
char
*
end
(
const
MyContainer
&
c
)
{
return
c
.
data
+
strlen
(
c
.
data
);
}
TEST_CASE
(
"Custom container"
)
{
MyContainer
data
{
"[1,2,3,4]"
};
json
as_json
=
json
::
parse
(
data
);
CHECK
(
as_json
.
at
(
0
)
==
1
);
CHECK
(
as_json
.
at
(
1
)
==
2
);
CHECK
(
as_json
.
at
(
2
)
==
3
);
CHECK
(
as_json
.
at
(
3
)
==
4
);
}
TEST_CASE
(
"Custom iterator"
)
{
const
char
*
raw_data
=
"[1,2,3,4]"
;
struct
MyIterator
{
using
difference_type
=
std
::
size_t
;
using
value_type
=
char
;
using
pointer
=
const
char
*
;
using
reference
=
const
char
&
;
using
iterator_category
=
std
::
input_iterator_tag
;
MyIterator
&
operator
++
()
{
++
ptr
;
return
*
this
;
}
reference
operator
*
()
const
{
return
*
ptr
;}
bool
operator
!=
(
const
MyIterator
&
rhs
)
const
{
return
ptr
!=
rhs
.
ptr
;
}
const
char
*
ptr
;
};
MyIterator
begin
{
raw_data
};
MyIterator
end
{
raw_data
+
strlen
(
raw_data
)};
json
as_json
=
json
::
parse
(
begin
,
end
);
CHECK
(
as_json
.
at
(
0
)
==
1
);
CHECK
(
as_json
.
at
(
1
)
==
2
);
CHECK
(
as_json
.
at
(
2
)
==
3
);
CHECK
(
as_json
.
at
(
3
)
==
4
);
}
}
\ No newline at end of file
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