diff --git a/doc/qbk/02_7_parsing.qbk b/doc/qbk/02_7_parsing.qbk
index 59428bbb..08cb3afe 100644
--- a/doc/qbk/02_7_parsing.qbk
+++ b/doc/qbk/02_7_parsing.qbk
@@ -165,9 +165,7 @@ extensions:
[Skip UTF-8 Validation]
[
UTF-8 byte sequences appearing within strings
- are not checked for validity
- [br]
- (as defined by
+ are not checked for validity (as defined by
[@https://www.unicode.org/versions/Unicode13.0.0/UnicodeStandard-13.0.pdf The Unicode Standard Version 13.0 Section 3.9]).
]
[
diff --git a/doc/qbk/quickref.xml b/doc/qbk/quickref.xml
index 4712ee6f..e5a752d9 100644
--- a/doc/qbk/quickref.xml
+++ b/doc/qbk/quickref.xml
@@ -104,6 +104,7 @@
error_codeerror_conditiongeneric_category
+ memory_resourcestring_viewsystem_error
diff --git a/doc/source.dox b/doc/source.dox
index db2a4be0..67151367 100644
--- a/doc/source.dox
+++ b/doc/source.dox
@@ -7,6 +7,11 @@ INPUT = \
$(LIB_DIR)/include/boost/json/detail/basic_parser.hpp \
$(LIB_DIR)/include/boost/pilfer.hpp
+# $(LIB_DIR)/include/boost/json/error.hpp \
+# $(LIB_DIR)/include/boost/json/string_view.hpp \
+# $(LIB_DIR)/include/boost/json/value_builder.hpp
+
+
ALIASES += esafe="@par Exception Safety"
INPUT_ENCODING = UTF-8
diff --git a/example/validate.cpp b/example/validate.cpp
index 1f2b57ef..00fc2524 100644
--- a/example/validate.cpp
+++ b/example/validate.cpp
@@ -9,7 +9,6 @@
/*
This example verifies that a file contains valid JSON.
- It is implementing by subclassing basic_parser
*/
#include
diff --git a/include/boost/json/array.hpp b/include/boost/json/array.hpp
index 539bac04..3a8165af 100644
--- a/include/boost/json/array.hpp
+++ b/include/boost/json/array.hpp
@@ -28,17 +28,13 @@ class value_ref;
/** A dynamically sized array of JSON values
This is the type used to represent JSON array values. It
- is modeled for equivalence to `std::vector`.
-
-
+ is modeled for equivalence to `std::vector`.\n
The elements are stored contiguously, which means that
elements can be accessed not only through iterators, but
also using offsets to regular pointers to elements. A
pointer to an element of an @ref array may be passed to
- any function that expects a pointer to @ref value.
-
-
+ any function that expects a pointer to @ref value.\n
The storage of the array is handled automatically, being
expanded and contracted as needed. Arrays usually occupy
@@ -48,16 +44,12 @@ class value_ref;
is inserted, but only when the additional memory is used
up. The total amount of allocated memory can be queried
using the @ref capacity function. Extra memory can be
- relinquished by calling @ref shrink_to_fit.
-
-
+ relinquished by calling @ref shrink_to_fit.\n
Reallocations are usually costly operations in terms of
performance. The @ref reserve function can be used to
eliminate reallocations if the number of elements is
- known beforehand.
-
-
+ known beforehand.\n
The complexity (efficiency) of common operations on
arrays is as follows:
@@ -99,6 +91,12 @@ class array
class undo_construct;
class undo_insert;
+ friend class value;
+
+ BOOST_JSON_DECL
+ explicit
+ array(detail::unchecked_array&& ua);
+
public:
/// The type used to represent unsigned integers
using size_type = std::size_t;
@@ -155,13 +153,6 @@ public:
destroy();
}
-#ifndef BOOST_JSON_DOCS
- // private
- explicit
- BOOST_JSON_DECL
- array(detail::unchecked_array&& ua);
-#endif
-
//------------------------------------------------------
/** Default constructor.
diff --git a/include/boost/json/detail/basic_parser.hpp b/include/boost/json/detail/basic_parser.hpp
index 540aafe2..e4247e89 100644
--- a/include/boost/json/detail/basic_parser.hpp
+++ b/include/boost/json/detail/basic_parser.hpp
@@ -39,9 +39,7 @@ namespace json {
JSON is presented to the parser by one or more calls
to @ref write_some. The parsing events are realized
through member function calls to a handler passed as
- an argument to the write function.
-
-
+ an argument to the write function.\n
The parser may dynamically allocate intermediate
storage as needed to accommodate the nesting level
@@ -59,9 +57,7 @@ namespace json {
function @ref parse. This class is designed for
users who wish to perform custom actions instead of
building a @ref value. For example, to produce a
- DOM from an external library.
-
-
+ DOM from an external library.\n
To use this class it is necessary to create a derived
class which calls @ref reset at the beginning of
@@ -378,9 +374,7 @@ public:
parsing event. The parse proceeds from the
current state, which is at the beginning of a
new JSON or in the middle of the current JSON
- if any characters were already parsed.
-
-
+ if any characters were already parsed.\n
The characters in the buffer are processed
starting from the beginning, until one of the
@@ -410,10 +404,8 @@ public:
member function returns `false`, it must set
the error code to a suitable value. This error
code will be returned by the write function to
- the caller.
-
-
-
+ the caller.\n
+
The following declaration meets the parser's
handler requirements:
diff --git a/include/boost/json/detail/object_impl.hpp b/include/boost/json/detail/object_impl.hpp
index 3c594968..e0f74ce2 100644
--- a/include/boost/json/detail/object_impl.hpp
+++ b/include/boost/json/detail/object_impl.hpp
@@ -20,7 +20,7 @@
namespace boost {
namespace json {
-struct key_value_pair;
+class key_value_pair;
namespace detail {
diff --git a/include/boost/json/error.hpp b/include/boost/json/error.hpp
index e8c92e2f..4f6ca825 100644
--- a/include/boost/json/error.hpp
+++ b/include/boost/json/error.hpp
@@ -21,27 +21,119 @@
namespace boost {
namespace json {
-#ifndef BOOST_JSON_STANDALONE
-
-/// The type of error code used by the library.
-using error_code = boost::system::error_code;
-
-/// The type of error category used by the library.
-using error_category = boost::system::error_category;
-
-/// The type of error condition used by the library.
-using error_condition = boost::system::error_condition;
-
-/// The type of system error thrown by the library.
-using system_error = boost::system::system_error;
-
#ifdef BOOST_JSON_DOCS
+
+/** The type of error code used by the library.
+
+ This type alias is set depending
+ on how the library is configured:
+
+ @par Use with Boost
+
+ If the macro `BOOST_JSON_STANDALONE` is
+ not defined, this type will be an alias
+ for `boost::system::error_code`.
+ Compiling a program using the library will
+ require Boost, and a compiler conforming
+ to C++11 or later.
+
+ @par Use without Boost
+
+ If the macro `BOOST_JSON_STANDALONE` is
+ defined, this type will be an alias
+ for `std::error_code`.
+ Compiling a program using the library will
+ require only a compiler conforming to C++17
+ or later.
+*/
+using error_code = __see_below__;
+
+/** The type of error category used by the library.
+
+ This type alias is set depending
+ on how the library is configured:
+
+ @par Use with Boost
+
+ If the macro `BOOST_JSON_STANDALONE` is
+ not defined, this type will be an alias
+ for `boost::system::error_category`.
+ Compiling a program using the library will
+ require Boost, and a compiler conforming
+ to C++11 or later.
+
+ @par Use without Boost
+
+ If the macro `BOOST_JSON_STANDALONE` is
+ defined, this type will be an alias
+ for `std::error_category`.
+ Compiling a program using the library will
+ require only a compiler conforming to C++17
+ or later.
+*/
+using error_category = __see_below__;
+
+/** The type of error condition used by the library.
+
+ This type alias is set depending
+ on how the library is configured:
+
+ @par Use with Boost
+
+ If the macro `BOOST_JSON_STANDALONE` is
+ not defined, this type will be an alias
+ for `boost::system::error_condition`.
+ Compiling a program using the library will
+ require Boost, and a compiler conforming
+ to C++11 or later.
+
+ @par Use without Boost
+
+ If the macro `BOOST_JSON_STANDALONE` is
+ defined, this type will be an alias
+ for `std::error_condition`.
+ Compiling a program using the library will
+ require only a compiler conforming to C++17
+ or later.
+*/
+using error_condition = __see_below__;
+
+/** The type of system error thrown by the library.
+
+ This type alias is set depending
+ on how the library is configured:
+
+ @par Use with Boost
+
+ If the macro `BOOST_JSON_STANDALONE` is
+ not defined, this type will be an alias
+ for `boost::system::system_error`.
+ Compiling a program using the library will
+ require Boost, and a compiler conforming
+ to C++11 or later.
+
+ @par Use without Boost
+
+ If the macro `BOOST_JSON_STANDALONE` is
+ defined, this type will be an alias
+ for `std::system_error`.
+ Compiling a program using the library will
+ require only a compiler conforming to C++17
+ or later.
+*/
+using system_error = __see_below__;
+
/// Returns the generic error category used by the library.
error_category const&
generic_category();
-#else
+
+#elif ! defined(BOOST_JSON_STANDALONE)
+
+using error_code = boost::system::error_code;
+using error_category = boost::system::error_category;
+using error_condition = boost::system::error_condition;
+using system_error = boost::system::system_error;
using boost::system::generic_category;
-#endif
#else
diff --git a/include/boost/json/impl/object.ipp b/include/boost/json/impl/object.ipp
index 05645fff..3673cb05 100644
--- a/include/boost/json/impl/object.ipp
+++ b/include/boost/json/impl/object.ipp
@@ -73,13 +73,6 @@ public:
//
//----------------------------------------------------------
-object::
-object(object_test const*)
-{
- object_impl impl(3, 1, 3, 0, sp_);
- impl_.swap(impl);
-}
-
object::
object(detail::unchecked_object&& uo)
: sp_(uo.storage())
@@ -90,6 +83,13 @@ object(detail::unchecked_object&& uo)
impl_.build();
}
+object::
+object(object_test const*)
+{
+ object_impl impl(3, 1, 3, 0, sp_);
+ impl_.swap(impl);
+}
+
object::
object(storage_ptr sp) noexcept
: sp_(std::move(sp))
diff --git a/include/boost/json/impl/parser.ipp b/include/boost/json/impl/parser.ipp
index d532465b..ad7996ce 100644
--- a/include/boost/json/impl/parser.ipp
+++ b/include/boost/json/impl/parser.ipp
@@ -20,6 +20,194 @@
namespace boost {
namespace json {
+bool
+parser::
+handler::
+on_document_begin(
+ error_code&)
+{
+ return true;
+}
+
+bool
+parser::
+handler::
+on_document_end(
+ error_code&)
+{
+ return true;
+}
+
+bool
+parser::
+handler::
+on_object_begin(
+ error_code&)
+{
+ vb.begin_object();
+ return true;
+}
+
+bool
+parser::
+handler::
+on_object_end(
+ error_code&)
+{
+ vb.end_object();
+ return true;
+}
+
+bool
+parser::
+handler::
+on_array_begin(
+ error_code&)
+{
+ vb.begin_array();
+ return true;
+}
+
+bool
+parser::
+handler::
+on_array_end(
+ error_code&)
+{
+ vb.end_array();
+ return true;
+}
+
+bool
+parser::
+handler::
+on_key_part(
+ string_view s,
+ error_code&)
+{
+ vb.insert_key_part(s);
+ return true;
+}
+
+bool
+parser::
+handler::
+on_key(
+ string_view s,
+ error_code&)
+{
+ vb.insert_key(s);
+ return true;
+}
+
+bool
+parser::
+handler::
+on_string_part(
+ string_view s,
+ error_code&)
+{
+ vb.insert_string_part(s);
+ return true;
+}
+
+bool
+parser::
+handler::
+on_string(
+ string_view s,
+ error_code&)
+{
+ vb.insert_string(s);
+ return true;
+}
+
+bool
+parser::
+handler::
+on_number_part(
+ string_view,
+ error_code&)
+{
+ return true;
+}
+
+bool
+parser::
+handler::
+on_int64(
+ std::int64_t i,
+ string_view,
+ error_code&)
+{
+ vb.insert_int64(i);
+ return true;
+}
+
+bool
+parser::
+handler::
+on_uint64(
+ std::uint64_t u,
+ string_view,
+ error_code&)
+{
+ vb.insert_uint64(u);
+ return true;
+}
+
+bool
+parser::
+handler::
+on_double(
+ double d,
+ string_view,
+ error_code&)
+{
+ vb.insert_double(d);
+ return true;
+}
+
+bool
+parser::
+handler::
+on_bool(
+ bool b,
+ error_code&)
+{
+ vb.insert_bool(b);
+ return true;
+}
+
+bool
+parser::
+handler::
+on_null(error_code&)
+{
+ vb.insert_null();
+ return true;
+}
+
+bool
+parser::
+handler::
+on_comment_part(
+ string_view, error_code&)
+{
+ return true;
+}
+
+bool
+parser::
+handler::
+on_comment(
+ string_view, error_code&)
+{
+ return true;
+}
+
+//----------------------------------------------------------
+
parser::
parser() noexcept
: parser(
@@ -122,12 +310,12 @@ value
parser::
release()
{
- /*
+ // VFALCO Do we need to put the throw
+ // in a separate raise() function?
if(! p_.is_complete())
BOOST_THROW_EXCEPTION(
std::logic_error(
"no value"));
- */
return p_.handler().vb.release();
}
diff --git a/include/boost/json/impl/value_builder.ipp b/include/boost/json/impl/value_builder.ipp
index e4bf32b3..05a95c64 100644
--- a/include/boost/json/impl/value_builder.ipp
+++ b/include/boost/json/impl/value_builder.ipp
@@ -98,56 +98,7 @@ reset(storage_ptr sp) noexcept
clear();
sp_ = std::move(sp);
lev_.st = state::begin;
-}
-value
-value_builder::
-release()
-{
- // An exception here means that the value
- // was not properly constructed. For example,
- // an array or object was not closed, or
- // there was no top level value.
- if( lev_.st != state::top ||
- lev_.count != 1)
- BOOST_THROW_EXCEPTION(
- std::logic_error(
- "no value"));
- auto ua = pop_array();
- BOOST_ASSERT(rs_.empty());
- union U
- {
- value v;
- U(){}
- ~U(){}
- };
- U u;
- ua.relocate(&u.v);
- lev_.st = state::need_reset;
- sp_ = {};
- return pilfer(u.v);
-}
-
-void
-value_builder::
-clear() noexcept
-{
- destroy();
- rs_.clear();
- lev_.count = 0;
- key_size_ = 0;
- str_size_ = 0;
- lev_.st = state::need_reset;
- sp_ = {};
-}
-
-//----------------------------------------------------------
-
-bool
-value_builder::
-on_document_begin(
- error_code&)
-{
// reset() must be called before
// building every new top level value.
BOOST_ASSERT(lev_.st == state::begin);
@@ -161,24 +112,86 @@ on_document_begin(
// inside a notional 1-element array.
rs_.add(sizeof(value));
lev_.st = state::top;
-
- return true;
}
-bool
+value
value_builder::
-on_document_end(error_code&)
+release()
{
// If this goes off, then an
- // array or object was never finished.
+ // array or object was never closed.
BOOST_ASSERT(lev_.st == state::top);
BOOST_ASSERT(lev_.count == 1);
- return true;
+
+ auto ua = pop_array();
+ BOOST_ASSERT(rs_.empty());
+ union U
+ {
+ value v;
+ U(){}
+ ~U(){}
+ };
+ U u;
+ ua.relocate(&u.v);
+ lev_.st = state::need_reset;
+
+ // give up the resource in case
+ // it uses shared ownership.
+ sp_ = {};
+
+ return pilfer(u.v);
}
-bool
+void
value_builder::
-on_object_begin(error_code&)
+clear() noexcept
+{
+ destroy();
+ rs_.clear();
+ lev_.count = 0;
+ key_size_ = 0;
+ str_size_ = 0;
+ lev_.st = state::need_reset;
+
+ // give up the resource in case
+ // it uses shared ownership.
+ sp_ = {};
+}
+
+//----------------------------------------------------------
+
+void
+value_builder::
+begin_array()
+{
+ // prevent splits from exceptions
+ rs_.prepare(
+ sizeof(level) +
+ sizeof(value) +
+ alignof(value) - 1);
+ push(lev_);
+ lev_.align =
+ detail::align_to(rs_);
+ rs_.add(sizeof(value));
+ lev_.count = 0;
+ lev_.st = state::arr;
+}
+
+void
+value_builder::
+end_array()
+{
+ BOOST_ASSERT(
+ lev_.st == state::arr);
+ auto ua = pop_array();
+ rs_.subtract(lev_.align);
+ pop(lev_);
+ emplace(std::move(ua));
+}
+
+void
+value_builder::
+begin_object()
{
// prevent splits from exceptions
rs_.prepare(
@@ -192,123 +205,65 @@ on_object_begin(error_code&)
object::value_type));
lev_.count = 0;
lev_.st = state::obj;
- return true;
}
-bool
+void
value_builder::
-on_object_end(
- error_code& ec)
+end_object()
{
BOOST_ASSERT(
lev_.st == state::obj);
auto uo = pop_object();
rs_.subtract(lev_.align);
pop(lev_);
- return emplace(
- ec, std::move(uo));
+ emplace(std::move(uo));
}
-bool
+void
value_builder::
-on_array_begin(error_code&)
+insert_key_part(
+ string_view s)
{
- // prevent splits from exceptions
- rs_.prepare(
- sizeof(level) +
- sizeof(value) +
- alignof(value) - 1);
- push(lev_);
- lev_.align =
- detail::align_to(rs_);
- rs_.add(sizeof(value));
- lev_.count = 0;
- lev_.st = state::arr;
- return true;
-}
-
-bool
-value_builder::
-on_array_end(
- error_code& ec)
-{
- BOOST_ASSERT(
- lev_.st == state::arr);
- auto ua = pop_array();
- rs_.subtract(lev_.align);
- pop(lev_);
- return emplace(
- ec, std::move(ua));
-}
-
-bool
-value_builder::
-on_key_part(
- string_view s,
- error_code& ec)
-{
- if( s.size() >
- string::max_size() - key_size_)
- {
- ec = error::key_too_large;
- return false;
- }
push_chars(s);
key_size_ += static_cast<
std::uint32_t>(s.size());
- return true;
}
-bool
+void
value_builder::
-on_key(
- string_view s,
- error_code& ec)
+insert_key(
+ string_view s)
{
BOOST_ASSERT(
lev_.st == state::obj);
- if(! on_key_part(s, ec))
- return false;
+ push_chars(s);
+ key_size_ += static_cast<
+ std::uint32_t>(s.size());
push(key_size_);
key_size_ = 0;
lev_.st = state::key;
- return true;
}
-bool
+void
value_builder::
-on_string_part(
- string_view s,
- error_code& ec)
+insert_string_part(
+ string_view s)
{
- if( s.size() >
- string::max_size() - str_size_)
- {
- ec = error::string_too_large;
- return false;
- }
push_chars(s);
str_size_ += static_cast<
std::uint32_t>(s.size());
- return true;
}
-bool
+void
value_builder::
-on_string(
- string_view s,
- error_code& ec)
+insert_string(
+ string_view s)
{
- if( s.size() >
- string::max_size() - str_size_)
- {
- ec = error::string_too_large;
- return false;
- }
if(str_size_ == 0)
{
// fast path
- return emplace(ec, s, sp_);
+ emplace(s, sp_);
+ return;
}
string str(sp_);
@@ -324,54 +279,46 @@ on_string(
str.data() + sv.size(),
s.data(), s.size());
str.grow(sv.size() + s.size());
- return emplace(
- ec, std::move(str), sp_);
+ emplace(std::move(str), sp_);
}
-bool
+void
value_builder::
-on_int64(
- int64_t i,
- string_view,
- error_code& ec)
+insert_int64(
+ int64_t i)
{
- return emplace(ec, i, sp_);
+ emplace(i, sp_);
}
-bool
+void
value_builder::
-on_uint64(
- uint64_t u,
- string_view,
- error_code& ec)
+insert_uint64(
+ uint64_t u)
{
- return emplace(ec, u, sp_);
+ emplace(u, sp_);
}
-bool
+void
value_builder::
-on_double(
- double d,
- string_view,
- error_code& ec)
+insert_double(
+ double d)
{
- return emplace(ec, d, sp_);
+ emplace(d, sp_);
}
-bool
+void
value_builder::
-on_bool(
- bool b,
- error_code& ec)
+insert_bool(
+ bool b)
{
- return emplace(ec, b, sp_);
+ emplace(b, sp_);
}
-bool
+void
value_builder::
-on_null(error_code& ec)
+insert_null()
{
- return emplace(ec, nullptr, sp_);
+ emplace(nullptr, sp_);
}
//----------------------------------------------------------
@@ -527,33 +474,19 @@ emplace_array(Args&&... args)
}
template
-bool
+void
value_builder::
emplace(
- error_code& ec,
Args&&... args)
{
if(lev_.st == state::key)
{
- if(lev_.count <
- object::max_size())
- {
- emplace_object(std::forward<
- Args>(args)...);
- return true;
- }
- ec = error::object_too_large;
- return false;
+ emplace_object(
+ std::forward(args)...);
+ return;
}
- if(lev_.count <
- array::max_size())
- {
- emplace_array(std::forward<
- Args>(args)...);
- return true;
- }
- ec = error::array_too_large;
- return false;
+ emplace_array(
+ std::forward(args)...);
}
template
diff --git a/include/boost/json/memory_resource.hpp b/include/boost/json/memory_resource.hpp
index 362b293e..92a64d28 100644
--- a/include/boost/json/memory_resource.hpp
+++ b/include/boost/json/memory_resource.hpp
@@ -20,9 +20,35 @@
namespace boost {
namespace json {
-#ifndef BOOST_JSON_STANDALONE
+#ifdef BOOST_JSON_DOCS
+
+/** The type of memory resource used by the library.
+
+ This type alias is set depending
+ on how the library is configured:
+
+ @par Use with Boost
+
+ If the macro `BOOST_JSON_STANDALONE` is
+ not defined, this type will be an alias
+ for `boost::container::pmr::memory_resource`.
+ Compiling a program using the library will
+ require Boost, and a compiler conforming
+ to C++11 or later.
+
+ @par Use without Boost
+
+ If the macro `BOOST_JSON_STANDALONE` is
+ defined, this type will be an alias
+ for `std::pmr::memory_resource`.
+ Compiling a program using the library will
+ require only a compiler conforming to C++17
+ or later.
+*/
+using memory_resource = __see_below__;
+
+#elif ! defined(BOOST_JSON_STANDALONE)
-/// The type of memory_resource used by the library.
using memory_resource = boost::container::pmr::memory_resource;
#else
diff --git a/include/boost/json/object.hpp b/include/boost/json/object.hpp
index 3dba63cc..f6edd321 100644
--- a/include/boost/json/object.hpp
+++ b/include/boost/json/object.hpp
@@ -35,24 +35,18 @@ class object_test;
/** A dynamically sized associative container of JSON key/value pairs.
This is an associative container whose elements
- are key/value pairs with unique keys.
-
-
+ are key/value pairs with unique keys.\n
The elements are stored contiguously, which means that
elements can be accessed not only through iterators, but
also using offsets to regular pointers to elements. A
pointer to an element of an @ref object may be passed to
any function that expects a pointer to
- @ref key_value_pair.
-
-
+ @ref key_value_pair.\n
The container also maintains an internal index to speed
up find operations, reducing the average complexity
- for most lookups and insertions
-
-
+ for most lookups and insertions.\n
Reallocations are usually costly operations in terms of
performance, as elements are copied and the internal
@@ -109,7 +103,14 @@ class object
return 1.0;
}
+ friend class value;
+
+ BOOST_JSON_DECL
+ explicit
+ object(detail::unchecked_object&& uo);
+
friend class object_test;
+
BOOST_JSON_DECL
object(object_test const*);
@@ -177,13 +178,6 @@ public:
impl_.destroy(sp_);
}
-#ifndef BOOST_JSON_DOCS
- // private
- BOOST_JSON_DECL
- explicit
- object(detail::unchecked_object&& uo);
-#endif
-
//------------------------------------------------------
/** Default constructor.
@@ -1210,14 +1204,13 @@ public:
Returns a reference to the value that is mapped
to a key equivalent to key, performing an insertion
- of a null value if such key does not already exist.
-
+ of a null value if such key does not already exist.\n
+
If an insertion occurs and results in a rehashing of
the container, all iterators are invalidated. Otherwise
iterators are not affected. References are not
invalidated. Rehashing occurs only if the new
- number of elements is greater than
- @ref capacity().
+ number of elements is greater than @ref capacity().
@par Complexity
diff --git a/include/boost/json/parser.hpp b/include/boost/json/parser.hpp
index f63b524a..1c6f3435 100644
--- a/include/boost/json/parser.hpp
+++ b/include/boost/json/parser.hpp
@@ -82,95 +82,24 @@ class parser
{
}
- bool on_document_begin(error_code& ec)
- {
- return vb.on_document_begin(ec);
- }
-
- bool on_document_end(error_code& ec)
- {
- return vb.on_document_end(ec);
- }
-
- bool on_object_begin(error_code& ec)
- {
- return vb.on_object_begin(ec);
- }
-
- bool on_object_end(error_code& ec)
- {
- return vb.on_object_end(ec);
- }
-
- bool on_array_begin(error_code& ec)
- {
- return vb.on_array_begin(ec);
- }
-
- bool on_array_end(error_code& ec)
- {
- return vb.on_array_end(ec);
- }
-
- bool on_key_part(string_view s, error_code& ec)
- {
- return vb.on_key_part(s, ec);
- }
-
- bool on_key(string_view s, error_code& ec)
- {
- return vb.on_key(s, ec);
- }
-
- bool on_string_part(string_view s, error_code& ec)
- {
- return vb.on_string_part(s, ec);
- }
-
- bool on_string(string_view s, error_code& ec)
- {
- return vb.on_string(s, ec);
- }
-
- bool on_number_part(string_view s, error_code& ec)
- {
- return vb.on_number_part(s, ec);
- }
-
- bool on_int64(std::int64_t i, string_view, error_code& ec)
- {
- return vb.on_int64(i, {}, ec);
- }
-
- bool on_uint64(std::uint64_t u, string_view, error_code& ec)
- {
- return vb.on_uint64(u, {}, ec);
- }
-
- bool on_double(double d, string_view, error_code& ec)
- {
- return vb.on_double(d, {}, ec);
- }
-
- bool on_bool(bool b, error_code& ec)
- {
- return vb.on_bool(b, ec);
- }
-
- bool on_null(error_code& ec)
- {
- return vb.on_null(ec);
- }
-
- bool on_comment_part(string_view, error_code&)
- {
- return true;
- }
-
- bool on_comment(string_view, error_code&)
- {
- return true;
- }
+ inline bool on_document_begin(error_code& ec);
+ inline bool on_document_end(error_code& ec);
+ inline bool on_object_begin(error_code& ec);
+ inline bool on_object_end(error_code& ec);
+ inline bool on_array_begin(error_code& ec);
+ inline bool on_array_end(error_code& ec);
+ inline bool on_key_part(string_view s, error_code& ec);
+ inline bool on_key(string_view s, error_code& ec);
+ inline bool on_string_part(string_view s, error_code& ec);
+ inline bool on_string(string_view s, error_code& ec);
+ inline bool on_number_part(string_view, error_code&);
+ inline bool on_int64(std::int64_t i, string_view, error_code& ec);
+ inline bool on_uint64(std::uint64_t u, string_view, error_code& ec);
+ inline bool on_double(double d, string_view, error_code& ec);
+ inline bool on_bool(bool b, error_code& ec);
+ inline bool on_null(error_code& ec);
+ inline bool on_comment_part(string_view, error_code&);
+ inline bool on_comment(string_view, error_code&);
};
basic_parser p_;
@@ -204,9 +133,7 @@ public:
@note
Before any JSON can be parsed, the function
- @ref reset must be called.
-
-
+ @ref reset must be called.\n
The `sp` parameter is only used to
allocate intermediate storage; it will not be used
@@ -241,9 +168,7 @@ public:
@note
Before any JSON can be parsed, the function
- @ref reset must be called.
-
-
+ @ref reset must be called.\n
The `sp` parameter is only used to
allocate intermediate storage; it will not be used
@@ -333,9 +258,7 @@ public:
buffer. The parse proceeds from the current
state, which is at the beginning of a new JSON
or in the middle of the current JSON if any
- characters were already parsed.
-
-
+ characters were already parsed.\n
The characters in the buffer are processed
starting from the beginning, until one of the
@@ -384,9 +307,7 @@ public:
buffer. The parse proceeds from the current
state, which is at the beginning of a new JSON
or in the middle of the current JSON if any
- characters were already parsed.
-
-
+ characters were already parsed.\n
The characters in the buffer are processed
starting from the beginning, until one of the
diff --git a/include/boost/json/string_view.hpp b/include/boost/json/string_view.hpp
index 40c1869a..50b825bb 100644
--- a/include/boost/json/string_view.hpp
+++ b/include/boost/json/string_view.hpp
@@ -21,9 +21,35 @@
namespace boost {
namespace json {
-#ifndef BOOST_JSON_STANDALONE
+#ifdef BOOST_JSON_DOCS
+
+/** The type of string view used by the library.
+
+ This type alias is set depending
+ on how the library is configured:
+
+ @par Use with Boost
+
+ If the macro `BOOST_JSON_STANDALONE` is
+ not defined, this type will be an alias
+ for `boost::string_view`.
+ Compiling a program using the library will
+ require Boost, and a compiler conforming
+ to C++11 or later.
+
+ @par Use without Boost
+
+ If the macro `BOOST_JSON_STANDALONE` is
+ defined, this type will be an alias
+ for `std::string_view`.
+ Compiling a program using the library will
+ require only a compiler conforming to C++17
+ or later.
+*/
+using string_view = __see_below__;
+
+#elif ! defined(BOOST_JSON_STANDALONE)
-/// The type of string view used by the library.
using string_view = boost::string_view;
#else
diff --git a/include/boost/json/value.hpp b/include/boost/json/value.hpp
index 3ee53dd4..c808abcf 100644
--- a/include/boost/json/value.hpp
+++ b/include/boost/json/value.hpp
@@ -76,6 +76,11 @@ class value
struct undo;
struct init_iter;
+ friend class value_builder;
+ friend class key_value_pair;
+ inline value(detail::unchecked_object&& uo);
+ inline value(detail::unchecked_array&& ua);
+
public:
/** Destructor.
@@ -90,12 +95,6 @@ public:
BOOST_JSON_DECL
~value();
-#ifndef BOOST_JSON_DOCS
- // private
- inline value(detail::unchecked_object&& uo);
- inline value(detail::unchecked_array&& ua);
-#endif
-
/** Default constructor.
The constructed value is null,
@@ -2670,8 +2669,9 @@ swap(value& lhs, value& rhs)
This is the type of element used by the @ref object
container.
*/
-struct key_value_pair
+class key_value_pair
{
+public:
/** Copy assignment (deleted).
*/
key_value_pair&
diff --git a/include/boost/json/value_builder.hpp b/include/boost/json/value_builder.hpp
index c62df10f..6e15d80a 100644
--- a/include/boost/json/value_builder.hpp
+++ b/include/boost/json/value_builder.hpp
@@ -22,34 +22,53 @@ namespace json {
//----------------------------------------------------------
-/** A factory for building a value DOM.
+/** A factory for building a value.
A value builder implements an algorithm for
efficiently constructing a @ref value from an
external source (provided by the caller).
-
- The builder uses a dynamically allocated internal
- storage to hold portions of the document, allowing
- complete objects and arrays to be constructed using
- a single allocation when their contents are
- eventually known. This internal storage is reused
- when creating multiple values with the same builder.
+ It uses a dynamically allocated internal storage
+ to hold portions of the document, allowing complete
+ objects and arrays to be constructed using a single
+ allocation when their contents are eventually known.
+ This internal storage is reused when creating multiple
+ values with the same builder. \n
To use the builder construct it with an optionally
specified memory resource to use for the internal
storage. Then call @ref reset once before building
each complete DOM, optionally specifying the
memory resource to use for the resulting @ref value.
+ Once the reset function is called, the value may
+ be built iteratively by calling the appropriate
+ insertion functions as desired. After construction
+ is finished, the caller can take ownership of the
+ resulting value by calling @ref release.
- The functions @ref on_document_begin and
- @ref on_document_end must be called exactly once
- at the beginning and at the end of construction.
- The remaining event handling functions are called
- according to their descriptions to build the document.
+ @par Example
+
+ The following code constructs a @ref value which
+ when serialized produces a JSON object with three
+ elements.
+
+ @code
+ value_builder vb;
+ vb.reset();
+ vb.begin_object();
+ vb.insert_key("a");
+ vb.insert_int64(1);
+ vb.insert_key("b");
+ vb.insert_null();
+ vb.insert_key("c");
+ vb.insert_string("hello");
+ vb.end_object();
+ assert( to_string(vb.release()) == "{\"a\":1,\"b\":null,\"c\":\"hello\"}" );
+ @endcode
*/
class value_builder
{
enum class state : char;
+
struct level
{
std::uint32_t count;
@@ -66,30 +85,26 @@ class value_builder
public:
/** Destructor.
- All dynamically allocated memory, including
- any partially built results, is freed.
+ All dynamically allocated memory and
+ partial or complete elements is freed.
*/
BOOST_JSON_DECL
~value_builder();
/** Constructor.
- Constructs a empty builder using the default
- memory resource, or the optionally specified
- @ref storage_ptr, to allocate intermediate storage.
+ Constructs a empty builder. Before any
+ @ref value can be built, the function
+ @ref reset must be called.
- @note
- Before any @ref value can be built,
- the function @ref start must be called.
-
-
-
- The `sp` parameter is only used to
- allocate intermediate storage; it will not be used
+ The `sp` parameter is only used to allocate
+ intermediate storage; it will not be used
for the @ref value returned by @ref release.
- @param sp The @ref storage_ptr to use for
- intermediate storage allocations.
+ @param sp A pointer to the @ref memory_resource
+ to use for intermediate storage allocations. If
+ this argument is omitted, the default memory
+ resource is used.
*/
BOOST_JSON_DECL
explicit
@@ -98,31 +113,32 @@ public:
/** Reserve internal storage space.
This function reserves space for `n` bytes
- in the parser's internal temporary storage.
+ in the builders's internal temporary storage.
The request is only a hint to the
- implementation.
+ implementation.
@par Exception Safety
Strong guarantee.
- @param n The number of bytes to reserve. A
- good choices is `C * sizeof(value)` where
- `C` is the total number of @ref value elements
- in a typical parsed JSON.
+ @param n The number of bytes to reserve.
*/
BOOST_JSON_DECL
void
reserve(std::size_t n);
- /** Prepare the builder for a new value.
+ /** Prepare to build a new value.
This function must be called before building
- a new @ref value. Any previously existing full
- or partial values are destroyed, but internal
+ a new @ref value. Any previously existing partial
+ or complete elements are destroyed, but internal
dynamically allocated memory is preserved which
may be reused to build new values.
+ @par Exception Safety
+
+ No-throw guarantee.
+
@param sp A pointer to the @ref memory_resource
to use for the resulting value. The builder will
acquire shared ownership of the memory resource.
@@ -131,13 +147,16 @@ public:
void
reset(storage_ptr sp = {}) noexcept;
- /** Return the parsed JSON as a @ref value.
+ /** Return the completed value.
If @ref is_complete() returns `true`, then the
parsed value is returned. Otherwise an
exception is thrown.
- @throw std::logic_error `! is_complete()`
+ @par Exception Safety
+
+ Basic guarantee.
+ Calls to `memory_resource::allocate` may throw.
@return The parsed value. Ownership of this
value is transferred to the caller.
@@ -153,10 +172,12 @@ public:
internal memory which may be reused on a
subsequent parse.
- @note
+ After calling this function, it is necessary
+ to call @ref start before building a new value.
- After this call, it is necessary to call
- @ref start to parse a new JSON incrementally.
+ @par Exception Safety
+
+ No-throw guarantee.
*/
BOOST_JSON_DECL
void
@@ -164,339 +185,245 @@ public:
//--------------------------------------------
- /** Begin building a new value.
+ /** Insert an array.
- This function must be called exactly once
- after calling @ref reset, before any other
- event functions are invoked.
+ This function opens a new, empty array
+ which will be inserted into the result as
+ the next element of the currently open array
+ or object, or as the top-level element if
+ no other elements exist.\n
- @return `true` on success.
+ After calling this function, elements
+ are inserted into the array by calling
+ the other insertion functions (including
+ @ref begin_array and @ref begin_object).\n
- @param ec Set to the error, if any occurred.
+ @par Exception Safety
+ Basic guarantee.
+ Calls to `memory_resource::allocate` may throw.
*/
BOOST_JSON_DECL
- bool
- on_document_begin(
- error_code& ec);
+ void
+ begin_array();
- /** Finish building a new value.
+ /** Insert an array.
- This function must be called exactly once
- before calling @ref release, and after all
- event functions have been called.
+ This function closes the current array,
+ which must have been opened by a previously
+ balanced call to @ref begin_array.
+ The array is then inserted into the currently
+ open array or object, or the top level if no
+ enclosing array or object is open.
- @return `true` on success.
-
- @param ec Set to the error, if any occurred.
+ @par Exception Safety
+ Basic guarantee.
+ Calls to `memory_resource::allocate` may throw.
*/
BOOST_JSON_DECL
- bool
- on_document_end(
- error_code& ec);
+ void
+ end_array();
- /** Begin building an object.
+ /** Insert an object.
- This instructs the builder to begin building
- a new JSON object, either as the top-level
- element of the resulting value, or as the
- next element of the current object or array
- being built.
+ This function opens a new, empty object
+ which will be inserted into the result as
+ the next element of the currently open array
+ or object, or as the top-level element if
+ no other elements exist.\n
- @return `true` on success.
+ After calling this function, elements are
+ inserted into the object by first inserting
+ the key using @ref insert_key and
+ @ref insert_key_part, and then calling
+ the other insertion functions (including
+ @ref begin_object and @ref begin_array) to
+ add the value corresponding to the key.\n
- @param ec Set to the error, if any occurred.
+ @par Exception Safety
+ Basic guarantee.
+ Calls to `memory_resource::allocate` may throw.
*/
BOOST_JSON_DECL
- bool
- on_object_begin(
- error_code& ec);
+ void
+ begin_object();
- /** Finish building an object.
+ /** Insert an object.
- This event function instructs the builder that
- the object currently being built, which was created
- by the last call to @ref on_object_begin, is finished.
+ This function closes the current object,
+ which must have been opened by a previously
+ balanced call to @ref begin_object.
+ The object is then inserted into the currently
+ open array or object, or the top level if no
+ enclosing array or object is open.
- @return `true` on success.
-
- @param ec Set to the error, if any occurred.
+ @par Exception Safety
+ Basic guarantee.
+ Calls to `memory_resource::allocate` may throw.
*/
BOOST_JSON_DECL
- bool
- on_object_end(
- error_code& ec);
+ void
+ end_object();
- /** Begin building an array.
-
- This instructs the builder to begin building
- a new JSON array, either as the top-level
- element of the resulting value, or as the
- next element of the current object or array
- being built.
-
- @return `true` on success.
-
- @param ec Set to the error, if any occurred.
- */
- BOOST_JSON_DECL
- bool
- on_array_begin(
- error_code& ec);
-
- /** Finish building an array.
-
- This function instructs the builder that the
- array currently being built, which was created
- by the last call to @ref on_array_begin, is finished.
-
- @return `true` on success.
-
- @param ec Set to the error, if any occurred.
- */
- BOOST_JSON_DECL
- bool
- on_array_end(
- error_code& ec);
-
- /** Continue creating a key.
+ /** Set the key for the next value.
This function appends the specified characters
- to the key being built as the next element of
- a currently open object. If a key is not currently
- being built, the behavior is undefined.
+ to the current key, which must be part of an
+ open object. If a key is not currently being
+ built or an object is not open, the behavior
+ is undefined.
- @return `true` on success.
+ @par Exception Safety
+ Basic guarantee.
+ Calls to `memory_resource::allocate` may throw.
@param s The characters to append. This may be empty.
-
- @param ec Set to the error, if any occurred.
*/
BOOST_JSON_DECL
- bool
- on_key_part(
- string_view s,
- error_code& ec);
+ void
+ insert_key_part(
+ string_view s);
- /** Finish creating a key.
+ /** Set the key for the next value.
This function appends the specified characters
- to the key being built as the next element of
- a currently open object, and finishes construction
- of the key. If a key is not currently being built,
- the behavior is undefined.
+ to the current key, which must be part of an
+ open object. If a key is not currently being
+ built or an object is not open, the behavior
+ is undefined. After the characters are inserted,
+ the key is finished and a value must be inserted
+ next.
- @return `true` on success.
+ @par Exception Safety
+ Basic guarantee.
+ Calls to `memory_resource::allocate` may throw.
@param s The characters to append. This may be empty.
-
- @param ec Set to the error, if any occurred.
*/
BOOST_JSON_DECL
- bool
- on_key(
- string_view s,
- error_code& ec);
+ void
+ insert_key(
+ string_view s);
- /** Begin or continue creating a string.
+ /** Insert a string.
This function appends the specified characters
- to the string being built. If a string is not
- currently being built, then a new empty string
- is started.
+ to the current string, which will be created if
+ it did not already exist from an immediately
+ prior call to @ref insert_string_part.
- @return `true` on success.
+ @par Exception Safety
+ Basic guarantee.
+ Calls to `memory_resource::allocate` may throw.
@param s The characters to append. This may be empty.
-
- @param ec Set to the error, if any occurred.
*/
BOOST_JSON_DECL
- bool
- on_string_part(
- string_view s,
- error_code& ec);
+ void
+ insert_string_part(
+ string_view s);
- /** Create a string or finish creating a string.
+ /** Insert a string.
This function appends the specified characters
- to the string being built. If a string is not
- currently being built, then a new string is created
- with the specified characters.
+ to the current string, which will be created if
+ it did not already exist from an immediately prior
+ call to @ref insert_string_part.
+ The string is then inserted into the currently
+ open array or object, or the top level if no
+ array or object is open.
- @return `true` on success.
+ @par Exception Safety
+ Basic guarantee.
+ Calls to `memory_resource::allocate` may throw.
@param s The characters to append. This may be empty.
-
- @param ec Set to the error, if any occurred.
*/
BOOST_JSON_DECL
- bool
- on_string(
- string_view s,
- error_code& ec);
+ void
+ insert_string(
+ string_view s);
- /** Begin building a number from a string.
+ /** Insert a number.
- This instructs the builder to begin building
- a new JSON number, either as the top-level
- element of the resulting value, or as the
- next element of the current object or array
- being built.
+ This function inserts a number into the currently
+ open array or object, or the top level if no
+ array or object is open.
- @note This function has no effect and always
- returns `true`.
+ @par Exception Safety
+ Basic guarantee.
+ Calls to `memory_resource::allocate` may throw.
- @return `true` on success.
-
- @param s The characters to append. This may be empty.
-
- @param ec Set to the error, if any occurred.
- */
- bool
- on_number_part(
- string_view s,
- error_code& ec)
- {
- (void)s;
- (void)ec;
- return true;
- }
-
- /** Build a number.
-
- This function builds a number from the specified
- value and adds it as the top-level element of the
- resulting value, or as the next element of the
- current object or array being built.
-
- @return `true` on success.
-
- @param i The integer to build.
-
- @param s The characters to append. This value is ignored.
-
- @param ec Set to the error, if any occurred.
+ @param i The number to insert.
*/
BOOST_JSON_DECL
- bool
- on_int64(
- int64_t i,
- string_view s,
- error_code& ec);
+ void
+ insert_int64(
+ int64_t i);
- /** Build a number.
+ /** Insert a number.
- This function builds a number from the specified
- value and adds it as the top-level element of the
- resulting value, or as the next element of the
- current object or array being built.
+ This function inserts a number into the currently
+ open array or object, or the top level if no
+ array or object is open.
- @return `true` on success.
+ @par Exception Safety
+ Basic guarantee.
+ Calls to `memory_resource::allocate` may throw.
- @param i The unsigned integer to build.
-
- @param s The characters to append. This value is ignored.
-
- @param ec Set to the error, if any occurred.
+ @param u The number to insert.
*/
BOOST_JSON_DECL
- bool
- on_uint64(
- uint64_t u,
- string_view s,
- error_code& ec);
+ void
+ insert_uint64(
+ uint64_t u);
- /** Build a number.
+ /** Insert a number.
- This function builds a number from the specified
- value and adds it as the top-level element of the
- resulting value, or as the next element of the
- current object or array being built.
+ This function inserts a number into the currently
+ open array or object, or the top level if no
+ array or object is open.
- @return `true` on success.
+ @par Exception Safety
+ Basic guarantee.
+ Calls to `memory_resource::allocate` may throw.
- @param i The floating point number to build.
-
- @param s The characters to append. This value is ignored.
-
- @param ec Set to the error, if any occurred.
+ @param d The number to insert.
*/
BOOST_JSON_DECL
- bool
- on_double(
- double d,
- string_view s,
- error_code& ec);
+ void
+ insert_double(
+ double d);
- /** Build a boolean.
+ /** Insert a boolean.
- This function builds a boolean from the specified
- value and adds it as the top-level element of the
- resulting value, or as the next element of the
- current object or array being built.
+ This function inserts a boolean into the currently
+ open array or object, or the top level if no
+ array or object is open.
- @return `true` on success.
+ @par Exception Safety
+ Basic guarantee.
+ Calls to `memory_resource::allocate` may throw.
- @param b The boolean to build.
-
- @param ec Set to the error, if any occurred.
+ @param b The boolean to insert.
*/
BOOST_JSON_DECL
- bool
- on_bool(
- bool b,
- error_code& ec);
+ void
+ insert_bool(
+ bool b);
/** Build a null.
- This function builds a null from the specified
- value and adds it as the top-level element of the
- resulting value, or as the next element of the
- current object or array being built.
+ This function inserts a null into the currently
+ open array or object, or the top level if no
+ array or object is open.
- @return `true` on success.
-
- @param ec Set to the error, if any occurred.
+ @par Exception Safety
+ Basic guarantee.
+ Calls to `memory_resource::allocate` may throw.
*/
BOOST_JSON_DECL
- bool
- on_null(error_code& ec);
-
- /** Specify part of comment.
-
- This function has no effect and always returns `true`.
-
- @param s The characters to append. This value is ignored.
-
- @param ec Set to the error, if any occurred.
- */
- bool
- on_comment_part(
- string_view s,
- error_code& ec)
- {
- (void)s;
- (void)ec;
- return true;
- }
-
- /** Specify a comment.
-
- This function has no effect and always returns `true`.
-
- @param s The characters to append. This value is ignored.
-
- @param ec Set to the error, if any occurred.
- */
- bool
- on_comment(
- string_view s,
- error_code& ec)
- {
- (void)s;
- (void)ec;
- return true;
- }
+ void
+ insert_null();
private:
inline
@@ -522,9 +449,8 @@ private:
Args&&... args);
template
- bool
+ void
emplace(
- error_code& ec,
Args&&... args);
template
diff --git a/test/value_builder.cpp b/test/value_builder.cpp
index d2157d5a..28fcce02 100644
--- a/test/value_builder.cpp
+++ b/test/value_builder.cpp
@@ -10,6 +10,8 @@
// Test that header file is self-contained.
#include
+#include
+
#include "test_suite.hpp"
namespace boost {
@@ -21,13 +23,20 @@ public:
void
testBuilder()
{
- error_code ec;
- value_builder vb;
- vb.reset();
- vb.on_document_begin(ec);
- vb.on_null(ec);
- vb.on_document_end(ec);
- vb.release();
+ // This is from the javadoc
+
+ value_builder vb;
+ vb.reset();
+ vb.begin_object();
+ vb.insert_key("a");
+ vb.insert_int64(1);
+ vb.insert_key("b");
+ vb.insert_null();
+ vb.insert_key("c");
+ vb.insert_string("hello");
+ vb.end_object();
+ assert( to_string(vb.release()) == "{\"a\":1,\"b\":null,\"c\":\"hello\"}" );
+
}
void