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