impl/value_stack.ipp

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