mirror of
https://github.com/boostorg/json.git
synced 2025-05-12 06:01:41 +00:00
scoped storage
This commit is contained in:
parent
1754d9cadd
commit
96ecab8cc8
335
bench/bench.cpp
335
bench/bench.cpp
@ -7,6 +7,8 @@
|
|||||||
// Official repository: https://github.com/vinniefalco/json
|
// Official repository: https://github.com/vinniefalco/json
|
||||||
//
|
//
|
||||||
|
|
||||||
|
//#define RAPIDJSON_SSE42
|
||||||
|
|
||||||
#include "lib/nlohmann/single_include/nlohmann/json.hpp"
|
#include "lib/nlohmann/single_include/nlohmann/json.hpp"
|
||||||
|
|
||||||
#include "lib/rapidjson/include/rapidjson/rapidjson.h"
|
#include "lib/rapidjson/include/rapidjson/rapidjson.h"
|
||||||
@ -19,7 +21,6 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <random>
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -47,10 +48,7 @@ class any_impl
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~any_impl() = default;
|
virtual ~any_impl() = default;
|
||||||
|
|
||||||
virtual string_view name() const noexcept = 0;
|
virtual string_view name() const noexcept = 0;
|
||||||
virtual void work(string_view s) const = 0;
|
|
||||||
|
|
||||||
virtual void parse(string_view s, int repeat) const = 0;
|
virtual void parse(string_view s, int repeat) const = 0;
|
||||||
virtual void serialize(string_view s, int repeat) const = 0;
|
virtual void serialize(string_view s, int repeat) const = 0;
|
||||||
};
|
};
|
||||||
@ -66,48 +64,6 @@ public:
|
|||||||
return "Boost.JSON";
|
return "Boost.JSON";
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
|
||||||
std::string
|
|
||||||
to_string(
|
|
||||||
json::value const& jv,
|
|
||||||
std::size_t size_hint)
|
|
||||||
{
|
|
||||||
std::string s;
|
|
||||||
std::size_t len = 0;
|
|
||||||
s.resize(size_hint);
|
|
||||||
json::serializer p(jv);
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
auto const used = p.next(
|
|
||||||
&s[len], s.size() - len);
|
|
||||||
len += used;
|
|
||||||
s.resize(len);
|
|
||||||
if(p.is_done())
|
|
||||||
break;
|
|
||||||
s.resize((len * 3) / 2);
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
work(string_view s) const override
|
|
||||||
{
|
|
||||||
std::string s2;
|
|
||||||
{
|
|
||||||
json::parser p;
|
|
||||||
boost::system::error_code ec;
|
|
||||||
p.write(s.data(), s.size(), ec);
|
|
||||||
s2 = to_string(p.get(), s.size() * 2);
|
|
||||||
dout << "s2.size() == " << s2.size() << std::endl;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
json::parser p;
|
|
||||||
boost::system::error_code ec;
|
|
||||||
p.write(s2.data(), s2.size(), ec);
|
|
||||||
dout << "ec.message() == " << ec.message() << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
parse(
|
parse(
|
||||||
string_view s,
|
string_view s,
|
||||||
@ -115,9 +71,9 @@ public:
|
|||||||
{
|
{
|
||||||
while(repeat--)
|
while(repeat--)
|
||||||
{
|
{
|
||||||
auto sp = json::make_storage<
|
json::scoped_storage<
|
||||||
json::block_storage>();
|
json::block_storage> ss;
|
||||||
json::parse(s, sp);
|
json::parse(s, ss);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,25 +98,6 @@ struct rapidjson_impl : public any_impl
|
|||||||
return "rapidjson";
|
return "rapidjson";
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
work(string_view s) const override
|
|
||||||
{
|
|
||||||
rapidjson::StringBuffer s2;
|
|
||||||
{
|
|
||||||
rapidjson::Document d;
|
|
||||||
d.Parse(s.data(), s.size());
|
|
||||||
s2.Clear();
|
|
||||||
rapidjson::Writer<
|
|
||||||
rapidjson::StringBuffer> wr(s2);
|
|
||||||
d.Accept(wr);
|
|
||||||
dout << "s2.GetSize() == " << s2.GetSize() << std::endl;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
rapidjson::Document d;
|
|
||||||
d.Parse(s2.GetString(), s2.GetSize());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
parse(string_view s, int repeat) const override
|
parse(string_view s, int repeat) const override
|
||||||
{
|
{
|
||||||
@ -197,13 +134,6 @@ struct nlohmann_impl : public any_impl
|
|||||||
return "nlohmann";
|
return "nlohmann";
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
work(string_view s) const override
|
|
||||||
{
|
|
||||||
auto jv = nlohmann::json::parse(
|
|
||||||
s.begin(), s.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
parse(string_view s, int repeat) const override
|
parse(string_view s, int repeat) const override
|
||||||
{
|
{
|
||||||
@ -220,247 +150,13 @@ struct nlohmann_impl : public any_impl
|
|||||||
|
|
||||||
//----------------------------------------------------------
|
//----------------------------------------------------------
|
||||||
|
|
||||||
class factory
|
struct file_item
|
||||||
{
|
{
|
||||||
std::string s_;
|
string_view name;
|
||||||
std::mt19937 g_;
|
std::string text;
|
||||||
std::string lorem_;
|
|
||||||
int depth_;
|
|
||||||
int indent_ = 4;
|
|
||||||
int max_depth_ = 6;
|
|
||||||
|
|
||||||
std::size_t
|
|
||||||
rand(std::size_t n)
|
|
||||||
{
|
|
||||||
return static_cast<std::size_t>(
|
|
||||||
std::uniform_int_distribution<
|
|
||||||
std::size_t>{0, n-1}(g_));
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
factory()
|
|
||||||
: lorem_(
|
|
||||||
// 40 characters
|
|
||||||
"Lorem ipsum dolor sit amet, consectetur " // 1
|
|
||||||
"adipiscing elit, sed do eiusmod tempor i" // 2
|
|
||||||
"ncididunt ut labore et dolore magna aliq" // 3
|
|
||||||
"ua. Ut enim ad minim veniam, quis nostru" // 4
|
|
||||||
"d exercitation ullamco laboris nisi ut a" // 5
|
|
||||||
"liquip ex ea commodo consequat. Duis aut" // 6
|
|
||||||
"e irure dolor in reprehenderit in volupt" // 7
|
|
||||||
"ate velit esse cillum dolore eu fugiat n" // 8
|
|
||||||
"ulla pariatur. Excepteur sint occaecat c" // 9
|
|
||||||
"upidatat non proident, sunt in culpa qui" // 10
|
|
||||||
" officia deserunt mollit anim id est lab" // 11
|
|
||||||
"orum."
|
|
||||||
)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string const&
|
|
||||||
key(std::string& s) noexcept
|
|
||||||
{
|
|
||||||
s.clear();
|
|
||||||
s.reserve(20);
|
|
||||||
auto const append =
|
|
||||||
[this, &s]()
|
|
||||||
{
|
|
||||||
s.push_back(
|
|
||||||
"0123456789"
|
|
||||||
"abcdefghijklmnopqrstuvwxyz"
|
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"[
|
|
||||||
this->rand(62)]);
|
|
||||||
};
|
|
||||||
append();
|
|
||||||
append();
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
append();
|
|
||||||
if(! rand(5) || s.size() >= s.max_size())
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
string_view
|
|
||||||
string() noexcept
|
|
||||||
{
|
|
||||||
return {
|
|
||||||
lorem_.data(),
|
|
||||||
1 + rand(lorem_.size()) };
|
|
||||||
//1 + rand(20) };
|
|
||||||
}
|
|
||||||
|
|
||||||
std::size_t
|
|
||||||
integer() noexcept
|
|
||||||
{
|
|
||||||
return rand(std::numeric_limits<
|
|
||||||
std::size_t>::max());
|
|
||||||
}
|
|
||||||
|
|
||||||
//---
|
|
||||||
|
|
||||||
private:
|
|
||||||
void
|
|
||||||
append_key() noexcept
|
|
||||||
{
|
|
||||||
auto const append =
|
|
||||||
[this]()
|
|
||||||
{
|
|
||||||
s_.push_back(
|
|
||||||
"0123456789"
|
|
||||||
"abcdefghijklmnopqrstuvwxyz"
|
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"[
|
|
||||||
rand(62)]);
|
|
||||||
};
|
|
||||||
s_.push_back('"');
|
|
||||||
append();
|
|
||||||
append();
|
|
||||||
append();
|
|
||||||
append();
|
|
||||||
append();
|
|
||||||
for(;;)
|
|
||||||
{
|
|
||||||
append();
|
|
||||||
if(! rand(5))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
s_.append("\" : ", 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
append_object()
|
|
||||||
{
|
|
||||||
s_.append("{\n", 2);
|
|
||||||
++depth_;
|
|
||||||
|
|
||||||
s_.append(depth_ * indent_, ' ');
|
|
||||||
append_key();
|
|
||||||
append_value();
|
|
||||||
while(rand(40))
|
|
||||||
{
|
|
||||||
s_.append(",\n", 2);
|
|
||||||
s_.append(depth_ * indent_, ' ');
|
|
||||||
append_key();
|
|
||||||
append_value();
|
|
||||||
}
|
|
||||||
s_.push_back('\n');
|
|
||||||
|
|
||||||
--depth_;
|
|
||||||
s_.append(depth_ * indent_, ' ');
|
|
||||||
s_.push_back('}');
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
append_array()
|
|
||||||
{
|
|
||||||
s_.append("[\n", 2);
|
|
||||||
++depth_;
|
|
||||||
|
|
||||||
s_.append(depth_ * indent_, ' ');
|
|
||||||
append_value();
|
|
||||||
while(rand(20))
|
|
||||||
{
|
|
||||||
s_.append(",\n", 2);
|
|
||||||
s_.append(depth_ * indent_, ' ');
|
|
||||||
append_value();
|
|
||||||
}
|
|
||||||
s_.push_back('\n');
|
|
||||||
|
|
||||||
--depth_;
|
|
||||||
s_.append(depth_ * indent_, ' ');
|
|
||||||
s_.push_back(']');
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
append_string()
|
|
||||||
{
|
|
||||||
auto const v = string();
|
|
||||||
s_.reserve(
|
|
||||||
s_.size() + 1 + v.size() + 1);
|
|
||||||
s_.push_back('\"');
|
|
||||||
s_.append(v.data(), v.size());
|
|
||||||
s_.push_back('\"');
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
append_integer()
|
|
||||||
{
|
|
||||||
auto const ns = std::to_string(
|
|
||||||
rand(std::numeric_limits<int>::max()));
|
|
||||||
s_.append(ns.c_str(), ns.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
append_boolean()
|
|
||||||
{
|
|
||||||
if(rand(2))
|
|
||||||
s_.append("true", 4);
|
|
||||||
else
|
|
||||||
s_.append("false", 5);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
append_null()
|
|
||||||
{
|
|
||||||
s_.append("null", 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
append_value()
|
|
||||||
{
|
|
||||||
switch(rand(depth_ < max_depth_ ? 6 : 4))
|
|
||||||
{
|
|
||||||
case 5: return append_object();
|
|
||||||
case 4: return append_array();
|
|
||||||
case 3: return append_string();
|
|
||||||
case 2: return append_integer();
|
|
||||||
case 1: return append_boolean();
|
|
||||||
case 0: return append_null();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
void
|
|
||||||
max_depth(int n)
|
|
||||||
{
|
|
||||||
max_depth_ = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
string_view
|
|
||||||
make_document()
|
|
||||||
{
|
|
||||||
s_.clear();
|
|
||||||
depth_ = 0;
|
|
||||||
append_array();
|
|
||||||
return s_;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//----------------------------------------------------------
|
using file_list = std::vector<file_item>;
|
||||||
|
|
||||||
// parse random documents
|
|
||||||
void
|
|
||||||
benchParse(
|
|
||||||
string_view doc,
|
|
||||||
any_impl& impl,
|
|
||||||
int repeat = 1)
|
|
||||||
{
|
|
||||||
using clock_type = std::chrono::steady_clock;
|
|
||||||
auto const when = clock_type::now();
|
|
||||||
dout << impl.name();
|
|
||||||
while(repeat--)
|
|
||||||
impl.work(doc);
|
|
||||||
auto const elapsed =
|
|
||||||
std::chrono::duration_cast<
|
|
||||||
std::chrono::milliseconds>(
|
|
||||||
clock_type::now() - when);
|
|
||||||
dout <<
|
|
||||||
" parse " <<
|
|
||||||
doc.size() << " bytes"
|
|
||||||
" in " << elapsed.count() << "ms" <<
|
|
||||||
"\n";
|
|
||||||
dout.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string
|
std::string
|
||||||
load_file(char const* path)
|
load_file(char const* path)
|
||||||
@ -476,14 +172,6 @@ load_file(char const* path)
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct file_item
|
|
||||||
{
|
|
||||||
string_view name;
|
|
||||||
std::string text;
|
|
||||||
};
|
|
||||||
|
|
||||||
using file_list = std::vector<file_item>;
|
|
||||||
|
|
||||||
void
|
void
|
||||||
benchParse(
|
benchParse(
|
||||||
file_list const& vs,
|
file_list const& vs,
|
||||||
@ -499,13 +187,14 @@ benchParse(
|
|||||||
std::endl;
|
std::endl;
|
||||||
for(unsigned j = 0; j < vi.size(); ++j)
|
for(unsigned j = 0; j < vi.size(); ++j)
|
||||||
{
|
{
|
||||||
for(unsigned k = 0; k < 3; ++k)
|
for(unsigned k = 0; k < 6; ++k)
|
||||||
{
|
{
|
||||||
auto const when = clock_type::now();
|
auto const when = clock_type::now();
|
||||||
vi[j]->parse(vs[i].text, 250);
|
vi[j]->parse(vs[i].text, 250);
|
||||||
auto const ms = std::chrono::duration_cast<
|
auto const ms = std::chrono::duration_cast<
|
||||||
std::chrono::milliseconds>(
|
std::chrono::milliseconds>(
|
||||||
clock_type::now() - when).count();
|
clock_type::now() - when).count();
|
||||||
|
if(k > 2)
|
||||||
dout << " " << vi[j]->name() << ": " <<
|
dout << " " << vi[j]->name() << ": " <<
|
||||||
std::to_string(ms) << "ms" <<
|
std::to_string(ms) << "ms" <<
|
||||||
std::endl;
|
std::endl;
|
||||||
@ -566,7 +255,7 @@ main(
|
|||||||
//vi.emplace_back(new nlohmann_impl);
|
//vi.emplace_back(new nlohmann_impl);
|
||||||
|
|
||||||
benchParse(vs, vi);
|
benchParse(vs, vi);
|
||||||
benchSerialize(vs, vi);
|
//benchSerialize(vs, vi);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
#include <boost/json/basic_parser.hpp>
|
#include <boost/json/basic_parser.hpp>
|
||||||
#include <boost/json/block_storage.hpp>
|
#include <boost/json/block_storage.hpp>
|
||||||
#include <boost/json/error.hpp>
|
#include <boost/json/error.hpp>
|
||||||
#include <boost/json/fixed_storage.hpp>
|
|
||||||
#include <boost/json/ieee_decimal.hpp>
|
#include <boost/json/ieee_decimal.hpp>
|
||||||
#include <boost/json/kind.hpp>
|
#include <boost/json/kind.hpp>
|
||||||
#include <boost/json/number.hpp>
|
#include <boost/json/number.hpp>
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
#include <boost/json/detail/config.hpp>
|
#include <boost/json/detail/config.hpp>
|
||||||
#include <boost/json/detail/assert.hpp>
|
#include <boost/json/detail/assert.hpp>
|
||||||
#include <boost/json/storage.hpp>
|
#include <boost/json/storage.hpp>
|
||||||
#include <cstddef>
|
#include <cstdint>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
@ -22,30 +22,45 @@ namespace json {
|
|||||||
|
|
||||||
/** A storage which uses a multiple fixed size blocks
|
/** A storage which uses a multiple fixed size blocks
|
||||||
*/
|
*/
|
||||||
class block_storage : public storage
|
class block_storage final
|
||||||
|
: public storage
|
||||||
{
|
{
|
||||||
struct block
|
struct block
|
||||||
{
|
{
|
||||||
std::size_t const size;
|
std::size_t const size;
|
||||||
std::size_t used;
|
std::uintptr_t top;
|
||||||
block* next;
|
block* next;
|
||||||
|
|
||||||
char*
|
block(
|
||||||
begin() noexcept
|
std::size_t size_,
|
||||||
|
block* next_)
|
||||||
|
: size(size_)
|
||||||
|
, top(reinterpret_cast<
|
||||||
|
std::uintptr_t>(this+1))
|
||||||
|
, next(next_)
|
||||||
{
|
{
|
||||||
return reinterpret_cast<
|
|
||||||
char*>(this+1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
char*
|
void*
|
||||||
end() noexcept
|
alloc(
|
||||||
|
std::size_t n,
|
||||||
|
std::size_t align) noexcept
|
||||||
{
|
{
|
||||||
return begin() + size;
|
// must be power of 2
|
||||||
|
BOOST_JSON_ASSERT(
|
||||||
|
(align & (align - 1)) == 0);
|
||||||
|
auto i = top;
|
||||||
|
if((i & (align - 1)) != 0)
|
||||||
|
i = (i | (align - 1)) + 1;
|
||||||
|
if(i + n > (reinterpret_cast<
|
||||||
|
std::uintptr_t>(this+1) + size))
|
||||||
|
return nullptr;
|
||||||
|
top = i + n;
|
||||||
|
return reinterpret_cast<void*>(i);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::size_t const block_size_;
|
std::size_t const block_size_;
|
||||||
std::size_t refs_ = 0;
|
|
||||||
block* head_ = nullptr;
|
block* head_ = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -64,7 +79,7 @@ public:
|
|||||||
|
|
||||||
explicit
|
explicit
|
||||||
block_storage(
|
block_storage(
|
||||||
std::size_t block_size = 256 * 1024)
|
std::size_t block_size = 64 * 1024)
|
||||||
: block_size_(block_size)
|
: block_size_(block_size)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -78,10 +93,8 @@ private:
|
|||||||
size + sizeof(block) - 1) /
|
size + sizeof(block) - 1) /
|
||||||
sizeof(block);
|
sizeof(block);
|
||||||
auto& b = *::new(
|
auto& b = *::new(
|
||||||
a.allocate(n + 1)) block{
|
a.allocate(n + 1)) block(
|
||||||
n * sizeof(block),
|
n * sizeof(block), head_);
|
||||||
0,
|
|
||||||
head_};
|
|
||||||
head_ = &b;
|
head_ = &b;
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
@ -91,35 +104,18 @@ private:
|
|||||||
std::size_t n,
|
std::size_t n,
|
||||||
std::size_t align) override
|
std::size_t align) override
|
||||||
{
|
{
|
||||||
(void)align;
|
|
||||||
// must be power of 2
|
|
||||||
BOOST_JSON_ASSERT(
|
|
||||||
(align & (align - 1)) == 0);
|
|
||||||
// cannot exceed max alignment
|
|
||||||
BOOST_JSON_ASSERT(
|
|
||||||
align <= sizeof(std::max_align_t));
|
|
||||||
auto const needed =
|
|
||||||
[&]
|
|
||||||
{
|
|
||||||
if(n < block_size_)
|
|
||||||
return block_size_;
|
|
||||||
return n + sizeof(block);
|
|
||||||
};
|
|
||||||
if(head_)
|
if(head_)
|
||||||
{
|
{
|
||||||
auto const avail =
|
auto p = head_->alloc(n, align);
|
||||||
head_->size - head_->used;
|
if(p)
|
||||||
if(avail < n)
|
return p;
|
||||||
alloc_block(needed());
|
|
||||||
}
|
}
|
||||||
|
if(n > block_size_ - 2 * align)
|
||||||
|
alloc_block(n + 2 * align);
|
||||||
else
|
else
|
||||||
{
|
alloc_block(block_size_);
|
||||||
alloc_block(needed());
|
auto p = head_->alloc(n, align);
|
||||||
}
|
BOOST_JSON_ASSERT(p);
|
||||||
++refs_;
|
|
||||||
auto p =
|
|
||||||
head_->begin() + head_->used;
|
|
||||||
head_->used += n;
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -129,9 +125,6 @@ private:
|
|||||||
std::size_t,
|
std::size_t,
|
||||||
std::size_t) noexcept override
|
std::size_t) noexcept override
|
||||||
{
|
{
|
||||||
if(--refs_ > 0)
|
|
||||||
return;
|
|
||||||
//clear();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#define BOOST_JSON_VALUE_IS_TRIVIAL
|
//#define BOOST_JSON_VALUE_IS_TRIVIAL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef BOOST_NO_EXCEPTIONS
|
#ifndef BOOST_NO_EXCEPTIONS
|
||||||
|
@ -1,95 +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_FIXED_STORAGE_HPP
|
|
||||||
#define BOOST_JSON_FIXED_STORAGE_HPP
|
|
||||||
|
|
||||||
#include <boost/json/detail/config.hpp>
|
|
||||||
#include <boost/json/detail/assert.hpp>
|
|
||||||
#include <boost/json/storage.hpp>
|
|
||||||
#include <cstddef>
|
|
||||||
#include <memory>
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
namespace boost {
|
|
||||||
namespace json {
|
|
||||||
|
|
||||||
/** A storage which uses a single fixed size allocation
|
|
||||||
*/
|
|
||||||
class fixed_storage : public storage
|
|
||||||
{
|
|
||||||
std::size_t const size_;
|
|
||||||
char* const base_;
|
|
||||||
std::size_t used_ = 0;
|
|
||||||
std::size_t refs_ = 0;
|
|
||||||
|
|
||||||
public:
|
|
||||||
~fixed_storage()
|
|
||||||
{
|
|
||||||
std::allocator<
|
|
||||||
char>{}.deallocate(base_, size_);
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit
|
|
||||||
fixed_storage(
|
|
||||||
std::size_t bytes)
|
|
||||||
: size_(
|
|
||||||
[bytes]
|
|
||||||
{
|
|
||||||
auto const align =
|
|
||||||
sizeof(std::max_align_t) - 1;
|
|
||||||
if(bytes & align)
|
|
||||||
return bytes | align;
|
|
||||||
return bytes;
|
|
||||||
}())
|
|
||||||
, base_(std::allocator<
|
|
||||||
char>{}.allocate(size_))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
void*
|
|
||||||
do_allocate(
|
|
||||||
std::size_t n,
|
|
||||||
std::size_t align) override
|
|
||||||
{
|
|
||||||
(void)align;
|
|
||||||
// must be power of 2
|
|
||||||
BOOST_JSON_ASSERT(
|
|
||||||
(align & (align - 1)) == 0);
|
|
||||||
auto offset = used_;
|
|
||||||
if(offset & (align - 1))
|
|
||||||
{
|
|
||||||
offset |= (align - 1);
|
|
||||||
++offset;
|
|
||||||
}
|
|
||||||
if( offset > size_ ||
|
|
||||||
n > size_ - offset)
|
|
||||||
BOOST_JSON_THROW(std::bad_alloc());
|
|
||||||
++refs_;
|
|
||||||
used_ = offset + n;
|
|
||||||
return base_ + offset;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
do_deallocate(
|
|
||||||
void*,
|
|
||||||
std::size_t,
|
|
||||||
std::size_t) noexcept override
|
|
||||||
{
|
|
||||||
if(--refs_ > 0)
|
|
||||||
return;
|
|
||||||
used_ = 0;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // json
|
|
||||||
} // boost
|
|
||||||
|
|
||||||
#endif
|
|
@ -194,7 +194,8 @@ undo_insert(
|
|||||||
array::
|
array::
|
||||||
~array()
|
~array()
|
||||||
{
|
{
|
||||||
release_storage();
|
if(sp_ && ! sp_->is_scoped())
|
||||||
|
release_storage();
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------
|
//----------------------------------------------------------
|
||||||
|
@ -260,7 +260,8 @@ const_iterator(
|
|||||||
object::
|
object::
|
||||||
~object()
|
~object()
|
||||||
{
|
{
|
||||||
release_storage();
|
if(sp_ && ! sp_->is_scoped())
|
||||||
|
release_storage();
|
||||||
}
|
}
|
||||||
|
|
||||||
object::
|
object::
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
#include <boost/json/parser.hpp>
|
#include <boost/json/parser.hpp>
|
||||||
#include <boost/json/error.hpp>
|
#include <boost/json/error.hpp>
|
||||||
#include <boost/json/block_storage.hpp>
|
|
||||||
#include <boost/json/detail/assert.hpp>
|
#include <boost/json/detail/assert.hpp>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
@ -20,32 +19,6 @@
|
|||||||
namespace boost {
|
namespace boost {
|
||||||
namespace json {
|
namespace json {
|
||||||
|
|
||||||
template<class T>
|
|
||||||
void
|
|
||||||
parser::
|
|
||||||
assign(T&& t)
|
|
||||||
{
|
|
||||||
auto& jv = *stack_.front();
|
|
||||||
BOOST_JSON_ASSERT(! jv.is_object());
|
|
||||||
if(obj_)
|
|
||||||
{
|
|
||||||
BOOST_JSON_ASSERT(jv.is_null());
|
|
||||||
jv = std::forward<T>(t);
|
|
||||||
stack_.pop();
|
|
||||||
}
|
|
||||||
else if(stack_.front()->is_array())
|
|
||||||
{
|
|
||||||
BOOST_JSON_ASSERT(s_.empty());
|
|
||||||
jv.if_array()->emplace_back(
|
|
||||||
std::forward<T>(t));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BOOST_JSON_ASSERT(jv.is_null());
|
|
||||||
jv = std::forward<T>(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
parser::
|
parser::
|
||||||
~parser()
|
~parser()
|
||||||
{
|
{
|
||||||
@ -55,8 +28,6 @@ parser::
|
|||||||
|
|
||||||
parser::
|
parser::
|
||||||
parser()
|
parser()
|
||||||
: jv_(make_storage<
|
|
||||||
block_storage>())
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -353,7 +324,24 @@ void
|
|||||||
parser::
|
parser::
|
||||||
on_bool(bool b, error_code&)
|
on_bool(bool b, error_code&)
|
||||||
{
|
{
|
||||||
assign(b);
|
auto& jv = *stack_.front();
|
||||||
|
BOOST_JSON_ASSERT(! jv.is_object());
|
||||||
|
if(obj_)
|
||||||
|
{
|
||||||
|
BOOST_JSON_ASSERT(jv.is_null());
|
||||||
|
jv.emplace_bool() = b;
|
||||||
|
stack_.pop();
|
||||||
|
}
|
||||||
|
else if(stack_.front()->is_array())
|
||||||
|
{
|
||||||
|
BOOST_JSON_ASSERT(s_.empty());
|
||||||
|
jv.if_array()->emplace_back(b);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BOOST_JSON_ASSERT(jv.is_null());
|
||||||
|
jv.emplace_bool() = b;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -30,6 +30,8 @@ void
|
|||||||
storage::
|
storage::
|
||||||
release() noexcept
|
release() noexcept
|
||||||
{
|
{
|
||||||
|
if(scoped_)
|
||||||
|
return;
|
||||||
if(--refs_ > 0)
|
if(--refs_ > 0)
|
||||||
return;
|
return;
|
||||||
delete this;
|
delete this;
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
namespace boost {
|
namespace boost {
|
||||||
namespace json {
|
namespace json {
|
||||||
|
|
||||||
class parser
|
class parser final
|
||||||
: public basic_parser
|
: public basic_parser
|
||||||
{
|
{
|
||||||
using size_type = unsigned;
|
using size_type = unsigned;
|
||||||
@ -76,10 +76,6 @@ public:
|
|||||||
release() noexcept;
|
release() noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<class T>
|
|
||||||
void
|
|
||||||
assign(T&& t);
|
|
||||||
|
|
||||||
BOOST_JSON_DECL
|
BOOST_JSON_DECL
|
||||||
void
|
void
|
||||||
reset();
|
reset();
|
||||||
|
@ -12,10 +12,10 @@
|
|||||||
|
|
||||||
#include <boost/json/detail/config.hpp>
|
#include <boost/json/detail/config.hpp>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <cstddef>
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
namespace json {
|
namespace json {
|
||||||
@ -25,7 +25,9 @@ namespace json {
|
|||||||
class storage
|
class storage
|
||||||
{
|
{
|
||||||
std::atomic<std::size_t> refs_;
|
std::atomic<std::size_t> refs_;
|
||||||
|
//std::size_t refs_;
|
||||||
unsigned long long id_ = 0;
|
unsigned long long id_ = 0;
|
||||||
|
bool scoped_ = false;
|
||||||
|
|
||||||
BOOST_JSON_DECL
|
BOOST_JSON_DECL
|
||||||
void
|
void
|
||||||
@ -38,18 +40,17 @@ class storage
|
|||||||
template<class T>
|
template<class T>
|
||||||
friend class basic_storage_ptr;
|
friend class basic_storage_ptr;
|
||||||
|
|
||||||
public:
|
template<class T>
|
||||||
static std::size_t constexpr max_align =
|
friend class scoped_storage;
|
||||||
sizeof(max_align_t);
|
|
||||||
|
|
||||||
|
public:
|
||||||
virtual
|
virtual
|
||||||
~storage() = default;
|
~storage() = default;
|
||||||
|
|
||||||
void*
|
void*
|
||||||
allocate(
|
allocate(
|
||||||
std::size_t n,
|
std::size_t n,
|
||||||
std::size_t align =
|
std::size_t align)
|
||||||
max_align)
|
|
||||||
{
|
{
|
||||||
return do_allocate(n, align);
|
return do_allocate(n, align);
|
||||||
}
|
}
|
||||||
@ -58,12 +59,17 @@ public:
|
|||||||
deallocate(
|
deallocate(
|
||||||
void* p,
|
void* p,
|
||||||
std::size_t n,
|
std::size_t n,
|
||||||
std::size_t align =
|
std::size_t align) noexcept
|
||||||
max_align)
|
|
||||||
{
|
{
|
||||||
return do_deallocate(p, n, align);
|
return do_deallocate(p, n, align);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
is_scoped() const noexcept
|
||||||
|
{
|
||||||
|
return scoped_;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
is_equal(
|
is_equal(
|
||||||
storage const& other) const noexcept
|
storage const& other) const noexcept
|
||||||
@ -125,7 +131,8 @@ class basic_storage_ptr
|
|||||||
template<class U>
|
template<class U>
|
||||||
friend class basic_storage_ptr;
|
friend class basic_storage_ptr;
|
||||||
|
|
||||||
using count = std::atomic<unsigned>;
|
template<class U>
|
||||||
|
friend class scoped_storage;
|
||||||
|
|
||||||
T* t_ = nullptr;
|
T* t_ = nullptr;
|
||||||
|
|
||||||
@ -136,7 +143,7 @@ class basic_storage_ptr
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Construct an null storage pointer
|
/** Construct a null storage pointer
|
||||||
|
|
||||||
This constructs a null storage pointer.
|
This constructs a null storage pointer.
|
||||||
|
|
||||||
@ -507,6 +514,31 @@ 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
|
/** Return a pointer to the default storage
|
||||||
|
|
||||||
This function returns the default storage, which is
|
This function returns the default storage, which is
|
||||||
|
@ -36,7 +36,6 @@ add_executable (json-tests
|
|||||||
basic_parser.cpp
|
basic_parser.cpp
|
||||||
block_storage.cpp
|
block_storage.cpp
|
||||||
error.cpp
|
error.cpp
|
||||||
fixed_storage.cpp
|
|
||||||
ieee_decimal.cpp
|
ieee_decimal.cpp
|
||||||
json.cpp
|
json.cpp
|
||||||
kind.cpp
|
kind.cpp
|
||||||
|
@ -32,7 +32,6 @@ local SOURCES =
|
|||||||
basic_parser.cpp
|
basic_parser.cpp
|
||||||
block_storage.cpp
|
block_storage.cpp
|
||||||
error.cpp
|
error.cpp
|
||||||
fixed_storage.cpp
|
|
||||||
ieee_decimal.cpp
|
ieee_decimal.cpp
|
||||||
json.cpp
|
json.cpp
|
||||||
kind.cpp
|
kind.cpp
|
||||||
|
@ -1,31 +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
|
|
||||||
//
|
|
||||||
|
|
||||||
// Test that header file is self-contained.
|
|
||||||
#include <boost/json/fixed_storage.hpp>
|
|
||||||
|
|
||||||
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
|
||||||
|
|
||||||
namespace boost {
|
|
||||||
namespace json {
|
|
||||||
|
|
||||||
class fixed_storage_test : public beast::unit_test::suite
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void run() override
|
|
||||||
{
|
|
||||||
make_storage<fixed_storage>(65536);
|
|
||||||
pass();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
BEAST_DEFINE_TESTSUITE(boost,json,fixed_storage);
|
|
||||||
|
|
||||||
} // json
|
|
||||||
} // boost
|
|
Loading…
x
Reference in New Issue
Block a user