/src/boost/boost/json/impl/monotonic_resource.ipp
Line | Count | Source |
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 | | |
18 | | #include <memory> |
19 | | |
20 | | namespace boost { |
21 | | namespace json { |
22 | | |
23 | | struct alignas(core::max_align_t) |
24 | | monotonic_resource::block : block_base |
25 | | { |
26 | | }; |
27 | | |
28 | | constexpr |
29 | | std::size_t |
30 | | monotonic_resource:: |
31 | | max_size() |
32 | 8.05k | { |
33 | 8.05k | return std::size_t(-1) - sizeof(block); |
34 | 8.05k | } |
35 | | |
36 | | // lowest power of 2 greater than or equal to n |
37 | | std::size_t |
38 | | monotonic_resource:: |
39 | | round_pow2( |
40 | | std::size_t n) noexcept |
41 | 4.60k | { |
42 | 4.60k | if(n & (n - 1)) |
43 | 509 | return next_pow2(n); |
44 | 4.09k | return n; |
45 | 4.60k | } |
46 | | |
47 | | // lowest power of 2 greater than n |
48 | | std::size_t |
49 | | monotonic_resource:: |
50 | | next_pow2( |
51 | | std::size_t n) noexcept |
52 | 2.24k | { |
53 | 2.24k | std::size_t result = min_size_; |
54 | 10.2k | while(result <= n) |
55 | 8.05k | { |
56 | 8.05k | if(result >= max_size() - result) |
57 | 0 | { |
58 | | // overflow |
59 | 0 | result = max_size(); |
60 | 0 | break; |
61 | 0 | } |
62 | 8.05k | result *= 2; |
63 | 8.05k | } |
64 | 2.24k | return result; |
65 | 2.24k | } |
66 | | |
67 | | //---------------------------------------------------------- |
68 | | |
69 | | monotonic_resource:: |
70 | | ~monotonic_resource() |
71 | 4.09k | { |
72 | 4.09k | release(); |
73 | 4.09k | } |
74 | | |
75 | | monotonic_resource:: |
76 | | monotonic_resource( |
77 | | std::size_t initial_size, |
78 | | storage_ptr upstream) noexcept |
79 | 4.09k | : buffer_{ |
80 | 4.09k | nullptr, 0, 0, nullptr} |
81 | 4.09k | , next_size_(round_pow2(initial_size)) |
82 | 4.09k | , upstream_(std::move(upstream)) |
83 | 4.09k | { |
84 | 4.09k | } |
85 | | |
86 | | monotonic_resource:: |
87 | | monotonic_resource( |
88 | | unsigned char* buffer, |
89 | | std::size_t size, |
90 | | storage_ptr upstream) noexcept |
91 | 0 | : buffer_{ |
92 | 0 | buffer, size, size, nullptr} |
93 | 0 | , next_size_(next_pow2(size)) |
94 | 0 | , upstream_(std::move(upstream)) |
95 | 0 | { |
96 | 0 | } |
97 | | |
98 | | void |
99 | | monotonic_resource:: |
100 | | release() noexcept |
101 | 4.09k | { |
102 | 4.09k | auto p = head_; |
103 | 5.82k | while(p != &buffer_) |
104 | 1.73k | { |
105 | 1.73k | auto next = p->next; |
106 | 1.73k | upstream_->deallocate(p, p->size); |
107 | 1.73k | p = next; |
108 | 1.73k | } |
109 | 4.09k | buffer_.p = reinterpret_cast< |
110 | 4.09k | unsigned char*>(buffer_.p) - ( |
111 | 4.09k | buffer_.size - buffer_.avail); |
112 | 4.09k | buffer_.avail = buffer_.size; |
113 | 4.09k | head_ = &buffer_; |
114 | 4.09k | } |
115 | | |
116 | | void* |
117 | | monotonic_resource:: |
118 | | do_allocate( |
119 | | std::size_t n, |
120 | | std::size_t align) |
121 | 75.5k | { |
122 | 75.5k | auto p = std::align(align, n, head_->p, head_->avail); |
123 | 75.5k | if(p) |
124 | 73.7k | { |
125 | 73.7k | head_->p = reinterpret_cast< |
126 | 73.7k | unsigned char*>(p) + n; |
127 | 73.7k | head_->avail -= n; |
128 | 73.7k | return p; |
129 | 73.7k | } |
130 | | |
131 | 1.73k | if(next_size_ < n) |
132 | 514 | next_size_ = round_pow2(n); |
133 | 1.73k | auto b = ::new(upstream_->allocate( |
134 | 1.73k | sizeof(block) + next_size_)) block; |
135 | 1.73k | b->p = b + 1; |
136 | 1.73k | b->avail = next_size_; |
137 | 1.73k | b->size = next_size_; |
138 | 1.73k | b->next = head_; |
139 | 1.73k | head_ = b; |
140 | 1.73k | next_size_ = next_pow2(next_size_); |
141 | | |
142 | 1.73k | p = std::align(align, n, head_->p, head_->avail); |
143 | 1.73k | BOOST_ASSERT(p); |
144 | 1.73k | head_->p = reinterpret_cast< |
145 | 1.73k | unsigned char*>(p) + n; |
146 | 1.73k | head_->avail -= n; |
147 | 1.73k | return p; |
148 | 75.5k | } |
149 | | |
150 | | void |
151 | | monotonic_resource:: |
152 | | do_deallocate( |
153 | | void*, |
154 | | std::size_t, |
155 | | std::size_t) |
156 | 316 | { |
157 | | // do nothing |
158 | 316 | } |
159 | | |
160 | | bool |
161 | | monotonic_resource:: |
162 | | do_is_equal( |
163 | | memory_resource const& mr) const noexcept |
164 | 0 | { |
165 | 0 | return this == &mr; |
166 | 0 | } |
167 | | |
168 | | } // namespace json |
169 | | } // namespace boost |
170 | | |
171 | | #endif |