null_resource is a singleton

This commit is contained in:
Vinnie Falco 2020-09-16 16:45:06 -07:00
parent 7bde63b316
commit a2917e736a
9 changed files with 120 additions and 114 deletions

View File

@ -158,6 +158,14 @@ available when using the library:
[table Functions and Types
[ [Name] [Description] ]
[
[__get_null_resource__]
[
Returns a pointer to a memory resource instance which
always throws an exception upon allocation. This is
used to to achieve the invariant that no parsing or
container operation will dynamically allocate memory.
]
][
[__is_deallocate_trivial__]
[
A customization point allowing a memory resource type
@ -182,13 +190,6 @@ available when using the library:
freed until the resource is destroyed, making it fast for
parsing but not suited for performing modifications.
]
][
[__null_resource__]
[
A memory resource always throws an exception upon allocation.
This is used to to achieve the invariant that no parsing
or container operation will dynamically allocate memory.
]
][
[__polymorphic_allocator__]
[
@ -285,11 +286,12 @@ To use the resource, construct it with a local buffer:
[heading Null Resource]
The __null_resource__ can only be default constructed. It offers a simple
invariant: all calls to allocate will throw the exception `std::bad_alloc`.
An instance of the null resource can be used to make parsing guarantee
that allocations from the heap are never made. This is explored in more
detail in a later section.
The function __get_null_resource__ returns a global instance of the
null resource. This resource offers a simple invariant: all calls to
allocate will throw the exception `std::bad_alloc`. An instance of
the null resource can be used to make parsing guarantee that
allocations from the heap are never made. This is explored
in more detail in a later section.
[/-----------------------------------------------------------------------------]

View File

@ -52,6 +52,7 @@
[def __error_code__ [link json.ref.boost__json__error_code `error_code`]]
[def __error_condition__ [link json.ref.boost__json__error_condition `error_condition`]]
[def __get__ [link json.ref.boost__json__get `get`]]
[def __get_null_resource__ [link json.ref.boost__json__get_null_resource `get_null_resource`]]
[def __has_value_from__ [link json.ref.boost__json__has_value_from `has_value_from`]]
[def __has_value_to__ [link json.ref.boost__json__has_value_to `has_value_to`]]
[def __is_deallocate_trivial__ [link json.ref.boost__json__is_deallocate_trivial `is_deallocate_trivial`]]
@ -60,7 +61,6 @@
[def __make_counted_resource__ [link json.ref.boost__json__make_counted_resource `make_counted_resource`]]
[def __memory_resource__ [link json.ref.boost__json__memory_resource `memory_resource`]]
[def __monotonic_resource__ [link json.ref.boost__json__monotonic_resource `monotonic_resource`]]
[def __null_resource__ [link json.ref.boost__json__null_resource `null_resource`]]
[def __number_cast__ [link json.ref.boost__json__number_cast `number_cast`]]
[def __object__ [link json.ref.boost__json__object `object`]]
[def __parse__ [link json.ref.boost__json__parse `parse`]]

View File

@ -24,7 +24,6 @@
<member><link linkend="json.ref.boost__json__basic_parser">basic_parser</link></member>
<member><link linkend="json.ref.boost__json__key_value_pair">key_value_pair</link></member>
<member><link linkend="json.ref.boost__json__monotonic_resource">monotonic_resource</link></member>
<member><link linkend="json.ref.boost__json__null_resource">null_resource</link></member>
<member><link linkend="json.ref.boost__json__object">object</link></member>
<member><link linkend="json.ref.boost__json__parser">parser</link></member>
<member><link linkend="json.ref.boost__json__parse_options">parse_options</link></member>
@ -41,6 +40,7 @@
<bridgehead renderas="sect3">Functions</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="json.ref.boost__json__get">get</link></member>
<member><link linkend="json.ref.boost__json__get_null_resource">get_null_resource</link></member>
<member><link linkend="json.ref.boost__json__make_counted_resource">make_counted_resource</link></member>
<member><link linkend="json.ref.boost__json__number_cast">number_cast</link></member>
<member><link linkend="json.ref.boost__json__parse">parse</link></member>

View File

@ -67,8 +67,7 @@ struct FuzzHelper {
void useDynLess() {
// this is on the heap because the size is chosen dynamically
std::unique_ptr<unsigned char[]> temp(new unsigned char[memlimit1]);
null_resource nr;
parser p(&nr,
parser p(get_null_resource(),
opt,
temp.get(),
memlimit1);

View File

@ -15,32 +15,85 @@
BOOST_JSON_NS_BEGIN
void*
null_resource::
do_allocate(
std::size_t,
std::size_t)
{
detail::throw_bad_alloc(
BOOST_CURRENT_LOCATION);
}
namespace detail {
void
null_resource::
do_deallocate(
void*,
std::size_t,
std::size_t)
{
// do nothing
}
/** A resource which always fails.
bool
null_resource::
do_is_equal(
memory_resource const& mr) const noexcept
This memory resource always throws the exception
`std::bad_alloc` in calls to `allocate`.
*/
class null_resource final
: public memory_resource
{
public:
/// Copy constructor (deleted)
null_resource(
null_resource const&) = delete;
/// Copy assignment (deleted)
null_resource& operator=(
null_resource const&) = delete;
/** Destructor
This destroys the resource.
@par Complexity
Constant.
@part Exception Safety
No-throw guarantee.
*/
~null_resource() noexcept = default;
/** Constructor
This constructs the resource.
@par Complexity
Constant.
@par Exception Safety
No-throw guarantee.
*/
/** @{ */
null_resource() noexcept = default;
protected:
void*
do_allocate(
std::size_t,
std::size_t) override
{
detail::throw_bad_alloc(
BOOST_CURRENT_LOCATION);
}
void
do_deallocate(
void*,
std::size_t,
std::size_t) override
{
// do nothing
}
bool
do_is_equal(
memory_resource const& mr
) const noexcept override
{
return this == &mr;
}
};
} // detail
memory_resource*
get_null_resource() noexcept
{
return this == &mr;
static detail::null_resource mr;
return &mr;
}
BOOST_JSON_NS_END

View File

@ -15,77 +15,20 @@
BOOST_JSON_NS_BEGIN
//----------------------------------------------------------
/** A resource which always fails.
/** Return a pointer to the null resource.
This memory resource always throws the exception
`std::bad_alloc` in calls to `allocate`.
@par Complexity
Constant.
@par Exception Safety
No-throw guarantee.
*/
class BOOST_JSON_CLASS_DECL
null_resource final
: public memory_resource
{
public:
/// Copy constructor (deleted)
null_resource(
null_resource const&) = delete;
/// Copy assignment (deleted)
null_resource& operator=(
null_resource const&) = delete;
/** Destructor
This destroys the resource.
@par Complexity
Constant.
@part Exception Safety
No-throw guarantee.
*/
~null_resource() noexcept = default;
/** Constructor
This constructs the resource.
@par Complexity
Constant.
@par Exception Safety
No-throw guarantee.
*/
/** @{ */
null_resource() noexcept = default;
protected:
#ifndef BOOST_JSON_DOCS
void*
do_allocate(
std::size_t n,
std::size_t align) override;
void
do_deallocate(
void* p,
std::size_t n,
std::size_t align) override;
bool
do_is_equal(
memory_resource const& mr
) const noexcept override;
#endif
};
template<>
struct is_deallocate_trivial<
null_resource>
{
static constexpr bool value = true;
};
BOOST_JSON_DECL
memory_resource*
get_null_resource() noexcept;
BOOST_JSON_NS_END

View File

@ -1053,7 +1053,14 @@ public:
return *this = value(init, storage());
}
/** Assignment.
/** Assignment
Assigns `t` to `*this`.
@par Effects
@code
*this = value( std::forward<T>(t), this->storage() );
@endcode
@par Constraints
@code

View File

@ -195,9 +195,11 @@ parser p(
template< class Handler >
void do_rpc( string_view s, Handler&& handler )
{
null_resource mr1; // The null resource guarantees we will never dynamically allocate
unsigned char temp[ 4096 ]; // The parser will use this storage for its temporary needs
parser p( &mr1, parse_options(), temp ); // Construct a strict parser using the temp buffer and no dynamic memory
parser p( // Construct a strict parser using the temp buffer and no dynamic memory
get_null_resource(), // The null resource guarantees we will never dynamically allocate
parse_options(), // Default constructed parse options allow only standard JSON
temp );
unsigned char buf[ 16384 ]; // Now we need a buffer to hold the actual JSON values
static_resource mr2( buf ); // The static resource is monotonic, using only a caller-provided buffer

View File

@ -10,6 +10,8 @@
// Test that header file is self-contained.
#include <boost/json/null_resource.hpp>
#include <boost/json/storage_ptr.hpp>
#include "test_suite.hpp"
BOOST_JSON_NS_BEGIN
@ -20,17 +22,15 @@ public:
void
test()
{
null_resource mr;
auto& mr = *get_null_resource();
BOOST_TEST_THROWS(
mr.allocate(16),
std::bad_alloc);
char buf[128];
// no-op
mr.deallocate(&buf[0], 128);
BOOST_TEST(mr == mr);
null_resource mr2;
BOOST_TEST(mr != mr2);
BOOST_TEST(
mr == *get_null_resource());
}
void