diff --git a/doc/qbk/02_07_allocators.qbk b/doc/qbk/02_07_allocators.qbk
index 899d9f15..4c57935e 100644
--- a/doc/qbk/02_07_allocators.qbk
+++ b/doc/qbk/02_07_allocators.qbk
@@ -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.
[/-----------------------------------------------------------------------------]
diff --git a/doc/qbk/main.qbk b/doc/qbk/main.qbk
index 7b23d8a4..fa66facd 100644
--- a/doc/qbk/main.qbk
+++ b/doc/qbk/main.qbk
@@ -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`]]
diff --git a/doc/qbk/quickref.xml b/doc/qbk/quickref.xml
index 14a5dbb1..a0ea32e4 100644
--- a/doc/qbk/quickref.xml
+++ b/doc/qbk/quickref.xml
@@ -24,7 +24,6 @@
basic_parser
key_value_pair
monotonic_resource
- null_resource
object
parser
parse_options
@@ -41,6 +40,7 @@
Functions
get
+ get_null_resource
make_counted_resource
number_cast
parse
diff --git a/fuzzing/fuzz_parser.cpp b/fuzzing/fuzz_parser.cpp
index fbd10e68..4d3eb518 100644
--- a/fuzzing/fuzz_parser.cpp
+++ b/fuzzing/fuzz_parser.cpp
@@ -67,8 +67,7 @@ struct FuzzHelper {
void useDynLess() {
// this is on the heap because the size is chosen dynamically
std::unique_ptr temp(new unsigned char[memlimit1]);
- null_resource nr;
- parser p(&nr,
+ parser p(get_null_resource(),
opt,
temp.get(),
memlimit1);
diff --git a/include/boost/json/impl/null_resource.ipp b/include/boost/json/impl/null_resource.ipp
index 05355ee0..a67e886a 100644
--- a/include/boost/json/impl/null_resource.ipp
+++ b/include/boost/json/impl/null_resource.ipp
@@ -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
diff --git a/include/boost/json/null_resource.hpp b/include/boost/json/null_resource.hpp
index 18326674..c074514e 100644
--- a/include/boost/json/null_resource.hpp
+++ b/include/boost/json/null_resource.hpp
@@ -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
diff --git a/include/boost/json/value.hpp b/include/boost/json/value.hpp
index e3cf0111..2cc2c333 100644
--- a/include/boost/json/value.hpp
+++ b/include/boost/json/value.hpp
@@ -1053,7 +1053,14 @@ public:
return *this = value(init, storage());
}
- /** Assignment.
+ /** Assignment
+
+ Assigns `t` to `*this`.
+
+ @par Effects
+ @code
+ *this = value( std::forward(t), this->storage() );
+ @endcode
@par Constraints
@code
diff --git a/test/doc_parsing.cpp b/test/doc_parsing.cpp
index 909b4540..5e8ef2fc 100644
--- a/test/doc_parsing.cpp
+++ b/test/doc_parsing.cpp
@@ -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
diff --git a/test/null_resource.cpp b/test/null_resource.cpp
index eedeb972..0e95a97b 100644
--- a/test/null_resource.cpp
+++ b/test/null_resource.cpp
@@ -10,6 +10,8 @@
// Test that header file is self-contained.
#include
+#include
+
#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