mirror of
https://github.com/boostorg/json.git
synced 2025-05-12 06:01:41 +00:00
Handler specifies structure and string limits
This commit is contained in:
parent
da65b25f4d
commit
f3d0710e37
@ -387,6 +387,11 @@ class boost_null_impl : public any_impl
|
|||||||
{
|
{
|
||||||
struct handler
|
struct handler
|
||||||
{
|
{
|
||||||
|
constexpr static std::size_t max_object_size = std::size_t(-1);
|
||||||
|
constexpr static std::size_t max_array_size = std::size_t(-1);
|
||||||
|
constexpr static std::size_t max_key_size = std::size_t(-1);
|
||||||
|
constexpr static std::size_t max_string_size = std::size_t(-1);
|
||||||
|
|
||||||
bool on_document_begin(error_code&) { return true; }
|
bool on_document_begin(error_code&) { return true; }
|
||||||
bool on_document_end(error_code&) { return true; }
|
bool on_document_end(error_code&) { return true; }
|
||||||
bool on_object_begin(error_code&) { return true; }
|
bool on_object_begin(error_code&) { return true; }
|
||||||
|
@ -26,15 +26,16 @@ using namespace boost::json;
|
|||||||
|
|
||||||
//[example_validate
|
//[example_validate
|
||||||
|
|
||||||
bool
|
// The null parser discards all the data
|
||||||
validate( string_view s )
|
class null_parser
|
||||||
{
|
{
|
||||||
// The null parser discards all the data
|
|
||||||
|
|
||||||
class null_parser
|
|
||||||
{
|
|
||||||
struct handler
|
struct handler
|
||||||
{
|
{
|
||||||
|
constexpr static std::size_t max_object_size = std::size_t(-1);
|
||||||
|
constexpr static std::size_t max_array_size = std::size_t(-1);
|
||||||
|
constexpr static std::size_t max_key_size = std::size_t(-1);
|
||||||
|
constexpr static std::size_t max_string_size = std::size_t(-1);
|
||||||
|
|
||||||
bool on_document_begin( error_code& ) { return true; }
|
bool on_document_begin( error_code& ) { return true; }
|
||||||
bool on_document_end( error_code& ) { return true; }
|
bool on_document_end( error_code& ) { return true; }
|
||||||
bool on_object_begin( error_code& ) { return true; }
|
bool on_object_begin( error_code& ) { return true; }
|
||||||
@ -57,7 +58,7 @@ validate( string_view s )
|
|||||||
|
|
||||||
basic_parser<handler> p_;
|
basic_parser<handler> p_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
null_parser()
|
null_parser()
|
||||||
: p_(parse_options())
|
: p_(parse_options())
|
||||||
{
|
{
|
||||||
@ -78,8 +79,11 @@ validate( string_view s )
|
|||||||
ec = error::extra_data;
|
ec = error::extra_data;
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool
|
||||||
|
validate( string_view s )
|
||||||
|
{
|
||||||
// Parse with the null parser and return false on error
|
// Parse with the null parser and return false on error
|
||||||
null_parser p;
|
null_parser p;
|
||||||
error_code ec;
|
error_code ec;
|
||||||
|
@ -17,13 +17,15 @@
|
|||||||
|
|
||||||
using namespace boost::json;
|
using namespace boost::json;
|
||||||
|
|
||||||
bool
|
class null_parser
|
||||||
validate( string_view s )
|
|
||||||
{
|
{
|
||||||
class null_parser
|
|
||||||
{
|
|
||||||
struct handler
|
struct handler
|
||||||
{
|
{
|
||||||
|
constexpr static std::size_t max_object_size = std::size_t(-1);
|
||||||
|
constexpr static std::size_t max_array_size = std::size_t(-1);
|
||||||
|
constexpr static std::size_t max_key_size = std::size_t(-1);
|
||||||
|
constexpr static std::size_t max_string_size = std::size_t(-1);
|
||||||
|
|
||||||
bool on_document_begin( error_code& ) { return true; }
|
bool on_document_begin( error_code& ) { return true; }
|
||||||
bool on_document_end( error_code& ) { return true; }
|
bool on_document_end( error_code& ) { return true; }
|
||||||
bool on_object_begin( error_code& ) { return true; }
|
bool on_object_begin( error_code& ) { return true; }
|
||||||
@ -46,7 +48,7 @@ validate( string_view s )
|
|||||||
|
|
||||||
basic_parser<handler> p_;
|
basic_parser<handler> p_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
null_parser()
|
null_parser()
|
||||||
: p_(parse_options())
|
: p_(parse_options())
|
||||||
{
|
{
|
||||||
@ -67,8 +69,11 @@ validate( string_view s )
|
|||||||
ec = error::extra_data;
|
ec = error::extra_data;
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool
|
||||||
|
validate( string_view s )
|
||||||
|
{
|
||||||
// Parse with the null parser and return false on error
|
// Parse with the null parser and return false on error
|
||||||
null_parser p;
|
null_parser p;
|
||||||
error_code ec;
|
error_code ec;
|
||||||
|
@ -1022,7 +1022,7 @@ public:
|
|||||||
std::size_t
|
std::size_t
|
||||||
max_size() noexcept
|
max_size() noexcept
|
||||||
{
|
{
|
||||||
return BOOST_JSON_MAX_STRUCTURED_SIZE;
|
return array_impl::max_size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return the number of elements that can be held in currently allocated memory.
|
/** Return the number of elements that can be held in currently allocated memory.
|
||||||
|
@ -965,10 +965,22 @@ parse_unescaped(const char* p)
|
|||||||
cs = detail::count_valid<AllowBadUTF8>(
|
cs = detail::count_valid<AllowBadUTF8>(
|
||||||
cs.begin(), cs.end());
|
cs.begin(), cs.end());
|
||||||
std::size_t size = cs.used(start);
|
std::size_t size = cs.used(start);
|
||||||
|
if(IsKey)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(total <= Handler::max_key_size);
|
||||||
if(BOOST_JSON_UNLIKELY(size >
|
if(BOOST_JSON_UNLIKELY(size >
|
||||||
BOOST_JSON_MAX_STRING_SIZE - total))
|
Handler::max_key_size - total))
|
||||||
return fail(cs.begin(), IsKey ?
|
return fail(cs.begin(),
|
||||||
error::key_too_large : error::string_too_large);
|
error::key_too_large);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(total <= Handler::max_string_size);
|
||||||
|
if(BOOST_JSON_UNLIKELY(size >
|
||||||
|
Handler::max_string_size - total))
|
||||||
|
return fail(cs.begin(),
|
||||||
|
error::string_too_large);
|
||||||
|
}
|
||||||
total += size;
|
total += size;
|
||||||
if(BOOST_JSON_UNLIKELY(! cs))
|
if(BOOST_JSON_UNLIKELY(! cs))
|
||||||
{
|
{
|
||||||
@ -1049,6 +1061,8 @@ parse_escaped(
|
|||||||
&Handler::on_key_part : &Handler::on_string_part;
|
&Handler::on_key_part : &Handler::on_string_part;
|
||||||
constexpr auto ev_too_large = IsKey ?
|
constexpr auto ev_too_large = IsKey ?
|
||||||
error::key_too_large : error::string_too_large;
|
error::key_too_large : error::string_too_large;
|
||||||
|
constexpr auto max_size = IsKey ?
|
||||||
|
Handler::max_key_size : Handler::max_string_size;
|
||||||
detail::clipped_const_stream cs(p, end_);
|
detail::clipped_const_stream cs(p, end_);
|
||||||
detail::buffer<BOOST_JSON_STACK_BUFFER_SIZE> temp;
|
detail::buffer<BOOST_JSON_STACK_BUFFER_SIZE> temp;
|
||||||
int digit;
|
int digit;
|
||||||
@ -1089,8 +1103,9 @@ do_str3:
|
|||||||
{
|
{
|
||||||
if(BOOST_JSON_LIKELY(! temp.empty()))
|
if(BOOST_JSON_LIKELY(! temp.empty()))
|
||||||
{
|
{
|
||||||
if(BOOST_JSON_UNLIKELY(temp.size() >
|
BOOST_ASSERT(total <= max_size);
|
||||||
BOOST_JSON_MAX_STRING_SIZE - total))
|
if(BOOST_JSON_UNLIKELY(
|
||||||
|
temp.size() > max_size - total))
|
||||||
return fail(cs.begin(), ev_too_large);
|
return fail(cs.begin(), ev_too_large);
|
||||||
total += temp.size();
|
total += temp.size();
|
||||||
if(BOOST_JSON_UNLIKELY(
|
if(BOOST_JSON_UNLIKELY(
|
||||||
@ -1238,8 +1253,9 @@ do_str3:
|
|||||||
// flush
|
// flush
|
||||||
if(BOOST_JSON_LIKELY(! temp.empty()))
|
if(BOOST_JSON_LIKELY(! temp.empty()))
|
||||||
{
|
{
|
||||||
if(BOOST_JSON_UNLIKELY(temp.size() >
|
BOOST_ASSERT(total <= max_size);
|
||||||
BOOST_JSON_MAX_STRING_SIZE - total))
|
if(BOOST_JSON_UNLIKELY(
|
||||||
|
temp.size() > max_size - total))
|
||||||
return fail(cs.begin(), ev_too_large);
|
return fail(cs.begin(), ev_too_large);
|
||||||
total += temp.size();
|
total += temp.size();
|
||||||
if(BOOST_JSON_UNLIKELY(
|
if(BOOST_JSON_UNLIKELY(
|
||||||
@ -1367,8 +1383,9 @@ do_str2:
|
|||||||
// flush
|
// flush
|
||||||
if(BOOST_JSON_LIKELY(! temp.empty()))
|
if(BOOST_JSON_LIKELY(! temp.empty()))
|
||||||
{
|
{
|
||||||
if(BOOST_JSON_UNLIKELY(temp.size() >
|
BOOST_ASSERT(total <= max_size);
|
||||||
BOOST_JSON_MAX_STRING_SIZE - total))
|
if(BOOST_JSON_UNLIKELY(
|
||||||
|
temp.size() > max_size - total))
|
||||||
return fail(cs.begin(), ev_too_large);
|
return fail(cs.begin(), ev_too_large);
|
||||||
total += temp.size();
|
total += temp.size();
|
||||||
if(BOOST_JSON_UNLIKELY(
|
if(BOOST_JSON_UNLIKELY(
|
||||||
@ -1383,8 +1400,9 @@ do_str2:
|
|||||||
c = *cs;
|
c = *cs;
|
||||||
if(BOOST_JSON_LIKELY(c == '\x22')) // '"'
|
if(BOOST_JSON_LIKELY(c == '\x22')) // '"'
|
||||||
{
|
{
|
||||||
if(BOOST_JSON_UNLIKELY(temp.size() >
|
BOOST_ASSERT(total <= max_size);
|
||||||
BOOST_JSON_MAX_STRING_SIZE - total))
|
if(BOOST_JSON_UNLIKELY(
|
||||||
|
temp.size() > max_size - total))
|
||||||
return fail(cs.begin(), ev_too_large);
|
return fail(cs.begin(), ev_too_large);
|
||||||
total += temp.size();
|
total += temp.size();
|
||||||
if(BOOST_JSON_UNLIKELY(
|
if(BOOST_JSON_UNLIKELY(
|
||||||
@ -1400,8 +1418,9 @@ do_str2:
|
|||||||
{
|
{
|
||||||
if(BOOST_JSON_LIKELY(! temp.empty()))
|
if(BOOST_JSON_LIKELY(! temp.empty()))
|
||||||
{
|
{
|
||||||
if(BOOST_JSON_UNLIKELY(temp.size() >
|
BOOST_ASSERT(total <= max_size);
|
||||||
BOOST_JSON_MAX_STRING_SIZE - total))
|
if(BOOST_JSON_UNLIKELY(
|
||||||
|
temp.size() > max_size - total))
|
||||||
return fail(cs.begin(), ev_too_large);
|
return fail(cs.begin(), ev_too_large);
|
||||||
total += temp.size();
|
total += temp.size();
|
||||||
if(BOOST_JSON_UNLIKELY(
|
if(BOOST_JSON_UNLIKELY(
|
||||||
@ -1512,7 +1531,7 @@ do_obj2:
|
|||||||
}
|
}
|
||||||
loop:
|
loop:
|
||||||
if(BOOST_JSON_UNLIKELY(++size >
|
if(BOOST_JSON_UNLIKELY(++size >
|
||||||
BOOST_JSON_MAX_STRUCTURED_SIZE))
|
Handler::max_object_size))
|
||||||
return fail(cs.begin(), error::object_too_large);
|
return fail(cs.begin(), error::object_too_large);
|
||||||
do_obj3:
|
do_obj3:
|
||||||
cs = parse_string<StackEmpty, true,
|
cs = parse_string<StackEmpty, true,
|
||||||
@ -1658,7 +1677,7 @@ do_arr2:
|
|||||||
}
|
}
|
||||||
loop:
|
loop:
|
||||||
if(BOOST_JSON_UNLIKELY(++size >
|
if(BOOST_JSON_UNLIKELY(++size >
|
||||||
BOOST_JSON_MAX_STRUCTURED_SIZE))
|
Handler::max_array_size))
|
||||||
return fail(cs.begin(), error::array_too_large);
|
return fail(cs.begin(), error::array_too_large);
|
||||||
do_arr3:
|
do_arr3:
|
||||||
// array is not empty, value required
|
// array is not empty, value required
|
||||||
|
@ -54,10 +54,7 @@ public:
|
|||||||
static
|
static
|
||||||
constexpr
|
constexpr
|
||||||
std::size_t
|
std::size_t
|
||||||
max_size() noexcept
|
max_size() noexcept;
|
||||||
{
|
|
||||||
return BOOST_JSON_MAX_STRUCTURED_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
value*
|
value*
|
||||||
data() const noexcept
|
data() const noexcept
|
||||||
|
@ -83,6 +83,24 @@ BOOST_JSON_NS_BEGIN
|
|||||||
the error code to a suitable value. This error
|
the error code to a suitable value. This error
|
||||||
code will be returned by the write function to
|
code will be returned by the write function to
|
||||||
the caller.
|
the caller.
|
||||||
|
\n
|
||||||
|
Handlers must also define the following
|
||||||
|
static data members:
|
||||||
|
|
||||||
|
@li `max_object_size`, the maximum number
|
||||||
|
of elements an object can contain,
|
||||||
|
|
||||||
|
@li `max_array_size`, the maximum number
|
||||||
|
of elements an array can contain,
|
||||||
|
|
||||||
|
@li `max_key_size`, the maximum length
|
||||||
|
for object keys, and
|
||||||
|
|
||||||
|
@li `max_string_size`, the maximum
|
||||||
|
length for strings.
|
||||||
|
|
||||||
|
If a value exceeding these limits
|
||||||
|
is encountered, parsing fails.
|
||||||
\n
|
\n
|
||||||
The following declaration meets the parser's
|
The following declaration meets the parser's
|
||||||
handler requirements:
|
handler requirements:
|
||||||
@ -90,6 +108,12 @@ BOOST_JSON_NS_BEGIN
|
|||||||
@code
|
@code
|
||||||
struct handler
|
struct handler
|
||||||
{
|
{
|
||||||
|
/// Value size limits
|
||||||
|
constexpr static std::size_t max_object_size = -1;
|
||||||
|
constexpr static std::size_t max_array_size = -1;
|
||||||
|
constexpr static std::size_t max_key_size = -1;
|
||||||
|
constexpr static std::size_t max_string_size = -1;
|
||||||
|
|
||||||
/// Called once when the JSON parsing begins.
|
/// Called once when the JSON parsing begins.
|
||||||
///
|
///
|
||||||
/// @return `true` on success.
|
/// @return `true` on success.
|
||||||
|
@ -13,6 +13,18 @@
|
|||||||
BOOST_JSON_NS_BEGIN
|
BOOST_JSON_NS_BEGIN
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
|
constexpr
|
||||||
|
std::size_t
|
||||||
|
array_impl::
|
||||||
|
max_size() noexcept
|
||||||
|
{
|
||||||
|
// max_size depends on the address model
|
||||||
|
using min = std::integral_constant<std::size_t,
|
||||||
|
(std::size_t(-1) - sizeof(table)) / sizeof(value)>;
|
||||||
|
return min::value < BOOST_JSON_MAX_STRUCTURED_SIZE ?
|
||||||
|
min::value : BOOST_JSON_MAX_STRUCTURED_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
auto
|
auto
|
||||||
array_impl::
|
array_impl::
|
||||||
index_of(value const* pos) const noexcept ->
|
index_of(value const* pos) const noexcept ->
|
||||||
|
@ -21,16 +21,14 @@ array_impl(
|
|||||||
std::size_t capacity,
|
std::size_t capacity,
|
||||||
storage_ptr const& sp)
|
storage_ptr const& sp)
|
||||||
{
|
{
|
||||||
auto constexpr soft_limit =
|
if(capacity > max_size())
|
||||||
(std::size_t(-1) - sizeof(table)) /
|
|
||||||
sizeof(value);
|
|
||||||
if( capacity > soft_limit ||
|
|
||||||
capacity > max_size())
|
|
||||||
detail::throw_length_error(
|
detail::throw_length_error(
|
||||||
"array too large",
|
"capacity > max_size()",
|
||||||
BOOST_CURRENT_LOCATION);
|
BOOST_CURRENT_LOCATION);
|
||||||
if(capacity > 0)
|
if(capacity > 0)
|
||||||
{
|
{
|
||||||
|
// make sure to update max_size
|
||||||
|
// if this is changed
|
||||||
tab_ = ::new(sp->allocate(
|
tab_ = ::new(sp->allocate(
|
||||||
(sizeof(table) +
|
(sizeof(table) +
|
||||||
capacity * sizeof(value) +
|
capacity * sizeof(value) +
|
||||||
|
@ -16,6 +16,19 @@
|
|||||||
BOOST_JSON_NS_BEGIN
|
BOOST_JSON_NS_BEGIN
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
|
||||||
|
constexpr
|
||||||
|
std::size_t
|
||||||
|
object_impl::
|
||||||
|
max_size() noexcept
|
||||||
|
{
|
||||||
|
// max_size depends on the address model
|
||||||
|
using min = std::integral_constant<std::size_t,
|
||||||
|
(std::size_t(-1) - sizeof(table)) /
|
||||||
|
(sizeof(value_type) + sizeof(index_t))>;
|
||||||
|
return min::value < BOOST_JSON_MAX_STRUCTURED_SIZE ?
|
||||||
|
min::value : BOOST_JSON_MAX_STRUCTURED_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
object_impl::
|
object_impl::
|
||||||
remove(
|
remove(
|
||||||
@ -41,7 +54,7 @@ bucket_sizes() noexcept ->
|
|||||||
{
|
{
|
||||||
// Taken from Boost.Intrusive and Boost.MultiIndex code,
|
// Taken from Boost.Intrusive and Boost.MultiIndex code,
|
||||||
// thanks to Ion Gaztanaga and Joaquin M Lopez Munoz.
|
// thanks to Ion Gaztanaga and Joaquin M Lopez Munoz.
|
||||||
static constexpr std::size_t list[33] =
|
static constexpr std::size_t list[34] =
|
||||||
{
|
{
|
||||||
0,
|
0,
|
||||||
|
|
||||||
@ -61,7 +74,9 @@ bucket_sizes() noexcept ->
|
|||||||
100663319, 201326611,
|
100663319, 201326611,
|
||||||
402653189, 805306457,
|
402653189, 805306457,
|
||||||
1610612741,
|
1610612741,
|
||||||
BOOST_JSON_MAX_STRUCTURED_SIZE // 3221225473
|
BOOST_JSON_MAX_STRUCTURED_SIZE,
|
||||||
|
// catch anything that exceeds max_size
|
||||||
|
std::size_t(-1)
|
||||||
};
|
};
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
@ -37,14 +37,12 @@ object_impl(
|
|||||||
std::uintptr_t salt,
|
std::uintptr_t salt,
|
||||||
storage_ptr const& sp)
|
storage_ptr const& sp)
|
||||||
{
|
{
|
||||||
// max capacity based on address model
|
if(capacity > max_size())
|
||||||
auto constexpr soft_limit =
|
|
||||||
(std::size_t(-1) - sizeof(table)) / (
|
|
||||||
sizeof(value_type) + sizeof(index_t));
|
|
||||||
if(capacity > soft_limit)
|
|
||||||
throw_length_error(
|
throw_length_error(
|
||||||
"capacity > soft_limit",
|
"capacity > max_size()",
|
||||||
BOOST_CURRENT_LOCATION);
|
BOOST_CURRENT_LOCATION);
|
||||||
|
// make sure to update max_size
|
||||||
|
// if this is changed
|
||||||
const auto n =
|
const auto n =
|
||||||
sizeof(table) +
|
sizeof(table) +
|
||||||
capacity *
|
capacity *
|
||||||
|
@ -31,7 +31,7 @@ class object_impl
|
|||||||
using index_t = std::uint32_t;
|
using index_t = std::uint32_t;
|
||||||
static index_t const null_index =
|
static index_t const null_index =
|
||||||
std::uint32_t(-1);
|
std::uint32_t(-1);
|
||||||
using bucket_size_array = const std::size_t [33];
|
using bucket_size_array = const std::size_t[34];
|
||||||
|
|
||||||
BOOST_JSON_DECL
|
BOOST_JSON_DECL
|
||||||
void
|
void
|
||||||
@ -62,6 +62,11 @@ public:
|
|||||||
do_destroy(sp);
|
do_destroy(sp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
constexpr
|
||||||
|
std::size_t
|
||||||
|
max_size() noexcept;
|
||||||
|
|
||||||
std::size_t
|
std::size_t
|
||||||
size() const noexcept
|
size() const noexcept
|
||||||
{
|
{
|
||||||
|
@ -97,7 +97,11 @@ public:
|
|||||||
std::size_t
|
std::size_t
|
||||||
max_size() noexcept
|
max_size() noexcept
|
||||||
{
|
{
|
||||||
return BOOST_JSON_MAX_STRING_SIZE;
|
// max_size depends on the address model
|
||||||
|
using min = std::integral_constant<std::size_t,
|
||||||
|
std::size_t(-1) - sizeof(table)>;
|
||||||
|
return min::value < BOOST_JSON_MAX_STRING_SIZE ?
|
||||||
|
min::value : BOOST_JSON_MAX_STRING_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_JSON_DECL
|
BOOST_JSON_DECL
|
||||||
|
@ -212,10 +212,6 @@ reserve(std::size_t new_capacity)
|
|||||||
{
|
{
|
||||||
if(new_capacity <= capacity())
|
if(new_capacity <= capacity())
|
||||||
return;
|
return;
|
||||||
if(new_capacity > max_size())
|
|
||||||
detail::throw_length_error(
|
|
||||||
"new_capacity > max_size()",
|
|
||||||
BOOST_CURRENT_LOCATION);
|
|
||||||
rehash(new_capacity);
|
rehash(new_capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -509,12 +509,12 @@ rehash(std::size_t new_capacity)
|
|||||||
BOOST_ASSERT(new_capacity > capacity());
|
BOOST_ASSERT(new_capacity > capacity());
|
||||||
std::size_t const* prime =
|
std::size_t const* prime =
|
||||||
object_impl::bucket_sizes();
|
object_impl::bucket_sizes();
|
||||||
while(new_capacity > *prime)
|
while(*prime < new_capacity)
|
||||||
++prime;
|
++prime;
|
||||||
new_capacity = *prime;
|
new_capacity = *prime;
|
||||||
if(new_capacity > max_size())
|
if(new_capacity > max_size())
|
||||||
detail::throw_length_error(
|
detail::throw_length_error(
|
||||||
"object too large",
|
"new_capacity > max_size()",
|
||||||
BOOST_CURRENT_LOCATION);
|
BOOST_CURRENT_LOCATION);
|
||||||
object_impl impl(
|
object_impl impl(
|
||||||
new_capacity,
|
new_capacity,
|
||||||
|
@ -860,7 +860,7 @@ public:
|
|||||||
std::size_t
|
std::size_t
|
||||||
max_size() noexcept
|
max_size() noexcept
|
||||||
{
|
{
|
||||||
return BOOST_JSON_MAX_STRUCTURED_SIZE;
|
return object_impl::max_size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return the number of elements that can be held in currently allocated memory
|
/** Return the number of elements that can be held in currently allocated memory
|
||||||
|
@ -104,6 +104,18 @@ class parser
|
|||||||
{
|
{
|
||||||
struct handler
|
struct handler
|
||||||
{
|
{
|
||||||
|
constexpr static std::size_t
|
||||||
|
max_object_size = object::max_size();
|
||||||
|
|
||||||
|
constexpr static std::size_t
|
||||||
|
max_array_size = array::max_size();
|
||||||
|
|
||||||
|
constexpr static std::size_t
|
||||||
|
max_key_size = string::max_size();
|
||||||
|
|
||||||
|
constexpr static std::size_t
|
||||||
|
max_string_size = string::max_size();
|
||||||
|
|
||||||
value_stack st;
|
value_stack st;
|
||||||
|
|
||||||
template<class... Args>
|
template<class... Args>
|
||||||
|
@ -62,6 +62,8 @@ class string
|
|||||||
friend struct detail::value_access;
|
friend struct detail::value_access;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
using string_impl = detail::string_impl;
|
||||||
|
|
||||||
inline
|
inline
|
||||||
string(
|
string(
|
||||||
char** key,
|
char** key,
|
||||||
@ -130,7 +132,7 @@ private:
|
|||||||
char>::value>::type;
|
char>::value>::type;
|
||||||
|
|
||||||
storage_ptr sp_; // must come first
|
storage_ptr sp_; // must come first
|
||||||
detail::string_impl impl_;
|
string_impl impl_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Destructor.
|
/** Destructor.
|
||||||
@ -190,7 +192,7 @@ public:
|
|||||||
: sp_(std::move(other.get().sp_))
|
: sp_(std::move(other.get().sp_))
|
||||||
, impl_(other.get().impl_)
|
, impl_(other.get().impl_)
|
||||||
{
|
{
|
||||||
::new(&other.get().impl_) detail::string_impl();
|
::new(&other.get().impl_) string_impl();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Constructor.
|
/** Constructor.
|
||||||
@ -437,7 +439,7 @@ public:
|
|||||||
: sp_(other.sp_)
|
: sp_(other.sp_)
|
||||||
, impl_(other.impl_)
|
, impl_(other.impl_)
|
||||||
{
|
{
|
||||||
::new(&other.impl_) detail::string_impl();
|
::new(&other.impl_) string_impl();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Constructor.
|
/** Constructor.
|
||||||
@ -1433,7 +1435,7 @@ public:
|
|||||||
std::size_t
|
std::size_t
|
||||||
max_size() noexcept
|
max_size() noexcept
|
||||||
{
|
{
|
||||||
return BOOST_JSON_MAX_STRING_SIZE;
|
return string_impl::max_size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Return the number of characters that can be held without a reallocation.
|
/** Return the number of characters that can be held without a reallocation.
|
||||||
|
@ -872,37 +872,15 @@ public:
|
|||||||
good_one(s);
|
good_one(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
testComments()
|
|
||||||
{
|
|
||||||
parse_options disabled;
|
|
||||||
parse_options enabled;
|
|
||||||
enabled.allow_comments = true;
|
|
||||||
|
|
||||||
const auto replace_and_test =
|
|
||||||
[&](string_view s)
|
|
||||||
{
|
|
||||||
static std::vector<string_view> comments =
|
|
||||||
{
|
|
||||||
"//\n",
|
|
||||||
"// \n",
|
|
||||||
"//aaaa\n",
|
|
||||||
"// aaaa\n",
|
|
||||||
"// /* \n",
|
|
||||||
"// /**/ \n",
|
|
||||||
"/**/",
|
|
||||||
"/*//*/",
|
|
||||||
"/*/*/",
|
|
||||||
"/******/",
|
|
||||||
"/*** ***/",
|
|
||||||
"/**aaaa***/",
|
|
||||||
"/*** aaaa***/"
|
|
||||||
};
|
|
||||||
|
|
||||||
class comment_parser
|
class comment_parser
|
||||||
{
|
{
|
||||||
struct handler
|
struct handler
|
||||||
{
|
{
|
||||||
|
constexpr static std::size_t max_object_size = std::size_t(-1);
|
||||||
|
constexpr static std::size_t max_array_size = std::size_t(-1);
|
||||||
|
constexpr static std::size_t max_key_size = std::size_t(-1);
|
||||||
|
constexpr static std::size_t max_string_size = std::size_t(-1);
|
||||||
|
|
||||||
std::string captured = "";
|
std::string captured = "";
|
||||||
bool on_document_begin( error_code& ) { return true; }
|
bool on_document_begin( error_code& ) { return true; }
|
||||||
bool on_document_end( error_code& ) { return true; }
|
bool on_document_end( error_code& ) { return true; }
|
||||||
@ -960,6 +938,33 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
testComments()
|
||||||
|
{
|
||||||
|
parse_options disabled;
|
||||||
|
parse_options enabled;
|
||||||
|
enabled.allow_comments = true;
|
||||||
|
|
||||||
|
const auto replace_and_test =
|
||||||
|
[&](string_view s)
|
||||||
|
{
|
||||||
|
static std::vector<string_view> comments =
|
||||||
|
{
|
||||||
|
"//\n",
|
||||||
|
"// \n",
|
||||||
|
"//aaaa\n",
|
||||||
|
"// aaaa\n",
|
||||||
|
"// /* \n",
|
||||||
|
"// /**/ \n",
|
||||||
|
"/**/",
|
||||||
|
"/*//*/",
|
||||||
|
"/*/*/",
|
||||||
|
"/******/",
|
||||||
|
"/*** ***/",
|
||||||
|
"/**aaaa***/",
|
||||||
|
"/*** aaaa***/"
|
||||||
|
};
|
||||||
|
|
||||||
std::string formatted = "";
|
std::string formatted = "";
|
||||||
std::string just_comments = "";
|
std::string just_comments = "";
|
||||||
std::size_t guess = std::count(
|
std::size_t guess = std::count(
|
||||||
@ -1064,6 +1069,73 @@ public:
|
|||||||
good("{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{},},},},},},}", enabled);
|
good("{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{\"a\":{},},},},},},}", enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class utf8_parser
|
||||||
|
{
|
||||||
|
struct handler
|
||||||
|
{
|
||||||
|
constexpr static std::size_t max_object_size = std::size_t(-1);
|
||||||
|
constexpr static std::size_t max_array_size = std::size_t(-1);
|
||||||
|
constexpr static std::size_t max_key_size = std::size_t(-1);
|
||||||
|
constexpr static std::size_t max_string_size = std::size_t(-1);
|
||||||
|
|
||||||
|
std::string captured = "";
|
||||||
|
bool on_document_begin( error_code& ) { return true; }
|
||||||
|
bool on_document_end( error_code& ) { return true; }
|
||||||
|
bool on_object_begin( error_code& ) { return true; }
|
||||||
|
bool on_object_end( std::size_t, error_code& ) { return true; }
|
||||||
|
bool on_array_begin( error_code& ) { return true; }
|
||||||
|
bool on_array_end( std::size_t, error_code& ) { return true; }
|
||||||
|
bool on_key_part( string_view, std::size_t, error_code& ) { return true; }
|
||||||
|
bool on_key( string_view, std::size_t, error_code& ) { return true; }
|
||||||
|
bool on_string_part( string_view sv, std::size_t, error_code& )
|
||||||
|
{
|
||||||
|
captured.append(sv.data(), sv.size());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool on_string( string_view sv, std::size_t, error_code& )
|
||||||
|
{
|
||||||
|
captured.append(sv.data(), sv.size());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool on_number_part( string_view, error_code&) { return true; }
|
||||||
|
bool on_int64( std::int64_t, string_view, error_code& ) { return true; }
|
||||||
|
bool on_uint64( std::uint64_t, string_view, error_code& ) { return true; }
|
||||||
|
bool on_double( double, string_view, error_code& ) { return true; }
|
||||||
|
bool on_bool( bool, error_code& ) { return true; }
|
||||||
|
bool on_null( error_code& ) { return true; }
|
||||||
|
bool on_comment_part( string_view, error_code& ) { return true; }
|
||||||
|
bool on_comment( string_view, error_code& ) { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
basic_parser<handler> p_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
utf8_parser()
|
||||||
|
: p_(parse_options())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t
|
||||||
|
write(
|
||||||
|
bool more,
|
||||||
|
char const* data,
|
||||||
|
std::size_t size,
|
||||||
|
error_code& ec)
|
||||||
|
{
|
||||||
|
auto const n = p_.write(
|
||||||
|
more, data, size, ec);
|
||||||
|
if(! ec && n < size)
|
||||||
|
ec = error::extra_data;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
string_view
|
||||||
|
captured() const noexcept
|
||||||
|
{
|
||||||
|
return p_.handler().captured;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
testUTF8Validation()
|
testUTF8Validation()
|
||||||
{
|
{
|
||||||
@ -1228,68 +1300,6 @@ public:
|
|||||||
bad("\"\\n\xf4\x80\x70\x80----------\"");
|
bad("\"\\n\xf4\x80\x70\x80----------\"");
|
||||||
bad("\"\\n\xf4\x80\xbf\x70-\\n\xf4\x80\xbf\x70\"");
|
bad("\"\\n\xf4\x80\xbf\x70-\\n\xf4\x80\xbf\x70\"");
|
||||||
|
|
||||||
class utf8_parser
|
|
||||||
{
|
|
||||||
struct handler
|
|
||||||
{
|
|
||||||
std::string captured = "";
|
|
||||||
bool on_document_begin( error_code& ) { return true; }
|
|
||||||
bool on_document_end( error_code& ) { return true; }
|
|
||||||
bool on_object_begin( error_code& ) { return true; }
|
|
||||||
bool on_object_end( std::size_t, error_code& ) { return true; }
|
|
||||||
bool on_array_begin( error_code& ) { return true; }
|
|
||||||
bool on_array_end( std::size_t, error_code& ) { return true; }
|
|
||||||
bool on_key_part( string_view, std::size_t, error_code& ) { return true; }
|
|
||||||
bool on_key( string_view, std::size_t, error_code& ) { return true; }
|
|
||||||
bool on_string_part( string_view sv, std::size_t, error_code& )
|
|
||||||
{
|
|
||||||
captured.append(sv.data(), sv.size());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool on_string( string_view sv, std::size_t, error_code& )
|
|
||||||
{
|
|
||||||
captured.append(sv.data(), sv.size());
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool on_number_part( string_view, error_code&) { return true; }
|
|
||||||
bool on_int64( std::int64_t, string_view, error_code& ) { return true; }
|
|
||||||
bool on_uint64( std::uint64_t, string_view, error_code& ) { return true; }
|
|
||||||
bool on_double( double, string_view, error_code& ) { return true; }
|
|
||||||
bool on_bool( bool, error_code& ) { return true; }
|
|
||||||
bool on_null( error_code& ) { return true; }
|
|
||||||
bool on_comment_part( string_view, error_code& ) { return true; }
|
|
||||||
bool on_comment( string_view, error_code& ) { return true; }
|
|
||||||
};
|
|
||||||
|
|
||||||
basic_parser<handler> p_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
utf8_parser()
|
|
||||||
: p_(parse_options())
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t
|
|
||||||
write(
|
|
||||||
bool more,
|
|
||||||
char const* data,
|
|
||||||
std::size_t size,
|
|
||||||
error_code& ec)
|
|
||||||
{
|
|
||||||
auto const n = p_.write(
|
|
||||||
more, data, size, ec);
|
|
||||||
if(! ec && n < size)
|
|
||||||
ec = error::extra_data;
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
string_view
|
|
||||||
captured() const noexcept
|
|
||||||
{
|
|
||||||
return p_.handler().captured;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto check =
|
const auto check =
|
||||||
[this](string_view expected)
|
[this](string_view expected)
|
||||||
{
|
{
|
||||||
@ -1360,15 +1370,16 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
testNumberLiteral()
|
|
||||||
{
|
|
||||||
class literal_parser
|
class literal_parser
|
||||||
{
|
{
|
||||||
struct handler
|
struct handler
|
||||||
{
|
{
|
||||||
std::string captured = "";
|
constexpr static std::size_t max_object_size = std::size_t(-1);
|
||||||
|
constexpr static std::size_t max_array_size = std::size_t(-1);
|
||||||
|
constexpr static std::size_t max_key_size = std::size_t(-1);
|
||||||
|
constexpr static std::size_t max_string_size = std::size_t(-1);
|
||||||
|
|
||||||
|
std::string captured = "";
|
||||||
bool on_document_begin( error_code& ) { return true; }
|
bool on_document_begin( error_code& ) { return true; }
|
||||||
bool on_document_end( error_code& ) { return true; }
|
bool on_document_end( error_code& ) { return true; }
|
||||||
bool on_object_begin( error_code& ) { return true; }
|
bool on_object_begin( error_code& ) { return true; }
|
||||||
@ -1437,6 +1448,9 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
testNumberLiteral()
|
||||||
|
{
|
||||||
const auto check =
|
const auto check =
|
||||||
[](string_view expected)
|
[](string_view expected)
|
||||||
{
|
{
|
||||||
|
@ -286,14 +286,8 @@ public:
|
|||||||
auto jv = parse(s, ec);
|
auto jv = parse(s, ec);
|
||||||
BOOST_TEST(! ec);
|
BOOST_TEST(! ec);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
testBasicParser()
|
|
||||||
{
|
|
||||||
// overflow in on_key_part
|
// overflow in on_key_part
|
||||||
{
|
{
|
||||||
null_parser p;
|
|
||||||
error_code ec;
|
error_code ec;
|
||||||
std::string big;
|
std::string big;
|
||||||
big = "\\b";
|
big = "\\b";
|
||||||
@ -301,13 +295,12 @@ public:
|
|||||||
string::max_size()*2, '*');
|
string::max_size()*2, '*');
|
||||||
auto const js =
|
auto const js =
|
||||||
"{\"" + big + "\":null}";
|
"{\"" + big + "\":null}";
|
||||||
p.write(js.data(), js.size(), ec);
|
auto jv = parse(js, ec);
|
||||||
BOOST_TEST(ec == error::key_too_large);
|
BOOST_TEST(ec == error::key_too_large);
|
||||||
}
|
}
|
||||||
|
|
||||||
// overflow in on_key
|
// overflow in on_key
|
||||||
{
|
{
|
||||||
null_parser p;
|
|
||||||
error_code ec;
|
error_code ec;
|
||||||
std::string big;
|
std::string big;
|
||||||
big = "\\b";
|
big = "\\b";
|
||||||
@ -315,13 +308,12 @@ public:
|
|||||||
(string::max_size()*3)/2, '*');
|
(string::max_size()*3)/2, '*');
|
||||||
auto const js =
|
auto const js =
|
||||||
"{\"" + big + "\":null}";
|
"{\"" + big + "\":null}";
|
||||||
p.write(js.data(), js.size(), ec);
|
auto jv = parse(js, ec);
|
||||||
BOOST_TEST(ec == error::key_too_large);
|
BOOST_TEST(ec == error::key_too_large);
|
||||||
}
|
}
|
||||||
|
|
||||||
// overflow in on_string_part
|
// overflow in on_string_part
|
||||||
{
|
{
|
||||||
null_parser p;
|
|
||||||
error_code ec;
|
error_code ec;
|
||||||
std::string big;
|
std::string big;
|
||||||
big = "\\b";
|
big = "\\b";
|
||||||
@ -329,13 +321,12 @@ public:
|
|||||||
string::max_size()*2, '*');
|
string::max_size()*2, '*');
|
||||||
auto const js =
|
auto const js =
|
||||||
"\"" + big + "\"";
|
"\"" + big + "\"";
|
||||||
p.write(js.data(), js.size(), ec);
|
auto jv = parse(js, ec);
|
||||||
BOOST_TEST(ec == error::string_too_large);
|
BOOST_TEST(ec == error::string_too_large);
|
||||||
}
|
}
|
||||||
|
|
||||||
// overflow in on_string
|
// overflow in on_string
|
||||||
{
|
{
|
||||||
null_parser p;
|
|
||||||
error_code ec;
|
error_code ec;
|
||||||
std::string big;
|
std::string big;
|
||||||
big = "\\b";
|
big = "\\b";
|
||||||
@ -343,14 +334,13 @@ public:
|
|||||||
(string::max_size()*3)/2, '*');
|
(string::max_size()*3)/2, '*');
|
||||||
auto const js =
|
auto const js =
|
||||||
"\"" + big + "\"";
|
"\"" + big + "\"";
|
||||||
p.write(js.data(), js.size(), ec);
|
auto jv = parse(js, ec);
|
||||||
BOOST_TEST(ec == error::string_too_large);
|
BOOST_TEST(ec == error::string_too_large);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// object overflow
|
// object overflow
|
||||||
{
|
{
|
||||||
null_parser p;
|
|
||||||
error_code ec;
|
error_code ec;
|
||||||
string_view s = R"({
|
string_view s = R"({
|
||||||
"00":0,"01":0,"02":0,"03":0,"04":0,"05":0,"06":0,"07":0,"08":0,"09":0,
|
"00":0,"01":0,"02":0,"03":0,"04":0,"05":0,"06":0,"07":0,"08":0,"09":0,
|
||||||
@ -358,20 +348,19 @@ public:
|
|||||||
"20":0
|
"20":0
|
||||||
})";
|
})";
|
||||||
|
|
||||||
p.write(s.data(), s.size(), ec);
|
auto jv = parse(s, ec);
|
||||||
BOOST_TEST(ec == error::object_too_large);
|
BOOST_TEST(ec == error::object_too_large);
|
||||||
}
|
}
|
||||||
|
|
||||||
// array overflow
|
// array overflow
|
||||||
{
|
{
|
||||||
null_parser p;
|
|
||||||
error_code ec;
|
error_code ec;
|
||||||
string_view s = "["
|
string_view s = "["
|
||||||
"0,0,0,0,0,0,0,0,0,0,"
|
"0,0,0,0,0,0,0,0,0,0,"
|
||||||
"0,0,0,0,0,0,0,0,0,0,"
|
"0,0,0,0,0,0,0,0,0,0,"
|
||||||
"0"
|
"0"
|
||||||
"]";
|
"]";
|
||||||
p.write(s.data(), s.size(), ec);
|
auto jv = parse(s, ec);
|
||||||
BOOST_TEST(ec == error::array_too_large);
|
BOOST_TEST(ec == error::array_too_large);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -390,7 +379,6 @@ public:
|
|||||||
testString();
|
testString();
|
||||||
testStack();
|
testStack();
|
||||||
testParser();
|
testParser();
|
||||||
testBasicParser();
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
BOOST_TEST_PASS();
|
BOOST_TEST_PASS();
|
||||||
|
@ -145,6 +145,11 @@ class null_parser
|
|||||||
{
|
{
|
||||||
struct handler
|
struct handler
|
||||||
{
|
{
|
||||||
|
constexpr static std::size_t max_object_size = std::size_t(-1);
|
||||||
|
constexpr static std::size_t max_array_size = std::size_t(-1);
|
||||||
|
constexpr static std::size_t max_key_size = std::size_t(-1);
|
||||||
|
constexpr static std::size_t max_string_size = std::size_t(-1);
|
||||||
|
|
||||||
bool on_document_begin( error_code& ) { return true; }
|
bool on_document_begin( error_code& ) { return true; }
|
||||||
bool on_document_end( error_code& ) { return true; }
|
bool on_document_end( error_code& ) { return true; }
|
||||||
bool on_object_begin( error_code& ) { return true; }
|
bool on_object_begin( error_code& ) { return true; }
|
||||||
@ -205,6 +210,11 @@ class fail_parser
|
|||||||
{
|
{
|
||||||
struct handler
|
struct handler
|
||||||
{
|
{
|
||||||
|
constexpr static std::size_t max_object_size = std::size_t(-1);
|
||||||
|
constexpr static std::size_t max_array_size = std::size_t(-1);
|
||||||
|
constexpr static std::size_t max_key_size = std::size_t(-1);
|
||||||
|
constexpr static std::size_t max_string_size = std::size_t(-1);
|
||||||
|
|
||||||
std::size_t n;
|
std::size_t n;
|
||||||
|
|
||||||
handler()
|
handler()
|
||||||
@ -445,6 +455,11 @@ class throw_parser
|
|||||||
{
|
{
|
||||||
struct handler
|
struct handler
|
||||||
{
|
{
|
||||||
|
constexpr static std::size_t max_object_size = std::size_t(-1);
|
||||||
|
constexpr static std::size_t max_array_size = std::size_t(-1);
|
||||||
|
constexpr static std::size_t max_key_size = std::size_t(-1);
|
||||||
|
constexpr static std::size_t max_string_size = std::size_t(-1);
|
||||||
|
|
||||||
std::size_t n;
|
std::size_t n;
|
||||||
|
|
||||||
handler()
|
handler()
|
||||||
|
@ -1640,13 +1640,7 @@ public:
|
|||||||
check_array(value{false,2}, false, 2);
|
check_array(value{false,2}, false, 2);
|
||||||
check_array(value{false,2,"3",nullptr}, false, 2, "3", nullptr);
|
check_array(value{false,2,"3",nullptr}, false, 2, "3", nullptr);
|
||||||
check_array(value{2,false,"3"}, 2, false, "3");
|
check_array(value{2,false,"3"}, 2, false, "3");
|
||||||
check_array(value{true,2,"3"}, true, 2, "3"); }
|
check_array(value{true,2,"3"}, true, 2, "3");
|
||||||
|
|
||||||
void
|
|
||||||
testMaxSize()
|
|
||||||
{
|
|
||||||
// The implementation requires these equal
|
|
||||||
BOOST_TEST(object::max_size() == array::max_size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
@ -1667,7 +1661,6 @@ public:
|
|||||||
testKeyValuePair();
|
testKeyValuePair();
|
||||||
testStdConstruction();
|
testStdConstruction();
|
||||||
testInitList();
|
testInitList();
|
||||||
testMaxSize();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user