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