impl/value_stack.ipp

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