impl/monotonic_resource.ipp

97.3% Lines (71/0/73) 90.0% List of functions (9/0/10)
monotonic_resource.ipp
f(x) Functions (10)
Line TLA Hits 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 238x monotonic_resource::
33 max_size()
34 {
35 238x 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 57x monotonic_resource::
41 round_pow2(
42 std::size_t n) noexcept
43 {
44 57x if(n & (n - 1))
45 15x return next_pow2(n);
46 42x return n;
47 }
48
49 // lowest power of 2 greater than n
50 std::size_t
51 68x monotonic_resource::
52 next_pow2(
53 std::size_t n) noexcept
54 {
55 68x std::size_t result = min_size_;
56 260x while(result <= n)
57 {
58 193x if(result >= max_size() - result)
59 {
60 // overflow
61 1x result = max_size();
62 1x break;
63 }
64 192x result *= 2;
65 }
66 68x return result;
67 }
68
69 //----------------------------------------------------------
70
71 57x monotonic_resource::
72 57x ~monotonic_resource()
73 {
74 57x release();
75 57x }
76
77 47x monotonic_resource::
78 monotonic_resource(
79 std::size_t initial_size,
80 47x storage_ptr upstream) noexcept
81 47x : buffer_{
82 nullptr, 0, 0, nullptr}
83 94x , next_size_(round_pow2(initial_size))
84 47x , upstream_(std::move(upstream))
85 {
86 47x }
87
88 10x monotonic_resource::
89 monotonic_resource(
90 unsigned char* buffer,
91 std::size_t size,
92 10x storage_ptr upstream) noexcept
93 10x : buffer_{
94 buffer, size, size, nullptr}
95 20x , next_size_(next_pow2(size))
96 10x , upstream_(std::move(upstream))
97 {
98 10x }
99
100 void
101 58x monotonic_resource::
102 release() noexcept
103 {
104 58x auto p = head_;
105 101x while(p != &buffer_)
106 {
107 43x auto next = p->next;
108 43x upstream_->deallocate(p, sizeof(block) + p->size);
109 43x p = next;
110 }
111 58x buffer_.p = reinterpret_cast<
112 58x unsigned char*>(buffer_.p) - (
113 58x buffer_.size - buffer_.avail);
114 58x buffer_.avail = buffer_.size;
115 58x head_ = &buffer_;
116 58x }
117
118 void*
119 129508x monotonic_resource::
120 do_allocate(
121 std::size_t n,
122 std::size_t align)
123 {
124 129508x auto p = std::align(align, n, head_->p, head_->avail);
125 129508x if(p)
126 {
127 129464x head_->p = reinterpret_cast<
128 129464x unsigned char*>(p) + n;
129 129464x head_->avail -= n;
130 129464x 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 44x std::size_t const pad = align > alignof(block)
137 44x ? align - alignof(block) : 0;
138 44x if(n > max_size() - pad)
139 2x throw_exception( std::bad_alloc(), BOOST_CURRENT_LOCATION );
140 43x if(next_size_ < n + pad)
141 10x next_size_ = round_pow2(n + pad);
142 43x auto b = ::new(upstream_->allocate(
143 43x sizeof(block) + next_size_)) block;
144 43x b->p = b + 1;
145 43x b->avail = next_size_;
146 43x b->size = next_size_;
147 43x b->next = head_;
148 43x head_ = b;
149 43x next_size_ = next_pow2(next_size_);
150
151 43x p = std::align(align, n, head_->p, head_->avail);
152 43x BOOST_ASSERT(p);
153 43x head_->p = reinterpret_cast<
154 43x unsigned char*>(p) + n;
155 43x head_->avail -= n;
156 43x return p;
157 }
158
159 void
160 29x monotonic_resource::
161 do_deallocate(
162 void*,
163 std::size_t,
164 std::size_t)
165 {
166 // do nothing
167 29x }
168
169 bool
170 monotonic_resource::
171 do_is_equal(
172 memory_resource const& mr) const noexcept
173 {
174 return this == &mr;
175 }
176
177 } // namespace json
178 } // namespace boost
179
180 #endif
181