mirror of
https://github.com/boostorg/json.git
synced 2025-05-11 05:33:57 +00:00
Refactor storage
This commit is contained in:
parent
9ff45bb8fa
commit
96c4b77d86
@ -14,15 +14,17 @@ source_group (TREE ${PROJECT_SOURCE_DIR}/include/boost/json PREFIX json FILES ${
|
||||
GroupSources(bench "/")
|
||||
|
||||
if (MSVC)
|
||||
add_compile_options(
|
||||
/GL # Whole program optimization
|
||||
/Ob2 # inline any suitable
|
||||
)
|
||||
|
||||
add_link_options(
|
||||
/LTCG # Link Time Code Generation
|
||||
)
|
||||
if (CMAKE_BUILD_TYPE EQUAL "Debug")
|
||||
else()
|
||||
add_compile_options(
|
||||
/GL # Whole program optimization
|
||||
/Ob2 # inline any suitable
|
||||
)
|
||||
|
||||
add_link_options(
|
||||
/LTCG # Link Time Code Generation
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
add_executable (bench
|
||||
|
418
bench/bench.cpp
418
bench/bench.cpp
@ -90,421 +90,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class boost_null_impl : public any_impl
|
||||
{
|
||||
struct null_parser : basic_parser
|
||||
{
|
||||
std::size_t n_ = std::size_t(-1);
|
||||
char buf[256];
|
||||
|
||||
void
|
||||
on_stack_info(
|
||||
stack& s) noexcept override
|
||||
{
|
||||
s.base = buf;
|
||||
s.capacity = sizeof(buf);
|
||||
}
|
||||
|
||||
void
|
||||
on_stack_grow(
|
||||
stack&,
|
||||
unsigned,
|
||||
error_code& ec) override
|
||||
{
|
||||
ec = error::too_deep;
|
||||
}
|
||||
|
||||
void
|
||||
on_document_begin(
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_object_begin(
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_object_end(
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_array_begin(
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_array_end(
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_key_data(
|
||||
string_view,
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_key_end(
|
||||
string_view,
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_string_data(
|
||||
string_view,
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_string_end(
|
||||
string_view,
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_number(
|
||||
ieee_decimal,
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_bool(
|
||||
bool,
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_null(error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
null_parser() = default;
|
||||
};
|
||||
public:
|
||||
string_view
|
||||
name() const noexcept override
|
||||
{
|
||||
return "null parser";
|
||||
}
|
||||
|
||||
void
|
||||
parse(
|
||||
string_view s,
|
||||
int repeat) const override
|
||||
{
|
||||
while(repeat--)
|
||||
{
|
||||
error_code ec;
|
||||
null_parser p;
|
||||
p.write(s.data(), s.size(), ec);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
serialize(
|
||||
string_view s,
|
||||
int repeat) const override
|
||||
{
|
||||
auto jv = json::parse(s);
|
||||
while(repeat--)
|
||||
to_string(jv);
|
||||
}
|
||||
};
|
||||
|
||||
class boost_vec_impl : public any_impl
|
||||
{
|
||||
struct vec_parser : basic_parser
|
||||
{
|
||||
std::vector<value> vec_;
|
||||
char buf[256];
|
||||
|
||||
void
|
||||
on_stack_info(
|
||||
stack& s) noexcept override
|
||||
{
|
||||
s.base = buf;
|
||||
s.capacity = sizeof(buf);
|
||||
}
|
||||
|
||||
void
|
||||
on_stack_grow(
|
||||
stack&,
|
||||
unsigned,
|
||||
error_code& ec) override
|
||||
{
|
||||
ec = error::too_deep;
|
||||
}
|
||||
|
||||
void
|
||||
on_document_begin(
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_object_begin(
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_object_end(
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_array_begin(
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_array_end(
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_key_data(
|
||||
string_view,
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_key_end(
|
||||
string_view,
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_string_data(
|
||||
string_view,
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_string_end(
|
||||
string_view,
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_number(
|
||||
ieee_decimal dec,
|
||||
error_code&) override
|
||||
{
|
||||
vec_.emplace_back(number(dec));
|
||||
}
|
||||
|
||||
void
|
||||
on_bool(
|
||||
bool,
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_null(error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
vec_parser() = default;
|
||||
};
|
||||
public:
|
||||
string_view
|
||||
name() const noexcept override
|
||||
{
|
||||
return "vector<value>";
|
||||
}
|
||||
|
||||
void
|
||||
parse(
|
||||
string_view s,
|
||||
int repeat) const override
|
||||
{
|
||||
while(repeat--)
|
||||
{
|
||||
error_code ec;
|
||||
vec_parser p;
|
||||
p.write(s.data(), s.size(), ec);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
serialize(
|
||||
string_view s,
|
||||
int repeat) const override
|
||||
{
|
||||
auto jv = json::parse(s);
|
||||
while(repeat--)
|
||||
to_string(jv);
|
||||
}
|
||||
};
|
||||
|
||||
class boost_arr_impl : public any_impl
|
||||
{
|
||||
struct arr_parser : basic_parser
|
||||
{
|
||||
storage_ptr sp_;
|
||||
array arr_;
|
||||
char buf[256];
|
||||
|
||||
void
|
||||
on_stack_info(
|
||||
stack& s) noexcept override
|
||||
{
|
||||
s.base = buf;
|
||||
s.capacity = sizeof(buf);
|
||||
}
|
||||
|
||||
void
|
||||
on_stack_grow(
|
||||
stack&,
|
||||
unsigned,
|
||||
error_code& ec) override
|
||||
{
|
||||
ec = error::too_deep;
|
||||
}
|
||||
|
||||
void
|
||||
on_document_begin(
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_object_begin(
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_object_end(
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_array_begin(
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_array_end(
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_key_data(
|
||||
string_view,
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_key_end(
|
||||
string_view,
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_string_data(
|
||||
string_view,
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_string_end(
|
||||
string_view,
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_number(
|
||||
ieee_decimal dec,
|
||||
error_code&) override
|
||||
{
|
||||
arr_.emplace_back(number(dec));
|
||||
}
|
||||
|
||||
void
|
||||
on_bool(
|
||||
bool,
|
||||
error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
on_null(error_code&) override
|
||||
{
|
||||
}
|
||||
|
||||
arr_parser(
|
||||
storage_ptr sp = default_storage())
|
||||
: arr_(std::move(sp))
|
||||
{
|
||||
}
|
||||
};
|
||||
public:
|
||||
string_view
|
||||
name() const noexcept override
|
||||
{
|
||||
return "array";
|
||||
}
|
||||
|
||||
void
|
||||
parse(
|
||||
string_view s,
|
||||
int repeat) const override
|
||||
{
|
||||
while(repeat--)
|
||||
{
|
||||
error_code ec;
|
||||
#if 1
|
||||
scoped_storage<
|
||||
block_storage> ss;
|
||||
arr_parser p(ss);
|
||||
#else
|
||||
arr_parser p;
|
||||
#endif
|
||||
p.write(s.data(), s.size(), ec);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
serialize(
|
||||
string_view s,
|
||||
int repeat) const override
|
||||
{
|
||||
auto jv = json::parse(s);
|
||||
while(repeat--)
|
||||
to_string(jv);
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
struct rapidjson_impl : public any_impl
|
||||
@ -674,9 +259,6 @@ main(
|
||||
vi.reserve(10);
|
||||
vi.emplace_back(new boost_impl);
|
||||
vi.emplace_back(new rapidjson_impl);
|
||||
//vi.emplace_back(new boost_null_impl);
|
||||
//vi.emplace_back(new boost_vec_impl);
|
||||
//vi.emplace_back(new boost_arr_impl);
|
||||
//vi.emplace_back(new nlohmann_impl);
|
||||
|
||||
//benchParse(vs, vi);
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <boost/json/parser.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/value.hpp>
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
#include <boost/json/kind.hpp>
|
||||
#include <boost/json/storage.hpp>
|
||||
#include <boost/json/storage_ptr.hpp>
|
||||
#include <boost/pilfer.hpp>
|
||||
#include <cstdlib>
|
||||
#include <initializer_list>
|
||||
|
@ -80,7 +80,8 @@ public:
|
||||
explicit
|
||||
block_storage(
|
||||
std::size_t block_size = 64 * 1024)
|
||||
: block_size_(block_size)
|
||||
: storage(false)
|
||||
, block_size_(block_size)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -19,8 +19,8 @@ inline
|
||||
T
|
||||
exchange(T& t, U u) noexcept
|
||||
{
|
||||
T v = t;
|
||||
t = u;
|
||||
T v = std::move(t);
|
||||
t = std::move(u);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
@ -52,14 +52,15 @@ impl_type::
|
||||
destroy(
|
||||
storage_ptr const& sp) noexcept
|
||||
{
|
||||
if(! vec || sp->is_scoped())
|
||||
return;
|
||||
auto it = vec + size;
|
||||
while(it != vec)
|
||||
(*--it).~value();
|
||||
sp->deallocate(vec,
|
||||
capacity * sizeof(value),
|
||||
alignof(value));
|
||||
if(vec && sp->need_free())
|
||||
{
|
||||
auto it = vec + size;
|
||||
while(it != vec)
|
||||
(*--it).~value();
|
||||
sp->deallocate(vec,
|
||||
capacity * sizeof(value),
|
||||
alignof(value));
|
||||
}
|
||||
vec = nullptr;
|
||||
size = 0;
|
||||
capacity = 0;
|
||||
@ -163,8 +164,7 @@ undo_insert(
|
||||
array::
|
||||
~array()
|
||||
{
|
||||
if(sp_)
|
||||
impl_.destroy(sp_);
|
||||
impl_.destroy(sp_);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
@ -558,7 +558,7 @@ array::
|
||||
destroy(
|
||||
value* first, value* last) noexcept
|
||||
{
|
||||
if(! sp_->is_scoped())
|
||||
if(sp_->need_free())
|
||||
while(last != first)
|
||||
(*--last).~value();
|
||||
}
|
||||
|
@ -260,7 +260,7 @@ const_iterator(
|
||||
object::
|
||||
~object()
|
||||
{
|
||||
if(sp_ && ! sp_->is_scoped())
|
||||
if(sp_->need_free())
|
||||
release_storage();
|
||||
}
|
||||
|
||||
|
@ -1,29 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot 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_HPP
|
||||
#define BOOST_JSON_IMPL_STORAGE_HPP
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
template<class Storage, class... Args>
|
||||
basic_storage_ptr<Storage>
|
||||
make_storage(Args&&... args)
|
||||
{
|
||||
return basic_storage_ptr<Storage>(
|
||||
new Storage(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
#endif
|
@ -1,67 +0,0 @@
|
||||
//
|
||||
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot 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_IPP
|
||||
#define BOOST_JSON_IMPL_STORAGE_IPP
|
||||
|
||||
#include <boost/json/storage.hpp>
|
||||
#include <boost/json/detail/assert.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
storage::
|
||||
storage(unsigned long long id) noexcept
|
||||
: refs_(1)
|
||||
, id_(id)
|
||||
{
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
storage_ptr const&
|
||||
default_storage() noexcept
|
||||
{
|
||||
struct builtin : storage
|
||||
{
|
||||
builtin()
|
||||
: storage(0x3b88990852d58ae4)
|
||||
{
|
||||
}
|
||||
|
||||
void*
|
||||
do_allocate(
|
||||
std::size_t n,
|
||||
std::size_t) override
|
||||
{
|
||||
return std::allocator<
|
||||
char>().allocate(n);
|
||||
}
|
||||
|
||||
void
|
||||
do_deallocate(
|
||||
void* p,
|
||||
std::size_t n,
|
||||
std::size_t) noexcept override
|
||||
{
|
||||
std::allocator<
|
||||
char>().deallocate(
|
||||
static_cast<char*>(p), n);
|
||||
}
|
||||
};
|
||||
static storage_ptr const sp =
|
||||
make_storage<builtin>();
|
||||
return sp;
|
||||
}
|
||||
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
#endif
|
88
include/boost/json/impl/storage_ptr.hpp
Normal file
88
include/boost/json/impl/storage_ptr.hpp
Normal file
@ -0,0 +1,88 @@
|
||||
//
|
||||
// Copyright (c) 2019 Vinnie Falco (vinnie dot falco at gmail dot 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 <boost/json/storage_ptr.hpp>
|
||||
#include <new>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
storage_ptr&
|
||||
storage_ptr::
|
||||
operator=(
|
||||
storage_ptr&& other) noexcept
|
||||
{
|
||||
release();
|
||||
p_ = other.p_;
|
||||
other.p_ = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
storage_ptr&
|
||||
storage_ptr::
|
||||
operator=(
|
||||
storage_ptr const& other) noexcept
|
||||
{
|
||||
if(other.p_)
|
||||
++other.p_->refs_;
|
||||
release();
|
||||
p_ = other.p_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
storage*
|
||||
storage_ptr::
|
||||
get() const noexcept
|
||||
{
|
||||
struct default_impl : storage
|
||||
{
|
||||
default_impl()
|
||||
: storage(true,
|
||||
0x3b88990852d58ae4)
|
||||
{
|
||||
}
|
||||
|
||||
void*
|
||||
do_allocate(
|
||||
std::size_t n,
|
||||
std::size_t) override
|
||||
{
|
||||
return ::operator new(n);
|
||||
}
|
||||
|
||||
void
|
||||
do_deallocate(
|
||||
void* p,
|
||||
std::size_t,
|
||||
std::size_t) noexcept override
|
||||
{
|
||||
::operator delete(p);
|
||||
}
|
||||
};
|
||||
//[[clang::require_constant_initialization]]
|
||||
static scoped_storage<default_impl> impl;
|
||||
return p_ ? p_ : impl.get();
|
||||
}
|
||||
|
||||
template<class Storage, class... Args>
|
||||
storage_ptr
|
||||
make_storage(Args&&... args)
|
||||
{
|
||||
return storage_ptr(new Storage(
|
||||
std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
#endif
|
@ -11,7 +11,7 @@
|
||||
#define BOOST_JSON_OBJECT_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
#include <boost/json/storage.hpp>
|
||||
#include <boost/json/storage_ptr.hpp>
|
||||
#include <boost/json/detail/string.hpp>
|
||||
#include <boost/pilfer.hpp>
|
||||
#include <cstdlib>
|
||||
|
@ -31,7 +31,6 @@ the program, with the macro BOOST_BEAST_SPLIT_COMPILATION defined.
|
||||
#include <boost/json/impl/object.ipp>
|
||||
#include <boost/json/impl/parser.ipp>
|
||||
#include <boost/json/impl/serializer.ipp>
|
||||
#include <boost/json/impl/storage.ipp>
|
||||
#include <boost/json/impl/string.ipp>
|
||||
#include <boost/json/impl/value.ipp>
|
||||
|
||||
|
@ -12,10 +12,7 @@
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
#include <atomic>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <cstddef>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
@ -24,26 +21,13 @@ namespace json {
|
||||
*/
|
||||
class storage
|
||||
{
|
||||
std::atomic<std::size_t> refs_;
|
||||
unsigned long long id_ = 0;
|
||||
bool scoped_ = false;
|
||||
std::atomic<
|
||||
unsigned long long> refs_{ 1 };
|
||||
unsigned long long const id_ = 0;
|
||||
bool const need_free_ = true;
|
||||
bool counted_ = true;
|
||||
|
||||
void
|
||||
addref() noexcept
|
||||
{
|
||||
if(! scoped_)
|
||||
++refs_;
|
||||
}
|
||||
|
||||
void
|
||||
release() noexcept
|
||||
{
|
||||
if(! scoped_ && --refs_ == 0)
|
||||
delete this;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
friend class basic_storage_ptr;
|
||||
friend class storage_ptr;
|
||||
|
||||
template<class T>
|
||||
friend class scoped_storage;
|
||||
@ -52,6 +36,21 @@ public:
|
||||
virtual
|
||||
~storage() = default;
|
||||
|
||||
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_);
|
||||
}
|
||||
void*
|
||||
allocate(
|
||||
std::size_t n,
|
||||
@ -69,21 +68,6 @@ public:
|
||||
return do_deallocate(p, n, align);
|
||||
}
|
||||
|
||||
bool
|
||||
is_scoped() const noexcept
|
||||
{
|
||||
return scoped_;
|
||||
}
|
||||
|
||||
bool
|
||||
is_equal(
|
||||
storage const& other) const noexcept
|
||||
{
|
||||
return (this == &other) || (
|
||||
this->id_ != 0 &&
|
||||
this->id_ == other.id_);
|
||||
}
|
||||
|
||||
friend
|
||||
bool
|
||||
operator==(
|
||||
@ -105,9 +89,13 @@ public:
|
||||
protected:
|
||||
// Choose a unique 64-bit random number from here:
|
||||
// https://www.random.org/cgi-bin/randbyte?nbytes=8&format=h
|
||||
BOOST_JSON_DECL
|
||||
explicit
|
||||
storage(unsigned long long id = 0) noexcept;
|
||||
storage(
|
||||
bool need_free,
|
||||
unsigned long long id = 0) noexcept
|
||||
: id_(id)
|
||||
, need_free_(need_free)
|
||||
{
|
||||
}
|
||||
|
||||
virtual
|
||||
void*
|
||||
@ -123,456 +111,7 @@ protected:
|
||||
std::size_t align) noexcept = 0;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
/** Manages a type-erased storage object and options for a set of JSON values.
|
||||
*/
|
||||
template<class T>
|
||||
class basic_storage_ptr
|
||||
{
|
||||
BOOST_JSON_STATIC_ASSERT(
|
||||
std::is_base_of<storage, T>::value);
|
||||
|
||||
template<class U>
|
||||
friend class basic_storage_ptr;
|
||||
|
||||
template<class U>
|
||||
friend class scoped_storage;
|
||||
|
||||
T* t_ = nullptr;
|
||||
|
||||
explicit
|
||||
basic_storage_ptr(T* t) noexcept
|
||||
: t_(t)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
/** Construct a null storage pointer
|
||||
|
||||
This constructs a null storage pointer.
|
||||
|
||||
@par Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
*/
|
||||
basic_storage_ptr() = default;
|
||||
|
||||
/** Destroy a storage pointer.
|
||||
|
||||
If `this` is not null, the reference counter
|
||||
on the @ref storage object is decrement. When
|
||||
the reference count reaches zero, the object
|
||||
is destroyed.
|
||||
|
||||
@par Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
*/
|
||||
~basic_storage_ptr()
|
||||
{
|
||||
if(t_)
|
||||
t_->release();
|
||||
}
|
||||
|
||||
/** Move construct a storage pointer.
|
||||
|
||||
After construction, the moved-from pointer
|
||||
will be null.
|
||||
|
||||
@par Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
|
||||
@param other The storage pointer to construct from.
|
||||
*/
|
||||
basic_storage_ptr(
|
||||
basic_storage_ptr&& other) noexcept
|
||||
: t_(other.t_)
|
||||
{
|
||||
other.t_ = nullptr;
|
||||
}
|
||||
|
||||
/** Copy construct a storage pointer.
|
||||
|
||||
If `other` points to a valid @ref storage
|
||||
object, then this pointer acquires shared
|
||||
ownership of the storage. Otherwise, the
|
||||
newly constructed pointer is equal to null.
|
||||
|
||||
@par Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
|
||||
@param other The storage pointer to construct from.
|
||||
*/
|
||||
basic_storage_ptr(
|
||||
basic_storage_ptr const& other) noexcept
|
||||
: t_(other.t_)
|
||||
{
|
||||
if(t_)
|
||||
t_->addref();
|
||||
}
|
||||
|
||||
|
||||
template<class U
|
||||
#ifndef GENERATING_DOCUMENTATION
|
||||
,class = typename std::enable_if<
|
||||
std::is_convertible<U*, T*>::value &&
|
||||
! std::is_same<U, T>::value
|
||||
>::type
|
||||
#endif
|
||||
>
|
||||
basic_storage_ptr(
|
||||
basic_storage_ptr<U>&& sp) noexcept
|
||||
: t_(sp.t_)
|
||||
{
|
||||
sp.t_ = nullptr;
|
||||
}
|
||||
|
||||
template<class U
|
||||
#ifndef GENERATING_DOCUMENTATION
|
||||
,class = typename std::enable_if<
|
||||
std::is_convertible<U*, T*>::value &&
|
||||
! std::is_same<U, T>::value
|
||||
>::type
|
||||
#endif
|
||||
>
|
||||
basic_storage_ptr(
|
||||
basic_storage_ptr<U> const& sp) noexcept
|
||||
: t_(sp.t_)
|
||||
{
|
||||
if(t_)
|
||||
t_->addref();
|
||||
}
|
||||
|
||||
/** Construct an null storage pointer
|
||||
|
||||
This constructs a null storage pointer.
|
||||
|
||||
@par Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
*/
|
||||
basic_storage_ptr(
|
||||
std::nullptr_t) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
/** Move assign a storage pointer.
|
||||
|
||||
If `this` points to a valid object, it is
|
||||
decremented as if by a call to the destructor.
|
||||
After construction, the moved-from pointer
|
||||
will be null.
|
||||
|
||||
@par Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
|
||||
@param other The storage pointer to assign from.
|
||||
*/
|
||||
basic_storage_ptr&
|
||||
operator=(
|
||||
basic_storage_ptr&& other) noexcept
|
||||
{
|
||||
if(t_)
|
||||
t_->release();
|
||||
t_ = other.t_;
|
||||
other.t_ = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Copy construct a storage pointer.
|
||||
|
||||
If `this` points to a valid object, it is
|
||||
decremented as if by a call to the destructor.
|
||||
If `other` points to a valid @ref storage
|
||||
object, then this pointer acquires shared
|
||||
ownership of the storage. Otherwise, the
|
||||
newly constructed pointer is equal to null.
|
||||
|
||||
@par Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
|
||||
@param other The storage pointer to assign from.
|
||||
*/
|
||||
basic_storage_ptr&
|
||||
operator=(
|
||||
basic_storage_ptr const& other) noexcept
|
||||
{
|
||||
if(other.t_)
|
||||
other.t_->addref();
|
||||
if(t_)
|
||||
t_->release();
|
||||
t_ = other.t_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** Return true if this points to a valid storage object.
|
||||
|
||||
This function returns true if @ref get() returns
|
||||
a non-null value.
|
||||
|
||||
@par Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
|
||||
*/
|
||||
explicit
|
||||
operator bool() const noexcept
|
||||
{
|
||||
return t_ != nullptr;
|
||||
}
|
||||
|
||||
/** Return a pointer to the storage object.
|
||||
|
||||
If `this` points to a valid storage object,
|
||||
it is returned. Otherwise the return value
|
||||
is `nullptr`.
|
||||
|
||||
@par Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
*/
|
||||
T*
|
||||
get() const noexcept
|
||||
{
|
||||
return t_;
|
||||
}
|
||||
|
||||
/** Return a pointer to the storage object.
|
||||
|
||||
If `this` points to a valid storage object,
|
||||
it is returned. Otherwise the return value
|
||||
is `nullptr`.
|
||||
|
||||
@par Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
*/
|
||||
T*
|
||||
operator->() const noexcept
|
||||
{
|
||||
return t_;
|
||||
}
|
||||
|
||||
/** Return a reference to the storage object.
|
||||
|
||||
If `this` points to a valid storage object,
|
||||
it is returned. Otherwise the behavior is
|
||||
undefined.
|
||||
|
||||
@par Precondition
|
||||
|
||||
`this` points to a valid storage object.
|
||||
|
||||
@par Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
*/
|
||||
T&
|
||||
operator*() const noexcept
|
||||
{
|
||||
return *t_;
|
||||
}
|
||||
|
||||
/** Create a new storage object and return a pointer to it.
|
||||
|
||||
This functions similarly to `make_shared`.
|
||||
|
||||
@par Mandates
|
||||
|
||||
`std::is_base_of_v<storage, U>`
|
||||
|
||||
@par Complexity
|
||||
|
||||
Same as `U(std::forward<Args>(args)...)`.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
Strong guarantee.
|
||||
|
||||
@param args Parameters forwarded to the constructor of `U`.
|
||||
|
||||
@tparam U the type of the storage object to create.
|
||||
*/
|
||||
template<class U, class... Args>
|
||||
friend
|
||||
basic_storage_ptr<U>
|
||||
make_storage(Args&&... args);
|
||||
};
|
||||
|
||||
/** Compare two storage pointers
|
||||
*/
|
||||
template<class T, class U>
|
||||
bool
|
||||
operator==(
|
||||
basic_storage_ptr<T> const& lhs,
|
||||
basic_storage_ptr<U> const& rhs) noexcept
|
||||
{
|
||||
return lhs.get() == rhs.get();
|
||||
}
|
||||
|
||||
/** Compare two storage pointers
|
||||
*/
|
||||
template<class T, class U>
|
||||
bool
|
||||
operator!=(
|
||||
basic_storage_ptr<T> const& lhs,
|
||||
basic_storage_ptr<U> const& rhs) noexcept
|
||||
{
|
||||
return lhs.get() != rhs.get();
|
||||
}
|
||||
|
||||
/** Compare two storage pointers
|
||||
*/
|
||||
template<class T>
|
||||
bool
|
||||
operator==(
|
||||
basic_storage_ptr<T> const& lhs,
|
||||
std::nullptr_t) noexcept
|
||||
{
|
||||
return lhs.get() == nullptr;
|
||||
}
|
||||
|
||||
/** Compare two storage pointers
|
||||
*/
|
||||
template<class T>
|
||||
bool
|
||||
operator!=(
|
||||
basic_storage_ptr<T> const& lhs,
|
||||
std::nullptr_t) noexcept
|
||||
{
|
||||
return lhs.get() != nullptr;
|
||||
}
|
||||
|
||||
/** Compare two storage pointers
|
||||
*/
|
||||
template<class T>
|
||||
bool
|
||||
operator==(
|
||||
std::nullptr_t,
|
||||
basic_storage_ptr<T> const& rhs) noexcept
|
||||
{
|
||||
return rhs.get() == nullptr;
|
||||
}
|
||||
|
||||
/** Compare two storage pointers
|
||||
*/
|
||||
template<class T>
|
||||
bool
|
||||
operator!=(
|
||||
std::nullptr_t,
|
||||
basic_storage_ptr<T> const& rhs) noexcept
|
||||
{
|
||||
return rhs.get() != nullptr;
|
||||
}
|
||||
|
||||
/// A type-erased storage pointer.
|
||||
using storage_ptr = basic_storage_ptr<storage>;
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
template<class T>
|
||||
class scoped_storage
|
||||
{
|
||||
T t_;
|
||||
|
||||
BOOST_JSON_STATIC_ASSERT(
|
||||
std::is_base_of<storage, T>::value);
|
||||
|
||||
public:
|
||||
template<class... Args>
|
||||
explicit
|
||||
scoped_storage(Args&&... args)
|
||||
: t_(std::forward<Args>(args)...)
|
||||
{
|
||||
t_.scoped_ = true;
|
||||
}
|
||||
|
||||
operator storage_ptr() noexcept
|
||||
{
|
||||
return storage_ptr(&t_);
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
/** Return a pointer to the default storage
|
||||
|
||||
This function returns the default storage, which is
|
||||
used when constructing a container without explicitly
|
||||
specifying the storage. The default storage uses the
|
||||
global allocator, equivalent to `std::allocator<char>`.
|
||||
|
||||
@par Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
|
||||
@par Thread Safety
|
||||
|
||||
May be called concurrently.
|
||||
*/
|
||||
BOOST_JSON_DECL
|
||||
storage_ptr const&
|
||||
default_storage() noexcept;
|
||||
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
#include <boost/json/impl/storage.hpp>
|
||||
#ifdef BOOST_JSON_HEADER_ONLY
|
||||
#include <boost/json/impl/storage.ipp>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
363
include/boost/json/storage_ptr.hpp
Normal file
363
include/boost/json/storage_ptr.hpp
Normal file
@ -0,0 +1,363 @@
|
||||
//
|
||||
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot 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_PTR_HPP
|
||||
#define BOOST_JSON_STORAGE_PTR_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
#include <boost/json/storage.hpp>
|
||||
#include <cstddef>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
/** Manages a type-erased storage object and options for a set of JSON values.
|
||||
*/
|
||||
class storage_ptr
|
||||
{
|
||||
template<class T>
|
||||
friend class scoped_storage;
|
||||
|
||||
storage* p_ = nullptr;
|
||||
|
||||
inline
|
||||
void
|
||||
release() const noexcept
|
||||
{
|
||||
if( p_ &&
|
||||
p_->counted_ &&
|
||||
--p_->refs_ == 0)
|
||||
delete p_;
|
||||
}
|
||||
|
||||
explicit
|
||||
storage_ptr(storage* p) noexcept
|
||||
: p_(p)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
/** Construct a default storage pointer
|
||||
|
||||
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;
|
||||
|
||||
storage_ptr(std::nullptr_t) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
/** Destroy a storage pointer.
|
||||
|
||||
This releases the pointed-to storage. If the
|
||||
storage is reference counted and this is the
|
||||
last reference. the storage object is destroyed.
|
||||
If the storage does not require deallocation,
|
||||
all memory allocated using this storage is
|
||||
invalidated.
|
||||
|
||||
@par Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
*/
|
||||
~storage_ptr()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
/** Move construct a storage pointer.
|
||||
|
||||
After construction, the moved-from pointer
|
||||
will be null.
|
||||
|
||||
@par Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
|
||||
@param other The storage pointer to construct from.
|
||||
*/
|
||||
storage_ptr(
|
||||
storage_ptr&& other) noexcept
|
||||
: p_(other.p_)
|
||||
{
|
||||
other.p_ = nullptr;
|
||||
}
|
||||
|
||||
/** Copy construct a storage pointer.
|
||||
|
||||
If `other` points to a valid @ref storage
|
||||
object, then this pointer acquires shared
|
||||
ownership of the storage. Otherwise, the
|
||||
newly constructed pointer is the default
|
||||
storage pointer.
|
||||
|
||||
@par Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
|
||||
@param other The storage pointer to construct from.
|
||||
*/
|
||||
storage_ptr(
|
||||
storage_ptr const& other) noexcept
|
||||
: p_(other.p_)
|
||||
{
|
||||
if(p_)
|
||||
++p_->refs_;
|
||||
}
|
||||
|
||||
/** Move assign a storage pointer.
|
||||
|
||||
If `this` points to a valid object, it is
|
||||
decremented as if by a call to the destructor.
|
||||
After construction, the moved-from pointer
|
||||
will be null.
|
||||
|
||||
@par Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
|
||||
@param other The storage pointer to assign from.
|
||||
*/
|
||||
inline
|
||||
storage_ptr&
|
||||
operator=(
|
||||
storage_ptr&& other) noexcept;
|
||||
|
||||
/** Copy construct a storage pointer.
|
||||
|
||||
If `this` points to a valid object, it is
|
||||
decremented as if by a call to the destructor.
|
||||
If `other` points to a valid @ref storage
|
||||
object, then this pointer acquires shared
|
||||
ownership of the storage. Otherwise, the
|
||||
newly constructed pointer is equal to null.
|
||||
|
||||
@par Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
|
||||
@param other The storage pointer to assign from.
|
||||
*/
|
||||
inline
|
||||
storage_ptr&
|
||||
operator=(
|
||||
storage_ptr const& other) noexcept;
|
||||
|
||||
/** Return a pointer to the storage object.
|
||||
|
||||
If `this` points to a valid storage object,
|
||||
it is returned. Otherwise the return value
|
||||
is `nullptr`.
|
||||
|
||||
@par Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
*/
|
||||
inline
|
||||
storage*
|
||||
get() const noexcept;
|
||||
|
||||
/** Return a pointer to the storage object.
|
||||
|
||||
If `this` points to a valid storage object,
|
||||
it is returned. Otherwise the return value
|
||||
is `nullptr`.
|
||||
|
||||
@par Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
*/
|
||||
storage*
|
||||
operator->() const noexcept
|
||||
{
|
||||
return get();
|
||||
}
|
||||
|
||||
/** Return a reference to the storage object.
|
||||
|
||||
If `this` points to a valid storage object,
|
||||
it is returned. Otherwise the behavior is
|
||||
undefined.
|
||||
|
||||
@par Precondition
|
||||
|
||||
`this` points to a valid storage object.
|
||||
|
||||
@par Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
*/
|
||||
storage&
|
||||
operator*() const noexcept
|
||||
{
|
||||
return *get();
|
||||
}
|
||||
|
||||
/** Create a new storage object and return a pointer to it.
|
||||
|
||||
This functions similarly to `make_shared`.
|
||||
|
||||
@par Mandates
|
||||
|
||||
`std::is_base_of_v<storage, U>`
|
||||
|
||||
@par Complexity
|
||||
|
||||
Same as `U(std::forward<Args>(args)...)`.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
Strong guarantee.
|
||||
|
||||
@param args Parameters forwarded to the constructor of `U`.
|
||||
|
||||
@tparam U the type of the storage object to create.
|
||||
*/
|
||||
template<class U, class... Args>
|
||||
friend
|
||||
storage_ptr
|
||||
make_storage(Args&&... args);
|
||||
};
|
||||
|
||||
#ifndef GENERATING_DOCUMENTATION
|
||||
inline
|
||||
bool
|
||||
operator==(
|
||||
storage_ptr const& lhs,
|
||||
storage_ptr const& rhs) noexcept
|
||||
{
|
||||
return lhs.get() == rhs.get();
|
||||
}
|
||||
|
||||
inline
|
||||
bool
|
||||
operator!=(
|
||||
storage_ptr const& lhs,
|
||||
storage_ptr const& rhs) noexcept
|
||||
{
|
||||
return lhs.get() != rhs.get();
|
||||
}
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
template<class T>
|
||||
class scoped_storage
|
||||
{
|
||||
T t_;
|
||||
|
||||
BOOST_JSON_STATIC_ASSERT(
|
||||
std::is_base_of<storage, T>::value);
|
||||
|
||||
public:
|
||||
template<class... Args>
|
||||
explicit
|
||||
scoped_storage(Args&&... args)
|
||||
: t_(std::forward<Args>(args)...)
|
||||
{
|
||||
t_.counted_ = false;
|
||||
}
|
||||
|
||||
T*
|
||||
get() noexcept
|
||||
{
|
||||
return &t_;
|
||||
}
|
||||
|
||||
T*
|
||||
operator->() noexcept
|
||||
{
|
||||
return get();
|
||||
}
|
||||
|
||||
operator storage_ptr() noexcept
|
||||
{
|
||||
return storage_ptr(&t_);
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
/** Return a pointer to the default storage
|
||||
|
||||
This function returns the default storage, which is
|
||||
used when constructing a container without explicitly
|
||||
specifying the storage. The default storage uses the
|
||||
global allocator, equivalent to `std::allocator<char>`.
|
||||
|
||||
@par Complexity
|
||||
|
||||
Constant.
|
||||
|
||||
@par Exception Safety
|
||||
|
||||
No-throw guarantee.
|
||||
|
||||
@par Thread Safety
|
||||
|
||||
May be called concurrently.
|
||||
*/
|
||||
inline
|
||||
storage_ptr
|
||||
default_storage() noexcept
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
} // json
|
||||
} // boost
|
||||
|
||||
#include <boost/json/impl/storage_ptr.hpp>
|
||||
|
||||
#endif
|
@ -11,7 +11,7 @@
|
||||
#define BOOST_JSON_STRING_HPP
|
||||
|
||||
#include <boost/json/detail/config.hpp>
|
||||
#include <boost/json/storage.hpp>
|
||||
#include <boost/json/storage_ptr.hpp>
|
||||
#include <boost/json/detail/assert.hpp>
|
||||
#include <boost/json/detail/string.hpp>
|
||||
#include <boost/pilfer.hpp>
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include <boost/json/kind.hpp>
|
||||
#include <boost/json/number.hpp>
|
||||
#include <boost/json/object.hpp>
|
||||
#include <boost/json/storage.hpp>
|
||||
#include <boost/json/storage_ptr.hpp>
|
||||
#include <boost/json/string.hpp>
|
||||
#include <boost/json/detail/is_specialized.hpp>
|
||||
#include <boost/json/detail/value.hpp>
|
||||
|
@ -43,6 +43,7 @@ add_executable (json-tests
|
||||
parser.cpp
|
||||
serializer.cpp
|
||||
storage.cpp
|
||||
storage_ptr.cpp
|
||||
string.cpp
|
||||
value.cpp
|
||||
)
|
||||
|
@ -40,6 +40,7 @@ local SOURCES =
|
||||
parser.cpp
|
||||
serializer.cpp
|
||||
storage.cpp
|
||||
storage_ptr.cpp
|
||||
string.cpp
|
||||
value.cpp
|
||||
ryu/d2fixed_test.cpp
|
||||
|
@ -198,7 +198,6 @@ public:
|
||||
array a1(init.begin(), init.end());
|
||||
array a2(pilfer(a1));
|
||||
BEAST_EXPECT(a1.empty());
|
||||
BEAST_EXPECT(! a1.get_storage());
|
||||
check(a2);
|
||||
check_storage(a2, default_storage());
|
||||
}
|
||||
|
@ -10,6 +10,8 @@
|
||||
// Test that header file is self-contained.
|
||||
#include <boost/json/block_storage.hpp>
|
||||
|
||||
#include <boost/json/storage_ptr.hpp>
|
||||
|
||||
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
188
test/storage.cpp
188
test/storage.cpp
@ -9,191 +9,3 @@
|
||||
|
||||
// Test that header file is self-contained.
|
||||
#include <boost/json/storage.hpp>
|
||||
|
||||
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
||||
|
||||
#include "test.hpp"
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
class storage_test : public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
struct throwing : storage
|
||||
{
|
||||
throwing()
|
||||
{
|
||||
throw std::exception{};
|
||||
}
|
||||
|
||||
void*
|
||||
do_allocate(
|
||||
std::size_t,
|
||||
std::size_t) override
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
do_deallocate(
|
||||
void*,
|
||||
std::size_t,
|
||||
std::size_t) noexcept override
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
testMembers()
|
||||
{
|
||||
auto const dsp = default_storage();
|
||||
auto const usp =
|
||||
make_storage<unique_storage>();
|
||||
|
||||
// ~storage_ptr()
|
||||
{
|
||||
// implied
|
||||
}
|
||||
|
||||
// storage_ptr()
|
||||
{
|
||||
storage_ptr sp;
|
||||
BEAST_EXPECT(! sp);
|
||||
}
|
||||
|
||||
// storage_ptr(storage_ptr&&)
|
||||
{
|
||||
storage_ptr sp1 = dsp;
|
||||
storage_ptr sp2(std::move(sp1));
|
||||
BEAST_EXPECT(! sp1);
|
||||
BEAST_EXPECT(*sp2 == *dsp);
|
||||
}
|
||||
|
||||
// storage_ptr(storage_ptr const&)
|
||||
{
|
||||
storage_ptr sp1 = dsp;
|
||||
storage_ptr sp2(sp1);
|
||||
BEAST_EXPECT(sp1);
|
||||
BEAST_EXPECT(sp2);
|
||||
BEAST_EXPECT(sp1 == sp2);
|
||||
}
|
||||
|
||||
// storage_ptr(basic_storage_ptr<U>&&)
|
||||
{
|
||||
basic_storage_ptr<unique_storage> sp1 =
|
||||
make_storage<unique_storage>();
|
||||
storage_ptr sp2(std::move(sp1));
|
||||
BEAST_EXPECT(! sp1);
|
||||
BEAST_EXPECT(sp2);
|
||||
}
|
||||
|
||||
// storage_ptr(basic_storage_ptr<U> const&)
|
||||
{
|
||||
basic_storage_ptr<unique_storage> sp1 =
|
||||
make_storage<unique_storage>();
|
||||
storage_ptr sp2(sp1);
|
||||
BEAST_EXPECT(sp1);
|
||||
BEAST_EXPECT(sp2);
|
||||
BEAST_EXPECT(*sp1 == *sp2);
|
||||
}
|
||||
|
||||
// storage_ptr(nullptr_t)
|
||||
{
|
||||
storage_ptr sp(nullptr);
|
||||
BEAST_EXPECT(! sp);
|
||||
}
|
||||
|
||||
// operator=(storage_ptr&&)
|
||||
{
|
||||
storage_ptr sp1(dsp);
|
||||
storage_ptr sp2(usp);
|
||||
sp2 = std::move(sp1);
|
||||
BEAST_EXPECT(! sp1);
|
||||
BEAST_EXPECT(*sp2 == *dsp);
|
||||
}
|
||||
|
||||
// operator=(storage_ptr const&)
|
||||
{
|
||||
storage_ptr sp1(dsp);
|
||||
storage_ptr sp2(usp);
|
||||
sp2 = sp1;
|
||||
BEAST_EXPECT(sp1);
|
||||
BEAST_EXPECT(*sp1 == *sp2);
|
||||
}
|
||||
|
||||
// operator bool()
|
||||
{
|
||||
storage_ptr sp;
|
||||
BEAST_EXPECT(! sp);
|
||||
sp = dsp;
|
||||
BEAST_EXPECT(sp);
|
||||
}
|
||||
|
||||
// get()
|
||||
{
|
||||
storage_ptr sp(dsp);
|
||||
BEAST_EXPECT(sp.get() == dsp.get());
|
||||
}
|
||||
|
||||
// operator->()
|
||||
{
|
||||
storage_ptr sp(dsp);
|
||||
BEAST_EXPECT(sp.operator->() == dsp.get());
|
||||
}
|
||||
|
||||
// operator*()
|
||||
{
|
||||
storage_ptr sp(dsp);
|
||||
BEAST_EXPECT(&sp.operator*() == dsp.get());
|
||||
}
|
||||
|
||||
// exception in make_storage
|
||||
{
|
||||
BEAST_THROWS(
|
||||
make_storage<throwing>(),
|
||||
std::exception);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testRelational()
|
||||
{
|
||||
basic_storage_ptr<unique_storage> sp1 =
|
||||
make_storage<unique_storage>();
|
||||
storage_ptr sp2 = sp1;
|
||||
basic_storage_ptr<unique_storage> sp3 =
|
||||
make_storage<unique_storage>();
|
||||
storage_ptr sp4;
|
||||
BEAST_EXPECT(sp1 == sp2);
|
||||
BEAST_EXPECT(sp1 != sp3);
|
||||
BEAST_EXPECT(sp4 == nullptr);
|
||||
BEAST_EXPECT(sp3 != nullptr);
|
||||
BEAST_EXPECT(nullptr == sp4);
|
||||
BEAST_EXPECT(nullptr != sp3);
|
||||
}
|
||||
|
||||
void
|
||||
testDefaultStorage()
|
||||
{
|
||||
// default_storage()
|
||||
{
|
||||
auto sp1 = default_storage();
|
||||
auto sp2 = default_storage();
|
||||
BEAST_EXPECT(*sp1 == *sp2);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
testMembers();
|
||||
testRelational();
|
||||
testDefaultStorage();
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(boost,json,storage);
|
||||
|
||||
} // json
|
||||
} // boost
|
||||
|
145
test/storage_ptr.cpp
Normal file
145
test/storage_ptr.cpp
Normal file
@ -0,0 +1,145 @@
|
||||
//
|
||||
// Copyright (c) 2018-2019 Vinnie Falco (vinnie dot falco at gmail dot 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_ptr.hpp>
|
||||
|
||||
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
||||
|
||||
#include "test.hpp"
|
||||
|
||||
namespace boost {
|
||||
namespace json {
|
||||
|
||||
class storage_ptr_test : public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
struct throwing : storage
|
||||
{
|
||||
throwing()
|
||||
: storage(false)
|
||||
{
|
||||
throw std::exception{};
|
||||
}
|
||||
|
||||
void*
|
||||
do_allocate(
|
||||
std::size_t,
|
||||
std::size_t) override
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
do_deallocate(
|
||||
void*,
|
||||
std::size_t,
|
||||
std::size_t) noexcept override
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
testMembers()
|
||||
{
|
||||
auto const dsp = default_storage();
|
||||
auto const usp =
|
||||
make_storage<unique_storage>();
|
||||
|
||||
// ~storage_ptr()
|
||||
{
|
||||
// implied
|
||||
}
|
||||
|
||||
// storage_ptr()
|
||||
{
|
||||
storage_ptr sp;
|
||||
BEAST_EXPECT(sp.get());
|
||||
}
|
||||
|
||||
// storage_ptr(storage_ptr&&)
|
||||
{
|
||||
storage_ptr sp1 = dsp;
|
||||
storage_ptr sp2(std::move(sp1));
|
||||
BEAST_EXPECT(sp1.get());
|
||||
BEAST_EXPECT(*sp2 == *dsp);
|
||||
}
|
||||
|
||||
// storage_ptr(storage_ptr const&)
|
||||
{
|
||||
storage_ptr sp1 = dsp;
|
||||
storage_ptr sp2(sp1);
|
||||
BEAST_EXPECT(sp1 == sp2);
|
||||
}
|
||||
|
||||
// operator=(storage_ptr&&)
|
||||
{
|
||||
storage_ptr sp1(dsp);
|
||||
storage_ptr sp2(usp);
|
||||
sp2 = std::move(sp1);
|
||||
BEAST_EXPECT(*sp2 == *dsp);
|
||||
}
|
||||
|
||||
// operator=(storage_ptr const&)
|
||||
{
|
||||
storage_ptr sp1(dsp);
|
||||
storage_ptr sp2(usp);
|
||||
sp2 = sp1;
|
||||
BEAST_EXPECT(*sp1 == *sp2);
|
||||
}
|
||||
|
||||
// get()
|
||||
{
|
||||
storage_ptr sp(dsp);
|
||||
BEAST_EXPECT(sp.get() == dsp.get());
|
||||
}
|
||||
|
||||
// operator->()
|
||||
{
|
||||
storage_ptr sp(dsp);
|
||||
BEAST_EXPECT(sp.operator->() == dsp.get());
|
||||
}
|
||||
|
||||
// operator*()
|
||||
{
|
||||
storage_ptr sp(dsp);
|
||||
BEAST_EXPECT(&sp.operator*() == dsp.get());
|
||||
}
|
||||
|
||||
// exception in make_storage
|
||||
{
|
||||
BEAST_THROWS(
|
||||
make_storage<throwing>(),
|
||||
std::exception);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
testDefaultStorage()
|
||||
{
|
||||
// default_storage()
|
||||
{
|
||||
auto sp1 = default_storage();
|
||||
auto sp2 = default_storage();
|
||||
BEAST_EXPECT(*sp1 == *sp2);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
testMembers();
|
||||
testDefaultStorage();
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(boost,json,storage_ptr);
|
||||
|
||||
} // json
|
||||
} // boost
|
107
test/test.hpp
107
test/test.hpp
@ -12,7 +12,7 @@
|
||||
|
||||
#include <boost/json/basic_parser.hpp>
|
||||
#include <boost/json/value.hpp>
|
||||
#include <boost/json/storage.hpp>
|
||||
#include <boost/json/storage_ptr.hpp>
|
||||
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
@ -27,25 +27,26 @@ namespace json {
|
||||
// unique_storage
|
||||
struct unique_storage : storage
|
||||
{
|
||||
unique_storage()
|
||||
: storage(true)
|
||||
{
|
||||
}
|
||||
|
||||
void*
|
||||
do_allocate(
|
||||
std::size_t n,
|
||||
std::size_t) override
|
||||
{
|
||||
return std::allocator<
|
||||
char>{}.allocate(n);
|
||||
return ::operator new(n);
|
||||
}
|
||||
|
||||
void
|
||||
do_deallocate(
|
||||
void* p,
|
||||
std::size_t n,
|
||||
std::size_t,
|
||||
std::size_t) noexcept override
|
||||
{
|
||||
auto cp =
|
||||
reinterpret_cast<char*>(p);
|
||||
return std::allocator<
|
||||
char>{}.deallocate(cp, n);
|
||||
return ::operator delete(p);
|
||||
}
|
||||
};
|
||||
|
||||
@ -66,7 +67,8 @@ struct fail_storage : storage
|
||||
std::size_t fail_max = 1;
|
||||
std::size_t fail = 0;
|
||||
|
||||
~fail_storage()
|
||||
fail_storage()
|
||||
: storage(true)
|
||||
{
|
||||
}
|
||||
|
||||
@ -81,39 +83,31 @@ struct fail_storage : storage
|
||||
fail = 0;
|
||||
throw test_failure{};
|
||||
}
|
||||
return std::allocator<
|
||||
char>{}.allocate(n);
|
||||
return ::operator new(n);
|
||||
}
|
||||
|
||||
void
|
||||
do_deallocate(
|
||||
void* p,
|
||||
std::size_t n,
|
||||
std::size_t,
|
||||
std::size_t) noexcept override
|
||||
{
|
||||
auto cp =
|
||||
reinterpret_cast<char*>(p);
|
||||
return std::allocator<
|
||||
char>{}.deallocate(cp, n);
|
||||
::operator delete(p);
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
||||
namespace detail {
|
||||
|
||||
#if 1
|
||||
|
||||
template<class F>
|
||||
void
|
||||
fail_loop(F&& f)
|
||||
{
|
||||
auto sp = make_storage<fail_storage>();
|
||||
while(sp->fail < 200)
|
||||
scoped_storage<fail_storage> ss;
|
||||
while(ss->fail < 200)
|
||||
{
|
||||
try
|
||||
{
|
||||
f(sp);
|
||||
f(ss);
|
||||
}
|
||||
catch(test_failure const&)
|
||||
{
|
||||
@ -121,72 +115,7 @@ fail_loop(F&& f)
|
||||
}
|
||||
break;
|
||||
}
|
||||
BEAST_EXPECT(sp->fail < 200);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template<class F>
|
||||
typename std::enable_if<
|
||||
std::is_same<void,
|
||||
decltype(std::declval<F const&>()(
|
||||
std::declval<storage_ptr>()))>::value
|
||||
>::type
|
||||
fail_loop(F&& f)
|
||||
{
|
||||
auto sp = make_storage<fail_storage>();
|
||||
while(sp->fail < 200)
|
||||
{
|
||||
try
|
||||
{
|
||||
f(sp);
|
||||
}
|
||||
catch(test_failure const&)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
BEAST_EXPECT(sp->fail < 200);
|
||||
}
|
||||
|
||||
template<class F>
|
||||
typename std::enable_if<
|
||||
std::is_same<void, decltype(
|
||||
std::declval<F const&>()())>::value
|
||||
>::type
|
||||
fail_loop(F&& f)
|
||||
{
|
||||
auto saved = default_storage();
|
||||
auto sp =
|
||||
make_storage<fail_storage>();
|
||||
default_storage(sp);
|
||||
while(sp->fail < 200)
|
||||
{
|
||||
try
|
||||
{
|
||||
f();
|
||||
}
|
||||
catch(test_failure const&)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
BEAST_EXPECT(sp->fail < 200);
|
||||
default_storage(saved);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // detail
|
||||
|
||||
template<class F>
|
||||
void
|
||||
fail_loop(F&& f)
|
||||
{
|
||||
detail::fail_loop(
|
||||
std::forward<F>(f));
|
||||
BEAST_EXPECT(ss->fail < 200);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------
|
||||
|
Loading…
x
Reference in New Issue
Block a user