diff --git a/bench/bench.cpp b/bench/bench.cpp
index a9c59ce7..0fde8363 100644
--- a/bench/bench.cpp
+++ b/bench/bench.cpp
@@ -274,7 +274,7 @@ public:
parser p;
while(repeat--)
{
- p.start();
+ p.reset();
error_code ec;
p.write(s.data(), s.size(), ec);
if(! ec)
@@ -341,7 +341,7 @@ public:
while(repeat--)
{
monotonic_resource mr;
- p.start(&mr);
+ p.reset(&mr);
error_code ec;
p.write(s.data(), s.size(), ec);
if(! ec)
diff --git a/doc/qbk/02_7_parsing.qbk b/doc/qbk/02_7_parsing.qbk
index eaf5b4ec..59428bbb 100644
--- a/doc/qbk/02_7_parsing.qbk
+++ b/doc/qbk/02_7_parsing.qbk
@@ -58,7 +58,7 @@ failure instead of an exception:
The calls above will produce values that use the default
memory resource. Each parse function allows an additional parameter
-specifying the memory resource to use. Here we start the parser with
+specifying the memory resource to use. Here we reset the parser with
a new instance of __monotonic_resource__ for the resulting value:
[snippet_parsing_3]
@@ -90,7 +90,7 @@ code are used instead:
[h4 Allocators]
When
-[link json.ref.boost__json__parser.start `start`]
+[link json.ref.boost__json__parser.reset `reset`]
is called with no arguments, the parser constructs the resulting
__value__ using the default memory resource. A __storage_ptr__
can also be passed to the function, and the resulting __value__ will
diff --git a/doc/qbk/quickref.xml b/doc/qbk/quickref.xml
index 6ca7ef78..4712ee6f 100644
--- a/doc/qbk/quickref.xml
+++ b/doc/qbk/quickref.xml
@@ -31,6 +31,7 @@
storage_ptr
string
value
+ value_builder
diff --git a/example/pretty.cpp b/example/pretty.cpp
index bee60395..be4c7469 100644
--- a/example/pretty.cpp
+++ b/example/pretty.cpp
@@ -27,7 +27,7 @@ parse_file( char const* filename )
{
file f( filename, "r" );
json::parser p;
- p.start();
+ p.reset();
do
{
char buf[4096];
diff --git a/include/boost/json/error.hpp b/include/boost/json/error.hpp
index ae093415..e8c92e2f 100644
--- a/include/boost/json/error.hpp
+++ b/include/boost/json/error.hpp
@@ -58,11 +58,9 @@ using std::generic_category;
*/
enum class error
{
- //----------------------------------
//
// parse errors
//
- //----------------------------------
/// syntax error
syntax = 1,
@@ -100,10 +98,6 @@ enum class error
/// illegal trailing surrogate
illegal_trailing_surrogate,
- /** The parser needs to be started.
- */
- need_start,
-
/// expected comma
expected_comma,
diff --git a/include/boost/json/impl/error.ipp b/include/boost/json/impl/error.ipp
index 2b61fc7c..f4f1d941 100644
--- a/include/boost/json/impl/error.ipp
+++ b/include/boost/json/impl/error.ipp
@@ -44,7 +44,6 @@ case error::illegal_escape_char: return "illegal character in escape sequence";
case error::illegal_extra_digits: return "illegal extra digits in number";
case error::illegal_leading_surrogate: return "illegal leading surrogate";
case error::illegal_trailing_surrogate: return "illegal trailing surrogate";
-case error::need_start: return "parser needs start";
case error::expected_comma: return "expected comma";
case error::expected_colon: return "expected colon";
diff --git a/include/boost/json/impl/parser.ipp b/include/boost/json/impl/parser.ipp
index 71a495a4..37bd2ec7 100644
--- a/include/boost/json/impl/parser.ipp
+++ b/include/boost/json/impl/parser.ipp
@@ -20,139 +20,6 @@
namespace boost {
namespace json {
-//----------------------------------------------------------
-
-/*
-
-Stack Layout:
- ... denotes 0 or more
- <> denotes empty storage
-
-array
- saved_state
- std::size_t
- state
- value...
-
-
-object
- saved_state
- std::size_t
- state
- value_type...
-
-
-key
- (chars)...
- std::size_t
-*/
-
-enum class parser::state : char
-{
- need_start, // start() not called yet
- begin, // we have a storage_ptr
-
- // These states indicate what is
- // currently at top of the stack.
-
- top, // top value, constructed if lev_.count==1
- arr, // empty array value
- obj, // empty object value
- key, // complete key
-};
-
-void
-parser::
-destroy() noexcept
-{
- if(key_size_ > 0)
- {
- // remove partial key
- BOOST_ASSERT(
- lev_.st == state::obj);
- BOOST_ASSERT(
- str_size_ == 0);
- rs_.subtract(key_size_);
- key_size_ = 0;
- }
- else if(str_size_ > 0)
- {
- // remove partial string
- rs_.subtract(str_size_);
- str_size_ = 0;
- }
- // unwind the rest
- do
- {
- switch(lev_.st)
- {
- case state::need_start:
- BOOST_ASSERT(
- rs_.empty());
- break;
-
- case state::begin:
- BOOST_ASSERT(
- rs_.empty());
- break;
-
- case state::top:
- if(lev_.count > 0)
- {
- BOOST_ASSERT(
- lev_.count == 1);
- auto ua =
- pop_array();
- BOOST_ASSERT(
- ua.size() == 1);
- BOOST_ASSERT(
- rs_.empty());
- }
- else
- {
- // never parsed a value
- rs_.subtract(
- sizeof(value));
- BOOST_ASSERT(
- rs_.empty());
- }
- break;
-
- case state::arr:
- {
- pop_array();
- rs_.subtract(lev_.align);
- pop(lev_);
- break;
- }
-
- case state::obj:
- {
- pop_object();
- rs_.subtract(lev_.align);
- pop(lev_);
- break;
- }
-
- case state::key:
- {
- std::uint32_t key_size;
- pop(key_size);
- pop_chars(key_size);
- lev_.st = state::obj;
- break;
- }
- }
- }
- while(! rs_.empty());
-}
-
-parser::
-~parser()
-{
- destroy();
-}
-
parser::
parser() noexcept
: parser(
@@ -182,40 +49,30 @@ parser(
storage_ptr sp,
const parse_options& opt) noexcept
: basic_parser(opt)
- , rs_(std::move(sp))
+ , vb_(std::move(sp))
{
- lev_.st = state::need_start;
}
void
parser::
-reserve(
- std::size_t bytes) noexcept
+reserve(std::size_t n)
{
- rs_.reserve(bytes);
+ vb_.reserve(n);
}
void
parser::
-start(storage_ptr sp) noexcept
+reset(storage_ptr sp) noexcept
{
- clear();
- sp_ = std::move(sp);
- lev_.st = state::begin;
+ vb_.reset(sp);
}
void
parser::
clear() noexcept
{
- destroy();
- rs_.clear();
+ vb_.clear();
basic_parser::reset();
- lev_.count = 0;
- key_size_ = 0;
- str_size_ = 0;
- lev_.st = state::need_start;
- sp_ = {};
}
std::size_t
@@ -227,7 +84,7 @@ write(
{
auto const n =
basic_parser::write_some(
- *this, true, data, size, ec);
+ vb_, true, data, size, ec);
if(! ec && n < size)
ec = error::extra_data;
return n;
@@ -253,7 +110,7 @@ parser::
finish(error_code& ec)
{
basic_parser::write_some(
- *this, false, nullptr, 0, ec);
+ vb_, false, nullptr, 0, ec);
}
void
@@ -267,403 +124,13 @@ value
parser::
release()
{
+ /*
if(! is_complete())
BOOST_THROW_EXCEPTION(
std::logic_error(
"no value"));
- BOOST_ASSERT(lev_.count == 1);
- BOOST_ASSERT(depth() == 0);
- auto ua = pop_array();
- BOOST_ASSERT(rs_.empty());
- union U
- {
- value v;
- U(){}
- ~U(){}
- };
- U u;
- ua.relocate(&u.v);
- basic_parser::reset();
- lev_.st = state::need_start;
- sp_ = {};
- return pilfer(u.v);
-}
-
-//----------------------------------------------------------
-
-template
-void
-parser::
-push(T const& t)
-{
- std::memcpy(
- rs_.push(sizeof(T)),
- &t, sizeof(T));
-}
-
-void
-parser::
-push_chars(string_view s)
-{
- std::memcpy(
- rs_.push(s.size()),
- s.data(), s.size());
-}
-
-template
-void
-parser::
-emplace_object(
- Args&&... args)
-{
- union U
- {
- object::value_type v;
- U(){}
- ~U(){}
- };
- U u;
- // perform stack reallocation up-front
- // VFALCO This is more than we need
- rs_.prepare(sizeof(object::value_type));
- std::uint32_t key_size;
- pop(key_size);
- auto const key =
- pop_chars(key_size);
- lev_.st = state::obj;
- BOOST_ASSERT((rs_.top() %
- alignof(object::value_type)) == 0);
- ::new(rs_.behind(
- sizeof(object::value_type)))
- object::value_type(
- key, std::forward(args)...);
- rs_.add_unchecked(sizeof(u.v));
- ++lev_.count;
-}
-
-template
-void
-parser::
-emplace_array(Args&&... args)
-{
- // prevent splits from exceptions
- rs_.prepare(sizeof(value));
- BOOST_ASSERT((rs_.top() %
- alignof(value)) == 0);
- ::new(rs_.behind(sizeof(value))) value(
- std::forward(args)...);
- rs_.add_unchecked(sizeof(value));
- ++lev_.count;
-}
-
-template
-bool
-parser::
-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;
- }
- if(lev_.count <
- array::max_size())
- {
- emplace_array(std::forward<
- Args>(args)...);
- return true;
- }
- ec = error::array_too_large;
- return false;
-}
-
-template
-void
-parser::
-pop(T& t)
-{
- std::memcpy(&t,
- rs_.pop(sizeof(T)),
- sizeof(T));
-}
-
-detail::unchecked_object
-parser::
-pop_object() noexcept
-{
- rs_.subtract(sizeof(
- object::value_type));
- if(lev_.count == 0)
- return { nullptr, 0, sp_ };
- auto const n = lev_.count * sizeof(
- object::value_type);
- return { reinterpret_cast<
- object::value_type*>(rs_.pop(n)),
- lev_.count, sp_ };
-}
-
-detail::unchecked_array
-parser::
-pop_array() noexcept
-{
- rs_.subtract(sizeof(value));
- if(lev_.count == 0)
- return { nullptr, 0, sp_ };
- auto const n =
- lev_.count * sizeof(value);
- return { reinterpret_cast(
- rs_.pop(n)), lev_.count, sp_ };
-}
-
-string_view
-parser::
-pop_chars(
- std::size_t size) noexcept
-{
- return {
- reinterpret_cast(
- rs_.pop(size)), size };
-}
-
-//----------------------------------------------------------
-
-bool
-parser::
-on_document_begin(
- error_code& ec)
-{
- if(lev_.st == state::need_start)
- {
- ec = error::need_start;
- return false;
- }
-
- lev_.count = 0;
- lev_.align = 0;
- key_size_ = 0;
- str_size_ = 0;
-
- // The top level `value` is kept
- // inside a notional 1-element array.
- rs_.add(sizeof(value));
- lev_.st = state::top;
-
- return true;
-}
-
-bool
-parser::
-on_document_end(error_code&)
-{
- BOOST_ASSERT(lev_.count == 1);
- return true;
-}
-
-bool
-parser::
-on_object_begin(error_code&)
-{
- // prevent splits from exceptions
- rs_.prepare(
- sizeof(level) +
- sizeof(object::value_type) +
- alignof(object::value_type) - 1);
- push(lev_);
- lev_.align = detail::align_to<
- object::value_type>(rs_);
- rs_.add(sizeof(
- object::value_type));
- lev_.count = 0;
- lev_.st = state::obj;
- return true;
-}
-
-bool
-parser::
-on_object_end(
- error_code& ec)
-{
- BOOST_ASSERT(
- lev_.st == state::obj);
- auto uo = pop_object();
- rs_.subtract(lev_.align);
- pop(lev_);
- return emplace(
- ec, std::move(uo));
-}
-
-bool
-parser::
-on_array_begin(error_code&)
-{
- // 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
-parser::
-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
-parser::
-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
-parser::
-on_key(
- string_view s,
- error_code& ec)
-{
- BOOST_ASSERT(
- lev_.st == state::obj);
- if(! on_key_part(s, ec))
- return false;
- push(key_size_);
- key_size_ = 0;
- lev_.st = state::key;
- return true;
-}
-
-bool
-parser::
-on_string_part(
- string_view s,
- error_code& ec)
-{
- 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
-parser::
-on_string(
- string_view s,
- error_code& ec)
-{
- 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_);
- }
-
- string str(sp_);
- auto const sv =
- pop_chars(str_size_);
- str_size_ = 0;
- str.reserve(
- sv.size() + s.size());
- std::memcpy(
- str.data(),
- sv.data(), sv.size());
- std::memcpy(
- str.data() + sv.size(),
- s.data(), s.size());
- str.grow(sv.size() + s.size());
- return emplace(
- ec, std::move(str), sp_);
-}
-
-bool
-parser::
-on_int64(
- int64_t i,
- string_view,
- error_code& ec)
-{
- return emplace(ec, i, sp_);
-}
-
-bool
-parser::
-on_uint64(
- uint64_t u,
- string_view,
- error_code& ec)
-{
- return emplace(ec, u, sp_);
-}
-
-bool
-parser::
-on_double(
- double d,
- string_view,
- error_code& ec)
-{
- return emplace(ec, d, sp_);
-}
-
-bool
-parser::
-on_bool(
- bool b,
- error_code& ec)
-{
- return emplace(ec, b, sp_);
-}
-
-bool
-parser::
-on_null(error_code& ec)
-{
- return emplace(ec, nullptr, sp_);
+ */
+ return vb_.release();
}
//----------------------------------------------------------
@@ -675,7 +142,7 @@ parse(
storage_ptr sp)
{
parser p;
- p.start(std::move(sp));
+ p.reset(std::move(sp));
p.write(
s.data(),
s.size(),
diff --git a/include/boost/json/impl/value_builder.ipp b/include/boost/json/impl/value_builder.ipp
new file mode 100644
index 00000000..e4bf32b3
--- /dev/null
+++ b/include/boost/json/impl/value_builder.ipp
@@ -0,0 +1,610 @@
+//
+// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+// Official repository: https://github.com/cppalliance/json
+//
+
+#ifndef BOOST_JSON_IMPL_VALUE_BUILDER_IPP
+#define BOOST_JSON_IMPL_VALUE_BUILDER_IPP
+
+#include
+#include
+#include
+#include
+
+namespace boost {
+namespace json {
+
+//----------------------------------------------------------
+
+/*
+
+Stack Layout:
+ ... denotes 0 or more
+ <> denotes empty storage
+
+array
+ saved_state
+ std::size_t
+ state
+ value...
+
+
+object
+ saved_state
+ std::size_t
+ state
+ value_type...
+
+
+key
+ (chars)...
+ std::size_t
+*/
+
+enum class value_builder::state : char
+{
+ need_reset, // reset() not called yet
+ begin, // we have a storage_ptr
+
+ // These states indicate what is
+ // currently at top of the stack.
+
+ top, // top value, constructed if lev_.count==1
+ arr, // empty array value
+ obj, // empty object value
+ key, // complete key
+};
+
+value_builder::
+~value_builder()
+{
+ destroy();
+}
+
+value_builder::
+value_builder(
+ storage_ptr sp) noexcept
+ : rs_(std::move(sp))
+{
+ lev_.st = state::need_reset;
+}
+
+void
+value_builder::
+reserve(std::size_t n)
+{
+#ifndef BOOST_NO_EXCEPTIONS
+ try
+ {
+#endif
+ rs_.reserve(n);
+#ifndef BOOST_NO_EXCEPTIONS
+ }
+ catch(std::bad_alloc const&)
+ {
+ // squelch the exception, per contract
+ }
+#endif
+}
+
+void
+value_builder::
+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);
+
+ lev_.count = 0;
+ lev_.align = 0;
+ key_size_ = 0;
+ str_size_ = 0;
+
+ // The top level `value` is kept
+ // inside a notional 1-element array.
+ rs_.add(sizeof(value));
+ lev_.st = state::top;
+
+ return true;
+}
+
+bool
+value_builder::
+on_document_end(error_code&)
+{
+ // If this goes off, then an
+ // array or object was never finished.
+ BOOST_ASSERT(lev_.st == state::top);
+ BOOST_ASSERT(lev_.count == 1);
+ return true;
+}
+
+bool
+value_builder::
+on_object_begin(error_code&)
+{
+ // prevent splits from exceptions
+ rs_.prepare(
+ sizeof(level) +
+ sizeof(object::value_type) +
+ alignof(object::value_type) - 1);
+ push(lev_);
+ lev_.align = detail::align_to<
+ object::value_type>(rs_);
+ rs_.add(sizeof(
+ object::value_type));
+ lev_.count = 0;
+ lev_.st = state::obj;
+ return true;
+}
+
+bool
+value_builder::
+on_object_end(
+ error_code& ec)
+{
+ BOOST_ASSERT(
+ lev_.st == state::obj);
+ auto uo = pop_object();
+ rs_.subtract(lev_.align);
+ pop(lev_);
+ return emplace(
+ ec, std::move(uo));
+}
+
+bool
+value_builder::
+on_array_begin(error_code&)
+{
+ // 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
+value_builder::
+on_key(
+ string_view s,
+ error_code& ec)
+{
+ BOOST_ASSERT(
+ lev_.st == state::obj);
+ if(! on_key_part(s, ec))
+ return false;
+ push(key_size_);
+ key_size_ = 0;
+ lev_.st = state::key;
+ return true;
+}
+
+bool
+value_builder::
+on_string_part(
+ string_view s,
+ error_code& ec)
+{
+ 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
+value_builder::
+on_string(
+ string_view s,
+ error_code& ec)
+{
+ 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_);
+ }
+
+ string str(sp_);
+ auto const sv =
+ pop_chars(str_size_);
+ str_size_ = 0;
+ str.reserve(
+ sv.size() + s.size());
+ std::memcpy(
+ str.data(),
+ sv.data(), sv.size());
+ std::memcpy(
+ str.data() + sv.size(),
+ s.data(), s.size());
+ str.grow(sv.size() + s.size());
+ return emplace(
+ ec, std::move(str), sp_);
+}
+
+bool
+value_builder::
+on_int64(
+ int64_t i,
+ string_view,
+ error_code& ec)
+{
+ return emplace(ec, i, sp_);
+}
+
+bool
+value_builder::
+on_uint64(
+ uint64_t u,
+ string_view,
+ error_code& ec)
+{
+ return emplace(ec, u, sp_);
+}
+
+bool
+value_builder::
+on_double(
+ double d,
+ string_view,
+ error_code& ec)
+{
+ return emplace(ec, d, sp_);
+}
+
+bool
+value_builder::
+on_bool(
+ bool b,
+ error_code& ec)
+{
+ return emplace(ec, b, sp_);
+}
+
+bool
+value_builder::
+on_null(error_code& ec)
+{
+ return emplace(ec, nullptr, sp_);
+}
+
+//----------------------------------------------------------
+
+void
+value_builder::
+destroy() noexcept
+{
+ if(key_size_ > 0)
+ {
+ // remove partial key
+ BOOST_ASSERT(
+ lev_.st == state::obj);
+ BOOST_ASSERT(
+ str_size_ == 0);
+ rs_.subtract(key_size_);
+ key_size_ = 0;
+ }
+ else if(str_size_ > 0)
+ {
+ // remove partial string
+ rs_.subtract(str_size_);
+ str_size_ = 0;
+ }
+ // unwind the rest
+ do
+ {
+ switch(lev_.st)
+ {
+ case state::need_reset:
+ BOOST_ASSERT(
+ rs_.empty());
+ break;
+
+ case state::begin:
+ BOOST_ASSERT(
+ rs_.empty());
+ break;
+
+ case state::top:
+ if(lev_.count > 0)
+ {
+ BOOST_ASSERT(
+ lev_.count == 1);
+ auto ua =
+ pop_array();
+ BOOST_ASSERT(
+ ua.size() == 1);
+ BOOST_ASSERT(
+ rs_.empty());
+ }
+ else
+ {
+ // never parsed a value
+ rs_.subtract(
+ sizeof(value));
+ BOOST_ASSERT(
+ rs_.empty());
+ }
+ break;
+
+ case state::arr:
+ {
+ pop_array();
+ rs_.subtract(lev_.align);
+ pop(lev_);
+ break;
+ }
+
+ case state::obj:
+ {
+ pop_object();
+ rs_.subtract(lev_.align);
+ pop(lev_);
+ break;
+ }
+
+ case state::key:
+ {
+ std::uint32_t key_size;
+ pop(key_size);
+ pop_chars(key_size);
+ lev_.st = state::obj;
+ break;
+ }
+ }
+ }
+ while(! rs_.empty());
+}
+
+template
+void
+value_builder::
+push(T const& t)
+{
+ std::memcpy(
+ rs_.push(sizeof(T)),
+ &t, sizeof(T));
+}
+
+void
+value_builder::
+push_chars(string_view s)
+{
+ std::memcpy(
+ rs_.push(s.size()),
+ s.data(), s.size());
+}
+
+template
+void
+value_builder::
+emplace_object(
+ Args&&... args)
+{
+ union U
+ {
+ object::value_type v;
+ U(){}
+ ~U(){}
+ };
+ U u;
+ // perform stack reallocation up-front
+ // VFALCO This is more than we need
+ rs_.prepare(sizeof(object::value_type));
+ std::uint32_t key_size;
+ pop(key_size);
+ auto const key = pop_chars(key_size);
+ lev_.st = state::obj;
+ BOOST_ASSERT((rs_.top() %
+ alignof(object::value_type)) == 0);
+ ::new(rs_.behind(
+ sizeof(object::value_type)))
+ object::value_type(
+ key, std::forward(args)...);
+ rs_.add_unchecked(sizeof(u.v));
+ ++lev_.count;
+}
+
+template
+void
+value_builder::
+emplace_array(Args&&... args)
+{
+ // prevent splits from exceptions
+ rs_.prepare(sizeof(value));
+ BOOST_ASSERT((rs_.top() %
+ alignof(value)) == 0);
+ ::new(rs_.behind(sizeof(value))) value(
+ std::forward(args)...);
+ rs_.add_unchecked(sizeof(value));
+ ++lev_.count;
+}
+
+template
+bool
+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;
+ }
+ if(lev_.count <
+ array::max_size())
+ {
+ emplace_array(std::forward<
+ Args>(args)...);
+ return true;
+ }
+ ec = error::array_too_large;
+ return false;
+}
+
+template
+void
+value_builder::
+pop(T& t)
+{
+ std::memcpy(&t,
+ rs_.pop(sizeof(T)),
+ sizeof(T));
+}
+
+detail::unchecked_object
+value_builder::
+pop_object() noexcept
+{
+ rs_.subtract(sizeof(
+ object::value_type));
+ if(lev_.count == 0)
+ return { nullptr, 0, sp_ };
+ auto const n = lev_.count * sizeof(
+ object::value_type);
+ return { reinterpret_cast<
+ object::value_type*>(rs_.pop(n)),
+ lev_.count, sp_ };
+}
+
+detail::unchecked_array
+value_builder::
+pop_array() noexcept
+{
+ rs_.subtract(sizeof(value));
+ if(lev_.count == 0)
+ return { nullptr, 0, sp_ };
+ auto const n =
+ lev_.count * sizeof(value);
+ return { reinterpret_cast(
+ rs_.pop(n)), lev_.count, sp_ };
+}
+
+string_view
+value_builder::
+pop_chars(
+ std::size_t size) noexcept
+{
+ return {
+ reinterpret_cast(
+ rs_.pop(size)), size };
+}
+
+} // json
+} // boost
+
+#endif
diff --git a/include/boost/json/parser.hpp b/include/boost/json/parser.hpp
index 259115bb..34487b74 100644
--- a/include/boost/json/parser.hpp
+++ b/include/boost/json/parser.hpp
@@ -13,6 +13,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -34,7 +35,7 @@ namespace json {
@par Usage
- Before parsing a new JSON, the function @ref start
+ Before parsing a new JSON, the function @ref reset
must be called, optionally passing the storage
pointer to be used by the @ref value container into
which the parsed results are stored. After the
@@ -70,24 +71,7 @@ namespace json {
*/
class parser : public basic_parser
{
- friend class basic_parser;
- enum class state : char;
- struct level
- {
- std::uint32_t count;
- char align;
- state st;
- };
-
- storage_ptr sp_;
- detail::raw_stack rs_;
- std::uint32_t key_size_ = 0;
- std::uint32_t str_size_ = 0;
- level lev_;
-
- inline
- void
- destroy() noexcept;
+ value_builder vb_;
public:
/** Destructor.
@@ -95,9 +79,7 @@ public:
All dynamically allocated memory, including
any partial parsing results, is freed.
*/
- BOOST_JSON_DECL
- virtual
- ~parser();
+ ~parser() = default;
/** Default constructor.
@@ -107,7 +89,7 @@ public:
@note
Before any JSON can be parsed, the function
- @ref start must be called.
+ @ref reset must be called.
*/
BOOST_JSON_DECL
parser() noexcept;
@@ -120,7 +102,7 @@ public:
@note
Before any JSON can be parsed, the function
- @ref start must be called.
+ @ref reset must be called.
@@ -135,14 +117,13 @@ public:
explicit
parser(storage_ptr sp) noexcept;
-
/** Constructor.
Constructs a parser using the specified options.
@note
Before any JSON can be parsed, the function
- @ref start must be called.
+ @ref reset must be called.
@param opt The options for the parser.
*/
@@ -158,7 +139,7 @@ public:
@note
Before any JSON can be parsed, the function
- @ref start must be called.
+ @ref reset must be called.
@@ -185,7 +166,7 @@ public:
@par Exception Safety
- No-throw guarantee.
+ Strong guarantee.
@param n The number of bytes to reserve. A
good choices is `C * sizeof(value)` where
@@ -194,7 +175,7 @@ public:
*/
BOOST_JSON_DECL
void
- reserve(std::size_t n) noexcept;
+ reserve(std::size_t n);
/** Start parsing JSON incrementally.
@@ -208,7 +189,7 @@ public:
*/
BOOST_JSON_DECL
void
- start(storage_ptr sp = {}) noexcept;
+ reset(storage_ptr sp = {}) noexcept;
/** Parse JSON incrementally.
@@ -355,7 +336,7 @@ public:
@note
After this call, it is necessary to call
- @ref start to parse a new JSON incrementally.
+ @ref reset to parse a new JSON incrementally.
*/
BOOST_JSON_DECL
void
@@ -375,158 +356,6 @@ public:
BOOST_JSON_DECL
value
release();
-
-private:
- template
- void
- push(T const& t);
-
- inline
- void
- push_chars(string_view s);
-
- template
- void
- emplace_object(
- Args&&... args);
-
- template
- void
- emplace_array(
- Args&&... args);
-
- template
- bool
- emplace(
- error_code& ec,
- Args&&... args);
-
- template
- void
- pop(T& t);
-
- inline
- detail::unchecked_object
- pop_object() noexcept;
-
- inline
- detail::unchecked_array
- pop_array() noexcept;
-
- inline
- string_view
- pop_chars(
- std::size_t size) noexcept;
-
- 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&)
- {
- return true;
- }
-
- inline
- bool
- on_int64(
- int64_t i,
- string_view,
- error_code& ec);
-
- inline
- bool
- on_uint64(
- 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&);
-
- bool
- on_comment_part(
- string_view,
- error_code&)
- {
- return true;
- }
-
- bool
- on_comment(
- string_view,
- error_code&)
- {
- return true;
- }
};
//----------------------------------------------------------
diff --git a/include/boost/json/src.hpp b/include/boost/json/src.hpp
index 847ded22..a7e0aa2f 100644
--- a/include/boost/json/src.hpp
+++ b/include/boost/json/src.hpp
@@ -36,6 +36,7 @@ in a translation unit of the program.
#include
#include
#include
+#include
#include
#include
diff --git a/include/boost/json/value_builder.hpp b/include/boost/json/value_builder.hpp
new file mode 100644
index 00000000..c62df10f
--- /dev/null
+++ b/include/boost/json/value_builder.hpp
@@ -0,0 +1,555 @@
+//
+// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+// Official repository: https://github.com/cppalliance/json
+//
+
+#ifndef BOOST_JSON_VALUE_BUILDER_HPP
+#define BOOST_JSON_VALUE_BUILDER_HPP
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace boost {
+namespace json {
+
+//----------------------------------------------------------
+
+/** A factory for building a value DOM.
+
+ 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.
+
+ 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.
+
+ 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.
+*/
+class value_builder
+{
+ enum class state : char;
+ struct level
+ {
+ std::uint32_t count;
+ char align;
+ state st;
+ };
+
+ storage_ptr sp_;
+ detail::raw_stack rs_;
+ std::uint32_t key_size_ = 0;
+ std::uint32_t str_size_ = 0;
+ level lev_;
+
+public:
+ /** Destructor.
+
+ All dynamically allocated memory, including
+ any partially built results, 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.
+
+ @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
+ for the @ref value returned by @ref release.
+
+ @param sp The @ref storage_ptr to use for
+ intermediate storage allocations.
+ */
+ BOOST_JSON_DECL
+ explicit
+ value_builder(storage_ptr sp = {}) noexcept;
+
+ /** Reserve internal storage space.
+
+ This function reserves space for `n` bytes
+ in the parser's internal temporary storage.
+ The request is only a hint to the
+ 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.
+ */
+ BOOST_JSON_DECL
+ void
+ reserve(std::size_t n);
+
+ /** Prepare the builder for 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
+ dynamically allocated memory is preserved which
+ may be reused to build new values.
+
+ @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.
+ */
+ BOOST_JSON_DECL
+ void
+ reset(storage_ptr sp = {}) noexcept;
+
+ /** Return the parsed JSON as a @ref value.
+
+ If @ref is_complete() returns `true`, then the
+ parsed value is returned. Otherwise an
+ exception is thrown.
+
+ @throw std::logic_error `! is_complete()`
+
+ @return The parsed value. Ownership of this
+ value is transferred to the caller.
+ */
+ BOOST_JSON_DECL
+ value
+ release();
+
+ /** Discard all parsed JSON results.
+
+ This function destroys all intermediate parsing
+ results, while preserving dynamically allocated
+ internal memory which may be reused on a
+ subsequent parse.
+
+ @note
+
+ After this call, it is necessary to call
+ @ref start to parse a new JSON incrementally.
+ */
+ BOOST_JSON_DECL
+ void
+ clear() noexcept;
+
+ //--------------------------------------------
+
+ /** Begin building a new value.
+
+ This function must be called exactly once
+ after calling @ref reset, before any other
+ event functions are invoked.
+
+ @return `true` on success.
+
+ @param ec Set to the error, if any occurred.
+ */
+ BOOST_JSON_DECL
+ bool
+ on_document_begin(
+ error_code& ec);
+
+ /** Finish building a new value.
+
+ This function must be called exactly once
+ before calling @ref release, and after all
+ event functions have been called.
+
+ @return `true` on success.
+
+ @param ec Set to the error, if any occurred.
+ */
+ BOOST_JSON_DECL
+ bool
+ on_document_end(
+ error_code& ec);
+
+ /** Begin building 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.
+
+ @return `true` on success.
+
+ @param ec Set to the error, if any occurred.
+ */
+ BOOST_JSON_DECL
+ bool
+ on_object_begin(
+ error_code& ec);
+
+ /** Finish building 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.
+
+ @return `true` on success.
+
+ @param ec Set to the error, if any occurred.
+ */
+ BOOST_JSON_DECL
+ bool
+ on_object_end(
+ error_code& ec);
+
+ /** 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.
+
+ 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.
+
+ @return `true` on success.
+
+ @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);
+
+ /** Finish creating a key.
+
+ 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.
+
+ @return `true` on success.
+
+ @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);
+
+ /** Begin or continue creating 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.
+
+ @return `true` on success.
+
+ @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);
+
+ /** Create a string or finish creating 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.
+
+ @return `true` on success.
+
+ @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);
+
+ /** Begin building a number from a string.
+
+ 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.
+
+ @note This function has no effect and always
+ returns `true`.
+
+ @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.
+ */
+ BOOST_JSON_DECL
+ bool
+ on_int64(
+ int64_t i,
+ string_view s,
+ error_code& ec);
+
+ /** 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 unsigned integer to build.
+
+ @param s The characters to append. This value is ignored.
+
+ @param ec Set to the error, if any occurred.
+ */
+ BOOST_JSON_DECL
+ bool
+ on_uint64(
+ uint64_t u,
+ string_view s,
+ error_code& ec);
+
+ /** 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 floating point number to build.
+
+ @param s The characters to append. This value is ignored.
+
+ @param ec Set to the error, if any occurred.
+ */
+ BOOST_JSON_DECL
+ bool
+ on_double(
+ double d,
+ string_view s,
+ error_code& ec);
+
+ /** Build 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.
+
+ @return `true` on success.
+
+ @param b The boolean to build.
+
+ @param ec Set to the error, if any occurred.
+ */
+ BOOST_JSON_DECL
+ bool
+ on_bool(
+ bool b,
+ error_code& ec);
+
+ /** 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.
+
+ @return `true` on success.
+
+ @param ec Set to the error, if any occurred.
+ */
+ 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;
+ }
+
+private:
+ inline
+ void
+ destroy() noexcept;
+
+ template
+ void
+ push(T const& t);
+
+ inline
+ void
+ push_chars(string_view s);
+
+ template
+ void
+ emplace_object(
+ Args&&... args);
+
+ template
+ void
+ emplace_array(
+ Args&&... args);
+
+ template
+ bool
+ emplace(
+ error_code& ec,
+ Args&&... args);
+
+ template
+ void
+ pop(T& t);
+
+ inline
+ detail::unchecked_object
+ pop_object() noexcept;
+
+ inline
+ detail::unchecked_array
+ pop_array() noexcept;
+
+ inline
+ string_view
+ pop_chars(
+ std::size_t size) noexcept;
+};
+
+} // json
+} // boost
+
+#ifdef BOOST_JSON_HEADER_ONLY
+#include
+#endif
+
+#endif
diff --git a/test/Jamfile b/test/Jamfile
index 7bf0f907..8b327e4e 100644
--- a/test/Jamfile
+++ b/test/Jamfile
@@ -43,8 +43,9 @@ local SOURCES =
string.cpp
string_view.cpp
system_error.cpp
- value_from.cpp
value.cpp
+ value_builder.cpp
+ value_from.cpp
value_to.cpp
value_ref.cpp
ryu/d2s_intrinsics_test.cpp
diff --git a/test/error.cpp b/test/error.cpp
index 8837494c..cb92c719 100644
--- a/test/error.cpp
+++ b/test/error.cpp
@@ -87,7 +87,6 @@ public:
check(condition::assign_error, error::integer_overflow);
check(condition::assign_error, error::not_exact);
- check(error::need_start);
check(error::test_failure);
}
};
diff --git a/test/parser.cpp b/test/parser.cpp
index 5364c3ff..5e561e17 100644
--- a/test/parser.cpp
+++ b/test/parser.cpp
@@ -38,7 +38,7 @@ public:
{
parser p(po);
error_code ec;
- p.start(std::move(sp));
+ p.reset(std::move(sp));
p.write(s.data(), s.size(), ec);
if(BOOST_TEST(! ec))
p.finish(ec);
@@ -108,7 +108,7 @@ public:
mr.fail_max = 0;
parser p(po);
error_code ec;
- p.start(&mr);
+ p.reset(&mr);
p.write(s.data(), i, ec);
if(BOOST_TEST(! ec))
p.write(
@@ -265,7 +265,7 @@ public:
auto const N = js.size() / 2;
error_code ec;
parser p;
- p.start();
+ p.reset();
p.write(js.data(), N, ec);
if(BOOST_TEST(! ec))
{
@@ -298,7 +298,7 @@ public:
BOOST_TEST_CHECKPOINT();
error_code ec;
parser p;
- p.start();
+ p.reset();
p.write(s.data(), s.size(), ec);
if(BOOST_TEST(! ec))
p.finish(ec);
@@ -595,7 +595,7 @@ public:
{
error_code ec;
parser p;
- p.start();
+ p.reset();
BOOST_TEST(
p.depth() == 0);
BOOST_TEST(
@@ -667,7 +667,7 @@ public:
{
error_code ec;
parser p;
- p.start();
+ p.reset();
BOOST_TEST(
p.depth() == 0);
BOOST_TEST(
@@ -690,19 +690,10 @@ public:
p.reserve(1024);
}
- // need start error
- {
- parser p;
- error_code ec;
- p.write("", 0, ec);
- BOOST_TEST(
- ec == error::need_start);
- }
-
// destroy after start
{
parser p;
- p.start();
+ p.reset();
}
// release before done
@@ -724,13 +715,13 @@ public:
{
{
parser p;
- p.start();
+ p.reset();
BOOST_TEST(p.write(
"null", 4) == 4);
}
{
parser p;
- p.start();
+ p.reset();
BOOST_TEST_THROWS(
p.write("x", 1),
system_error);
@@ -852,7 +843,7 @@ R"xx({
make_counted_resource();
parser p(sp);
error_code ec;
- p.start();
+ p.reset();
p.write(in.data(), in.size(), ec);
if(BOOST_TEST(! ec))
p.finish(ec);
@@ -862,7 +853,7 @@ R"xx({
}
try
{
- p.start();
+ p.reset();
p.write(in.data(), in.size());
p.finish();
BOOST_TEST(to_string(p.release()) == out);
@@ -967,7 +958,7 @@ R"xx({
{
parser p;
error_code ec;
- p.start();
+ p.reset();
p.write("nullx", 5, ec);
BOOST_TEST(ec ==
error::extra_data);
@@ -976,7 +967,7 @@ R"xx({
{
parser p;
error_code ec;
- p.start();
+ p.reset();
p.write("[123,", 5, ec);
if(BOOST_TEST(! ec))
p.finish(ec);
diff --git a/test/snippets.cpp b/test/snippets.cpp
index 8bf9294e..55c51b86 100644
--- a/test/snippets.cpp
+++ b/test/snippets.cpp
@@ -735,7 +735,7 @@ usingParsing()
parser p;
// This must be called once before parsing every new JSON.
- p.start();
+ p.reset();
// Write the entire character buffer, indicating
// to the parser that there is no more data.
@@ -745,7 +745,7 @@ usingParsing()
// Take ownership of the resulting value.
value jv = p.release();
- // At this point the parser may be re-used by calling p.start() again.
+ // At this point the parser may be re-used by calling p.reset() again.
//]
}
@@ -756,7 +756,7 @@ usingParsing()
error_code ec;
// This must be called once before parsing every new JSON
- p.start();
+ p.reset();
// Write the first part of the buffer
p.write( "[1,2,", 5, ec);
@@ -772,7 +772,7 @@ usingParsing()
if(! ec)
value jv = p.release();
- // At this point the parser may be re-used by calling p.start() again.
+ // At this point the parser may be re-used by calling p.reset() again.
//]
}
@@ -786,7 +786,7 @@ usingParsing()
monotonic_resource mr;
// Use the monotonic resource for the parsed value
- p.start( &mr );
+ p.reset( &mr );
// Write the entire JSON
p.write( "[1,2,3,4,5]", 11, ec );
@@ -812,7 +812,7 @@ usingParsing()
// Fully parses a valid JSON string and
// extracts the resulting value
- p.start( sp );
+ p.reset( sp );
p.write( "[true, false, 1, 0]", 19, ec );
p.finish( ec );
@@ -823,7 +823,7 @@ usingParsing()
// The intermediate storage that was used
// for the last value will be reused here.
- p.start( sp );
+ p.reset( sp );
p.write( "[null]", 6, ec );
p.finish( ec );
@@ -845,7 +845,7 @@ usingParsing()
parser p;
error_code ec;
- p.start();
+ p.reset();
p.write( good.data(), good.size(), ec );
// Valid JSON
@@ -853,7 +853,7 @@ usingParsing()
ec.clear();
- p.start();
+ p.reset();
p.write( bad.data(), bad.size(), ec );
// Error, trailing commas are not permitted
@@ -868,29 +868,27 @@ usingParsing()
string_view comment = "/* example comment */[1, 2, 3]";
// Comments are not permitted by default
- parser standard;
+ parser p1;
parse_options po;
po.allow_comments = true;
-
+
// Constructs a parser that will treat
// comments as whitespace.
- parser extended(po);
+ parser p2(po);
error_code ec;
- standard.start();
- standard.write( comment.data(),
- comment.size(), ec );
+ p1.reset();
+ p1.write( comment.data(), comment.size(), ec );
// Error, invalid JSON
assert( ec );
ec.clear();
- extended.start();
- extended.write( comment.data(),
- comment.size(), ec );
+ p2.reset();
+ p2.write( comment.data(), comment.size(), ec );
// Ok, comments are permitted
assert( ! ec );
diff --git a/test/value_builder.cpp b/test/value_builder.cpp
new file mode 100644
index 00000000..d2157d5a
--- /dev/null
+++ b/test/value_builder.cpp
@@ -0,0 +1,43 @@
+//
+// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+// Official repository: https://github.com/vinniefalco/BeastLounge
+//
+
+// Test that header file is self-contained.
+#include
+
+#include "test_suite.hpp"
+
+namespace boost {
+namespace json {
+
+class value_builder_test
+{
+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();
+ }
+
+ void
+ run()
+ {
+ testBuilder();
+ }
+};
+
+TEST_SUITE(value_builder_test, "boost.json.value_builder");
+
+} // json
+} // boost