mirror of
https://github.com/boostorg/json.git
synced 2025-05-11 21:53:58 +00:00
storage_ptr uses memory_resource
This commit is contained in:
parent
33e8e468cb
commit
a47b0f3fc1
24
.travis.yml
24
.travis.yml
@ -197,20 +197,22 @@ jobs:
|
||||
- COMMENT=standalone
|
||||
- STANDALONE=1
|
||||
- B2_VARIANT=variant=debug
|
||||
- B2_TOOLSET=gcc-7
|
||||
- B2_TOOLSET=gcc-9
|
||||
- B2_CXXSTD=17
|
||||
- B2_DEFINES="define=BOOST_JSON_STANDALONE=1"
|
||||
addons: *gcc-7
|
||||
addons: *gcc-9
|
||||
|
||||
- os: "linux"
|
||||
env:
|
||||
- COMMENT=standalone
|
||||
- STANDALONE=1
|
||||
- B2_VARIANT=variant=debug
|
||||
- B2_TOOLSET=clang-7
|
||||
- B2_CXXSTD=17
|
||||
- B2_DEFINES="define=BOOST_JSON_STANDALONE=1"
|
||||
addons: *clang-7
|
||||
# VFALCO This needs to use a later version of
|
||||
# libstdc++ which has <memory_resource>
|
||||
#- os: "linux"
|
||||
# env:
|
||||
# - COMMENT=standalone
|
||||
# - STANDALONE=1
|
||||
# - B2_VARIANT=variant=debug
|
||||
# - B2_TOOLSET=clang-9
|
||||
# - B2_CXXSTD=17
|
||||
# - B2_DEFINES="define=BOOST_JSON_STANDALONE=1"
|
||||
# addons: *clang-9
|
||||
|
||||
# libstdc++
|
||||
- { os: "linux", dist: "trusty", # xenial has libstdc++ from gcc 5.4.0 with newer ABI
|
||||
|
15
README.md
15
README.md
@ -40,13 +40,14 @@ return types in public interfaces.
|
||||
|
||||
The design of the library also achieves these goals:
|
||||
|
||||
* Requires only C++11
|
||||
* Support stateful allocators
|
||||
* Top performance of general libraries
|
||||
* Uniform interface on all C++ versions
|
||||
* Strict parser and serializer which work incrementally
|
||||
* Security-aware treatment of untrusted inputs
|
||||
* Fast compilation performance
|
||||
* Requires only C++11.
|
||||
* Support stateful allocators.
|
||||
* Top performance of general libraries.
|
||||
* Uniform interface on all C++ versions.
|
||||
* Key lookup in objects has constant average complexity.
|
||||
* Strict parser and serializer which work incrementally.
|
||||
* Security-aware treatment of untrusted inputs.
|
||||
* Fast compilation performance.
|
||||
|
||||
## CMake
|
||||
|
||||
|
@ -320,8 +320,8 @@ public:
|
||||
parser p;
|
||||
while(repeat--)
|
||||
{
|
||||
scoped_storage<pool> ss;
|
||||
p.start(ss);
|
||||
monotonic_resource mr;
|
||||
p.start(&mr);
|
||||
error_code ec;
|
||||
p.write(s.data(), s.size(), ec);
|
||||
if(! ec)
|
||||
@ -335,8 +335,8 @@ public:
|
||||
string_view s,
|
||||
std::size_t repeat) const override
|
||||
{
|
||||
scoped_storage<pool> sp;
|
||||
auto jv = json::parse(s, sp);
|
||||
monotonic_resource mr;
|
||||
auto jv = json::parse(s, &mr);
|
||||
serializer sr;
|
||||
string out;
|
||||
out.reserve(512);
|
||||
|
@ -45,6 +45,7 @@ The design of the library also achieves these goals:
|
||||
* Safe, easy to use interfaces.
|
||||
* Stateful allocator support.
|
||||
* Uniform interface on all C++ versions.
|
||||
* Key lookup in objects has constant average complexity.
|
||||
* Strict parser and serializer which work incrementally.
|
||||
* Security-aware treatment of untrusted inputs.
|
||||
* Fast compilation performance.
|
||||
|
@ -15,12 +15,11 @@
|
||||
#include <boost/json/array.hpp>
|
||||
#include <boost/json/error.hpp>
|
||||
#include <boost/json/kind.hpp>
|
||||
#include <boost/json/monotonic_resource.hpp>
|
||||
#include <boost/json/number_cast.hpp>
|
||||
#include <boost/json/object.hpp>
|
||||
#include <boost/json/parser.hpp>
|
||||
#include <boost/json/pool.hpp>
|
||||
#include <boost/json/serializer.hpp>
|
||||
#include <boost/json/storage.hpp>
|
||||
#include <boost/json/storage_ptr.hpp>
|
||||
#include <boost/json/string.hpp>
|
||||
#include <boost/json/to_value.hpp>
|
||||
|
@ -149,9 +149,10 @@ public:
|
||||
*/
|
||||
~array()
|
||||
{
|
||||
if( impl_.data() &&
|
||||
sp_->need_free())
|
||||
destroy();
|
||||
if( ! impl_.data() ||
|
||||
sp_.is_not_counted_and_deallocate_is_null())
|
||||
return;
|
||||
destroy();
|
||||
}
|
||||
|
||||
#ifndef BOOST_JSON_DOCS
|
||||
|
@ -40,6 +40,9 @@ generic_category();
|
||||
using boost::system::generic_category;
|
||||
#endif
|
||||
|
||||
/// The type of memory_resource used by the library.
|
||||
using memory_resource = boost::container::pmr::memory_resource;
|
||||
|
||||
#else
|
||||
|
||||
using error_code = std::error_code;
|
||||
@ -48,6 +51,7 @@ using error_condition = std::error_condition;
|
||||
using string_view = std::string_view;
|
||||
using system_error = std::system_error;
|
||||
using std::generic_category;
|
||||
using memory_resource = std::pmr::memory_resource;
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -13,12 +13,14 @@
|
||||
#ifndef BOOST_JSON_STANDALONE
|
||||
# include <boost/config.hpp>
|
||||
# include <boost/assert.hpp>
|
||||
# include <boost/container/pmr/memory_resource.hpp>
|
||||
# include <boost/system/error_code.hpp>
|
||||
# include <boost/system/system_error.hpp>
|
||||
# include <boost/utility/string_view.hpp>
|
||||
# include <boost/throw_exception.hpp>
|
||||
#else
|
||||
# include <cassert>
|
||||
# include <memory_resource>
|
||||
# include <string_view>
|
||||
# include <system_error>
|
||||
#endif
|
||||
|
@ -7,36 +7,38 @@
|
||||
// Official repository: https://github.com/vinniefalco/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_IMPL_STORAGE_HPP
|
||||
#define BOOST_JSON_IMPL_STORAGE_HPP
|
||||
#ifndef BOOST_JSON_DETAIL_COUNTED_RESOURCE_HPP
|
||||
#define BOOST_JSON_DETAIL_COUNTED_RESOURCE_HPP
|
||||
|
||||
#include <utility>
|
||||
#include <boost/json/config.hpp>
|
||||
#include <atomic>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
struct counted_resource
|
||||
: memory_resource
|
||||
{
|
||||
std::atomic<std::size_t> refs{ 1 };
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct storage_impl : storage
|
||||
class counted_resource_impl final
|
||||
: public counted_resource
|
||||
{
|
||||
T t;
|
||||
|
||||
public:
|
||||
template<class... Args>
|
||||
constexpr
|
||||
explicit
|
||||
storage_impl(
|
||||
bool counted,
|
||||
counted_resource_impl(
|
||||
Args&&... args)
|
||||
: storage(
|
||||
T::id,
|
||||
T::need_free,
|
||||
counted)
|
||||
, t(std::forward<Args>(args)...)
|
||||
: t(std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
|
||||
void*
|
||||
allocate(
|
||||
do_allocate(
|
||||
std::size_t n,
|
||||
std::size_t align) override
|
||||
{
|
||||
@ -44,12 +46,20 @@ struct storage_impl : storage
|
||||
}
|
||||
|
||||
void
|
||||
deallocate(
|
||||
do_deallocate(
|
||||
void* p,
|
||||
std::size_t n,
|
||||
std::size_t align) noexcept override
|
||||
std::size_t align) override
|
||||
{
|
||||
t.deallocate(p, n, align);
|
||||
return t.deallocate(p, n, align);
|
||||
}
|
||||
|
||||
bool
|
||||
do_is_equal(
|
||||
memory_resource const& mr) const noexcept override
|
||||
{
|
||||
// VFALCO Is always false ok?
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
56
include/boost/json/detail/default_resource.hpp
Normal file
56
include/boost/json/detail/default_resource.hpp
Normal file
@ -0,0 +1,56 @@
|
||||
//
|
||||
// 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/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_DEFAULT_RESOURCE_HPP
|
||||
#define BOOST_JSON_DEFAULT_RESOURCE_HPP
|
||||
|
||||
#include <boost/json/config.hpp>
|
||||
#include <new>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
namespace detail {
|
||||
|
||||
/** A simple memory resource that uses operator new and delete.
|
||||
*/
|
||||
class default_resource final
|
||||
: public memory_resource
|
||||
{
|
||||
public:
|
||||
void*
|
||||
do_allocate(
|
||||
std::size_t n,
|
||||
std::size_t align) override
|
||||
{
|
||||
return ::operator new(n);
|
||||
}
|
||||
|
||||
void
|
||||
do_deallocate(
|
||||
void* p,
|
||||
std::size_t,
|
||||
std::size_t) override
|
||||
{
|
||||
::operator delete(p);
|
||||
}
|
||||
|
||||
bool
|
||||
do_is_equal(
|
||||
memory_resource const& mr) const noexcept
|
||||
{
|
||||
return dynamic_cast<
|
||||
default_resource const*>(&mr) != nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
} // detail
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
#endif
|
@ -28,10 +28,12 @@ index_of(value const* pos) const noexcept ->
|
||||
unchecked_array::
|
||||
~unchecked_array()
|
||||
{
|
||||
if(data_ && sp_->need_free())
|
||||
for(unsigned long i = 0;
|
||||
i < size_; ++i)
|
||||
data_[i].~value();
|
||||
if(! data_ ||
|
||||
sp_.is_not_counted_and_deallocate_is_null())
|
||||
return;
|
||||
for(unsigned long i = 0;
|
||||
i < size_; ++i)
|
||||
data_[i].~value();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -96,8 +96,10 @@ array_impl::
|
||||
destroy(
|
||||
storage_ptr const& sp) noexcept
|
||||
{
|
||||
if(tab_ && sp->need_free())
|
||||
destroy_impl(sp);
|
||||
if(! tab_ ||
|
||||
sp.is_not_counted_and_deallocate_is_null())
|
||||
return;
|
||||
destroy_impl(sp);
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
@ -132,10 +132,12 @@ destroy(
|
||||
key_value_pair* p,
|
||||
std::size_t n) noexcept
|
||||
{
|
||||
// VFALCO We check need_free here even
|
||||
// VFALCO We check again here even
|
||||
// though some callers already check it.
|
||||
if( n == 0 ||
|
||||
! p->value().storage()->need_free())
|
||||
if(n == 0 || ! p)
|
||||
return;
|
||||
auto const& sp = p->value().storage();
|
||||
if(sp.is_not_counted_and_deallocate_is_null())
|
||||
return;
|
||||
p += n;
|
||||
while(n--)
|
||||
|
@ -53,7 +53,7 @@ public:
|
||||
destroy(storage_ptr const& sp) noexcept
|
||||
{
|
||||
if( tab_ == nullptr ||
|
||||
! sp->need_free())
|
||||
sp.is_not_counted_and_deallocate_is_null())
|
||||
return;
|
||||
do_destroy(sp);
|
||||
}
|
||||
|
@ -22,7 +22,6 @@ namespace boost {
|
||||
namespace json {
|
||||
|
||||
class value;
|
||||
class string_test;
|
||||
|
||||
namespace detail {
|
||||
|
||||
|
@ -464,9 +464,10 @@ array::
|
||||
destroy(
|
||||
value* first, value* last) noexcept
|
||||
{
|
||||
if(sp_->need_free())
|
||||
while(last != first)
|
||||
(*--last).~value();
|
||||
if(sp_.is_not_counted_and_deallocate_is_null())
|
||||
return;
|
||||
while(last != first)
|
||||
(*--last).~value();
|
||||
}
|
||||
|
||||
void
|
||||
|
136
include/boost/json/impl/monotonic_resource.ipp
Normal file
136
include/boost/json/impl/monotonic_resource.ipp
Normal file
@ -0,0 +1,136 @@
|
||||
//
|
||||
// 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/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_IMPL_MONOTONIC_RESOURCE_IPP
|
||||
#define BOOST_JSON_IMPL_MONOTONIC_RESOURCE_IPP
|
||||
|
||||
#include <boost/json/monotonic_resource.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
struct monotonic_resource::block
|
||||
{
|
||||
std::size_t const size;
|
||||
std::uintptr_t top;
|
||||
block* next;
|
||||
|
||||
block(
|
||||
std::size_t size_,
|
||||
block* next_)
|
||||
: size(size_)
|
||||
, top(reinterpret_cast<
|
||||
std::uintptr_t>(this+1))
|
||||
, next(next_)
|
||||
{
|
||||
}
|
||||
|
||||
void*
|
||||
alloc(
|
||||
std::size_t n,
|
||||
std::size_t align) noexcept
|
||||
{
|
||||
// must be power of 2
|
||||
BOOST_ASSERT(
|
||||
(align & (align - 1)) == 0);
|
||||
auto i = top;
|
||||
if((i & (align - 1)) != 0)
|
||||
i = (i | (align - 1)) + 1;
|
||||
if(i + n > (reinterpret_cast<
|
||||
std::uintptr_t>(this+1) + size))
|
||||
return nullptr;
|
||||
top = i + n;
|
||||
return reinterpret_cast<void*>(i);
|
||||
}
|
||||
};
|
||||
|
||||
auto
|
||||
monotonic_resource::
|
||||
alloc_block(std::size_t size) ->
|
||||
block&
|
||||
{
|
||||
auto const n = (
|
||||
size + sizeof(block) - 1) /
|
||||
sizeof(block);
|
||||
auto const bytes =
|
||||
(n + 1) * sizeof(block);
|
||||
auto& b = *::new(
|
||||
::operator new(bytes)) block(
|
||||
n * sizeof(block), head_);
|
||||
head_ = &b;
|
||||
return b;
|
||||
}
|
||||
|
||||
monotonic_resource::
|
||||
~monotonic_resource()
|
||||
{
|
||||
for(auto b = head_; b;)
|
||||
{
|
||||
auto next = b->next;
|
||||
::operator delete(b);
|
||||
b = next;
|
||||
}
|
||||
}
|
||||
|
||||
monotonic_resource::
|
||||
monotonic_resource() noexcept
|
||||
: block_size_(64 * 1024)
|
||||
{
|
||||
}
|
||||
|
||||
monotonic_resource::
|
||||
monotonic_resource(
|
||||
std::size_t block_size) noexcept
|
||||
: block_size_(block_size)
|
||||
{
|
||||
}
|
||||
|
||||
void*
|
||||
monotonic_resource::
|
||||
do_allocate(
|
||||
std::size_t n,
|
||||
std::size_t align)
|
||||
{
|
||||
if(head_)
|
||||
{
|
||||
auto p = head_->alloc(n, align);
|
||||
if(p)
|
||||
return p;
|
||||
}
|
||||
if(n > block_size_ - 2 * align)
|
||||
alloc_block(n + 2 * align);
|
||||
else
|
||||
alloc_block(block_size_);
|
||||
auto p = head_->alloc(n, align);
|
||||
BOOST_ASSERT(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
monotonic_resource::
|
||||
do_deallocate(
|
||||
void*,
|
||||
std::size_t,
|
||||
std::size_t)
|
||||
{
|
||||
// nothing
|
||||
}
|
||||
|
||||
bool
|
||||
monotonic_resource::
|
||||
do_is_equal(
|
||||
memory_resource const& mr) const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
#endif
|
@ -1,86 +0,0 @@
|
||||
//
|
||||
// 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/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_IMPL_STORAGE_PTR_HPP
|
||||
#define BOOST_JSON_IMPL_STORAGE_PTR_HPP
|
||||
|
||||
#include <new>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct default_impl
|
||||
{
|
||||
static
|
||||
constexpr
|
||||
std::uint64_t
|
||||
id = 0x3b88990852d58ae4;
|
||||
|
||||
static
|
||||
constexpr
|
||||
bool
|
||||
need_free = true;
|
||||
|
||||
void*
|
||||
allocate(
|
||||
std::size_t n,
|
||||
std::size_t)
|
||||
{
|
||||
return ::operator new(n);
|
||||
}
|
||||
|
||||
void
|
||||
deallocate(
|
||||
void* p,
|
||||
std::size_t,
|
||||
std::size_t) noexcept
|
||||
{
|
||||
::operator delete(p);
|
||||
}
|
||||
};
|
||||
|
||||
} // detail
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
storage*
|
||||
storage_ptr::
|
||||
get() const noexcept
|
||||
{
|
||||
BOOST_JSON_REQUIRE_CONST_INIT
|
||||
static scoped_storage<
|
||||
detail::default_impl> ss;
|
||||
return p_ ? p_ : &ss.impl_;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
template<class Storage, class... Args>
|
||||
storage_ptr
|
||||
make_storage(Args&&... args)
|
||||
{
|
||||
// If this generates an error, it means that your
|
||||
// type `Storage` does not meet the named requirements.
|
||||
//
|
||||
static_assert(is_storage<Storage>::value,
|
||||
"Storage requirements not met");
|
||||
return storage_ptr(new
|
||||
detail::storage_impl<Storage>(true,
|
||||
std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
#endif
|
@ -371,8 +371,9 @@ key_value_pair::
|
||||
~key_value_pair()
|
||||
{
|
||||
auto const& sp = value_.storage();
|
||||
if(sp->need_free())
|
||||
sp->deallocate(key_, len_ + 1, 1);
|
||||
if(sp.is_not_counted_and_deallocate_is_null())
|
||||
return;
|
||||
sp->deallocate(key_, len_ + 1, 1);
|
||||
}
|
||||
|
||||
key_value_pair::
|
||||
|
80
include/boost/json/monotonic_resource.hpp
Normal file
80
include/boost/json/monotonic_resource.hpp
Normal file
@ -0,0 +1,80 @@
|
||||
//
|
||||
// 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/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_MONOTONIC_RESOURCE_HPP
|
||||
#define BOOST_JSON_MONOTONIC_RESOURCE_HPP
|
||||
|
||||
#include <boost/json/config.hpp>
|
||||
#include <boost/json/storage_ptr.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
/** A fast memory resource using many large fixed size blocks.
|
||||
*/
|
||||
class monotonic_resource final
|
||||
: public memory_resource
|
||||
{
|
||||
struct block;
|
||||
std::size_t const block_size_ = 64 * 1024;
|
||||
block* head_ = nullptr;
|
||||
|
||||
inline block& alloc_block(std::size_t size);
|
||||
|
||||
public:
|
||||
BOOST_JSON_DECL
|
||||
~monotonic_resource();
|
||||
|
||||
BOOST_JSON_DECL
|
||||
monotonic_resource() noexcept;
|
||||
|
||||
BOOST_JSON_DECL
|
||||
monotonic_resource(
|
||||
std::size_t block_size) noexcept;
|
||||
|
||||
BOOST_JSON_DECL
|
||||
void*
|
||||
do_allocate(
|
||||
std::size_t n,
|
||||
std::size_t align) override;
|
||||
|
||||
BOOST_JSON_DECL
|
||||
void
|
||||
do_deallocate(
|
||||
void* p,
|
||||
std::size_t n,
|
||||
std::size_t align) override;
|
||||
|
||||
BOOST_JSON_DECL
|
||||
bool
|
||||
do_is_equal(
|
||||
memory_resource const& mr) const noexcept override;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct is_deallocate_null<
|
||||
monotonic_resource>
|
||||
{
|
||||
static
|
||||
constexpr
|
||||
bool
|
||||
deallocate_is_null() noexcept
|
||||
{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
#ifdef BOOST_JSON_HEADER_ONLY
|
||||
#include <boost/json/impl/monotonic_resource.ipp>
|
||||
#endif
|
||||
|
||||
#endif
|
@ -11,7 +11,7 @@
|
||||
#define BOOST_JSON_PARSER_HPP
|
||||
|
||||
#include <boost/json/config.hpp>
|
||||
#include <boost/json/storage.hpp>
|
||||
#include <boost/json/storage_ptr.hpp>
|
||||
#include <boost/json/value.hpp>
|
||||
#include <boost/json/string.hpp>
|
||||
#include <boost/json/detail/basic_parser.hpp>
|
||||
|
@ -1,139 +0,0 @@
|
||||
//
|
||||
// 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/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_POOL_HPP
|
||||
#define BOOST_JSON_POOL_HPP
|
||||
|
||||
#include <boost/json/config.hpp>
|
||||
#include <boost/json/storage.hpp>
|
||||
#include <cstdint>
|
||||
#include <new>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
/** A storage which uses a multiple fixed size blocks
|
||||
*/
|
||||
class pool
|
||||
{
|
||||
struct block
|
||||
{
|
||||
std::size_t const size;
|
||||
std::uintptr_t top;
|
||||
block* next;
|
||||
|
||||
block(
|
||||
std::size_t size_,
|
||||
block* next_)
|
||||
: size(size_)
|
||||
, top(reinterpret_cast<
|
||||
std::uintptr_t>(this+1))
|
||||
, next(next_)
|
||||
{
|
||||
}
|
||||
|
||||
void*
|
||||
alloc(
|
||||
std::size_t n,
|
||||
std::size_t align) noexcept
|
||||
{
|
||||
// must be power of 2
|
||||
BOOST_ASSERT(
|
||||
(align & (align - 1)) == 0);
|
||||
auto i = top;
|
||||
if((i & (align - 1)) != 0)
|
||||
i = (i | (align - 1)) + 1;
|
||||
if(i + n > (reinterpret_cast<
|
||||
std::uintptr_t>(this+1) + size))
|
||||
return nullptr;
|
||||
top = i + n;
|
||||
return reinterpret_cast<void*>(i);
|
||||
}
|
||||
};
|
||||
|
||||
std::size_t const block_size_;
|
||||
block* head_ = nullptr;
|
||||
|
||||
public:
|
||||
static
|
||||
constexpr
|
||||
std::uint64_t
|
||||
id = 0;
|
||||
|
||||
static
|
||||
constexpr
|
||||
bool
|
||||
need_free = false;
|
||||
|
||||
~pool()
|
||||
{
|
||||
for(auto b = head_; b;)
|
||||
{
|
||||
auto next = b->next;
|
||||
::operator delete(b);
|
||||
b = next;
|
||||
}
|
||||
}
|
||||
|
||||
explicit
|
||||
pool(
|
||||
std::size_t block_size = 64 * 1024)
|
||||
: block_size_(block_size)
|
||||
{
|
||||
}
|
||||
|
||||
void*
|
||||
allocate(
|
||||
std::size_t n,
|
||||
std::size_t align)
|
||||
{
|
||||
if(head_)
|
||||
{
|
||||
auto p = head_->alloc(n, align);
|
||||
if(p)
|
||||
return p;
|
||||
}
|
||||
if(n > block_size_ - 2 * align)
|
||||
alloc_block(n + 2 * align);
|
||||
else
|
||||
alloc_block(block_size_);
|
||||
auto p = head_->alloc(n, align);
|
||||
BOOST_ASSERT(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
deallocate(
|
||||
void*,
|
||||
std::size_t,
|
||||
std::size_t) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
block&
|
||||
alloc_block(std::size_t size)
|
||||
{
|
||||
auto const n = (
|
||||
size + sizeof(block) - 1) /
|
||||
sizeof(block);
|
||||
auto const bytes =
|
||||
(n + 1) * sizeof(block);
|
||||
auto& b = *::new(
|
||||
::operator new(bytes)) block(
|
||||
n * sizeof(block), head_);
|
||||
head_ = &b;
|
||||
return b;
|
||||
}
|
||||
};
|
||||
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
#endif
|
@ -29,6 +29,7 @@ in a translation unit of the program.
|
||||
|
||||
#include <boost/json/impl/array.ipp>
|
||||
#include <boost/json/impl/error.ipp>
|
||||
#include <boost/json/impl/monotonic_resource.ipp>
|
||||
#include <boost/json/impl/object.ipp>
|
||||
#include <boost/json/impl/parser.ipp>
|
||||
#include <boost/json/impl/serializer.ipp>
|
||||
|
@ -1,219 +0,0 @@
|
||||
//
|
||||
// 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/json
|
||||
//
|
||||
|
||||
#ifndef BOOST_JSON_STORAGE_HPP
|
||||
#define BOOST_JSON_STORAGE_HPP
|
||||
|
||||
#include <boost/json/config.hpp>
|
||||
#include <atomic>
|
||||
#include <cstddef>
|
||||
#include <stddef.h> // for ::max_align_t
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
namespace detail {
|
||||
template<class T>
|
||||
struct storage_impl;
|
||||
} // detail
|
||||
|
||||
/** Abstract interface to a memory resource used with JSON.
|
||||
|
||||
This interface is modeled similarly to
|
||||
`std::pmr::memory_resource` with some notable
|
||||
differences:
|
||||
|
||||
@li Instances may be reference counted.
|
||||
|
||||
@li The function @ref is_equal is implemented
|
||||
as a non-virtual member which does not require
|
||||
RTTI or `typeinfo`.
|
||||
|
||||
@li The function @ref need_free is provided to
|
||||
allow the implementation to optionally inform
|
||||
callers that calls to deallocate memory are not
|
||||
required.
|
||||
*/
|
||||
class storage
|
||||
{
|
||||
std::atomic<std::size_t> refs_{ 1 };
|
||||
std::uint64_t const id_ = 0;
|
||||
bool const need_free_ ;
|
||||
bool const counted_;
|
||||
|
||||
friend class storage_ptr;
|
||||
|
||||
template<class T>
|
||||
friend struct detail::storage_impl;
|
||||
|
||||
// Choose a unique 64-bit random number from here:
|
||||
// https://www.random.org/cgi-bin/randbyte?nbytes=8&format=h
|
||||
constexpr
|
||||
explicit
|
||||
storage(
|
||||
unsigned long long id,
|
||||
bool need_free,
|
||||
bool counted) noexcept
|
||||
: id_(id)
|
||||
, need_free_(need_free || counted)
|
||||
, counted_(counted)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
virtual
|
||||
~storage() = default;
|
||||
|
||||
/** Returns `true` if calls to `deallocate` are required.
|
||||
*/
|
||||
inline
|
||||
bool
|
||||
need_free() const noexcept
|
||||
{
|
||||
return need_free_;
|
||||
}
|
||||
|
||||
bool
|
||||
is_equal(
|
||||
storage const& other) const noexcept
|
||||
{
|
||||
return (this == &other) || (
|
||||
this->id_ != 0 &&
|
||||
this->id_ == other.id_);
|
||||
}
|
||||
|
||||
/** Allocate memory.
|
||||
|
||||
Allocates storage with for space of at
|
||||
least `bytes` octets. The returned storage
|
||||
is aligned to the specified alignment is
|
||||
supported, and to `alignof(max_align_t)`
|
||||
otherwise.
|
||||
|
||||
@throw std::exception if storage of the
|
||||
requested size and alignment cannot be
|
||||
obtained.
|
||||
*/
|
||||
BOOST_JSON_NODISCARD
|
||||
virtual
|
||||
void*
|
||||
allocate(
|
||||
std::size_t n,
|
||||
std::size_t align =
|
||||
alignof(max_align_t)) = 0;
|
||||
|
||||
/** Deallocate memory.
|
||||
|
||||
Deallocates the storage pointed to by `p`.
|
||||
|
||||
@par Preconditions
|
||||
|
||||
`p` was returned by a prior call to
|
||||
`u.allocate( bytes, align )` where
|
||||
`this->is_equal(u)`, and the storage
|
||||
`p` points to was not previously
|
||||
deallocated.
|
||||
*/
|
||||
virtual
|
||||
void
|
||||
deallocate(
|
||||
void* p,
|
||||
std::size_t n,
|
||||
std::size_t align =
|
||||
alignof(max_align_t)) = 0;
|
||||
|
||||
friend
|
||||
bool
|
||||
operator==(
|
||||
storage const& lhs,
|
||||
storage const& rhs) noexcept;
|
||||
|
||||
friend
|
||||
bool
|
||||
operator!=(
|
||||
storage const& lhs,
|
||||
storage const& rhs) noexcept;
|
||||
};
|
||||
|
||||
/** Return true if lhs equals rhs.
|
||||
*/
|
||||
inline
|
||||
bool
|
||||
operator==(
|
||||
storage const& lhs,
|
||||
storage const& rhs) noexcept
|
||||
{
|
||||
return lhs.is_equal(rhs);
|
||||
}
|
||||
|
||||
/** Return true if lhs does not equal rhs.
|
||||
*/
|
||||
inline
|
||||
bool
|
||||
operator!=(
|
||||
storage const& lhs,
|
||||
storage const& rhs) noexcept
|
||||
{
|
||||
return ! lhs.is_equal(rhs);
|
||||
}
|
||||
|
||||
/** Metafunction to determine if a type meets the requirements of Storage.
|
||||
|
||||
This type alias is `std::true_type` if the type
|
||||
`T` satisfies the syntactic requirements of <em>Storage</em>,
|
||||
otherwise it is equivalent to `std::false_type`.
|
||||
|
||||
@par Exemplar
|
||||
|
||||
For the following declaration,
|
||||
`is_storage<Storage>` is `std::true_type`:
|
||||
|
||||
@code
|
||||
struct Storage
|
||||
{
|
||||
static constexpr std::uint64_t id = 0;
|
||||
static_constexpr bool need_free = true;
|
||||
|
||||
void* allocate( std::size_t bytes, std::size_t align );
|
||||
void deallocate( void* p, std::size_t bytes, std::size_t align );
|
||||
};
|
||||
@endcode
|
||||
|
||||
@tparam T The type to check.
|
||||
*/
|
||||
#if BOOST_JSON_DOCS
|
||||
template<class T>
|
||||
using is_storage = __see_below__;
|
||||
#else
|
||||
template<class T, class = void>
|
||||
struct is_storage : std::false_type {};
|
||||
|
||||
template<class T>
|
||||
struct is_storage<T, detail::void_t<decltype(
|
||||
std::declval<std::uint64_t&>() = T::id,
|
||||
std::declval<bool&>() = T::need_free,
|
||||
std::declval<void*&>() =
|
||||
std::declval<T&>().allocate(
|
||||
std::declval<std::size_t>(),
|
||||
std::declval<std::size_t>()),
|
||||
std::declval<T&>().deallocate(
|
||||
std::declval<void*>(),
|
||||
std::declval<std::size_t>(),
|
||||
std::declval<std::size_t>())
|
||||
) > > : std::true_type
|
||||
{
|
||||
};
|
||||
#endif
|
||||
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
#include <boost/json/impl/storage.hpp>
|
||||
|
||||
#endif
|
@ -11,14 +11,29 @@
|
||||
#define BOOST_JSON_STORAGE_PTR_HPP
|
||||
|
||||
#include <boost/json/config.hpp>
|
||||
#include <boost/json/storage.hpp>
|
||||
#include <boost/json/detail/counted_resource.hpp>
|
||||
#include <boost/json/detail/default_resource.hpp>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
template<class T>
|
||||
struct is_deallocate_null
|
||||
{
|
||||
static
|
||||
constexpr
|
||||
bool
|
||||
deallocate_is_null() noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/** Manages a type-erased storage object.
|
||||
|
||||
This container is used to hold a shared reference
|
||||
@ -26,75 +41,60 @@ namespace json {
|
||||
*/
|
||||
class storage_ptr
|
||||
{
|
||||
template<class T>
|
||||
friend class scoped_storage;
|
||||
friend struct detail::counted_resource;
|
||||
using counted_resource =
|
||||
detail::counted_resource;
|
||||
|
||||
storage* p_ = nullptr;
|
||||
std::uintptr_t i_ = 0;
|
||||
|
||||
static
|
||||
memory_resource*
|
||||
get_default() noexcept
|
||||
{
|
||||
BOOST_JSON_REQUIRE_CONST_INIT
|
||||
static detail::default_resource impl;
|
||||
return &impl;
|
||||
}
|
||||
|
||||
counted_resource*
|
||||
get_counted() const noexcept
|
||||
{
|
||||
return reinterpret_cast<
|
||||
counted_resource*>(i_ & ~3);
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
addref() const noexcept
|
||||
{
|
||||
if(p_ && p_->counted_)
|
||||
++p_->refs_;
|
||||
if(is_counted())
|
||||
++get_counted()->refs;
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
release() const noexcept
|
||||
{
|
||||
if( p_ && p_->counted_ &&
|
||||
--p_->refs_ == 0)
|
||||
delete p_;
|
||||
if(is_counted())
|
||||
{
|
||||
auto const p = get_counted();
|
||||
if(--p->refs == 0)
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
explicit
|
||||
template<class T>
|
||||
storage_ptr(
|
||||
storage* p) noexcept
|
||||
: p_(p)
|
||||
detail::counted_resource_impl<T>* p) noexcept
|
||||
: i_(reinterpret_cast<
|
||||
std::uintptr_t>(p) + 1 +
|
||||
(is_deallocate_null<
|
||||
T>::deallocate_is_null() ? 2 : 0))
|
||||
{
|
||||
BOOST_ASSERT(p);
|
||||
}
|
||||
|
||||
public:
|
||||
/** Default constructor.
|
||||
|
||||
This constructs a default storage pointer.
|
||||
The default storage is not reference counted,
|
||||
uses global operator new and delete to obtain
|
||||
memory, and requires calls to `deallocate`.
|
||||
|
||||
@par Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
*/
|
||||
storage_ptr() = default;
|
||||
|
||||
/** Construct a pointer to default storage.
|
||||
|
||||
This constructs a default storage pointer.
|
||||
The default storage is not reference counted,
|
||||
uses global operator new and delete to obtain
|
||||
memory, and requires calls to `deallocate`.
|
||||
|
||||
@par Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
*/
|
||||
storage_ptr(
|
||||
std::nullptr_t) noexcept
|
||||
: storage_ptr()
|
||||
{
|
||||
}
|
||||
|
||||
/** Destructor.
|
||||
|
||||
This releases the pointed-to storage. If the
|
||||
@ -117,6 +117,63 @@ public:
|
||||
release();
|
||||
}
|
||||
|
||||
/** Default constructor.
|
||||
|
||||
This constructs a default storage pointer.
|
||||
The default storage is not reference counted,
|
||||
uses global operator new and delete to obtain
|
||||
memory, and requires calls to `deallocate`.
|
||||
|
||||
@par Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
*/
|
||||
storage_ptr() noexcept
|
||||
: i_(0)
|
||||
{
|
||||
}
|
||||
|
||||
/** Construct a pointer to default storage.
|
||||
|
||||
This constructs a default storage pointer.
|
||||
The default storage is not reference counted,
|
||||
uses global operator new and delete to obtain
|
||||
memory, and requires calls to `deallocate`.
|
||||
|
||||
@par Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
*/
|
||||
storage_ptr(
|
||||
std::nullptr_t) noexcept
|
||||
: storage_ptr()
|
||||
{
|
||||
}
|
||||
|
||||
/** Construct a pointer to a memory resource.
|
||||
*/
|
||||
template<class T, class =
|
||||
typename std::enable_if<
|
||||
std::is_convertible<
|
||||
T*, memory_resource*>::value>>
|
||||
storage_ptr(T* p) noexcept
|
||||
: i_(reinterpret_cast<
|
||||
std::uintptr_t>(p) +
|
||||
(is_deallocate_null<
|
||||
T>::deallocate_is_null() ?
|
||||
2 : 0))
|
||||
{
|
||||
BOOST_ASSERT(p);
|
||||
}
|
||||
|
||||
/** Move constructor.
|
||||
|
||||
After construction, the moved-from object
|
||||
@ -134,8 +191,8 @@ public:
|
||||
*/
|
||||
storage_ptr(
|
||||
storage_ptr&& other) noexcept
|
||||
: p_(detail::exchange(
|
||||
other.p_, nullptr))
|
||||
: i_(detail::exchange(
|
||||
other.i_, 0))
|
||||
{
|
||||
}
|
||||
|
||||
@ -156,7 +213,7 @@ public:
|
||||
*/
|
||||
storage_ptr(
|
||||
storage_ptr const& other) noexcept
|
||||
: p_(other.p_)
|
||||
: i_(other.i_)
|
||||
{
|
||||
addref();
|
||||
}
|
||||
@ -184,9 +241,8 @@ public:
|
||||
storage_ptr&& other) noexcept
|
||||
{
|
||||
release();
|
||||
p_ = detail::exchange(
|
||||
other.p_,
|
||||
nullptr);
|
||||
i_ = detail::exchange(
|
||||
other.i_, 0);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -212,10 +268,34 @@ public:
|
||||
{
|
||||
other.addref();
|
||||
release();
|
||||
p_ = other.p_;
|
||||
i_ = other.i_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Return `true` if the storage pointer has shared ownership of the memory resource.
|
||||
*/
|
||||
bool
|
||||
is_counted() const noexcept
|
||||
{
|
||||
return (i_ & 1) != 0;
|
||||
}
|
||||
|
||||
/** Return `true` if the memory resource does not require deallocate.
|
||||
*/
|
||||
bool
|
||||
deallocate_is_null() const noexcept
|
||||
{
|
||||
return (i_ & 2) != 0;
|
||||
}
|
||||
|
||||
/** Return `true` if ownership of the memory resource is not shared and deallocate is null.
|
||||
*/
|
||||
bool
|
||||
is_not_counted_and_deallocate_is_null() const noexcept
|
||||
{
|
||||
return (i_ & 3) == 2;
|
||||
}
|
||||
|
||||
/** Return a pointer to the storage object.
|
||||
|
||||
@par Complexity
|
||||
@ -226,9 +306,14 @@ public:
|
||||
|
||||
No-throw guarantee.
|
||||
*/
|
||||
inline
|
||||
storage*
|
||||
get() const noexcept;
|
||||
memory_resource*
|
||||
get() const noexcept
|
||||
{
|
||||
if(i_ != 0)
|
||||
return reinterpret_cast<
|
||||
memory_resource*>(i_ & ~3);
|
||||
return get_default();
|
||||
}
|
||||
|
||||
/** Return a pointer to the storage object.
|
||||
|
||||
@ -240,7 +325,7 @@ public:
|
||||
|
||||
No-throw guarantee.
|
||||
*/
|
||||
storage*
|
||||
memory_resource*
|
||||
operator->() const noexcept
|
||||
{
|
||||
return get();
|
||||
@ -260,7 +345,7 @@ public:
|
||||
|
||||
No-throw guarantee.
|
||||
*/
|
||||
storage&
|
||||
memory_resource&
|
||||
operator*() const noexcept
|
||||
{
|
||||
return *get();
|
||||
@ -269,16 +354,16 @@ public:
|
||||
template<class U, class... Args>
|
||||
friend
|
||||
storage_ptr
|
||||
make_storage(Args&&... args);
|
||||
make_counted_resource(Args&&... args);
|
||||
};
|
||||
|
||||
/** Create a new, counted storage object and return a pointer to it.
|
||||
/** Create a new, counted memory resource and return a pointer to it.
|
||||
|
||||
This functions similarly to `make_shared`.
|
||||
|
||||
@par Mandates
|
||||
@code
|
||||
is_storage<T>::value == true
|
||||
std::is_base_of< memory_resource, T >::value == true
|
||||
@endcode
|
||||
|
||||
@par Complexity
|
||||
@ -291,11 +376,22 @@ public:
|
||||
|
||||
@param args Parameters forwarded to the constructor of `T`.
|
||||
|
||||
@tparam T the type of the storage object to create.
|
||||
@tparam T the concrete type of the memory resource to create.
|
||||
*/
|
||||
template<class T, class... Args>
|
||||
storage_ptr
|
||||
make_storage(Args&&... args);
|
||||
make_counted_resource(Args&&... args)
|
||||
{
|
||||
// If this generates an error, it means that your
|
||||
// type `Storage` does not meet the named requirements.
|
||||
//
|
||||
BOOST_STATIC_ASSERT(
|
||||
std::is_base_of<
|
||||
memory_resource, T>::value);
|
||||
return storage_ptr(new
|
||||
detail::counted_resource_impl<T>(
|
||||
std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
/** Return true if lhs equals rhs.
|
||||
|
||||
@ -327,101 +423,7 @@ operator!=(
|
||||
return lhs.get() != rhs.get();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
/** A wrapper to provide deterministic lifetime to a @ref storage object.
|
||||
|
||||
This wrapper enables the caller to construct a
|
||||
@ref storage objects whose lifetime is controlled
|
||||
by the lifetime of the wrapper instead of a
|
||||
reference counted.
|
||||
|
||||
@par Example
|
||||
|
||||
This example creates a @ref pool with
|
||||
bounded lifetime and uses it to parse a JSON,
|
||||
then print it to `std::cout`.
|
||||
|
||||
@code
|
||||
|
||||
{
|
||||
scoped_storage<pool> sp;
|
||||
|
||||
auto jv = parse( str, sp );
|
||||
}
|
||||
|
||||
@endcode
|
||||
*/
|
||||
template<class Storage>
|
||||
class scoped_storage
|
||||
{
|
||||
friend storage_ptr;
|
||||
|
||||
detail::storage_impl<Storage> impl_;
|
||||
|
||||
// If this generates an error, it means that your
|
||||
// type `Storage` does not meet the named requirements.
|
||||
//
|
||||
static_assert(is_storage<Storage>::value,
|
||||
"Storage requirements not met");
|
||||
|
||||
public:
|
||||
/** Constructor.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
Any exceptions thrown by `Storage::Storage`.
|
||||
|
||||
@param args Arguments forwarded to the
|
||||
constructor of the storage object.
|
||||
*/
|
||||
template<class... Args>
|
||||
constexpr
|
||||
explicit
|
||||
scoped_storage(Args&&... args)
|
||||
: impl_(false,
|
||||
std::forward<Args>(args)...)
|
||||
{
|
||||
}
|
||||
|
||||
/** Return a pointer to the Storage object.
|
||||
*/
|
||||
Storage*
|
||||
get() noexcept
|
||||
{
|
||||
return &impl_;
|
||||
}
|
||||
|
||||
/** Return a pointer to the Storage object.
|
||||
*/
|
||||
Storage*
|
||||
operator->() noexcept
|
||||
{
|
||||
return &impl_.t;
|
||||
}
|
||||
|
||||
/** Return a storage pointer to the Storage object.
|
||||
*/
|
||||
storage_ptr
|
||||
get_storage_ptr() noexcept
|
||||
{
|
||||
return storage_ptr(&impl_);
|
||||
}
|
||||
|
||||
/** Implicit conversion to @ref storage_ptr.
|
||||
|
||||
This function allows `*this` to be passed
|
||||
wherever a @ref storage_ptr is expected.
|
||||
*/
|
||||
operator storage_ptr() noexcept
|
||||
{
|
||||
return get_storage_ptr();
|
||||
}
|
||||
};
|
||||
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
#include <boost/json/impl/storage_ptr.hpp>
|
||||
|
||||
#endif
|
||||
|
@ -30,13 +30,12 @@ local SOURCES =
|
||||
error.cpp
|
||||
json.cpp
|
||||
kind.cpp
|
||||
monotonic_resource.cpp
|
||||
number_cast.cpp
|
||||
object.cpp
|
||||
parser.cpp
|
||||
pool.cpp
|
||||
serializer.cpp
|
||||
snippets.cpp
|
||||
storage.cpp
|
||||
storage_ptr.cpp
|
||||
string.cpp
|
||||
to_value.cpp
|
||||
|
@ -8,7 +8,7 @@
|
||||
//
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include <boost/json/pool.hpp>
|
||||
#include <boost/json/monotonic_resource.hpp>
|
||||
|
||||
#include <boost/json/parser.hpp>
|
||||
|
||||
@ -46,7 +46,7 @@ R"xx({
|
||||
}
|
||||
}
|
||||
})xx"
|
||||
, make_storage<pool>());
|
||||
, make_counted_resource<monotonic_resource>());
|
||||
BOOST_TEST_PASS();
|
||||
}
|
||||
|
||||
@ -57,7 +57,7 @@ R"xx({
|
||||
}
|
||||
};
|
||||
|
||||
TEST_SUITE(pool_test, "boost.json.pool");
|
||||
TEST_SUITE(pool_test, "boost.json.monotonic_resource");
|
||||
|
||||
} // json
|
||||
} // boost
|
@ -10,7 +10,7 @@
|
||||
// Test that header file is self-contained.
|
||||
#include <boost/json/object.hpp>
|
||||
|
||||
#include <boost/json/pool.hpp>
|
||||
#include <boost/json/monotonic_resource.hpp>
|
||||
|
||||
#include <cmath>
|
||||
#include <type_traits>
|
||||
@ -256,7 +256,7 @@ public:
|
||||
// object(pilfered<object>)
|
||||
{
|
||||
auto const sp =
|
||||
make_storage<unique_storage>();
|
||||
make_counted_resource<unique_resource>();
|
||||
object o1({
|
||||
{"a", 1},
|
||||
{"b", true},
|
||||
@ -271,7 +271,7 @@ public:
|
||||
check(o2, 3);
|
||||
}
|
||||
|
||||
auto const sp = make_storage<unique_storage>();
|
||||
auto const sp = make_counted_resource<unique_resource>();
|
||||
auto const sp0 = storage_ptr{};
|
||||
|
||||
// object(object const&)
|
||||
@ -929,12 +929,12 @@ public:
|
||||
|
||||
// destroy key_value_pair array with need_free=false
|
||||
{
|
||||
scoped_storage<pool> sp;
|
||||
monotonic_resource mr;
|
||||
object o({
|
||||
{"a", 1},
|
||||
{"b", true},
|
||||
{"b", {1,2,3}},
|
||||
{"c", "hello"}}, sp);
|
||||
{"c", "hello"}}, &mr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
// Test that header file is self-contained.
|
||||
#include <boost/json/parser.hpp>
|
||||
|
||||
#include <boost/json/pool.hpp>
|
||||
#include <boost/json/monotonic_resource.hpp>
|
||||
#include <boost/json/serializer.hpp>
|
||||
|
||||
#include <sstream>
|
||||
@ -99,12 +99,11 @@ public:
|
||||
for(std::size_t i = 1;
|
||||
i < s.size(); ++i)
|
||||
{
|
||||
scoped_storage<
|
||||
fail_storage> ss;
|
||||
ss->fail_max = 0;
|
||||
fail_resource mr;
|
||||
mr.fail_max = 0;
|
||||
parser p;
|
||||
error_code ec;
|
||||
p.start(ss);
|
||||
p.start(&mr);
|
||||
p.write(s.data(), i, ec);
|
||||
if(BOOST_TEST(! ec))
|
||||
p.write(
|
||||
@ -762,16 +761,16 @@ public:
|
||||
{
|
||||
{
|
||||
error_code ec;
|
||||
scoped_storage<pool> sp;
|
||||
auto jv = parse(js, ec, sp);
|
||||
monotonic_resource mr;
|
||||
auto jv = parse(js, ec, &mr);
|
||||
BOOST_TEST(! ec);
|
||||
check_round_trip(jv);
|
||||
}
|
||||
|
||||
{
|
||||
error_code ec;
|
||||
scoped_storage<pool> sp;
|
||||
auto jv = parse("xxx", ec, sp);
|
||||
monotonic_resource mr;
|
||||
auto jv = parse("xxx", ec, &mr);
|
||||
BOOST_TEST(ec);
|
||||
BOOST_TEST(jv.is_null());
|
||||
}
|
||||
@ -795,15 +794,15 @@ public:
|
||||
// parse(string_view, storage_ptr)
|
||||
{
|
||||
{
|
||||
scoped_storage<pool> sp;
|
||||
check_round_trip(parse(js, sp));
|
||||
monotonic_resource mr;
|
||||
check_round_trip(parse(js, &mr));
|
||||
}
|
||||
|
||||
{
|
||||
scoped_storage<pool> sp;
|
||||
monotonic_resource mr;
|
||||
value jv;
|
||||
BOOST_TEST_THROWS(
|
||||
jv = parse("xxx", sp),
|
||||
jv = parse("xxx", &mr),
|
||||
system_error);
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ usingStrings()
|
||||
|
||||
string str1; // empty string, default storage
|
||||
|
||||
string str2( make_storage<pool>() ); // empty string, pool storage
|
||||
string str2( make_counted_resource<monotonic_resource>() ); // empty string, pool storage
|
||||
|
||||
//]
|
||||
}
|
||||
@ -95,7 +95,7 @@ usingArrays()
|
||||
|
||||
array arr1; // empty array, default storage
|
||||
|
||||
array arr2( make_storage<pool>() ); // empty array, pool storage
|
||||
array arr2( make_counted_resource<monotonic_resource>() ); // empty array, pool storage
|
||||
|
||||
//]
|
||||
}
|
||||
@ -138,7 +138,7 @@ usingObjects()
|
||||
|
||||
object obj1; // empty object, default storage
|
||||
|
||||
object obj2( make_storage<pool>() ); // empty object, pool storage
|
||||
object obj2( make_counted_resource<monotonic_resource>() ); // empty object, pool storage
|
||||
|
||||
//]
|
||||
}
|
||||
@ -202,7 +202,7 @@ usingStorage()
|
||||
|
||||
value parse_fast( string_view s )
|
||||
{
|
||||
return parse( s, make_storage<pool>() );
|
||||
return parse( s, make_counted_resource<monotonic_resource>() );
|
||||
}
|
||||
|
||||
//]
|
||||
@ -213,9 +213,9 @@ void do_json(value const&) {}
|
||||
|
||||
void do_rpc( string_view cmd )
|
||||
{
|
||||
scoped_storage<pool> sp;
|
||||
monotonic_resource mr;
|
||||
|
||||
value const jv = parse( cmd, sp );
|
||||
value const jv = parse( cmd, &mr );
|
||||
|
||||
do_json( jv );
|
||||
}
|
||||
@ -224,20 +224,10 @@ void do_rpc( string_view cmd )
|
||||
|
||||
//[snippet_storage_4
|
||||
|
||||
struct Storage
|
||||
{
|
||||
static constexpr std::uint64_t id = 0;
|
||||
static constexpr bool need_free = true;
|
||||
|
||||
void* allocate( std::size_t bytes, std::size_t align );
|
||||
void deallocate( void* p, std::size_t bytes, std::size_t align );
|
||||
};
|
||||
// TODO
|
||||
|
||||
//]
|
||||
|
||||
BOOST_STATIC_ASSERT(
|
||||
is_storage<Storage>::value);
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
void
|
||||
@ -263,7 +253,7 @@ usingParsing()
|
||||
{
|
||||
//[snippet_parsing_3
|
||||
|
||||
value jv = parse( "[1,2,3,4,5]", make_storage<pool>() );
|
||||
value jv = parse( "[1,2,3,4,5]", make_counted_resource<monotonic_resource>() );
|
||||
|
||||
//]
|
||||
}
|
||||
@ -322,10 +312,10 @@ usingParsing()
|
||||
error_code ec;
|
||||
|
||||
// Declare a new, scoped instance of the block storage
|
||||
scoped_storage< pool > sp;
|
||||
monotonic_resource mr;
|
||||
|
||||
// Use the scoped instance for the parsed value
|
||||
p.start( sp );
|
||||
p.start( &mr );
|
||||
|
||||
// Write the entire JSON
|
||||
p.write( "[1,2,3,4,5]", 11, ec );
|
||||
|
@ -1,11 +0,0 @@
|
||||
//
|
||||
// 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/json
|
||||
//
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include <boost/json/storage.hpp>
|
@ -19,60 +19,36 @@ namespace json {
|
||||
class storage_ptr_test
|
||||
{
|
||||
public:
|
||||
struct not_storage
|
||||
{
|
||||
void*
|
||||
allocate(
|
||||
std::size_t,
|
||||
std::size_t)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
deallocate(
|
||||
void*,
|
||||
std::size_t,
|
||||
std::size_t) noexcept
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_STATIC_ASSERT(
|
||||
! is_storage<not_storage>::value);
|
||||
|
||||
struct throwing
|
||||
: memory_resource
|
||||
{
|
||||
static
|
||||
constexpr
|
||||
std::uint64_t
|
||||
id = 0;
|
||||
|
||||
static
|
||||
constexpr
|
||||
bool
|
||||
need_free = true;
|
||||
|
||||
throwing()
|
||||
{
|
||||
throw std::exception{};
|
||||
}
|
||||
|
||||
void*
|
||||
allocate(
|
||||
do_allocate(
|
||||
std::size_t,
|
||||
std::size_t)
|
||||
std::size_t) override
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
deallocate(
|
||||
do_deallocate(
|
||||
void*,
|
||||
std::size_t,
|
||||
std::size_t) noexcept
|
||||
std::size_t) noexcept override
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
do_is_equal(
|
||||
memory_resource const&) const noexcept override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
@ -80,7 +56,7 @@ public:
|
||||
{
|
||||
auto const dsp = storage_ptr{};
|
||||
auto const usp =
|
||||
make_storage<unique_storage>();
|
||||
make_counted_resource<unique_resource>();
|
||||
|
||||
// ~storage_ptr()
|
||||
{
|
||||
@ -145,7 +121,7 @@ public:
|
||||
// exception in make_storage
|
||||
{
|
||||
BOOST_TEST_THROWS(
|
||||
make_storage<throwing>(),
|
||||
make_counted_resource<throwing>(),
|
||||
std::exception);
|
||||
}
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ public:
|
||||
// string(storage_ptr)
|
||||
{
|
||||
auto const sp =
|
||||
make_storage<unique_storage>();
|
||||
make_counted_resource<unique_resource>();
|
||||
string s(sp);
|
||||
BOOST_TEST(s.empty());
|
||||
BOOST_TEST(*s.storage() == *sp.get());
|
||||
|
@ -38,31 +38,22 @@ struct test_failure : std::exception
|
||||
}
|
||||
};
|
||||
|
||||
struct fail_storage
|
||||
struct fail_resource
|
||||
: memory_resource
|
||||
{
|
||||
static
|
||||
constexpr
|
||||
std::uint64_t
|
||||
id = 0;
|
||||
|
||||
static
|
||||
constexpr
|
||||
bool
|
||||
need_free = true;
|
||||
|
||||
std::size_t fail_max = 0;
|
||||
std::size_t fail = 0;
|
||||
std::size_t nalloc = 0;
|
||||
|
||||
~fail_storage()
|
||||
~fail_resource()
|
||||
{
|
||||
BOOST_TEST(nalloc == 0);
|
||||
}
|
||||
|
||||
void*
|
||||
allocate(
|
||||
do_allocate(
|
||||
std::size_t n,
|
||||
std::size_t)
|
||||
std::size_t) override
|
||||
{
|
||||
if(++fail == fail_max)
|
||||
{
|
||||
@ -76,28 +67,35 @@ struct fail_storage
|
||||
}
|
||||
|
||||
void
|
||||
deallocate(
|
||||
do_deallocate(
|
||||
void* p,
|
||||
std::size_t,
|
||||
std::size_t) noexcept
|
||||
std::size_t) noexcept override
|
||||
{
|
||||
if(BOOST_TEST(nalloc > 0))
|
||||
--nalloc;
|
||||
::operator delete(p);
|
||||
}
|
||||
|
||||
bool
|
||||
do_is_equal(
|
||||
memory_resource const& mr) const noexcept override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template<class F>
|
||||
void
|
||||
fail_loop(F&& f)
|
||||
{
|
||||
scoped_storage<fail_storage> ss;
|
||||
ss->fail_max = 1;
|
||||
while(ss->fail < 200)
|
||||
fail_resource ss;
|
||||
ss.fail_max = 1;
|
||||
while(ss.fail < 200)
|
||||
{
|
||||
try
|
||||
{
|
||||
f(ss);
|
||||
f(&ss);
|
||||
}
|
||||
catch(test_failure const&)
|
||||
{
|
||||
@ -105,39 +103,39 @@ fail_loop(F&& f)
|
||||
}
|
||||
break;
|
||||
}
|
||||
BOOST_TEST(ss->fail < 200);
|
||||
BOOST_TEST(ss.fail < 200);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
struct unique_storage
|
||||
struct unique_resource
|
||||
: memory_resource
|
||||
{
|
||||
static
|
||||
constexpr
|
||||
std::uint64_t
|
||||
id = 0;
|
||||
|
||||
static
|
||||
constexpr
|
||||
bool
|
||||
need_free = true;
|
||||
unique_resource() = default;
|
||||
|
||||
void*
|
||||
allocate(
|
||||
do_allocate(
|
||||
std::size_t n,
|
||||
std::size_t)
|
||||
std::size_t) override
|
||||
{
|
||||
return ::operator new(n);
|
||||
}
|
||||
|
||||
void
|
||||
deallocate(
|
||||
do_deallocate(
|
||||
void* p,
|
||||
std::size_t,
|
||||
std::size_t) noexcept
|
||||
std::size_t) noexcept override
|
||||
{
|
||||
return ::operator delete(p);
|
||||
}
|
||||
|
||||
bool
|
||||
do_is_equal(
|
||||
memory_resource const& mr) const noexcept override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
@ -43,7 +43,7 @@ public:
|
||||
testSpecial()
|
||||
{
|
||||
auto dsp = storage_ptr{};
|
||||
auto sp = make_storage<unique_storage>();
|
||||
auto sp = make_counted_resource<unique_resource>();
|
||||
|
||||
// ~value()
|
||||
{
|
||||
@ -468,7 +468,7 @@ public:
|
||||
testConversion()
|
||||
{
|
||||
auto dsp = storage_ptr{};
|
||||
auto sp = make_storage<unique_storage>();
|
||||
auto sp = make_counted_resource<unique_resource>();
|
||||
|
||||
// value(object)
|
||||
// value(object, storage_ptr)
|
||||
@ -1050,7 +1050,7 @@ public:
|
||||
testGetStorage()
|
||||
{
|
||||
auto const sp =
|
||||
make_storage<unique_storage>();
|
||||
make_counted_resource<unique_resource>();
|
||||
|
||||
value obj(object{}, sp);
|
||||
value arr(array{}, sp);
|
||||
|
Loading…
x
Reference in New Issue
Block a user