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