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