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