From c06b17aab81ec89ece8471867e68ea210d63caab Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Wed, 28 Dec 2022 09:05:08 -0800 Subject: [PATCH] caller provided serializer storage --- include/boost/json/detail/impl/stack.ipp | 29 ++++++++++---- include/boost/json/detail/stack.hpp | 18 ++++++--- include/boost/json/impl/serialize.ipp | 32 ++++++++++----- include/boost/json/impl/serializer.ipp | 12 ++++++ include/boost/json/serializer.hpp | 34 +++++++++++++++- test/serializer.cpp | 50 +++++++++++++++++++++++- 6 files changed, 150 insertions(+), 25 deletions(-) diff --git a/include/boost/json/detail/impl/stack.ipp b/include/boost/json/detail/impl/stack.ipp index cca46cef7..ab0467821 100644 --- a/include/boost/json/detail/impl/stack.ipp +++ b/include/boost/json/detail/impl/stack.ipp @@ -19,9 +19,21 @@ namespace detail { stack:: ~stack() { - if(buf_) + if(base_ != buf_) sp_->deallocate( - buf_, cap_); + base_, cap_); +} + +stack:: +stack( + storage_ptr sp, + unsigned char* buf, + std::size_t buf_size) noexcept + : sp_(std::move(sp)) + , cap_(buf_size) + , base_(buf) + , buf_(buf) +{ } void @@ -30,15 +42,16 @@ reserve(std::size_t n) { if(cap_ >= n) return; - auto const buf = static_cast< - char*>(sp_->allocate(n)); - if(buf_) + auto const base = static_cast< + unsigned char*>(sp_->allocate(n)); + if(base_) { if(size_ > 0) - std::memcpy(buf, buf_, size_); - sp_->deallocate(buf_, cap_); + std::memcpy(base, base_, size_); + if(base_ != buf_) + sp_->deallocate(base_, cap_); } - buf_ = buf; + base_ = base; cap_ = n; } diff --git a/include/boost/json/detail/stack.hpp b/include/boost/json/detail/stack.hpp index 3d64ab944..be2a6137b 100644 --- a/include/boost/json/detail/stack.hpp +++ b/include/boost/json/detail/stack.hpp @@ -23,12 +23,20 @@ class stack storage_ptr sp_; std::size_t cap_ = 0; std::size_t size_ = 0; - char* buf_ = nullptr; + unsigned char* base_ = nullptr; + unsigned char* buf_ = nullptr; public: BOOST_JSON_DECL ~stack(); + stack() = default; + + stack( + storage_ptr sp, + unsigned char* buf, + std::size_t buf_size) noexcept; + bool empty() const noexcept { @@ -57,7 +65,7 @@ class stack //BOOST_ASSERT(cap_ >= size_ + n); reserve(size_ + n); std::memcpy( - buf_ + size_, &t, n); + base_ + size_, &t, n); size_ += n; } @@ -68,7 +76,7 @@ class stack auto const n = sizeof(T); BOOST_ASSERT(size_ + n <= cap_); std::memcpy( - buf_ + size_, &t, n); + base_ + size_, &t, n); size_ += n; } @@ -79,7 +87,7 @@ class stack auto const n = sizeof(T); BOOST_ASSERT(size_ >= n); std::memcpy(&t, - buf_ + size_ - n, n); + base_ + size_ - n, n); } template @@ -90,7 +98,7 @@ class stack BOOST_ASSERT(size_ >= n); size_ -= n; std::memcpy( - &t, buf_ + size_, n); + &t, base_ + size_, n); } }; diff --git a/include/boost/json/impl/serialize.ipp b/include/boost/json/impl/serialize.ipp index f88f6a42d..73b0afae8 100644 --- a/include/boost/json/impl/serialize.ipp +++ b/include/boost/json/impl/serialize.ipp @@ -65,9 +65,13 @@ std::string serialize( value const& jv) { - std::string s; - serializer sr; + unsigned char buf[256]; + serializer sr( + storage_ptr(), + buf, + sizeof(buf)); sr.reset(&jv); + std::string s; serialize_impl(s, sr); return s; } @@ -76,8 +80,12 @@ std::string serialize( array const& arr) { + unsigned char buf[256]; + serializer sr( + storage_ptr(), + buf, + sizeof(buf)); std::string s; - serializer sr; sr.reset(&arr); serialize_impl(s, sr); return s; @@ -87,8 +95,12 @@ std::string serialize( object const& obj) { + unsigned char buf[256]; + serializer sr( + storage_ptr(), + buf, + sizeof(buf)); std::string s; - serializer sr; sr.reset(&obj); serialize_impl(s, sr); return s; @@ -98,11 +110,7 @@ std::string serialize( string const& str) { - std::string s; - serializer sr; - sr.reset(&str); - serialize_impl(s, sr); - return s; + return serialize( str.subview() ); } // this is here for key_value_pair::key() @@ -110,8 +118,12 @@ std::string serialize( string_view sv) { + unsigned char buf[256]; + serializer sr( + storage_ptr(), + buf, + sizeof(buf)); std::string s; - serializer sr; sr.reset(sv); serialize_impl(s, sr); return s; diff --git a/include/boost/json/impl/serializer.ipp b/include/boost/json/impl/serializer.ipp index 002219896..723bc5a2b 100644 --- a/include/boost/json/impl/serializer.ipp +++ b/include/boost/json/impl/serializer.ipp @@ -40,6 +40,18 @@ enum class serializer::state : char serializer:: ~serializer() noexcept = default; +serializer:: +serializer( + storage_ptr sp, + unsigned char* buf, + std::size_t buf_size) noexcept + : st_( + std::move(sp), + buf, + buf_size) +{ +} + bool serializer:: suspend(state st) diff --git a/include/boost/json/serializer.hpp b/include/boost/json/serializer.hpp index 808000c4c..64752a4a3 100644 --- a/include/boost/json/serializer.hpp +++ b/include/boost/json/serializer.hpp @@ -114,7 +114,7 @@ class serializer BOOST_JSON_DECL ~serializer() noexcept; - /** Default constructor + /** Constructor This constructs a serializer with no value. The value may be set later by calling @ref reset. @@ -130,6 +130,38 @@ class serializer BOOST_JSON_DECL serializer() noexcept; + /** Constructor + + This constructs a serializer with no value. + The value may be set later by calling @ref reset. + If serialization is attempted with no value, + the output is as if a null value is serialized. + + @par Complexity + Constant. + + @par Exception Safety + No-throw guarantee. + + @param sp A pointer to the @ref memory_resource + to use when producing partial output. + Shared ownership of the memory resource + is retained until the serializer is + destroyed. + + @param buf An optional static buffer to + use for temporary storage when producing + partial output. + + @param buf_size The number of bytes of + valid memory pointed to by `buf`. + */ + BOOST_JSON_DECL + serializer( + storage_ptr sp, + unsigned char* buf = nullptr, + std::size_t buf_size = 0) noexcept; + /** Returns `true` if the serialization is complete This function returns `true` when all of the diff --git a/test/serializer.cpp b/test/serializer.cpp index 02bc89c58..6875c132b 100644 --- a/test/serializer.cpp +++ b/test/serializer.cpp @@ -10,8 +10,10 @@ // Test that header file is self-contained. #include -#include #include +#include +#include +#include #include #include "parse-vectors.hpp" @@ -368,6 +370,52 @@ class serializer_test BOOST_TEST(sr.read(buf) == "null"); } + // serializer(storage_ptr) + { + { + serializer sr((storage_ptr())); + char buf[32]; + BOOST_TEST(sr.read(buf) == "null"); + } + { + serializer sr(get_null_resource()); + char buf[1]; + BOOST_TEST_THROWS( + sr.read(buf), + std::exception); + } + } + + // serializer(storage_ptr, unsigned char*, size_t) + { + { + unsigned char temp[256]; + serializer sr( + get_null_resource(), + temp, + sizeof(temp)); + char buf[32]; + BOOST_TEST(sr.read(&buf[0], 1) == "n"); + BOOST_TEST(sr.read(&buf[1], 2) == "ul"); + BOOST_TEST(sr.read(&buf[3], 1) == "l"); + BOOST_TEST( + std::memcmp(buf, "null", 4) == 0); + } + { + unsigned char temp[1]; + serializer sr( + get_null_resource(), + temp, + sizeof(temp)); + array ar({1, 2, 3}); + sr.reset(&ar); + char buf[32]; + BOOST_TEST_THROWS( + sr.read(&buf[0], 1), + std::exception); + } + } + // done() { value jv = 1;