diff --git a/bench/bench.cpp b/bench/bench.cpp index 1525acd7..05914f2e 100644 --- a/bench/bench.cpp +++ b/bench/bench.cpp @@ -114,7 +114,11 @@ public: int repeat) const override { while(repeat--) - json::parse(s); + { + auto sp = json::make_storage< + json::block_storage>(); + json::parse(s, sp); + } } void diff --git a/include/boost/json.hpp b/include/boost/json.hpp index 60a4b16a..8df3ca23 100644 --- a/include/boost/json.hpp +++ b/include/boost/json.hpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include diff --git a/include/boost/json/block_storage.hpp b/include/boost/json/block_storage.hpp new file mode 100644 index 00000000..901595d4 --- /dev/null +++ b/include/boost/json/block_storage.hpp @@ -0,0 +1,141 @@ +// +// 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_BLOCK_STORAGE_HPP +#define BOOST_JSON_BLOCK_STORAGE_HPP + +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace json { + +/** A storage which uses a multiple fixed size blocks +*/ +class block_storage : public storage +{ + struct block + { + std::size_t const size; + std::size_t used; + block* next; + + char* + begin() noexcept + { + return reinterpret_cast< + char*>(this+1); + } + + char* + end() noexcept + { + return begin() + size; + } + }; + + std::size_t const block_size_; + std::size_t refs_ = 0; + block* head_ = nullptr; + +public: + ~block_storage() + { + std::allocator a; + auto b = head_; + while(b) + { + auto next = b->next; + a.deallocate(b, + sizeof(*b) + b->size); + b = next; + } + } + + explicit + block_storage( + std::size_t block_size = 256 * 1024) + : block_size_(block_size) + { + } + +private: + block& + alloc_block(std::size_t size) + { + std::allocator a; + auto const n = ( + size + sizeof(block) - 1) / + sizeof(block); + auto& b = *::new( + a.allocate(n + 1)) block{ + n * sizeof(block), + 0, + head_}; + head_ = &b; + return b; + } + + 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); + // 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_) + { + auto const avail = + head_->size - head_->used; + if(avail < n) + alloc_block(needed()); + } + else + { + alloc_block(needed()); + } + ++refs_; + auto p = + head_->begin() + head_->used; + head_->used += n; + return p; + } + + void + do_deallocate( + void*, + std::size_t, + std::size_t) noexcept override + { + if(--refs_ > 0) + return; + //clear(); + } +}; + +} // json +} // boost + +#endif diff --git a/include/boost/json/fixed_storage.hpp b/include/boost/json/fixed_storage.hpp index 258e502a..45a04296 100644 --- a/include/boost/json/fixed_storage.hpp +++ b/include/boost/json/fixed_storage.hpp @@ -11,7 +11,10 @@ #define BOOST_JSON_FIXED_STORAGE_HPP #include +#include #include +#include +#include #include namespace boost { @@ -21,22 +24,32 @@ namespace json { */ class fixed_storage : public storage { - char* const base_; std::size_t const size_; + char* const base_; std::size_t used_ = 0; std::size_t refs_ = 0; public: ~fixed_storage() { - delete[] base_; + std::allocator< + char>{}.deallocate(base_, size_); } explicit fixed_storage( std::size_t bytes) - : base_(new char[bytes]) - , size_(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_)) { } @@ -46,6 +59,7 @@ protected: std::size_t n, std::size_t align) override { + (void)align; // must be power of 2 BOOST_JSON_ASSERT( (align & (align - 1)) == 0); diff --git a/include/boost/json/impl/parser.ipp b/include/boost/json/impl/parser.ipp index 289045b5..1c4dbb00 100644 --- a/include/boost/json/impl/parser.ipp +++ b/include/boost/json/impl/parser.ipp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -54,6 +55,8 @@ parser:: parser:: parser() + : jv_(make_storage< + block_storage>()) { } diff --git a/include/boost/json/parser.hpp b/include/boost/json/parser.hpp index 43ed1799..406f575c 100644 --- a/include/boost/json/parser.hpp +++ b/include/boost/json/parser.hpp @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 3b6ba4df..bfd0d60a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -34,7 +34,9 @@ add_executable (json-tests assign_string.cpp assign_vector.cpp basic_parser.cpp + block_storage.cpp error.cpp + fixed_storage.cpp ieee_decimal.cpp json.cpp kind.cpp diff --git a/test/Jamfile b/test/Jamfile index ee0a174e..fe16a161 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -30,7 +30,9 @@ local SOURCES = assign_string.cpp assign_vector.cpp basic_parser.cpp + block_storage.cpp error.cpp + fixed_storage.cpp ieee_decimal.cpp json.cpp kind.cpp diff --git a/test/block_storage.cpp b/test/block_storage.cpp new file mode 100644 index 00000000..7ed9fb0a --- /dev/null +++ b/test/block_storage.cpp @@ -0,0 +1,31 @@ +// +// 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 + +#include + +namespace boost { +namespace json { + +class block_storage_test : public beast::unit_test::suite +{ +public: + void run() override + { + make_storage(); + pass(); + } +}; + +BEAST_DEFINE_TESTSUITE(boost,json,block_storage); + +} // json +} // boost diff --git a/test/fixed_storage.cpp b/test/fixed_storage.cpp new file mode 100644 index 00000000..0c043b73 --- /dev/null +++ b/test/fixed_storage.cpp @@ -0,0 +1,31 @@ +// +// 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 + +#include + +namespace boost { +namespace json { + +class fixed_storage_test : public beast::unit_test::suite +{ +public: + void run() override + { + make_storage(65536); + pass(); + } +}; + +BEAST_DEFINE_TESTSUITE(boost,json,fixed_storage); + +} // json +} // boost