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