TLA Line data Source code
1 : //
2 : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3 : //
4 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 : //
7 : // Official repository: https://github.com/boostorg/json
8 : //
9 :
10 : #ifndef BOOST_JSON_IMPL_VALUE_STACK_IPP
11 : #define BOOST_JSON_IMPL_VALUE_STACK_IPP
12 :
13 : #include <boost/json/value_stack.hpp>
14 : #include <cstring>
15 : #include <memory>
16 : #include <stdexcept>
17 : #include <utility>
18 :
19 : namespace boost {
20 : namespace json {
21 :
22 : //--------------------------------------
23 :
24 HIT 2076914 : value_stack::
25 : stack::
26 : ~stack()
27 : {
28 2076914 : clear();
29 2076914 : if( begin_ != temp_ &&
30 75357 : begin_ != nullptr)
31 75349 : sp_->deallocate(
32 75349 : begin_,
33 75349 : (end_ - begin_) *
34 : sizeof(value));
35 2076914 : }
36 :
37 2076914 : value_stack::
38 : stack::
39 : stack(
40 : storage_ptr sp,
41 : void* temp,
42 2076914 : std::size_t size) noexcept
43 2076914 : : sp_(std::move(sp))
44 : {
45 : // the buffer stores `value`s, so it has to be aligned for one;
46 : // align it up the same way static_resource does for its buffer
47 2076914 : void* const aligned = std::align(
48 : alignof(value),
49 : min_size_ * sizeof(value),
50 : temp, size);
51 2076914 : if(aligned)
52 : {
53 2001518 : temp_ = temp;
54 2001518 : begin_ = reinterpret_cast<
55 : value*>(temp);
56 2001518 : top_ = begin_;
57 2001518 : end_ = begin_ +
58 2001518 : size / sizeof(value);
59 : }
60 : else
61 : {
62 75396 : temp_ = temp;
63 75396 : begin_ = nullptr;
64 75396 : top_ = nullptr;
65 75396 : end_ = nullptr;
66 : }
67 2076914 : }
68 :
69 : void
70 4153167 : value_stack::
71 : stack::
72 : run_dtors(bool b) noexcept
73 : {
74 4153167 : run_dtors_ = b;
75 4153167 : }
76 :
77 : std::size_t
78 4213837 : value_stack::
79 : stack::
80 : size() const noexcept
81 : {
82 4213837 : return top_ - begin_;
83 : }
84 :
85 : bool
86 64466 : value_stack::
87 : stack::
88 : has_chars()
89 : {
90 64466 : return chars_ != 0;
91 : }
92 :
93 : //--------------------------------------
94 :
95 : // destroy the values but
96 : // not the stack allocation.
97 : void
98 6230081 : value_stack::
99 : stack::
100 : clear() noexcept
101 : {
102 6230081 : if(top_ != begin_)
103 : {
104 86 : if(run_dtors_)
105 86 : for(auto it = top_;
106 339 : it-- != begin_;)
107 253 : it->~value();
108 86 : top_ = begin_;
109 : }
110 6230081 : chars_ = 0;
111 6230081 : }
112 :
113 : void
114 1868 : value_stack::
115 : stack::
116 : maybe_grow()
117 : {
118 1868 : if(top_ >= end_)
119 266 : grow_one();
120 1868 : }
121 :
122 : // make room for at least one more value
123 : void
124 66512 : value_stack::
125 : stack::
126 : grow_one()
127 : {
128 66512 : BOOST_ASSERT(chars_ == 0);
129 66512 : std::size_t const capacity =
130 66512 : end_ - begin_;
131 66512 : std::size_t new_cap = min_size_;
132 : // VFALCO check overflow here
133 66554 : while(new_cap < capacity + 1)
134 42 : new_cap <<= 1;
135 : auto const begin =
136 : reinterpret_cast<value*>(
137 66512 : sp_->allocate(
138 : new_cap * sizeof(value)));
139 66512 : std::size_t const cur_size = top_ - begin_;
140 66512 : if(begin_)
141 : {
142 11 : std::memcpy(
143 : reinterpret_cast<char*>(begin),
144 11 : reinterpret_cast<char*>(begin_),
145 11 : size() * sizeof(value));
146 11 : if(begin_ != temp_)
147 9 : sp_->deallocate(begin_,
148 : capacity * sizeof(value));
149 : }
150 : // book-keeping
151 66512 : top_ = begin + cur_size;
152 66512 : end_ = begin + new_cap;
153 66512 : begin_ = begin;
154 66512 : }
155 :
156 : // make room for nchars additional characters.
157 : void
158 16180 : value_stack::
159 : stack::
160 : grow(std::size_t nchars)
161 : {
162 : // needed capacity in values
163 : std::size_t const needed =
164 16180 : size() +
165 16180 : 1 +
166 16180 : ((chars_ + nchars +
167 16180 : sizeof(value) - 1) /
168 16180 : sizeof(value));
169 16180 : std::size_t const capacity =
170 16180 : end_ - begin_;
171 16180 : BOOST_ASSERT(
172 : needed > capacity);
173 16180 : std::size_t new_cap = min_size_;
174 : // VFALCO check overflow here
175 57842 : while(new_cap < needed)
176 41662 : new_cap <<= 1;
177 : auto const begin =
178 : reinterpret_cast<value*>(
179 16180 : sp_->allocate(
180 : new_cap * sizeof(value)));
181 16180 : std::size_t const cur_size = top_ - begin_;
182 16180 : if(begin_)
183 : {
184 : std::size_t amount =
185 7334 : size() * sizeof(value);
186 7334 : if(chars_ > 0)
187 6 : amount += sizeof(value) + chars_;
188 7334 : std::memcpy(
189 : reinterpret_cast<char*>(begin),
190 7334 : reinterpret_cast<char*>(begin_),
191 : amount);
192 7334 : if(begin_ != temp_)
193 7334 : sp_->deallocate(begin_,
194 : capacity * sizeof(value));
195 : }
196 : // book-keeping
197 16180 : top_ = begin + cur_size;
198 16180 : end_ = begin + new_cap;
199 16180 : begin_ = begin;
200 16180 : }
201 :
202 : //--------------------------------------
203 :
204 : void
205 20149 : value_stack::
206 : stack::
207 : append(string_view s)
208 : {
209 20149 : std::size_t const bytes_avail =
210 : reinterpret_cast<
211 20149 : char const*>(end_) -
212 : reinterpret_cast<
213 20149 : char const*>(top_);
214 : // make sure there is room for
215 : // pushing one more value without
216 : // clobbering the string.
217 40298 : if(sizeof(value) + chars_ +
218 20149 : s.size() > bytes_avail)
219 16180 : grow(s.size());
220 :
221 : // copy the new piece
222 20149 : std::memcpy(
223 : reinterpret_cast<char*>(
224 20149 : top_ + 1) + chars_,
225 20149 : s.data(), s.size());
226 20149 : chars_ += s.size();
227 :
228 : // ensure a pushed value cannot
229 : // clobber the released string.
230 20149 : BOOST_ASSERT(
231 : reinterpret_cast<char*>(
232 : top_ + 1) + chars_ <=
233 : reinterpret_cast<char*>(
234 : end_));
235 20149 : }
236 :
237 : string_view
238 17021 : value_stack::
239 : stack::
240 : release_string() noexcept
241 : {
242 : // ensure a pushed value cannot
243 : // clobber the released string.
244 17021 : BOOST_ASSERT(
245 : reinterpret_cast<char*>(
246 : top_ + 1) + chars_ <=
247 : reinterpret_cast<char*>(
248 : end_));
249 17021 : auto const n = chars_;
250 17021 : chars_ = 0;
251 : return { reinterpret_cast<
252 17021 : char const*>(top_ + 1), n };
253 : }
254 :
255 : // transfer ownership of the top n
256 : // elements of the stack to the caller
257 : value*
258 2113656 : value_stack::
259 : stack::
260 : release(std::size_t n) noexcept
261 : {
262 2113656 : BOOST_ASSERT(n <= size());
263 2113656 : BOOST_ASSERT(chars_ == 0);
264 2113656 : top_ -= n;
265 2113656 : return top_;
266 : }
267 :
268 : template<class... Args>
269 : value&
270 2119951 : value_stack::
271 : stack::
272 : push(Args&&... args)
273 : {
274 2119951 : BOOST_ASSERT(chars_ == 0);
275 2119951 : if(top_ >= end_)
276 66246 : grow_one();
277 : value& jv = detail::access::
278 2119951 : construct_value(top_,
279 : std::forward<Args>(args)...);
280 2119887 : ++top_;
281 2119887 : return jv;
282 : }
283 :
284 : template<class Unchecked>
285 : void
286 37000 : value_stack::
287 : stack::
288 : exchange(Unchecked&& u)
289 : {
290 37000 : BOOST_ASSERT(chars_ == 0);
291 : union U
292 : {
293 : value v;
294 37000 : U() {}
295 37000 : ~U() {}
296 37000 : } jv;
297 : // construct value on the stack
298 : // to avoid clobbering top_[0],
299 : // which belongs to `u`.
300 : detail::access::
301 37000 : construct_value(
302 37000 : &jv.v, std::move(u));
303 36923 : std::memcpy(
304 : reinterpret_cast<
305 36923 : char*>(top_),
306 : &jv.v, sizeof(value));
307 36923 : ++top_;
308 37000 : }
309 :
310 : //----------------------------------------------------------
311 :
312 2076914 : value_stack::
313 : ~value_stack()
314 : {
315 : // default dtor is here so the
316 : // definition goes in the library
317 : // instead of the caller's TU.
318 2076914 : }
319 :
320 2076914 : value_stack::
321 : value_stack(
322 : storage_ptr sp,
323 : unsigned char* temp_buffer,
324 2076914 : std::size_t temp_size) noexcept
325 2076914 : : st_(
326 2076914 : std::move(sp),
327 : temp_buffer,
328 2076914 : temp_size)
329 : {
330 2076914 : }
331 :
332 : void
333 4153167 : value_stack::
334 : reset(storage_ptr sp) noexcept
335 : {
336 4153167 : st_.clear();
337 :
338 4153167 : sp_.~storage_ptr();
339 12459493 : ::new(&sp_) storage_ptr(
340 4153167 : pilfer(sp));
341 :
342 : // `stack` needs this
343 : // to clean up correctly
344 8306334 : st_.run_dtors(
345 4153167 : ! sp_.is_not_shared_and_deallocate_is_trivial());
346 4153167 : }
347 :
348 : value
349 2076656 : value_stack::
350 : release() noexcept
351 : {
352 : // This means the caller did not
353 : // cause a single top level element
354 : // to be produced.
355 2076656 : BOOST_ASSERT(st_.size() == 1);
356 :
357 : // give up shared ownership
358 2076656 : sp_ = {};
359 :
360 2076656 : return pilfer(*st_.release(1));
361 : }
362 :
363 : //----------------------------------------------------------
364 :
365 : void
366 2120 : value_stack::
367 : push_array(std::size_t n)
368 : {
369 : // we already have room if n > 0
370 2120 : if(BOOST_JSON_UNLIKELY(n == 0))
371 819 : st_.maybe_grow();
372 : detail::unchecked_array ua(
373 2120 : st_.release(n), n, sp_);
374 2120 : st_.exchange(std::move(ua));
375 2120 : }
376 :
377 : void
378 34880 : value_stack::
379 : push_object(std::size_t n)
380 : {
381 : // we already have room if n > 0
382 34880 : if(BOOST_JSON_UNLIKELY(n == 0))
383 1049 : st_.maybe_grow();
384 : detail::unchecked_object uo(
385 34880 : st_.release(n * 2), n, sp_);
386 34880 : st_.exchange(std::move(uo));
387 34880 : }
388 :
389 : void
390 20149 : value_stack::
391 : push_chars(
392 : string_view s)
393 : {
394 20149 : st_.append(s);
395 20149 : }
396 :
397 : void
398 38358 : value_stack::
399 : push_key(
400 : string_view s)
401 : {
402 38358 : if(! st_.has_chars())
403 : {
404 30297 : st_.push(detail::key_t{}, s, sp_);
405 30237 : return;
406 : }
407 8061 : auto part = st_.release_string();
408 8061 : st_.push(detail::key_t{}, part, s, sp_);
409 : }
410 :
411 : void
412 26108 : value_stack::
413 : push_string(
414 : string_view s)
415 : {
416 26108 : if(! st_.has_chars())
417 : {
418 : // fast path
419 17148 : st_.push(s, sp_);
420 17144 : return;
421 : }
422 :
423 : // VFALCO We could add a special
424 : // private ctor to string that just
425 : // creates uninitialized space,
426 : // to reduce member function calls.
427 8960 : auto part = st_.release_string();
428 17920 : auto& str = st_.push(
429 8960 : string_kind, sp_).get_string();
430 8960 : str.reserve(
431 8960 : part.size() + s.size());
432 8960 : std::memcpy(
433 8960 : str.data(),
434 8960 : part.data(), part.size());
435 8960 : std::memcpy(
436 8960 : str.data() + part.size(),
437 8960 : s.data(), s.size());
438 8960 : str.grow(part.size() + s.size());
439 : }
440 :
441 : void
442 5816 : value_stack::
443 : push_int64(
444 : std::int64_t i)
445 : {
446 5816 : st_.push(i, sp_);
447 5816 : }
448 :
449 : void
450 70 : value_stack::
451 : push_uint64(
452 : std::uint64_t u)
453 : {
454 70 : st_.push(u, sp_);
455 70 : }
456 :
457 : void
458 2039830 : value_stack::
459 : push_double(
460 : double d)
461 : {
462 2039830 : st_.push(d, sp_);
463 2039830 : }
464 :
465 : void
466 400 : value_stack::
467 : push_bool(
468 : bool b)
469 : {
470 400 : st_.push(b, sp_);
471 400 : }
472 :
473 : void
474 9369 : value_stack::
475 : push_null()
476 : {
477 9369 : st_.push(nullptr, sp_);
478 9369 : }
479 :
480 : } // namespace json
481 : } // namespace boost
482 :
483 : #endif
|