100.00% Lines (435/435) 100.00% Functions (49/49)
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_IPP 10   #ifndef BOOST_JSON_IMPL_OBJECT_IPP
11   #define BOOST_JSON_IMPL_OBJECT_IPP 11   #define BOOST_JSON_IMPL_OBJECT_IPP
12   12  
13   #include <boost/core/detail/static_assert.hpp> 13   #include <boost/core/detail/static_assert.hpp>
14   #include <boost/container_hash/hash.hpp> 14   #include <boost/container_hash/hash.hpp>
15   #include <boost/json/object.hpp> 15   #include <boost/json/object.hpp>
16   #include <boost/json/detail/digest.hpp> 16   #include <boost/json/detail/digest.hpp>
17   #include <boost/json/detail/except.hpp> 17   #include <boost/json/detail/except.hpp>
18   #include <algorithm> 18   #include <algorithm>
19   #include <cmath> 19   #include <cmath>
20   #include <cstdlib> 20   #include <cstdlib>
21   #include <cstring> 21   #include <cstring>
22   #include <new> 22   #include <new>
23   #include <stdexcept> 23   #include <stdexcept>
24   #include <type_traits> 24   #include <type_traits>
25   25  
26   namespace boost { 26   namespace boost {
27   namespace json { 27   namespace json {
28   namespace detail { 28   namespace detail {
29   29  
30   template<class CharRange> 30   template<class CharRange>
31   std::pair<key_value_pair*, std::size_t> 31   std::pair<key_value_pair*, std::size_t>
HITCBC 32   42845 find_in_object( 32   42845 find_in_object(
33   object const& obj, 33   object const& obj,
34   CharRange key) noexcept 34   CharRange key) noexcept
35   { 35   {
HITCBC 36   42845 BOOST_ASSERT(obj.t_->capacity > 0); 36   42845 BOOST_ASSERT(obj.t_->capacity > 0);
HITCBC 37   42845 if(obj.t_->is_small()) 37   42845 if(obj.t_->is_small())
38   { 38   {
HITCBC 39   40997 auto it = &(*obj.t_)[0]; 39   40997 auto it = &(*obj.t_)[0];
40   auto const last = 40   auto const last =
HITCBC 41   40997 &(*obj.t_)[obj.t_->size]; 41   40997 &(*obj.t_)[obj.t_->size];
HITCBC 42   75329 for(;it != last; ++it) 42   75329 for(;it != last; ++it)
HITCBC 43   35055 if( key == it->key() ) 43   35055 if( key == it->key() )
HITCBC 44   723 return { it, 0 }; 44   723 return { it, 0 };
HITCBC 45   40274 return { nullptr, 0 }; 45   40274 return { nullptr, 0 };
46   } 46   }
47   std::pair< 47   std::pair<
48   key_value_pair*, 48   key_value_pair*,
HITCBC 49   1848 std::size_t> result; 49   1848 std::size_t> result;
HITCBC 50   1848 BOOST_ASSERT(obj.t_->salt != 0); 50   1848 BOOST_ASSERT(obj.t_->salt != 0);
HITCBC 51   1848 result.second = detail::digest(key.begin(), key.end(), obj.t_->salt); 51   1848 result.second = detail::digest(key.begin(), key.end(), obj.t_->salt);
HITCBC 52   1848 auto i = obj.t_->bucket( 52   1848 auto i = obj.t_->bucket(
53   result.second); 53   result.second);
HITCBC 54   2681 while(i != object::null_index_) 54   2583 while(i != object::null_index_)
55   { 55   {
HITCBC 56   1171 auto& v = (*obj.t_)[i]; 56   1073 auto& v = (*obj.t_)[i];
HITCBC 57   1171 if( key == v.key() ) 57   1073 if( key == v.key() )
58   { 58   {
HITCBC 59   338 result.first = &v; 59   338 result.first = &v;
HITCBC 60   338 return result; 60   338 return result;
61   } 61   }
HITCBC 62   833 i = access::next(v); 62   735 i = access::next(v);
63   } 63   }
HITCBC 64   1510 result.first = nullptr; 64   1510 result.first = nullptr;
HITCBC 65   1510 return result; 65   1510 return result;
66   } 66   }
67   67  
68   68  
69   template 69   template
70   std::pair<key_value_pair*, std::size_t> 70   std::pair<key_value_pair*, std::size_t>
71   find_in_object<string_view>( 71   find_in_object<string_view>(
72   object const& obj, 72   object const& obj,
73   string_view key) noexcept; 73   string_view key) noexcept;
74   74  
75   } // namespace detail 75   } // namespace detail
76   76  
77   //---------------------------------------------------------- 77   //----------------------------------------------------------
78   78  
79   constexpr object::table::table() = default; 79   constexpr object::table::table() = default;
80   80  
81   // empty objects point here 81   // empty objects point here
82   BOOST_JSON_REQUIRE_CONST_INIT 82   BOOST_JSON_REQUIRE_CONST_INIT
83   object::table object::empty_; 83   object::table object::empty_;
84   84  
85   std::size_t 85   std::size_t
HITCBC 86   7115 object::table:: 86   7092 object::table::
87   digest(string_view key) const noexcept 87   digest(string_view key) const noexcept
88   { 88   {
HITCBC 89   7115 BOOST_ASSERT(salt != 0); 89   7092 BOOST_ASSERT(salt != 0);
HITCBC 90   7115 return detail::digest( 90   7092 return detail::digest(
HITCBC 91   14230 key.begin(), key.end(), salt); 91   14184 key.begin(), key.end(), salt);
92   } 92   }
93   93  
94   auto 94   auto
HITCBC 95   10517 object::table:: 95   10517 object::table::
96   bucket(std::size_t hash) noexcept -> 96   bucket(std::size_t hash) noexcept ->
97   index_t& 97   index_t&
98   { 98   {
99   return reinterpret_cast< 99   return reinterpret_cast<
HITCBC 100   10517 index_t*>(&(*this)[capacity])[ 100   10517 index_t*>(&(*this)[capacity])[
HITCBC 101   10517 hash % capacity]; 101   10517 hash % capacity];
102   } 102   }
103   103  
104   auto 104   auto
HITCBC 105   7082 object::table:: 105   7082 object::table::
106   bucket(string_view key) noexcept -> 106   bucket(string_view key) noexcept ->
107   index_t& 107   index_t&
108   { 108   {
HITCBC 109   7082 return bucket(digest(key)); 109   7082 return bucket(digest(key));
110   } 110   }
111   111  
112   void 112   void
HITCBC 113   392 object::table:: 113   392 object::table::
114   clear() noexcept 114   clear() noexcept
115   { 115   {
HITCBC 116   392 BOOST_ASSERT(! is_small()); 116   392 BOOST_ASSERT(! is_small());
117   // initialize buckets 117   // initialize buckets
HITCBC 118   784 std::memset( 118   784 std::memset(
119   reinterpret_cast<index_t*>( 119   reinterpret_cast<index_t*>(
HITCBC 120   392 &(*this)[capacity]), 120   392 &(*this)[capacity]),
121   0xff, // null_index_ 121   0xff, // null_index_
HITCBC 122   392 capacity * sizeof(index_t)); 122   392 capacity * sizeof(index_t));
HITCBC 123   392 } 123   392 }
124   124  
125   object::table* 125   object::table*
HITCBC 126   35479 object::table:: 126   35479 object::table::
127   allocate( 127   allocate(
128   std::size_t capacity, 128   std::size_t capacity,
129   std::uintptr_t salt, 129   std::uintptr_t salt,
130   storage_ptr const& sp) 130   storage_ptr const& sp)
131   { 131   {
132   BOOST_CORE_STATIC_ASSERT( 132   BOOST_CORE_STATIC_ASSERT(
133   alignof(key_value_pair) >= alignof(index_t)); 133   alignof(key_value_pair) >= alignof(index_t));
HITCBC 134   35479 BOOST_ASSERT(capacity > 0); 134   35479 BOOST_ASSERT(capacity > 0);
HITCBC 135   35479 BOOST_ASSERT(capacity <= max_size()); 135   35479 BOOST_ASSERT(capacity <= max_size());
136   table* p; 136   table* p;
HITCBC 137   35479 if(capacity <= detail::small_object_size_) 137   35479 if(capacity <= detail::small_object_size_)
138   { 138   {
139   p = reinterpret_cast< 139   p = reinterpret_cast<
HITCBC 140   35076 table*>(sp->allocate( 140   35076 table*>(sp->allocate(
HITCBC 141   35076 sizeof(table) + capacity * 141   35076 sizeof(table) + capacity *
142   sizeof(key_value_pair))); 142   sizeof(key_value_pair)));
HITCBC 143   34985 p->capacity = static_cast< 143   34985 p->capacity = static_cast<
144   std::uint32_t>(capacity); 144   std::uint32_t>(capacity);
145   } 145   }
146   else 146   else
147   { 147   {
148   p = reinterpret_cast< 148   p = reinterpret_cast<
HITCBC 149   403 table*>(sp->allocate( 149   403 table*>(sp->allocate(
HITCBC 150   403 sizeof(table) + capacity * ( 150   403 sizeof(table) + capacity * (
151   sizeof(key_value_pair) + 151   sizeof(key_value_pair) +
152   sizeof(index_t)))); 152   sizeof(index_t))));
HITCBC 153   388 p->capacity = static_cast< 153   388 p->capacity = static_cast<
154   std::uint32_t>(capacity); 154   std::uint32_t>(capacity);
HITCBC 155   388 p->clear(); 155   388 p->clear();
156   } 156   }
HITCBC 157   35373 if(salt) 157   35373 if(salt)
158   { 158   {
HITCBC 159   489 p->salt = salt; 159   489 p->salt = salt;
160   } 160   }
161   else 161   else
162   { 162   {
163   // VFALCO This would be better if it 163   // VFALCO This would be better if it
164   // was random, but maybe this 164   // was random, but maybe this
165   // is good enough. 165   // is good enough.
HITCBC 166   34884 p->salt = reinterpret_cast< 166   34884 p->salt = reinterpret_cast<
167   std::uintptr_t>(p); 167   std::uintptr_t>(p);
168   } 168   }
HITCBC 169   35373 return p; 169   35373 return p;
170   } 170   }
171   171  
172   //---------------------------------------------------------- 172   //----------------------------------------------------------
173   173  
174   void 174   void
HITCBC 175   374 object:: 175   374 object::
176   revert_construct:: 176   revert_construct::
177   destroy() noexcept 177   destroy() noexcept
178   { 178   {
HITCBC 179   374 obj_->destroy(); 179   374 obj_->destroy();
HITCBC 180   374 } 180   374 }
181   181  
182   //---------------------------------------------------------- 182   //----------------------------------------------------------
183   183  
184   void 184   void
HITCBC 185   230 object:: 185   230 object::
186   revert_insert:: 186   revert_insert::
187   destroy() noexcept 187   destroy() noexcept
188   { 188   {
HITCBC 189   230 obj_->destroy( 189   230 obj_->destroy(
HITCBC 190   230 &(*obj_->t_)[size_], 190   230 &(*obj_->t_)[size_],
HITCBC 191   230 obj_->end()); 191   230 obj_->end());
HITCBC 192   230 } 192   230 }
193   193  
194   //---------------------------------------------------------- 194   //----------------------------------------------------------
195   // 195   //
196   // Construction 196   // Construction
197   // 197   //
198   //---------------------------------------------------------- 198   //----------------------------------------------------------
199   199  
HITCBC 200   34879 object:: 200   34879 object::
HITCBC 201   34879 object(detail::unchecked_object&& uo) 201   34879 object(detail::unchecked_object&& uo)
HITCBC 202   34879 : sp_(uo.storage()) 202   34879 : sp_(uo.storage())
203   { 203   {
HITCBC 204   34879 if(uo.size() == 0) 204   34879 if(uo.size() == 0)
205   { 205   {
HITCBC 206   1049 t_ = &empty_; 206   1049 t_ = &empty_;
HITCBC 207   1049 return; 207   1049 return;
208   } 208   }
209   // should already be checked 209   // should already be checked
HITCBC 210   33830 BOOST_ASSERT( 210   33830 BOOST_ASSERT(
211   uo.size() <= max_size()); 211   uo.size() <= max_size());
HITCBC 212   33830 t_ = table::allocate( 212   33830 t_ = table::allocate(
HITCBC 213   33830 uo.size(), 0, sp_); 213   33830 uo.size(), 0, sp_);
214   214  
215   // insert all elements, keeping 215   // insert all elements, keeping
216   // the last of any duplicate keys. 216   // the last of any duplicate keys.
HITCBC 217   33791 auto dest = begin(); 217   33791 auto dest = begin();
HITCBC 218   33791 auto src = uo.release(); 218   33791 auto src = uo.release();
HITCBC 219   33791 auto const end = src + 2 * uo.size(); 219   33791 auto const end = src + 2 * uo.size();
HITCBC 220   33791 if(t_->is_small()) 220   33791 if(t_->is_small())
221   { 221   {
HITCBC 222   33758 t_->size = 0; 222   33758 t_->size = 0;
HITCBC 223   70267 while(src != end) 223   70267 while(src != end)
224   { 224   {
HITCBC 225   36509 access::construct_key_value_pair( 225   36509 access::construct_key_value_pair(
HITCBC 226   36509 dest, pilfer(src[0]), pilfer(src[1])); 226   36509 dest, pilfer(src[0]), pilfer(src[1]));
HITCBC 227   36509 src += 2; 227   36509 src += 2;
HITCBC 228   36509 auto result = detail::find_in_object(*this, dest->key()); 228   36509 auto result = detail::find_in_object(*this, dest->key());
HITCBC 229   36509 if(! result.first) 229   36509 if(! result.first)
230   { 230   {
HITCBC 231   36499 ++dest; 231   36499 ++dest;
HITCBC 232   36499 ++t_->size; 232   36499 ++t_->size;
HITCBC 233   36499 continue; 233   36499 continue;
234   } 234   }
235   // handle duplicate 235   // handle duplicate
HITCBC 236   10 auto& v = *result.first; 236   10 auto& v = *result.first;
237   // don't bother to check if 237   // don't bother to check if
238   // storage deallocate is trivial 238   // storage deallocate is trivial
HITCBC 239   10 v.~key_value_pair(); 239   10 v.~key_value_pair();
240   // trivial relocate 240   // trivial relocate
HITCBC 241   10 std::memcpy( 241   10 std::memcpy(
242   static_cast<void*>(&v), 242   static_cast<void*>(&v),
243   dest, sizeof(v)); 243   dest, sizeof(v));
244   } 244   }
HITCBC 245   33758 return; 245   33758 return;
246   } 246   }
HITCBC 247   1674 while(src != end) 247   1674 while(src != end)
248   { 248   {
HITCBC 249   1641 access::construct_key_value_pair( 249   1641 access::construct_key_value_pair(
HITCBC 250   1641 dest, pilfer(src[0]), pilfer(src[1])); 250   1641 dest, pilfer(src[0]), pilfer(src[1]));
HITCBC 251   1641 src += 2; 251   1641 src += 2;
HITCBC 252   1641 auto& head = t_->bucket(dest->key()); 252   1641 auto& head = t_->bucket(dest->key());
HITCBC 253   1641 auto i = head; 253   1641 auto i = head;
254   for(;;) 254   for(;;)
255   { 255   {
HITCBC 256   2471 if(i == null_index_) 256   2446 if(i == null_index_)
257   { 257   {
258   // end of bucket 258   // end of bucket
HITCBC 259   1640 access::next( 259   1640 access::next(
HITCBC 260   1640 *dest) = head; 260   1640 *dest) = head;
HITCBC 261   1640 head = static_cast<index_t>( 261   1640 head = static_cast<index_t>(
HITCBC 262   1640 dest - begin()); 262   1640 dest - begin());
HITCBC 263   1640 ++dest; 263   1640 ++dest;
HITCBC 264   1640 break; 264   1640 break;
265   } 265   }
HITCBC 266   831 auto& v = (*t_)[i]; 266   806 auto& v = (*t_)[i];
HITCBC 267   831 if(v.key() != dest->key()) 267   806 if(v.key() != dest->key())
268   { 268   {
HITCBC 269   830 i = access::next(v); 269   805 i = access::next(v);
HITCBC 270   830 continue; 270   805 continue;
271   } 271   }
272   272  
273   // handle duplicate 273   // handle duplicate
HITCBC 274   1 access::next(*dest) = 274   1 access::next(*dest) =
HITCBC 275   1 access::next(v); 275   1 access::next(v);
276   // don't bother to check if 276   // don't bother to check if
277   // storage deallocate is trivial 277   // storage deallocate is trivial
HITCBC 278   1 v.~key_value_pair(); 278   1 v.~key_value_pair();
279   // trivial relocate 279   // trivial relocate
HITCBC 280   1 std::memcpy( 280   1 std::memcpy(
281   static_cast<void*>(&v), 281   static_cast<void*>(&v),
282   dest, sizeof(v)); 282   dest, sizeof(v));
HITCBC 283   1 break; 283   1 break;
HITCBC 284   830 } 284   805 }
285   } 285   }
HITCBC 286   33 t_->size = static_cast< 286   33 t_->size = static_cast<
HITCBC 287   33 index_t>(dest - begin()); 287   33 index_t>(dest - begin());
HITCBC 288   39 } 288   39 }
289   289  
HITCBC 290   35946 object:: 290   35946 object::
HITCBC 291   34396 ~object() noexcept 291   34396 ~object() noexcept
292   { 292   {
HITCBC 293   35946 if(sp_.is_not_shared_and_deallocate_is_trivial()) 293   35946 if(sp_.is_not_shared_and_deallocate_is_trivial())
HITCBC 294   5 return; 294   5 return;
HITCBC 295   35941 if(t_->capacity == 0) 295   35941 if(t_->capacity == 0)
HITCBC 296   1545 return; 296   1545 return;
HITCBC 297   34396 destroy(); 297   34396 destroy();
HITCBC 298   35946 } 298   35946 }
299   299  
HITCBC 300   7 object:: 300   7 object::
301   object( 301   object(
302   std::size_t min_capacity, 302   std::size_t min_capacity,
HITCBC 303   7 storage_ptr sp) 303   7 storage_ptr sp)
HITCBC 304   7 : sp_(std::move(sp)) 304   7 : sp_(std::move(sp))
HITCBC 305   7 , t_(&empty_) 305   7 , t_(&empty_)
306   { 306   {
HITCBC 307   7 reserve(min_capacity); 307   7 reserve(min_capacity);
HITCBC 308   7 } 308   7 }
309   309  
HITCBC 310   71 object:: 310   71 object::
HITCBC 311   71 object(object&& other) noexcept 311   71 object(object&& other) noexcept
HITCBC 312   71 : sp_(other.sp_) 312   71 : sp_(other.sp_)
HITCBC 313   142 , t_(detail::exchange( 313   142 , t_(detail::exchange(
HITCBC 314   71 other.t_, &empty_)) 314   71 other.t_, &empty_))
315   { 315   {
HITCBC 316   71 } 316   71 }
317   317  
HITCBC 318   184 object:: 318   184 object::
319   object( 319   object(
320   object&& other, 320   object&& other,
HITCBC 321   184 storage_ptr sp) 321   184 storage_ptr sp)
HITCBC 322   184 : sp_(std::move(sp)) 322   184 : sp_(std::move(sp))
323   { 323   {
HITCBC 324   184 if(*sp_ == *other.sp_) 324   184 if(*sp_ == *other.sp_)
325   { 325   {
HITCBC 326   192 t_ = detail::exchange( 326   192 t_ = detail::exchange(
HITCBC 327   96 other.t_, &empty_); 327   96 other.t_, &empty_);
HITCBC 328   96 return; 328   96 return;
329   } 329   }
330   330  
HITCBC 331   88 t_ = &empty_; 331   88 t_ = &empty_;
HITCBC 332   151 object(other, sp_).swap(*this); 332   151 object(other, sp_).swap(*this);
HITCBC 333   63 } 333   63 }
334   334  
HITCBC 335   197 object:: 335   197 object::
336   object( 336   object(
337   object const& other, 337   object const& other,
HITCBC 338   197 storage_ptr sp) 338   197 storage_ptr sp)
HITCBC 339   197 : sp_(std::move(sp)) 339   197 : sp_(std::move(sp))
HITCBC 340   197 , t_(&empty_) 340   197 , t_(&empty_)
341   { 341   {
HITCBC 342   197 reserve(other.size()); 342   197 reserve(other.size());
HITCBC 343   185 revert_construct r(*this); 343   185 revert_construct r(*this);
HITCBC 344   185 if(t_->is_small()) 344   185 if(t_->is_small())
345   { 345   {
HITCBC 346   712 for(auto const& v : other) 346   712 for(auto const& v : other)
347   { 347   {
HITCBC 348   724 ::new(end()) 348   724 ::new(end())
HITCBC 349   800 key_value_pair(v, sp_); 349   800 key_value_pair(v, sp_);
HITCBC 350   572 ++t_->size; 350   572 ++t_->size;
351   } 351   }
HITCBC 352   64 r.commit(); 352   64 r.commit();
HITCBC 353   64 return; 353   64 return;
354   } 354   }
HITCBC 355   2485 for(auto const& v : other) 355   2485 for(auto const& v : other)
356   { 356   {
357   // skip duplicate checking 357   // skip duplicate checking
358   auto& head = 358   auto& head =
HITCBC 359   2480 t_->bucket(v.key()); 359   2480 t_->bucket(v.key());
HITCBC 360   2480 auto pv = ::new(end()) 360   2480 auto pv = ::new(end())
HITCBC 361   2520 key_value_pair(v, sp_); 361   2520 key_value_pair(v, sp_);
HITCBC 362   2440 access::next(*pv) = head; 362   2440 access::next(*pv) = head;
HITCBC 363   2440 head = t_->size; 363   2440 head = t_->size;
HITCBC 364   2440 ++t_->size; 364   2440 ++t_->size;
365   } 365   }
HITCBC 366   5 r.commit(); 366   5 r.commit();
HITCBC 367   313 } 367   313 }
368   368  
HITCBC 369   381 object:: 369   381 object::
370   object( 370   object(
371   std::initializer_list<std::pair< 371   std::initializer_list<std::pair<
372   string_view, value_ref>> init, 372   string_view, value_ref>> init,
373   std::size_t min_capacity, 373   std::size_t min_capacity,
HITCBC 374   381 storage_ptr sp) 374   381 storage_ptr sp)
HITCBC 375   381 : sp_(std::move(sp)) 375   381 : sp_(std::move(sp))
HITCBC 376   381 , t_(&empty_) 376   381 , t_(&empty_)
377   { 377   {
HITCBC 378   381 if( min_capacity < init.size()) 378   381 if( min_capacity < init.size())
HITCBC 379   335 min_capacity = init.size(); 379   335 min_capacity = init.size();
HITCBC 380   381 reserve(min_capacity); 380   381 reserve(min_capacity);
HITCBC 381   365 revert_construct r(*this); 381   365 revert_construct r(*this);
HITCBC 382   365 insert(init); 382   365 insert(init);
HITCBC 383   252 r.commit(); 383   252 r.commit();
HITCBC 384   494 } 384   494 }
385   385  
386   //---------------------------------------------------------- 386   //----------------------------------------------------------
387   // 387   //
388   // Assignment 388   // Assignment
389   // 389   //
390   //---------------------------------------------------------- 390   //----------------------------------------------------------
391   391  
392   object& 392   object&
HITCBC 393   22 object:: 393   22 object::
394   operator=(object const& other) 394   operator=(object const& other)
395   { 395   {
HITCBC 396   39 object tmp(other, sp_); 396   39 object tmp(other, sp_);
HITCBC 397   5 this->~object(); 397   5 this->~object();
HITCBC 398   5 ::new(this) object(pilfer(tmp)); 398   5 ::new(this) object(pilfer(tmp));
HITCBC 399   5 return *this; 399   5 return *this;
HITCBC 400   5 } 400   5 }
401   401  
402   object& 402   object&
HITCBC 403   7 object:: 403   7 object::
404   operator=(object&& other) 404   operator=(object&& other)
405   { 405   {
HITCBC 406   11 object tmp(std::move(other), sp_); 406   11 object tmp(std::move(other), sp_);
HITCBC 407   3 this->~object(); 407   3 this->~object();
HITCBC 408   3 ::new(this) object(pilfer(tmp)); 408   3 ::new(this) object(pilfer(tmp));
HITCBC 409   3 return *this; 409   3 return *this;
HITCBC 410   3 } 410   3 }
411   411  
412   object& 412   object&
HITCBC 413   7 object:: 413   7 object::
414   operator=( 414   operator=(
415   std::initializer_list<std::pair< 415   std::initializer_list<std::pair<
416   string_view, value_ref>> init) 416   string_view, value_ref>> init)
417   { 417   {
HITCBC 418   11 object tmp(init, sp_); 418   11 object tmp(init, sp_);
HITCBC 419   3 this->~object(); 419   3 this->~object();
HITCBC 420   3 ::new(this) object(pilfer(tmp)); 420   3 ::new(this) object(pilfer(tmp));
HITCBC 421   3 return *this; 421   3 return *this;
HITCBC 422   3 } 422   3 }
423   423  
424   //---------------------------------------------------------- 424   //----------------------------------------------------------
425   // 425   //
426   // Lookup 426   // Lookup
427   // 427   //
428   //---------------------------------------------------------- 428   //----------------------------------------------------------
429   429  
430   system::result<value&> 430   system::result<value&>
HITCBC 431   4 object:: 431   4 object::
432   try_at(string_view key) noexcept 432   try_at(string_view key) noexcept
433   { 433   {
HITCBC 434   4 auto it = find(key); 434   4 auto it = find(key);
HITCBC 435   4 if( it != end() ) 435   4 if( it != end() )
HITCBC 436   2 return it->value(); 436   2 return it->value();
437   437  
HITCBC 438   2 system::error_code ec; 438   2 system::error_code ec;
HITCBC 439   2 BOOST_JSON_FAIL(ec, error::out_of_range); 439   2 BOOST_JSON_FAIL(ec, error::out_of_range);
HITCBC 440   2 return ec; 440   2 return ec;
441   } 441   }
442   442  
443   system::result<value const&> 443   system::result<value const&>
HITCBC 444   108 object:: 444   108 object::
445   try_at(string_view key) const noexcept 445   try_at(string_view key) const noexcept
446   { 446   {
HITCBC 447   108 auto it = find(key); 447   108 auto it = find(key);
HITCBC 448   108 if( it != end() ) 448   108 if( it != end() )
HITCBC 449   102 return it->value(); 449   102 return it->value();
450   450  
HITCBC 451   6 system::error_code ec; 451   6 system::error_code ec;
HITCBC 452   6 BOOST_JSON_FAIL(ec, error::out_of_range); 452   6 BOOST_JSON_FAIL(ec, error::out_of_range);
HITCBC 453   6 return ec; 453   6 return ec;
454   } 454   }
455   455  
456   value const& 456   value const&
HITCBC 457   104 object:: 457   104 object::
458   at(string_view key, source_location const& loc) const& 458   at(string_view key, source_location const& loc) const&
459   { 459   {
HITCBC 460   104 return try_at(key).value(loc); 460   104 return try_at(key).value(loc);
461   } 461   }
462   462  
463   //---------------------------------------------------------- 463   //----------------------------------------------------------
464   // 464   //
465   // Modifiers 465   // Modifiers
466   // 466   //
467   //---------------------------------------------------------- 467   //----------------------------------------------------------
468   468  
469   void 469   void
HITCBC 470   7 object:: 470   7 object::
471   clear() noexcept 471   clear() noexcept
472   { 472   {
HITCBC 473   7 if(empty()) 473   7 if(empty())
HITCBC 474   2 return; 474   2 return;
HITCBC 475   5 if(! sp_.is_not_shared_and_deallocate_is_trivial()) 475   5 if(! sp_.is_not_shared_and_deallocate_is_trivial())
HITCBC 476   5 destroy(begin(), end()); 476   5 destroy(begin(), end());
HITCBC 477   5 if(! t_->is_small()) 477   5 if(! t_->is_small())
HITCBC 478   4 t_->clear(); 478   4 t_->clear();
HITCBC 479   5 t_->size = 0; 479   5 t_->size = 0;
480   } 480   }
481   481  
482   void 482   void
HITCBC 483   425 object:: 483   425 object::
484   insert( 484   insert(
485   std::initializer_list<std::pair< 485   std::initializer_list<std::pair<
486   string_view, value_ref>> init) 486   string_view, value_ref>> init)
487   { 487   {
HITCBC 488   425 auto const n0 = size(); 488   425 auto const n0 = size();
HITCBC 489   425 if(init.size() > max_size() - n0) 489   425 if(init.size() > max_size() - n0)
490   { 490   {
491   BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION; 491   BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
HITCBC 492   1 detail::throw_system_error( error::object_too_large, &loc ); 492   1 detail::throw_system_error( error::object_too_large, &loc );
493   } 493   }
HITCBC 494   424 revert_insert r( *this, n0 + init.size() ); 494   424 revert_insert r( *this, n0 + init.size() );
HITCBC 495   417 if(t_->is_small()) 495   417 if(t_->is_small())
496   { 496   {
HITCBC 497   2032 for(auto& iv : init) 497   2032 for(auto& iv : init)
498   { 498   {
499   auto result = 499   auto result =
HITCBC 500   1832 detail::find_in_object(*this, iv.first); 500   1832 detail::find_in_object(*this, iv.first);
HITCBC 501   1832 if(result.first) 501   1832 if(result.first)
502   { 502   {
503   // ignore duplicate 503   // ignore duplicate
HITCBC 504   4 continue; 504   4 continue;
505   } 505   }
HITCBC 506   1905 ::new(end()) key_value_pair( 506   1905 ::new(end()) key_value_pair(
507   iv.first, 507   iv.first,
HITCBC 508   2056 iv.second.make_value(sp_)); 508   2056 iv.second.make_value(sp_));
HITCBC 509   1751 ++t_->size; 509   1751 ++t_->size;
510   } 510   }
HITCBC 511   200 r.commit(); 511   200 r.commit();
HITCBC 512   200 return; 512   200 return;
513   } 513   }
HITCBC 514   1999 for(auto& iv : init) 514   1999 for(auto& iv : init)
515   { 515   {
HITCBC 516   1939 auto& head = t_->bucket(iv.first); 516   1939 auto& head = t_->bucket(iv.first);
HITCBC 517   1939 auto i = head; 517   1939 auto i = head;
518   for(;;) 518   for(;;)
519   { 519   {
HITCBC 520   2914 if(i == null_index_) 520   2598 if(i == null_index_)
521   { 521   {
522   // VFALCO value_ref should construct 522   // VFALCO value_ref should construct
523   // a key_value_pair using placement 523   // a key_value_pair using placement
HITCBC 524   1937 auto& v = *::new(end()) 524   1937 auto& v = *::new(end())
525   key_value_pair( 525   key_value_pair(
526   iv.first, 526   iv.first,
HITCBC 527   2097 iv.second.make_value(sp_)); 527   2097 iv.second.make_value(sp_));
HITCBC 528   1857 access::next(v) = head; 528   1857 access::next(v) = head;
HITCBC 529   1857 head = static_cast<index_t>( 529   1857 head = static_cast<index_t>(
HITCBC 530   1857 t_->size); 530   1857 t_->size);
HITCBC 531   1857 ++t_->size; 531   1857 ++t_->size;
HITCBC 532   1857 break; 532   1857 break;
533   } 533   }
HITCBC 534   977 auto& v = (*t_)[i]; 534   661 auto& v = (*t_)[i];
HITCBC 535   977 if(v.key() == iv.first) 535   661 if(v.key() == iv.first)
536   { 536   {
537   // ignore duplicate 537   // ignore duplicate
HITCBC 538   2 break; 538   2 break;
539   } 539   }
HITCBC 540   975 i = access::next(v); 540   659 i = access::next(v);
HITCBC 541   975 } 541   659 }
542   } 542   }
HITCBC 543   60 r.commit(); 543   60 r.commit();
HITCBC 544   417 } 544   417 }
545   545  
546   auto 546   auto
HITCBC 547   6 object:: 547   6 object::
548   erase(const_iterator pos) noexcept -> 548   erase(const_iterator pos) noexcept ->
549   iterator 549   iterator
550   { 550   {
HITCBC 551   6 return do_erase(pos, 551   6 return do_erase(pos,
HITCBC 552   2 [this](iterator p) { 552   2 [this](iterator p) {
553   // the casts silence warnings 553   // the casts silence warnings
HITCBC 554   2 std::memcpy( 554   2 std::memcpy(
555   static_cast<void*>(p), 555   static_cast<void*>(p),
HITCBC 556   2 static_cast<void const*>(end()), 556   2 static_cast<void const*>(end()),
557   sizeof(*p)); 557   sizeof(*p));
HITCBC 558   2 }, 558   2 },
HITCBC 559   3 [this](iterator p) { 559   3 [this](iterator p) {
HITCBC 560   3 reindex_relocate(end(), p); 560   3 reindex_relocate(end(), p);
HITCBC 561   6 }); 561   6 });
562   } 562   }
563   563  
564   auto 564   auto
HITCBC 565   5 object:: 565   5 object::
566   erase(string_view key) noexcept -> 566   erase(string_view key) noexcept ->
567   std::size_t 567   std::size_t
568   { 568   {
HITCBC 569   5 auto it = find(key); 569   5 auto it = find(key);
HITCBC 570   5 if(it == end()) 570   5 if(it == end())
HITCBC 571   1 return 0; 571   1 return 0;
HITCBC 572   4 erase(it); 572   4 erase(it);
HITCBC 573   4 return 1; 573   4 return 1;
574   } 574   }
575   575  
576   auto 576   auto
HITCBC 577   3 object:: 577   3 object::
578   stable_erase(const_iterator pos) noexcept -> 578   stable_erase(const_iterator pos) noexcept ->
579   iterator 579   iterator
580   { 580   {
HITCBC 581   3 return do_erase(pos, 581   3 return do_erase(pos,
HITCBC 582   2 [this](iterator p) { 582   2 [this](iterator p) {
583   // the casts silence warnings 583   // the casts silence warnings
HITCBC 584   2 std::memmove( 584   2 std::memmove(
585   static_cast<void*>(p), 585   static_cast<void*>(p),
HITCBC 586   2 static_cast<void const*>(p + 1), 586   2 static_cast<void const*>(p + 1),
HITCBC 587   2 sizeof(*p) * (end() - p)); 587   2 sizeof(*p) * (end() - p));
HITCBC 588   2 }, 588   2 },
HITCBC 589   1 [this](iterator p) { 589   1 [this](iterator p) {
HITCBC 590   10 for (; p != end(); ++p) 590   10 for (; p != end(); ++p)
591   { 591   {
HITCBC 592   9 reindex_relocate(p + 1, p); 592   9 reindex_relocate(p + 1, p);
593   } 593   }
HITCBC 594   3 }); 594   3 });
595   } 595   }
596   596  
597   auto 597   auto
HITCBC 598   2 object:: 598   2 object::
599   stable_erase(string_view key) noexcept -> 599   stable_erase(string_view key) noexcept ->
600   std::size_t 600   std::size_t
601   { 601   {
HITCBC 602   2 auto it = find(key); 602   2 auto it = find(key);
HITCBC 603   2 if(it == end()) 603   2 if(it == end())
HITCBC 604   1 return 0; 604   1 return 0;
HITCBC 605   1 stable_erase(it); 605   1 stable_erase(it);
HITCBC 606   1 return 1; 606   1 return 1;
607   } 607   }
608   608  
609   void 609   void
HITCBC 610   36 object:: 610   36 object::
611   swap(object& other) 611   swap(object& other)
612   { 612   {
HITCBC 613   36 if(*sp_ == *other.sp_) 613   36 if(*sp_ == *other.sp_)
614   { 614   {
HITCBC 615   52 t_ = detail::exchange( 615   52 t_ = detail::exchange(
HITCBC 616   26 other.t_, t_); 616   26 other.t_, t_);
HITCBC 617   26 return; 617   26 return;
618   } 618   }
619   object temp1( 619   object temp1(
HITCBC 620   10 std::move(*this), 620   10 std::move(*this),
HITCBC 621   24 other.storage()); 621   24 other.storage());
622   object temp2( 622   object temp2(
HITCBC 623   6 std::move(other), 623   6 std::move(other),
HITCBC 624   16 this->storage()); 624   16 this->storage());
HITCBC 625   2 other.~object(); 625   2 other.~object();
HITCBC 626   2 ::new(&other) object(pilfer(temp1)); 626   2 ::new(&other) object(pilfer(temp1));
HITCBC 627   2 this->~object(); 627   2 this->~object();
HITCBC 628   2 ::new(this) object(pilfer(temp2)); 628   2 ::new(this) object(pilfer(temp2));
HITCBC 629   6 } 629   6 }
630   630  
631   //---------------------------------------------------------- 631   //----------------------------------------------------------
632   // 632   //
633   // Lookup 633   // Lookup
634   // 634   //
635   //---------------------------------------------------------- 635   //----------------------------------------------------------
636   636  
637   auto 637   auto
HITCBC 638   146 object:: 638   146 object::
639   operator[](string_view key) -> 639   operator[](string_view key) ->
640   value& 640   value&
641   { 641   {
642   auto const result = 642   auto const result =
HITCBC 643   146 emplace(key, nullptr); 643   146 emplace(key, nullptr);
HITCBC 644   292 return result.first->value(); 644   292 return result.first->value();
645   } 645   }
646   646  
647   auto 647   auto
HITCBC 648   8 object:: 648   8 object::
649   count(string_view key) const noexcept -> 649   count(string_view key) const noexcept ->
650   std::size_t 650   std::size_t
651   { 651   {
HITCBC 652   8 if(find(key) == end()) 652   8 if(find(key) == end())
HITCBC 653   3 return 0; 653   3 return 0;
HITCBC 654   5 return 1; 654   5 return 1;
655   } 655   }
656   656  
657   auto 657   auto
HITCBC 658   27 object:: 658   27 object::
659   find(string_view key) noexcept -> 659   find(string_view key) noexcept ->
660   iterator 660   iterator
661   { 661   {
HITCBC 662   27 if(empty()) 662   27 if(empty())
HITCBC 663   1 return end(); 663   1 return end();
664   auto const p = 664   auto const p =
HITCBC 665   26 detail::find_in_object(*this, key).first; 665   26 detail::find_in_object(*this, key).first;
HITCBC 666   26 if(p) 666   26 if(p)
HITCBC 667   20 return p; 667   20 return p;
HITCBC 668   6 return end(); 668   6 return end();
669   } 669   }
670   670  
671   auto 671   auto
HITCBC 672   879 object:: 672   879 object::
673   find(string_view key) const noexcept -> 673   find(string_view key) const noexcept ->
674   const_iterator 674   const_iterator
675   { 675   {
HITCBC 676   879 if(empty()) 676   879 if(empty())
HITCBC 677   1 return end(); 677   1 return end();
678   auto const p = 678   auto const p =
HITCBC 679   878 detail::find_in_object(*this, key).first; 679   878 detail::find_in_object(*this, key).first;
HITCBC 680   878 if(p) 680   878 if(p)
HITCBC 681   866 return p; 681   866 return p;
HITCBC 682   12 return end(); 682   12 return end();
683   } 683   }
684   684  
685   bool 685   bool
HITCBC 686   3 object:: 686   3 object::
687   contains( 687   contains(
688   string_view key) const noexcept 688   string_view key) const noexcept
689   { 689   {
HITCBC 690   3 if(empty()) 690   3 if(empty())
HITCBC 691   1 return false; 691   1 return false;
HITCBC 692   2 return detail::find_in_object(*this, key).first 692   2 return detail::find_in_object(*this, key).first
HITCBC 693   2 != nullptr; 693   2 != nullptr;
694   } 694   }
695   695  
696   value const* 696   value const*
HITCBC 697   3 object:: 697   3 object::
698   if_contains( 698   if_contains(
699   string_view key) const noexcept 699   string_view key) const noexcept
700   { 700   {
HITCBC 701   3 auto const it = find(key); 701   3 auto const it = find(key);
HITCBC 702   3 if(it != end()) 702   3 if(it != end())
HITCBC 703   2 return &it->value(); 703   2 return &it->value();
HITCBC 704   1 return nullptr; 704   1 return nullptr;
705   } 705   }
706   706  
707   value* 707   value*
HITCBC 708   5 object:: 708   5 object::
709   if_contains( 709   if_contains(
710   string_view key) noexcept 710   string_view key) noexcept
711   { 711   {
HITCBC 712   5 auto const it = find(key); 712   5 auto const it = find(key);
HITCBC 713   5 if(it != end()) 713   5 if(it != end())
HITCBC 714   4 return &it->value(); 714   4 return &it->value();
HITCBC 715   1 return nullptr; 715   1 return nullptr;
716   } 716   }
717   717  
718   //---------------------------------------------------------- 718   //----------------------------------------------------------
719   // 719   //
720   // (private) 720   // (private)
721   // 721   //
722   //---------------------------------------------------------- 722   //----------------------------------------------------------
723   723  
724   key_value_pair* 724   key_value_pair*
HITCBC 725   3781 object:: 725   3781 object::
726   insert_impl( 726   insert_impl(
727   pilfered<key_value_pair> p, 727   pilfered<key_value_pair> p,
728   std::size_t hash) 728   std::size_t hash)
729   { 729   {
HITCBC 730   3781 BOOST_ASSERT( 730   3781 BOOST_ASSERT(
731   capacity() > size()); 731   capacity() > size());
HITCBC 732   3781 if(t_->is_small()) 732   3781 if(t_->is_small())
733   { 733   {
HITCBC 734   2194 auto const pv = ::new(end()) 734   2194 auto const pv = ::new(end())
HITCBC 735   2194 key_value_pair(p); 735   2194 key_value_pair(p);
HITCBC 736   2194 ++t_->size; 736   2194 ++t_->size;
HITCBC 737   2194 return pv; 737   2194 return pv;
738   } 738   }
739   auto& head = 739   auto& head =
HITCBC 740   1587 t_->bucket(hash); 740   1587 t_->bucket(hash);
HITCBC 741   1587 auto const pv = ::new(end()) 741   1587 auto const pv = ::new(end())
HITCBC 742   1587 key_value_pair(p); 742   1587 key_value_pair(p);
HITCBC 743   1587 access::next(*pv) = head; 743   1587 access::next(*pv) = head;
HITCBC 744   1587 head = t_->size; 744   1587 head = t_->size;
HITCBC 745   1587 ++t_->size; 745   1587 ++t_->size;
HITCBC 746   1587 return pv; 746   1587 return pv;
747   } 747   }
748   748  
749   // allocate new table, copy elements there, and rehash them 749   // allocate new table, copy elements there, and rehash them
750   object::table* 750   object::table*
HITCBC 751   1656 object:: 751   1656 object::
752   reserve_impl(std::size_t new_capacity) 752   reserve_impl(std::size_t new_capacity)
753   { 753   {
HITCBC 754   1656 BOOST_ASSERT( 754   1656 BOOST_ASSERT(
755   new_capacity > t_->capacity); 755   new_capacity > t_->capacity);
HITCBC 756   1649 auto t = table::allocate( 756   1649 auto t = table::allocate(
757   growth(new_capacity), 757   growth(new_capacity),
HITCBC 758   1656 t_->salt, sp_); 758   1656 t_->salt, sp_);
HITCBC 759   1582 if(! empty()) 759   1582 if(! empty())
HITCBC 760   488 std::memcpy( 760   488 std::memcpy(
761   static_cast< 761   static_cast<
HITCBC 762   488 void*>(&(*t)[0]), 762   488 void*>(&(*t)[0]),
HITCBC 763   488 begin(), 763   488 begin(),
HITCBC 764   488 size() * sizeof( 764   488 size() * sizeof(
765   key_value_pair)); 765   key_value_pair));
HITCBC 766   1582 t->size = t_->size; 766   1582 t->size = t_->size;
HITCBC 767   1582 std::swap(t_, t); 767   1582 std::swap(t_, t);
768   768  
HITCBC 769   1582 if(! t_->is_small()) 769   1582 if(! t_->is_small())
770   { 770   {
771   // rebuild hash table, 771   // rebuild hash table,
772   // without dup checks 772   // without dup checks
HITCBC 773   355 auto p = end(); 773   355 auto p = end();
HITCBC 774   355 index_t i = t_->size; 774   355 index_t i = t_->size;
HITCBC 775   1360 while(i-- > 0) 775   1360 while(i-- > 0)
776   { 776   {
HITCBC 777   1005 --p; 777   1005 --p;
778   auto& head = 778   auto& head =
HITCBC 779   1005 t_->bucket(p->key()); 779   1005 t_->bucket(p->key());
HITCBC 780   1005 access::next(*p) = head; 780   1005 access::next(*p) = head;
HITCBC 781   1005 head = i; 781   1005 head = i;
782   } 782   }
783   } 783   }
784   784  
HITCBC 785   1582 return t; 785   1582 return t;
786   } 786   }
787   787  
788   bool 788   bool
HITCBC 789   75 object:: 789   75 object::
790   equal(object const& other) const noexcept 790   equal(object const& other) const noexcept
791   { 791   {
HITCBC 792   75 if(size() != other.size()) 792   75 if(size() != other.size())
HITCBC 793   5 return false; 793   5 return false;
HITCBC 794   70 auto const end_ = other.end(); 794   70 auto const end_ = other.end();
HITCBC 795   825 for(auto e : *this) 795   825 for(auto e : *this)
796   { 796   {
HITCBC 797   757 auto it = other.find(e.key()); 797   757 auto it = other.find(e.key());
HITCBC 798   757 if(it == end_) 798   757 if(it == end_)
HITCBC 799   1 return false; 799   1 return false;
HITCBC 800   756 if(it->value() != e.value()) 800   756 if(it->value() != e.value())
HITCBC 801   1 return false; 801   1 return false;
HITCBC 802   757 } 802   757 }
HITCBC 803   68 return true; 803   68 return true;
804   } 804   }
805   805  
806   std::size_t 806   std::size_t
HITCBC 807   1656 object:: 807   1656 object::
808   growth( 808   growth(
809   std::size_t new_size) const 809   std::size_t new_size) const
810   { 810   {
HITCBC 811   1656 if(new_size > max_size()) 811   1656 if(new_size > max_size())
812   { 812   {
813   BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION; 813   BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
HITCBC 814   7 detail::throw_system_error( error::object_too_large, &loc ); 814   7 detail::throw_system_error( error::object_too_large, &loc );
815   } 815   }
HITCBC 816   1649 std::size_t const old = capacity(); 816   1649 std::size_t const old = capacity();
HITCBC 817   1649 if(old > max_size() - old / 2) 817   1649 if(old > max_size() - old / 2)
HITCBC 818   2 return new_size; 818   2 return new_size;
HITCBC 819   1647 std::size_t const g = 819   1647 std::size_t const g =
HITCBC 820   1647 old + old / 2; // 1.5x 820   1647 old + old / 2; // 1.5x
HITCBC 821   1647 if(g < new_size) 821   1647 if(g < new_size)
HITCBC 822   1245 return new_size; 822   1245 return new_size;
HITCBC 823   402 return g; 823   402 return g;
824   } 824   }
825   825  
826   void 826   void
HITCBC 827   17 object:: 827   17 object::
828   remove( 828   remove(
829   index_t& head, 829   index_t& head,
830   key_value_pair& v) noexcept 830   key_value_pair& v) noexcept
831   { 831   {
HITCBC 832   17 BOOST_ASSERT(! t_->is_small()); 832   17 BOOST_ASSERT(! t_->is_small());
833   auto const i = static_cast< 833   auto const i = static_cast<
HITCBC 834   17 index_t>(&v - begin()); 834   17 index_t>(&v - begin());
HITCBC 835   17 if(head == i) 835   17 if(head == i)
836   { 836   {
HITCBC 837   11 head = access::next(v); 837   11 head = access::next(v);
HITCBC 838   11 return; 838   11 return;
839   } 839   }
840   auto* pn = 840   auto* pn =
HITCBC 841   6 &access::next((*t_)[head]); 841   6 &access::next((*t_)[head]);
HITCBC 842   7 while(*pn != i) 842   7 while(*pn != i)
HITCBC 843   1 pn = &access::next((*t_)[*pn]); 843   1 pn = &access::next((*t_)[*pn]);
HITCBC 844   6 *pn = access::next(v); 844   6 *pn = access::next(v);
845   } 845   }
846   846  
847   void 847   void
HITCBC 848   34770 object:: 848   34770 object::
849   destroy() noexcept 849   destroy() noexcept
850   { 850   {
HITCBC 851   34770 BOOST_ASSERT(t_->capacity > 0); 851   34770 BOOST_ASSERT(t_->capacity > 0);
HITCBC 852   34770 BOOST_ASSERT(! sp_.is_not_shared_and_deallocate_is_trivial()); 852   34770 BOOST_ASSERT(! sp_.is_not_shared_and_deallocate_is_trivial());
HITCBC 853   34770 destroy(begin(), end()); 853   34770 destroy(begin(), end());
HITCBC 854   34770 table::deallocate(t_, sp_); 854   34770 table::deallocate(t_, sp_);
HITCBC 855   34770 } 855   34770 }
856   856  
857   void 857   void
HITCBC 858   35005 object:: 858   35005 object::
859   destroy( 859   destroy(
860   key_value_pair* first, 860   key_value_pair* first,
861   key_value_pair* last) noexcept 861   key_value_pair* last) noexcept
862   { 862   {
HITCBC 863   35005 BOOST_ASSERT(! sp_.is_not_shared_and_deallocate_is_trivial()); 863   35005 BOOST_ASSERT(! sp_.is_not_shared_and_deallocate_is_trivial());
HITCBC 864   83514 while(last != first) 864   83514 while(last != first)
HITCBC 865   48509 (--last)->~key_value_pair(); 865   48509 (--last)->~key_value_pair();
HITCBC 866   35005 } 866   35005 }
867   867  
868   template<class FS, class FB> 868   template<class FS, class FB>
869   auto 869   auto
HITCBC 870   9 object:: 870   9 object::
871   do_erase( 871   do_erase(
872   const_iterator pos, 872   const_iterator pos,
873   FS small_reloc, 873   FS small_reloc,
874   FB big_reloc) noexcept 874   FB big_reloc) noexcept
875   -> iterator 875   -> iterator
876   { 876   {
HITCBC 877   9 auto p = begin() + (pos - begin()); 877   9 auto p = begin() + (pos - begin());
HITCBC 878   9 if(t_->is_small()) 878   9 if(t_->is_small())
879   { 879   {
HITCBC 880   4 p->~value_type(); 880   4 p->~value_type();
HITCBC 881   4 --t_->size; 881   4 --t_->size;
HITCBC 882   4 if(p != end()) 882   4 if(p != end())
883   { 883   {
HITCBC 884   4 small_reloc(p); 884   4 small_reloc(p);
885   } 885   }
HITCBC 886   4 return p; 886   4 return p;
887   } 887   }
HITCBC 888   5 remove(t_->bucket(p->key()), *p); 888   5 remove(t_->bucket(p->key()), *p);
HITCBC 889   5 p->~value_type(); 889   5 p->~value_type();
HITCBC 890   5 --t_->size; 890   5 --t_->size;
HITCBC 891   5 if(p != end()) 891   5 if(p != end())
892   { 892   {
HITCBC 893   4 big_reloc(p); 893   4 big_reloc(p);
894   } 894   }
HITCBC 895   5 return p; 895   5 return p;
896   } 896   }
897   897  
898   void 898   void
HITCBC 899   12 object:: 899   12 object::
900   reindex_relocate( 900   reindex_relocate(
901   key_value_pair* src, 901   key_value_pair* src,
902   key_value_pair* dst) noexcept 902   key_value_pair* dst) noexcept
903   { 903   {
HITCBC 904   12 BOOST_ASSERT(! t_->is_small()); 904   12 BOOST_ASSERT(! t_->is_small());
HITCBC 905   12 auto& head = t_->bucket(src->key()); 905   12 auto& head = t_->bucket(src->key());
HITCBC 906   12 remove(head, *src); 906   12 remove(head, *src);
907   // the casts silence warnings 907   // the casts silence warnings
HITCBC 908   12 std::memcpy( 908   12 std::memcpy(
909   static_cast<void*>(dst), 909   static_cast<void*>(dst),
910   static_cast<void const*>(src), 910   static_cast<void const*>(src),
911   sizeof(*dst)); 911   sizeof(*dst));
HITCBC 912   12 access::next(*dst) = head; 912   12 access::next(*dst) = head;
HITCBC 913   12 head = static_cast< 913   12 head = static_cast<
HITCBC 914   12 index_t>(dst - begin()); 914   12 index_t>(dst - begin());
HITCBC 915   12 } 915   12 }
916   916  
917   } // namespace json 917   } // namespace json
918   } // namespace boost 918   } // namespace boost
919   919  
920   //---------------------------------------------------------- 920   //----------------------------------------------------------
921   // 921   //
922   // std::hash specialization 922   // std::hash specialization
923   // 923   //
924   //---------------------------------------------------------- 924   //----------------------------------------------------------
925   925  
926   std::size_t 926   std::size_t
HITCBC 927   8 std::hash<::boost::json::object>::operator()( 927   8 std::hash<::boost::json::object>::operator()(
928   ::boost::json::object const& jo) const noexcept 928   ::boost::json::object const& jo) const noexcept
929   { 929   {
HITCBC 930   8 return ::boost::hash< ::boost::json::object >()( jo ); 930   8 return ::boost::hash< ::boost::json::object >()( jo );
931   } 931   }
932   932  
933   //---------------------------------------------------------- 933   //----------------------------------------------------------
934   934  
935   935  
936   #endif 936   #endif