TLA Line data Source code
1 : //
2 : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3 : // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
4 : //
5 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 : //
8 : // Official repository: https://github.com/boostorg/json
9 : //
10 :
11 : #ifndef BOOST_JSON_IMPL_MONOTONIC_RESOURCE_IPP
12 : #define BOOST_JSON_IMPL_MONOTONIC_RESOURCE_IPP
13 :
14 : #include <boost/json/monotonic_resource.hpp>
15 : #include <boost/json/detail/except.hpp>
16 : #include <boost/core/max_align.hpp>
17 : #include <boost/throw_exception.hpp>
18 :
19 : #include <memory>
20 : #include <new>
21 :
22 : namespace boost {
23 : namespace json {
24 :
25 : struct alignas(core::max_align_t)
26 : monotonic_resource::block : block_base
27 : {
28 : };
29 :
30 : constexpr
31 : std::size_t
32 HIT 238 : monotonic_resource::
33 : max_size()
34 : {
35 238 : return std::size_t(-1) - sizeof(block);
36 : }
37 :
38 : // lowest power of 2 greater than or equal to n
39 : std::size_t
40 57 : monotonic_resource::
41 : round_pow2(
42 : std::size_t n) noexcept
43 : {
44 57 : if(n & (n - 1))
45 15 : return next_pow2(n);
46 42 : return n;
47 : }
48 :
49 : // lowest power of 2 greater than n
50 : std::size_t
51 68 : monotonic_resource::
52 : next_pow2(
53 : std::size_t n) noexcept
54 : {
55 68 : std::size_t result = min_size_;
56 260 : while(result <= n)
57 : {
58 193 : if(result >= max_size() - result)
59 : {
60 : // overflow
61 1 : result = max_size();
62 1 : break;
63 : }
64 192 : result *= 2;
65 : }
66 68 : return result;
67 : }
68 :
69 : //----------------------------------------------------------
70 :
71 57 : monotonic_resource::
72 57 : ~monotonic_resource()
73 : {
74 57 : release();
75 57 : }
76 :
77 47 : monotonic_resource::
78 : monotonic_resource(
79 : std::size_t initial_size,
80 47 : storage_ptr upstream) noexcept
81 47 : : buffer_{
82 : nullptr, 0, 0, nullptr}
83 94 : , next_size_(round_pow2(initial_size))
84 47 : , upstream_(std::move(upstream))
85 : {
86 47 : }
87 :
88 10 : monotonic_resource::
89 : monotonic_resource(
90 : unsigned char* buffer,
91 : std::size_t size,
92 10 : storage_ptr upstream) noexcept
93 10 : : buffer_{
94 : buffer, size, size, nullptr}
95 20 : , next_size_(next_pow2(size))
96 10 : , upstream_(std::move(upstream))
97 : {
98 10 : }
99 :
100 : void
101 58 : monotonic_resource::
102 : release() noexcept
103 : {
104 58 : auto p = head_;
105 101 : while(p != &buffer_)
106 : {
107 43 : auto next = p->next;
108 43 : upstream_->deallocate(p, sizeof(block) + p->size);
109 43 : p = next;
110 : }
111 58 : buffer_.p = reinterpret_cast<
112 58 : unsigned char*>(buffer_.p) - (
113 58 : buffer_.size - buffer_.avail);
114 58 : buffer_.avail = buffer_.size;
115 58 : head_ = &buffer_;
116 58 : }
117 :
118 : void*
119 129508 : monotonic_resource::
120 : do_allocate(
121 : std::size_t n,
122 : std::size_t align)
123 : {
124 129508 : auto p = std::align(align, n, head_->p, head_->avail);
125 129508 : if(p)
126 : {
127 129464 : head_->p = reinterpret_cast<
128 129464 : unsigned char*>(p) + n;
129 129464 : head_->avail -= n;
130 129464 : return p;
131 : }
132 :
133 : // a new block is only aligned to alignof(block), so an
134 : // over-aligned request may need up to align - alignof(block)
135 : // bytes of padding in addition to n
136 44 : std::size_t const pad = align > alignof(block)
137 44 : ? align - alignof(block) : 0;
138 44 : if(n > max_size() - pad)
139 2 : throw_exception( std::bad_alloc(), BOOST_CURRENT_LOCATION );
140 43 : if(next_size_ < n + pad)
141 10 : next_size_ = round_pow2(n + pad);
142 43 : auto b = ::new(upstream_->allocate(
143 43 : sizeof(block) + next_size_)) block;
144 43 : b->p = b + 1;
145 43 : b->avail = next_size_;
146 43 : b->size = next_size_;
147 43 : b->next = head_;
148 43 : head_ = b;
149 43 : next_size_ = next_pow2(next_size_);
150 :
151 43 : p = std::align(align, n, head_->p, head_->avail);
152 43 : BOOST_ASSERT(p);
153 43 : head_->p = reinterpret_cast<
154 43 : unsigned char*>(p) + n;
155 43 : head_->avail -= n;
156 43 : return p;
157 : }
158 :
159 : void
160 29 : monotonic_resource::
161 : do_deallocate(
162 : void*,
163 : std::size_t,
164 : std::size_t)
165 : {
166 : // do nothing
167 29 : }
168 :
169 : bool
170 MIS 0 : monotonic_resource::
171 : do_is_equal(
172 : memory_resource const& mr) const noexcept
173 : {
174 0 : return this == &mr;
175 : }
176 :
177 : } // namespace json
178 : } // namespace boost
179 :
180 : #endif
|