100.00% Lines (168/168) 100.00% Functions (37/37)
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_OBJECT_HPP 10   #ifndef BOOST_JSON_IMPL_OBJECT_HPP
11   #define BOOST_JSON_IMPL_OBJECT_HPP 11   #define BOOST_JSON_IMPL_OBJECT_HPP
12   12  
13   #include <boost/core/detail/static_assert.hpp> 13   #include <boost/core/detail/static_assert.hpp>
14   #include <boost/json/value.hpp> 14   #include <boost/json/value.hpp>
15   #include <iterator> 15   #include <iterator>
16   #include <cmath> 16   #include <cmath>
17   #include <type_traits> 17   #include <type_traits>
18   #include <utility> 18   #include <utility>
19   19  
20   namespace boost { 20   namespace boost {
21   namespace json { 21   namespace json {
22   22  
23   namespace detail { 23   namespace detail {
24   24  
25   // Objects with size less than or equal 25   // Objects with size less than or equal
26   // to this number will use a linear search 26   // to this number will use a linear search
27   // instead of the more expensive hash function. 27   // instead of the more expensive hash function.
28   static 28   static
29   constexpr 29   constexpr
30   std::size_t 30   std::size_t
31   small_object_size_ = 18; 31   small_object_size_ = 18;
32   32  
33   BOOST_CORE_STATIC_ASSERT( 33   BOOST_CORE_STATIC_ASSERT(
34   small_object_size_ < BOOST_JSON_MAX_STRUCTURED_SIZE); 34   small_object_size_ < BOOST_JSON_MAX_STRUCTURED_SIZE);
35   35  
36   } // detail 36   } // detail
37   37  
38   //---------------------------------------------------------- 38   //----------------------------------------------------------
39   39  
40   struct alignas(key_value_pair) 40   struct alignas(key_value_pair)
41   object::table 41   object::table
42   { 42   {
43   std::uint32_t size = 0; 43   std::uint32_t size = 0;
44   std::uint32_t capacity = 0; 44   std::uint32_t capacity = 0;
45   std::uintptr_t salt = 0; 45   std::uintptr_t salt = 0;
46   46  
47   #if defined(_MSC_VER) && BOOST_JSON_ARCH == 32 47   #if defined(_MSC_VER) && BOOST_JSON_ARCH == 32
48   // VFALCO If we make key_value_pair smaller, 48   // VFALCO If we make key_value_pair smaller,
49   // then we might want to revisit this 49   // then we might want to revisit this
50   // padding. 50   // padding.
51   BOOST_CORE_STATIC_ASSERT( sizeof(key_value_pair) == 32 ); 51   BOOST_CORE_STATIC_ASSERT( sizeof(key_value_pair) == 32 );
52   char pad[4] = {}; // silence warnings 52   char pad[4] = {}; // silence warnings
53   #endif 53   #endif
54   54  
55   constexpr table(); 55   constexpr table();
56   56  
57   // returns true if we use a linear 57   // returns true if we use a linear
58   // search instead of the hash table. 58   // search instead of the hash table.
HITCBC 59   122186 bool is_small() const noexcept 59   122186 bool is_small() const noexcept
60   { 60   {
HITCBC 61   122186 return capacity <= 61   122186 return capacity <=
HITCBC 62   122186 detail::small_object_size_; 62   122186 detail::small_object_size_;
63   } 63   }
64   64  
65   key_value_pair& 65   key_value_pair&
HITCBC 66   294485 operator[]( 66   294046 operator[](
67   std::size_t pos) noexcept 67   std::size_t pos) noexcept
68   { 68   {
69   return reinterpret_cast< 69   return reinterpret_cast<
70   key_value_pair*>( 70   key_value_pair*>(
HITCBC 71   294485 this + 1)[pos]; 71   294046 this + 1)[pos];
72   } 72   }
73   73  
74   // VFALCO This is exported for tests 74   // VFALCO This is exported for tests
75   BOOST_JSON_DECL 75   BOOST_JSON_DECL
76   std::size_t 76   std::size_t
77   digest(string_view key) const noexcept; 77   digest(string_view key) const noexcept;
78   78  
79   inline 79   inline
80   index_t& 80   index_t&
81   bucket(std::size_t hash) noexcept; 81   bucket(std::size_t hash) noexcept;
82   82  
83   inline 83   inline
84   index_t& 84   index_t&
85   bucket(string_view key) noexcept; 85   bucket(string_view key) noexcept;
86   86  
87   inline 87   inline
88   void 88   void
89   clear() noexcept; 89   clear() noexcept;
90   90  
91   static 91   static
92   inline 92   inline
93   table* 93   table*
94   allocate( 94   allocate(
95   std::size_t capacity, 95   std::size_t capacity,
96   std::uintptr_t salt, 96   std::uintptr_t salt,
97   storage_ptr const& sp); 97   storage_ptr const& sp);
98   98  
99   static 99   static
100   void 100   void
HITCBC 101   36352 deallocate( 101   36352 deallocate(
102   table* p, 102   table* p,
103   storage_ptr const& sp) noexcept 103   storage_ptr const& sp) noexcept
104   { 104   {
HITCBC 105   36352 if(p->capacity == 0) 105   36352 if(p->capacity == 0)
HITCBC 106   983 return; 106   983 return;
HITCBC 107   35369 if(! p->is_small()) 107   35369 if(! p->is_small())
HITCBC 108   388 sp->deallocate(p, 108   388 sp->deallocate(p,
HITCBC 109   388 sizeof(table) + p->capacity * ( 109   388 sizeof(table) + p->capacity * (
110   sizeof(key_value_pair) + 110   sizeof(key_value_pair) +
111   sizeof(index_t))); 111   sizeof(index_t)));
112   else 112   else
HITCBC 113   34981 sp->deallocate(p, 113   34981 sp->deallocate(p,
HITCBC 114   34981 sizeof(table) + p->capacity * 114   34981 sizeof(table) + p->capacity *
115   sizeof(key_value_pair)); 115   sizeof(key_value_pair));
116   } 116   }
117   }; 117   };
118   118  
119   //---------------------------------------------------------- 119   //----------------------------------------------------------
120   120  
121   class object::revert_construct 121   class object::revert_construct
122   { 122   {
123   object* obj_; 123   object* obj_;
124   124  
125   BOOST_JSON_DECL 125   BOOST_JSON_DECL
126   void 126   void
127   destroy() noexcept; 127   destroy() noexcept;
128   128  
129   public: 129   public:
130   explicit 130   explicit
HITCBC 131   705 revert_construct( 131   705 revert_construct(
132   object& obj) noexcept 132   object& obj) noexcept
HITCBC 133   705 : obj_(&obj) 133   705 : obj_(&obj)
134   { 134   {
HITCBC 135   705 } 135   705 }
136   136  
HITCBC 137   705 ~revert_construct() 137   705 ~revert_construct()
HITCBC 138   374 { 138   374 {
HITCBC 139   705 if(! obj_) 139   705 if(! obj_)
HITCBC 140   331 return; 140   331 return;
HITCBC 141   374 destroy(); 141   374 destroy();
HITCBC 142   705 } 142   705 }
143   143  
144   void 144   void
HITCBC 145   331 commit() noexcept 145   331 commit() noexcept
146   { 146   {
HITCBC 147   331 obj_ = nullptr; 147   331 obj_ = nullptr;
HITCBC 148   331 } 148   331 }
149   }; 149   };
150   150  
151   //---------------------------------------------------------- 151   //----------------------------------------------------------
152   152  
153   class object::revert_insert 153   class object::revert_insert
154   { 154   {
155   object* obj_; 155   object* obj_;
156   table* t_ = nullptr; 156   table* t_ = nullptr;
157   std::size_t size_; 157   std::size_t size_;
158   158  
159   BOOST_JSON_DECL 159   BOOST_JSON_DECL
160   void 160   void
161   destroy() noexcept; 161   destroy() noexcept;
162   162  
163   public: 163   public:
164   explicit 164   explicit
HITCBC 165   503 revert_insert( 165   503 revert_insert(
166   object& obj, 166   object& obj,
167   std::size_t capacity) 167   std::size_t capacity)
HITCBC 168   503 : obj_(&obj) 168   503 : obj_(&obj)
HITCBC 169   503 , size_(obj_->size()) 169   503 , size_(obj_->size())
170   { 170   {
HITCBC 171   503 if( capacity > obj_->capacity() ) 171   503 if( capacity > obj_->capacity() )
HITCBC 172   138 t_ = obj_->reserve_impl(capacity); 172   138 t_ = obj_->reserve_impl(capacity);
HITCBC 173   494 } 173   494 }
174   174  
HITCBC 175   494 ~revert_insert() 175   494 ~revert_insert()
HITCBC 176   230 { 176   230 {
HITCBC 177   494 if(! obj_) 177   494 if(! obj_)
HITCBC 178   264 return; 178   264 return;
179   179  
HITCBC 180   230 destroy(); 180   230 destroy();
HITCBC 181   230 if( t_ ) 181   230 if( t_ )
182   { 182   {
HITCBC 183   117 table::deallocate( obj_->t_, obj_->sp_ ); 183   117 table::deallocate( obj_->t_, obj_->sp_ );
HITCBC 184   117 obj_->t_ = t_; 184   117 obj_->t_ = t_;
185   } 185   }
186   else 186   else
187   { 187   {
HITCBC 188   113 obj_->t_->size = static_cast<index_t>(size_); 188   113 obj_->t_->size = static_cast<index_t>(size_);
189   } 189   }
HITCBC 190   494 } 190   494 }
191   191  
192   void 192   void
HITCBC 193   264 commit() noexcept 193   264 commit() noexcept
194   { 194   {
HITCBC 195   264 BOOST_ASSERT(obj_); 195   264 BOOST_ASSERT(obj_);
HITCBC 196   264 if( t_ ) 196   264 if( t_ )
HITCBC 197   12 table::deallocate( t_, obj_->sp_ ); 197   12 table::deallocate( t_, obj_->sp_ );
HITCBC 198   264 obj_ = nullptr; 198   264 obj_ = nullptr;
HITCBC 199   264 } 199   264 }
200   }; 200   };
201   201  
202   //---------------------------------------------------------- 202   //----------------------------------------------------------
203   // 203   //
204   // Iterators 204   // Iterators
205   // 205   //
206   //---------------------------------------------------------- 206   //----------------------------------------------------------
207   207  
208   auto 208   auto
HITCBC 209   70788 object:: 209   70788 object::
210   begin() noexcept -> 210   begin() noexcept ->
211   iterator 211   iterator
212   { 212   {
HITCBC 213   70788 return &(*t_)[0]; 213   70788 return &(*t_)[0];
214   } 214   }
215   215  
216   auto 216   auto
HITCBC 217   53205 object:: 217   53205 object::
218   begin() const noexcept -> 218   begin() const noexcept ->
219   const_iterator 219   const_iterator
220   { 220   {
HITCBC 221   53205 return &(*t_)[0]; 221   53205 return &(*t_)[0];
222   } 222   }
223   223  
224   auto 224   auto
HITCBC 225   3 object:: 225   3 object::
226   cbegin() const noexcept -> 226   cbegin() const noexcept ->
227   const_iterator 227   const_iterator
228   { 228   {
HITCBC 229   3 return &(*t_)[0]; 229   3 return &(*t_)[0];
230   } 230   }
231   231  
232   auto 232   auto
HITCBC 233   46093 object:: 233   46093 object::
234   end() noexcept -> 234   end() noexcept ->
235   iterator 235   iterator
236   { 236   {
HITCBC 237   46093 return &(*t_)[t_->size]; 237   46093 return &(*t_)[t_->size];
238   } 238   }
239   239  
240   auto 240   auto
HITCBC 241   27786 object:: 241   27786 object::
242   end() const noexcept -> 242   end() const noexcept ->
243   const_iterator 243   const_iterator
244   { 244   {
HITCBC 245   27786 return &(*t_)[t_->size]; 245   27786 return &(*t_)[t_->size];
246   } 246   }
247   247  
248   auto 248   auto
HITCBC 249   3 object:: 249   3 object::
250   cend() const noexcept -> 250   cend() const noexcept ->
251   const_iterator 251   const_iterator
252   { 252   {
HITCBC 253   3 return &(*t_)[t_->size]; 253   3 return &(*t_)[t_->size];
254   } 254   }
255   255  
256   auto 256   auto
HITCBC 257   2 object:: 257   2 object::
258   rbegin() noexcept -> 258   rbegin() noexcept ->
259   reverse_iterator 259   reverse_iterator
260   { 260   {
HITCBC 261   2 return reverse_iterator(end()); 261   2 return reverse_iterator(end());
262   } 262   }
263   263  
264   auto 264   auto
HITCBC 265   2 object:: 265   2 object::
266   rbegin() const noexcept -> 266   rbegin() const noexcept ->
267   const_reverse_iterator 267   const_reverse_iterator
268   { 268   {
HITCBC 269   2 return const_reverse_iterator(end()); 269   2 return const_reverse_iterator(end());
270   } 270   }
271   271  
272   auto 272   auto
HITCBC 273   2 object:: 273   2 object::
274   crbegin() const noexcept -> 274   crbegin() const noexcept ->
275   const_reverse_iterator 275   const_reverse_iterator
276   { 276   {
HITCBC 277   2 return const_reverse_iterator(end()); 277   2 return const_reverse_iterator(end());
278   } 278   }
279   279  
280   auto 280   auto
HITCBC 281   2 object:: 281   2 object::
282   rend() noexcept -> 282   rend() noexcept ->
283   reverse_iterator 283   reverse_iterator
284   { 284   {
HITCBC 285   2 return reverse_iterator(begin()); 285   2 return reverse_iterator(begin());
286   } 286   }
287   287  
288   auto 288   auto
HITCBC 289   2 object:: 289   2 object::
290   rend() const noexcept -> 290   rend() const noexcept ->
291   const_reverse_iterator 291   const_reverse_iterator
292   { 292   {
HITCBC 293   2 return const_reverse_iterator(begin()); 293   2 return const_reverse_iterator(begin());
294   } 294   }
295   295  
296   auto 296   auto
HITCBC 297   2 object:: 297   2 object::
298   crend() const noexcept -> 298   crend() const noexcept ->
299   const_reverse_iterator 299   const_reverse_iterator
300   { 300   {
HITCBC 301   2 return const_reverse_iterator(begin()); 301   2 return const_reverse_iterator(begin());
302   } 302   }
303   303  
304   //---------------------------------------------------------- 304   //----------------------------------------------------------
305   // 305   //
306   // Capacity 306   // Capacity
307   // 307   //
308   //---------------------------------------------------------- 308   //----------------------------------------------------------
309   309  
310   bool 310   bool
HITCBC 311   10473 object:: 311   10473 object::
312   empty() const noexcept 312   empty() const noexcept
313   { 313   {
HITCBC 314   10473 return t_->size == 0; 314   10473 return t_->size == 0;
315   } 315   }
316   316  
317   auto 317   auto
HITCBC 318   44249 object:: 318   44249 object::
319   size() const noexcept -> 319   size() const noexcept ->
320   std::size_t 320   std::size_t
321   { 321   {
HITCBC 322   44249 return t_->size; 322   44249 return t_->size;
323   } 323   }
324   324  
325   constexpr 325   constexpr
326   std::size_t 326   std::size_t
HITCBC 327   73125 object:: 327   73125 object::
328   max_size() noexcept 328   max_size() noexcept
329   { 329   {
330   // max_size depends on the address model 330   // max_size depends on the address model
331   using min = std::integral_constant<std::size_t, 331   using min = std::integral_constant<std::size_t,
332   (std::size_t(-1) - sizeof(table)) / 332   (std::size_t(-1) - sizeof(table)) /
333   (sizeof(key_value_pair) + sizeof(index_t))>; 333   (sizeof(key_value_pair) + sizeof(index_t))>;
334   return min::value < BOOST_JSON_MAX_STRUCTURED_SIZE ? 334   return min::value < BOOST_JSON_MAX_STRUCTURED_SIZE ?
HITCBC 335   73125 min::value : BOOST_JSON_MAX_STRUCTURED_SIZE; 335   73125 min::value : BOOST_JSON_MAX_STRUCTURED_SIZE;
336   } 336   }
337   337  
338   auto 338   auto
HITCBC 339   18848 object:: 339   18848 object::
340   capacity() const noexcept -> 340   capacity() const noexcept ->
341   std::size_t 341   std::size_t
342   { 342   {
HITCBC 343   18848 return t_->capacity; 343   18848 return t_->capacity;
344   } 344   }
345   345  
346   void 346   void
HITCBC 347   4742 object:: 347   4742 object::
348   reserve(std::size_t new_capacity) 348   reserve(std::size_t new_capacity)
349   { 349   {
HITCBC 350   4742 if( new_capacity <= capacity() ) 350   4742 if( new_capacity <= capacity() )
HITCBC 351   3224 return; 351   3224 return;
HITCBC 352   1518 table* const old_table = reserve_impl(new_capacity); 352   1518 table* const old_table = reserve_impl(new_capacity);
HITCBC 353   1453 table::deallocate( old_table, sp_ ); 353   1453 table::deallocate( old_table, sp_ );
354   } 354   }
355   355  
356   //---------------------------------------------------------- 356   //----------------------------------------------------------
357   // 357   //
358   // Lookup 358   // Lookup
359   // 359   //
360   //---------------------------------------------------------- 360   //----------------------------------------------------------
361   361  
362   value& 362   value&
HITCBC 363   42 object:: 363   42 object::
364   at(string_view key, source_location const& loc) & 364   at(string_view key, source_location const& loc) &
365   { 365   {
HITCBC 366   42 auto const& self = *this; 366   42 auto const& self = *this;
HITCBC 367   42 return const_cast< value& >( self.at(key, loc) ); 367   42 return const_cast< value& >( self.at(key, loc) );
368   } 368   }
369   369  
370   value&& 370   value&&
HITCBC 371   5 object:: 371   5 object::
372   at(string_view key, source_location const& loc) && 372   at(string_view key, source_location const& loc) &&
373   { 373   {
HITCBC 374   5 return std::move( at(key, loc) ); 374   5 return std::move( at(key, loc) );
375   } 375   }
376   376  
377   //---------------------------------------------------------- 377   //----------------------------------------------------------
378   378  
379   template<class P, class> 379   template<class P, class>
380   auto 380   auto
HITCBC 381   3127 object:: 381   3127 object::
382   insert(P&& p) -> 382   insert(P&& p) ->
383   std::pair<iterator, bool> 383   std::pair<iterator, bool>
384   { 384   {
HITCBC 385   3422 key_value_pair v( 385   3422 key_value_pair v(
HITCBC 386   3127 std::forward<P>(p), sp_); 386   3127 std::forward<P>(p), sp_);
HITCBC 387   5791 return emplace_impl( v.key(), pilfer(v) ); 387   5791 return emplace_impl( v.key(), pilfer(v) );
HITCBC 388   2979 } 388   2979 }
389   389  
390   template<class M> 390   template<class M>
391   auto 391   auto
HITCBC 392   17 object:: 392   17 object::
393   insert_or_assign( 393   insert_or_assign(
394   string_view key, M&& m) -> 394   string_view key, M&& m) ->
395   std::pair<iterator, bool> 395   std::pair<iterator, bool>
396   { 396   {
HITCBC 397   17 std::pair<iterator, bool> result = emplace_impl( 397   17 std::pair<iterator, bool> result = emplace_impl(
398   key, key, static_cast<M&&>(m) ); 398   key, key, static_cast<M&&>(m) );
HITCBC 399   10 if( !result.second ) 399   10 if( !result.second )
400   { 400   {
HITCBC 401   8 value(static_cast<M>(m), sp_).swap( 401   8 value(static_cast<M>(m), sp_).swap(
HITCBC 402   3 result.first->value()); 402   3 result.first->value());
403   } 403   }
HITCBC 404   9 return result; 404   9 return result;
405   } 405   }
406   406  
407   template<class Arg> 407   template<class Arg>
408   auto 408   auto
HITCBC 409   995 object:: 409   995 object::
410   emplace( 410   emplace(
411   string_view key, 411   string_view key,
412   Arg&& arg) -> 412   Arg&& arg) ->
413   std::pair<iterator, bool> 413   std::pair<iterator, bool>
414   { 414   {
HITCBC 415   995 return emplace_impl( key, key, static_cast<Arg&&>(arg) ); 415   995 return emplace_impl( key, key, static_cast<Arg&&>(arg) );
416   } 416   }
417   417  
418   //---------------------------------------------------------- 418   //----------------------------------------------------------
419   // 419   //
420   // (private) 420   // (private)
421   // 421   //
422   //---------------------------------------------------------- 422   //----------------------------------------------------------
423   423  
424   template<class InputIt> 424   template<class InputIt>
425   void 425   void
HITCBC 426   78 object:: 426   78 object::
427   construct( 427   construct(
428   InputIt first, 428   InputIt first,
429   InputIt last, 429   InputIt last,
430   std::size_t min_capacity, 430   std::size_t min_capacity,
431   std::input_iterator_tag) 431   std::input_iterator_tag)
432   { 432   {
HITCBC 433   78 reserve(min_capacity); 433   78 reserve(min_capacity);
HITCBC 434   76 revert_construct r(*this); 434   76 revert_construct r(*this);
HITCBC 435   753 while(first != last) 435   753 while(first != last)
436   { 436   {
HITCBC 437   750 insert(*first); 437   750 insert(*first);
HITCBC 438   677 ++first; 438   677 ++first;
439   } 439   }
HITCBC 440   3 r.commit(); 440   3 r.commit();
HITCBC 441   76 } 441   76 }
442   442  
443   template<class InputIt> 443   template<class InputIt>
444   void 444   void
HITCBC 445   82 object:: 445   82 object::
446   construct( 446   construct(
447   InputIt first, 447   InputIt first,
448   InputIt last, 448   InputIt last,
449   std::size_t min_capacity, 449   std::size_t min_capacity,
450   std::forward_iterator_tag) 450   std::forward_iterator_tag)
451   { 451   {
HITCBC 452   82 auto n = static_cast< 452   82 auto n = static_cast<
HITCBC 453   82 std::size_t>(std::distance( 453   82 std::size_t>(std::distance(
454   first, last)); 454   first, last));
HITCBC 455   82 if( n < min_capacity) 455   82 if( n < min_capacity)
HITCBC 456   76 n = min_capacity; 456   76 n = min_capacity;
HITCBC 457   82 reserve(n); 457   82 reserve(n);
HITCBC 458   79 revert_construct r(*this); 458   79 revert_construct r(*this);
HITCBC 459   771 while(first != last) 459   771 while(first != last)
460   { 460   {
HITCBC 461   764 insert(*first); 461   764 insert(*first);
HITCBC 462   692 ++first; 462   692 ++first;
463   } 463   }
HITCBC 464   7 r.commit(); 464   7 r.commit();
HITCBC 465   79 } 465   79 }
466   466  
467   template<class InputIt> 467   template<class InputIt>
468   void 468   void
HITCBC 469   94 object:: 469   94 object::
470   insert( 470   insert(
471   InputIt first, 471   InputIt first,
472   InputIt last, 472   InputIt last,
473   std::input_iterator_tag) 473   std::input_iterator_tag)
474   { 474   {
475   // Since input iterators cannot be rewound, 475   // Since input iterators cannot be rewound,
476   // we keep inserted elements on an exception. 476   // we keep inserted elements on an exception.
477   // 477   //
HITCBC 478   871 while(first != last) 478   871 while(first != last)
479   { 479   {
HITCBC 480   867 insert(*first); 480   867 insert(*first);
HITCBC 481   777 ++first; 481   777 ++first;
482   } 482   }
HITCBC 483   4 } 483   4 }
484   484  
485   template<class InputIt> 485   template<class InputIt>
486   void 486   void
HITCBC 487   80 object:: 487   80 object::
488   insert( 488   insert(
489   InputIt first, 489   InputIt first,
490   InputIt last, 490   InputIt last,
491   std::forward_iterator_tag) 491   std::forward_iterator_tag)
492   { 492   {
HITCBC 493   80 auto const n = 493   80 auto const n =
494   static_cast<std::size_t>( 494   static_cast<std::size_t>(
HITCBC 495   80 std::distance(first, last)); 495   80 std::distance(first, last));
HITCBC 496   80 auto const n0 = size(); 496   80 auto const n0 = size();
HITCBC 497   80 if(n > max_size() - n0) 497   80 if(n > max_size() - n0)
498   { 498   {
499   BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION; 499   BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
HITCBC 500   1 detail::throw_system_error( error::object_too_large, &loc ); 500   1 detail::throw_system_error( error::object_too_large, &loc );
501   } 501   }
HITCBC 502   79 revert_insert r( *this, n0 + n ); 502   79 revert_insert r( *this, n0 + n );
HITCBC 503   738 while(first != last) 503   738 while(first != last)
504   { 504   {
HITCBC 505   734 insert(*first); 505   734 insert(*first);
HITCBC 506   661 ++first; 506   661 ++first;
507   } 507   }
HITCBC 508   4 r.commit(); 508   4 r.commit();
HITCBC 509   77 } 509   77 }
510   510  
511   template< class... Args > 511   template< class... Args >
512   std::pair<object::iterator, bool> 512   std::pair<object::iterator, bool>
HITCBC 513   3991 object:: 513   3991 object::
514   emplace_impl( string_view key, Args&& ... args ) 514   emplace_impl( string_view key, Args&& ... args )
515   { 515   {
HITCBC 516   3991 std::pair<iterator, std::size_t> search_result(nullptr, 0); 516   3991 std::pair<iterator, std::size_t> search_result(nullptr, 0);
HITCBC 517   3991 if( !empty() ) 517   3991 if( !empty() )
518   { 518   {
HITCBC 519   3462 search_result = detail::find_in_object(*this, key); 519   3462 search_result = detail::find_in_object(*this, key);
HITCBC 520   3462 if( search_result.first ) 520   3462 if( search_result.first )
HITCBC 521   30 return { search_result.first, false }; 521   30 return { search_result.first, false };
522   } 522   }
523   523  
524   // we create the new value before reserving, in case it is a reference to 524   // we create the new value before reserving, in case it is a reference to
525   // a subobject of the current object 525   // a subobject of the current object
HITCBC 526   4253 key_value_pair kv( static_cast<Args&&>(args)..., sp_ ); 526   4253 key_value_pair kv( static_cast<Args&&>(args)..., sp_ );
527   // the key might get deallocated too 527   // the key might get deallocated too
HITCBC 528   3808 key = kv.key(); 528   3808 key = kv.key();
529   529  
HITCBC 530   3808 std::size_t const old_capacity = capacity(); 530   3808 std::size_t const old_capacity = capacity();
HITCBC 531   3808 reserve(size() + 1); 531   3808 reserve(size() + 1);
HITCBC 532   4294 if( (empty() && capacity() > detail::small_object_size_) 532   4294 if( (empty() && capacity() > detail::small_object_size_)
HITCBC 533   4294 || (capacity() != old_capacity) ) 533   4294 || (capacity() != old_capacity) )
HITCBC 534   724 search_result.second = detail::digest( 534   724 search_result.second = detail::digest(
HITCBC 535   724 key.begin(), key.end(), t_->salt); 535   724 key.begin(), key.end(), t_->salt);
536   536  
HITCBC 537   3781 BOOST_ASSERT( 537   3781 BOOST_ASSERT(
538   t_->is_small() || 538   t_->is_small() ||
539   (search_result.second == 539   (search_result.second ==
540   detail::digest(key.begin(), key.end(), t_->salt)) ); 540   detail::digest(key.begin(), key.end(), t_->salt)) );
541   541  
HITCBC 542   3781 return { insert_impl(pilfer(kv), search_result.second), true }; 542   3781 return { insert_impl(pilfer(kv), search_result.second), true };
HITCBC 543   3808 } 543   3808 }
544   544  
545   //---------------------------------------------------------- 545   //----------------------------------------------------------
546   546  
547   namespace detail { 547   namespace detail {
548   548  
HITCBC 549   34879 unchecked_object:: 549   34879 unchecked_object::
HITCBC 550   1086 ~unchecked_object() 550   1086 ~unchecked_object()
551   { 551   {
HITCBC 552   34879 if(! data_) 552   34879 if(! data_)
HITCBC 553   33791 return; 553   33791 return;
HITCBC 554   1088 if(sp_.is_not_shared_and_deallocate_is_trivial()) 554   1088 if(sp_.is_not_shared_and_deallocate_is_trivial())
HITCBC 555   2 return; 555   2 return;
HITCBC 556   1086 value* p = data_; 556   1086 value* p = data_;
HITCBC 557   1146 while(size_--) 557   1146 while(size_--)
558   { 558   {
HITCBC 559   60 p[0].~value(); 559   60 p[0].~value();
HITCBC 560   60 p[1].~value(); 560   60 p[1].~value();
HITCBC 561   60 p += 2; 561   60 p += 2;
562   } 562   }
HITCBC 563   34879 } 563   34879 }
564   564  
565   } // detail 565   } // detail
566   566  
567   } // namespace json 567   } // namespace json
568   } // namespace boost 568   } // namespace boost
569   569  
570   #endif 570   #endif