mirror of
https://github.com/boostorg/json.git
synced 2025-05-11 21:53:58 +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 "/")
|
GroupSources(bench "/")
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
add_compile_options(
|
if (CMAKE_BUILD_TYPE EQUAL "Debug")
|
||||||
/GL # Whole program optimization
|
else()
|
||||||
/Ob2 # inline any suitable
|
add_compile_options(
|
||||||
)
|
/GL # Whole program optimization
|
||||||
|
/Ob2 # inline any suitable
|
||||||
add_link_options(
|
)
|
||||||
/LTCG # Link Time Code Generation
|
|
||||||
)
|
|
||||||
|
|
||||||
|
add_link_options(
|
||||||
|
/LTCG # Link Time Code Generation
|
||||||
|
)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_executable (bench
|
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
|
struct rapidjson_impl : public any_impl
|
||||||
@ -674,9 +259,6 @@ main(
|
|||||||
vi.reserve(10);
|
vi.reserve(10);
|
||||||
vi.emplace_back(new boost_impl);
|
vi.emplace_back(new boost_impl);
|
||||||
vi.emplace_back(new rapidjson_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);
|
//vi.emplace_back(new nlohmann_impl);
|
||||||
|
|
||||||
//benchParse(vs, vi);
|
//benchParse(vs, vi);
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
#include <boost/json/parser.hpp>
|
#include <boost/json/parser.hpp>
|
||||||
#include <boost/json/serializer.hpp>
|
#include <boost/json/serializer.hpp>
|
||||||
#include <boost/json/storage.hpp>
|
#include <boost/json/storage.hpp>
|
||||||
|
#include <boost/json/storage_ptr.hpp>
|
||||||
#include <boost/json/string.hpp>
|
#include <boost/json/string.hpp>
|
||||||
#include <boost/json/value.hpp>
|
#include <boost/json/value.hpp>
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
#include <boost/json/detail/config.hpp>
|
#include <boost/json/detail/config.hpp>
|
||||||
#include <boost/json/kind.hpp>
|
#include <boost/json/kind.hpp>
|
||||||
#include <boost/json/storage.hpp>
|
#include <boost/json/storage_ptr.hpp>
|
||||||
#include <boost/pilfer.hpp>
|
#include <boost/pilfer.hpp>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
|
@ -80,7 +80,8 @@ public:
|
|||||||
explicit
|
explicit
|
||||||
block_storage(
|
block_storage(
|
||||||
std::size_t block_size = 64 * 1024)
|
std::size_t block_size = 64 * 1024)
|
||||||
: block_size_(block_size)
|
: storage(false)
|
||||||
|
, block_size_(block_size)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,8 +19,8 @@ inline
|
|||||||
T
|
T
|
||||||
exchange(T& t, U u) noexcept
|
exchange(T& t, U u) noexcept
|
||||||
{
|
{
|
||||||
T v = t;
|
T v = std::move(t);
|
||||||
t = u;
|
t = std::move(u);
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,14 +52,15 @@ impl_type::
|
|||||||
destroy(
|
destroy(
|
||||||
storage_ptr const& sp) noexcept
|
storage_ptr const& sp) noexcept
|
||||||
{
|
{
|
||||||
if(! vec || sp->is_scoped())
|
if(vec && sp->need_free())
|
||||||
return;
|
{
|
||||||
auto it = vec + size;
|
auto it = vec + size;
|
||||||
while(it != vec)
|
while(it != vec)
|
||||||
(*--it).~value();
|
(*--it).~value();
|
||||||
sp->deallocate(vec,
|
sp->deallocate(vec,
|
||||||
capacity * sizeof(value),
|
capacity * sizeof(value),
|
||||||
alignof(value));
|
alignof(value));
|
||||||
|
}
|
||||||
vec = nullptr;
|
vec = nullptr;
|
||||||
size = 0;
|
size = 0;
|
||||||
capacity = 0;
|
capacity = 0;
|
||||||
@ -163,8 +164,7 @@ undo_insert(
|
|||||||
array::
|
array::
|
||||||
~array()
|
~array()
|
||||||
{
|
{
|
||||||
if(sp_)
|
impl_.destroy(sp_);
|
||||||
impl_.destroy(sp_);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------
|
//----------------------------------------------------------
|
||||||
@ -558,7 +558,7 @@ array::
|
|||||||
destroy(
|
destroy(
|
||||||
value* first, value* last) noexcept
|
value* first, value* last) noexcept
|
||||||
{
|
{
|
||||||
if(! sp_->is_scoped())
|
if(sp_->need_free())
|
||||||
while(last != first)
|
while(last != first)
|
||||||
(*--last).~value();
|
(*--last).~value();
|
||||||
}
|
}
|
||||||
|
@ -260,7 +260,7 @@ const_iterator(
|
|||||||
object::
|
object::
|
||||||
~object()
|
~object()
|
||||||
{
|
{
|
||||||
if(sp_ && ! sp_->is_scoped())
|
if(sp_->need_free())
|
||||||
release_storage();
|
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
|
#define BOOST_JSON_OBJECT_HPP
|
||||||
|
|
||||||
#include <boost/json/detail/config.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/json/detail/string.hpp>
|
||||||
#include <boost/pilfer.hpp>
|
#include <boost/pilfer.hpp>
|
||||||
#include <cstdlib>
|
#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/object.ipp>
|
||||||
#include <boost/json/impl/parser.ipp>
|
#include <boost/json/impl/parser.ipp>
|
||||||
#include <boost/json/impl/serializer.ipp>
|
#include <boost/json/impl/serializer.ipp>
|
||||||
#include <boost/json/impl/storage.ipp>
|
|
||||||
#include <boost/json/impl/string.ipp>
|
#include <boost/json/impl/string.ipp>
|
||||||
#include <boost/json/impl/value.ipp>
|
#include <boost/json/impl/value.ipp>
|
||||||
|
|
||||||
|
@ -12,10 +12,7 @@
|
|||||||
|
|
||||||
#include <boost/json/detail/config.hpp>
|
#include <boost/json/detail/config.hpp>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <cstdlib>
|
#include <cstddef>
|
||||||
#include <memory>
|
|
||||||
#include <type_traits>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
namespace json {
|
namespace json {
|
||||||
@ -24,26 +21,13 @@ namespace json {
|
|||||||
*/
|
*/
|
||||||
class storage
|
class storage
|
||||||
{
|
{
|
||||||
std::atomic<std::size_t> refs_;
|
std::atomic<
|
||||||
unsigned long long id_ = 0;
|
unsigned long long> refs_{ 1 };
|
||||||
bool scoped_ = false;
|
unsigned long long const id_ = 0;
|
||||||
|
bool const need_free_ = true;
|
||||||
|
bool counted_ = true;
|
||||||
|
|
||||||
void
|
friend class storage_ptr;
|
||||||
addref() noexcept
|
|
||||||
{
|
|
||||||
if(! scoped_)
|
|
||||||
++refs_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
release() noexcept
|
|
||||||
{
|
|
||||||
if(! scoped_ && --refs_ == 0)
|
|
||||||
delete this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class T>
|
|
||||||
friend class basic_storage_ptr;
|
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
friend class scoped_storage;
|
friend class scoped_storage;
|
||||||
@ -52,6 +36,21 @@ public:
|
|||||||
virtual
|
virtual
|
||||||
~storage() = default;
|
~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*
|
void*
|
||||||
allocate(
|
allocate(
|
||||||
std::size_t n,
|
std::size_t n,
|
||||||
@ -69,21 +68,6 @@ public:
|
|||||||
return do_deallocate(p, n, align);
|
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
|
friend
|
||||||
bool
|
bool
|
||||||
operator==(
|
operator==(
|
||||||
@ -105,9 +89,13 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
// Choose a unique 64-bit random number from here:
|
// Choose a unique 64-bit random number from here:
|
||||||
// https://www.random.org/cgi-bin/randbyte?nbytes=8&format=h
|
// https://www.random.org/cgi-bin/randbyte?nbytes=8&format=h
|
||||||
BOOST_JSON_DECL
|
storage(
|
||||||
explicit
|
bool need_free,
|
||||||
storage(unsigned long long id = 0) noexcept;
|
unsigned long long id = 0) noexcept
|
||||||
|
: id_(id)
|
||||||
|
, need_free_(need_free)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
virtual
|
virtual
|
||||||
void*
|
void*
|
||||||
@ -123,456 +111,7 @@ protected:
|
|||||||
std::size_t align) noexcept = 0;
|
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
|
} // json
|
||||||
} // boost
|
} // boost
|
||||||
|
|
||||||
#include <boost/json/impl/storage.hpp>
|
|
||||||
#ifdef BOOST_JSON_HEADER_ONLY
|
|
||||||
#include <boost/json/impl/storage.ipp>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#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
|
#define BOOST_JSON_STRING_HPP
|
||||||
|
|
||||||
#include <boost/json/detail/config.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/assert.hpp>
|
||||||
#include <boost/json/detail/string.hpp>
|
#include <boost/json/detail/string.hpp>
|
||||||
#include <boost/pilfer.hpp>
|
#include <boost/pilfer.hpp>
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
#include <boost/json/kind.hpp>
|
#include <boost/json/kind.hpp>
|
||||||
#include <boost/json/number.hpp>
|
#include <boost/json/number.hpp>
|
||||||
#include <boost/json/object.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/string.hpp>
|
||||||
#include <boost/json/detail/is_specialized.hpp>
|
#include <boost/json/detail/is_specialized.hpp>
|
||||||
#include <boost/json/detail/value.hpp>
|
#include <boost/json/detail/value.hpp>
|
||||||
|
@ -43,6 +43,7 @@ add_executable (json-tests
|
|||||||
parser.cpp
|
parser.cpp
|
||||||
serializer.cpp
|
serializer.cpp
|
||||||
storage.cpp
|
storage.cpp
|
||||||
|
storage_ptr.cpp
|
||||||
string.cpp
|
string.cpp
|
||||||
value.cpp
|
value.cpp
|
||||||
)
|
)
|
||||||
|
@ -40,6 +40,7 @@ local SOURCES =
|
|||||||
parser.cpp
|
parser.cpp
|
||||||
serializer.cpp
|
serializer.cpp
|
||||||
storage.cpp
|
storage.cpp
|
||||||
|
storage_ptr.cpp
|
||||||
string.cpp
|
string.cpp
|
||||||
value.cpp
|
value.cpp
|
||||||
ryu/d2fixed_test.cpp
|
ryu/d2fixed_test.cpp
|
||||||
|
@ -198,7 +198,6 @@ public:
|
|||||||
array a1(init.begin(), init.end());
|
array a1(init.begin(), init.end());
|
||||||
array a2(pilfer(a1));
|
array a2(pilfer(a1));
|
||||||
BEAST_EXPECT(a1.empty());
|
BEAST_EXPECT(a1.empty());
|
||||||
BEAST_EXPECT(! a1.get_storage());
|
|
||||||
check(a2);
|
check(a2);
|
||||||
check_storage(a2, default_storage());
|
check_storage(a2, default_storage());
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
// Test that header file is self-contained.
|
// Test that header file is self-contained.
|
||||||
#include <boost/json/block_storage.hpp>
|
#include <boost/json/block_storage.hpp>
|
||||||
|
|
||||||
|
#include <boost/json/storage_ptr.hpp>
|
||||||
|
|
||||||
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
|
188
test/storage.cpp
188
test/storage.cpp
@ -9,191 +9,3 @@
|
|||||||
|
|
||||||
// Test that header file is self-contained.
|
// Test that header file is self-contained.
|
||||||
#include <boost/json/storage.hpp>
|
#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/basic_parser.hpp>
|
||||||
#include <boost/json/value.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 <boost/beast/_experimental/unit_test/suite.hpp>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
@ -27,25 +27,26 @@ namespace json {
|
|||||||
// unique_storage
|
// unique_storage
|
||||||
struct unique_storage : storage
|
struct unique_storage : storage
|
||||||
{
|
{
|
||||||
|
unique_storage()
|
||||||
|
: storage(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void*
|
void*
|
||||||
do_allocate(
|
do_allocate(
|
||||||
std::size_t n,
|
std::size_t n,
|
||||||
std::size_t) override
|
std::size_t) override
|
||||||
{
|
{
|
||||||
return std::allocator<
|
return ::operator new(n);
|
||||||
char>{}.allocate(n);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
do_deallocate(
|
do_deallocate(
|
||||||
void* p,
|
void* p,
|
||||||
std::size_t n,
|
std::size_t,
|
||||||
std::size_t) noexcept override
|
std::size_t) noexcept override
|
||||||
{
|
{
|
||||||
auto cp =
|
return ::operator delete(p);
|
||||||
reinterpret_cast<char*>(p);
|
|
||||||
return std::allocator<
|
|
||||||
char>{}.deallocate(cp, n);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -66,7 +67,8 @@ struct fail_storage : storage
|
|||||||
std::size_t fail_max = 1;
|
std::size_t fail_max = 1;
|
||||||
std::size_t fail = 0;
|
std::size_t fail = 0;
|
||||||
|
|
||||||
~fail_storage()
|
fail_storage()
|
||||||
|
: storage(true)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,39 +83,31 @@ struct fail_storage : storage
|
|||||||
fail = 0;
|
fail = 0;
|
||||||
throw test_failure{};
|
throw test_failure{};
|
||||||
}
|
}
|
||||||
return std::allocator<
|
return ::operator new(n);
|
||||||
char>{}.allocate(n);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
do_deallocate(
|
do_deallocate(
|
||||||
void* p,
|
void* p,
|
||||||
std::size_t n,
|
std::size_t,
|
||||||
std::size_t) noexcept override
|
std::size_t) noexcept override
|
||||||
{
|
{
|
||||||
auto cp =
|
::operator delete(p);
|
||||||
reinterpret_cast<char*>(p);
|
|
||||||
return std::allocator<
|
|
||||||
char>{}.deallocate(cp, n);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------------------------------------------------
|
//----------------------------------------------------------
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
|
|
||||||
template<class F>
|
template<class F>
|
||||||
void
|
void
|
||||||
fail_loop(F&& f)
|
fail_loop(F&& f)
|
||||||
{
|
{
|
||||||
auto sp = make_storage<fail_storage>();
|
scoped_storage<fail_storage> ss;
|
||||||
while(sp->fail < 200)
|
while(ss->fail < 200)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
f(sp);
|
f(ss);
|
||||||
}
|
}
|
||||||
catch(test_failure const&)
|
catch(test_failure const&)
|
||||||
{
|
{
|
||||||
@ -121,72 +115,7 @@ fail_loop(F&& f)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
BEAST_EXPECT(sp->fail < 200);
|
BEAST_EXPECT(ss->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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------
|
//----------------------------------------------------------
|
||||||
|
Loading…
x
Reference in New Issue
Block a user