Chris@16
|
1
|
Chris@16
|
2 // Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
Chris@16
|
3 // Copyright (C) 2005-2011 Daniel James
|
Chris@16
|
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
|
Chris@16
|
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
6
|
Chris@16
|
7 #ifndef BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED
|
Chris@16
|
8 #define BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED
|
Chris@16
|
9
|
Chris@101
|
10 #include <boost/config.hpp>
|
Chris@101
|
11 #if defined(BOOST_HAS_PRAGMA_ONCE)
|
Chris@101
|
12 #pragma once
|
Chris@16
|
13 #endif
|
Chris@16
|
14
|
Chris@16
|
15 #include <boost/unordered/detail/table.hpp>
|
Chris@16
|
16 #include <boost/unordered/detail/extract_key.hpp>
|
Chris@16
|
17
|
Chris@16
|
18 namespace boost { namespace unordered { namespace detail {
|
Chris@16
|
19
|
Chris@16
|
20 template <typename A, typename T> struct grouped_node;
|
Chris@16
|
21 template <typename T> struct grouped_ptr_node;
|
Chris@16
|
22 template <typename Types> struct grouped_table_impl;
|
Chris@16
|
23
|
Chris@16
|
24 template <typename A, typename T>
|
Chris@16
|
25 struct grouped_node :
|
Chris@16
|
26 boost::unordered::detail::value_base<T>
|
Chris@16
|
27 {
|
Chris@16
|
28 typedef typename ::boost::unordered::detail::rebind_wrap<
|
Chris@16
|
29 A, grouped_node<A, T> >::type allocator;
|
Chris@16
|
30 typedef typename ::boost::unordered::detail::
|
Chris@16
|
31 allocator_traits<allocator>::pointer node_pointer;
|
Chris@16
|
32 typedef node_pointer link_pointer;
|
Chris@16
|
33
|
Chris@16
|
34 link_pointer next_;
|
Chris@16
|
35 node_pointer group_prev_;
|
Chris@16
|
36 std::size_t hash_;
|
Chris@16
|
37
|
Chris@16
|
38 grouped_node() :
|
Chris@16
|
39 next_(),
|
Chris@16
|
40 group_prev_(),
|
Chris@16
|
41 hash_(0)
|
Chris@16
|
42 {}
|
Chris@16
|
43
|
Chris@16
|
44 void init(node_pointer self)
|
Chris@16
|
45 {
|
Chris@16
|
46 group_prev_ = self;
|
Chris@16
|
47 }
|
Chris@16
|
48
|
Chris@16
|
49 private:
|
Chris@16
|
50 grouped_node& operator=(grouped_node const&);
|
Chris@16
|
51 };
|
Chris@16
|
52
|
Chris@16
|
53 template <typename T>
|
Chris@16
|
54 struct grouped_ptr_node :
|
Chris@16
|
55 boost::unordered::detail::ptr_bucket
|
Chris@16
|
56 {
|
Chris@101
|
57 typedef T value_type;
|
Chris@16
|
58 typedef boost::unordered::detail::ptr_bucket bucket_base;
|
Chris@16
|
59 typedef grouped_ptr_node<T>* node_pointer;
|
Chris@16
|
60 typedef ptr_bucket* link_pointer;
|
Chris@16
|
61
|
Chris@16
|
62 node_pointer group_prev_;
|
Chris@16
|
63 std::size_t hash_;
|
Chris@101
|
64 boost::unordered::detail::value_base<T> value_base_;
|
Chris@16
|
65
|
Chris@16
|
66 grouped_ptr_node() :
|
Chris@16
|
67 bucket_base(),
|
Chris@16
|
68 group_prev_(0),
|
Chris@16
|
69 hash_(0)
|
Chris@16
|
70 {}
|
Chris@16
|
71
|
Chris@16
|
72 void init(node_pointer self)
|
Chris@16
|
73 {
|
Chris@16
|
74 group_prev_ = self;
|
Chris@16
|
75 }
|
Chris@16
|
76
|
Chris@101
|
77 void* address() { return value_base_.address(); }
|
Chris@101
|
78 value_type& value() { return value_base_.value(); }
|
Chris@101
|
79 value_type* value_ptr() { return value_base_.value_ptr(); }
|
Chris@101
|
80
|
Chris@16
|
81 private:
|
Chris@16
|
82 grouped_ptr_node& operator=(grouped_ptr_node const&);
|
Chris@16
|
83 };
|
Chris@16
|
84
|
Chris@16
|
85 // If the allocator uses raw pointers use grouped_ptr_node
|
Chris@16
|
86 // Otherwise use grouped_node.
|
Chris@16
|
87
|
Chris@16
|
88 template <typename A, typename T, typename NodePtr, typename BucketPtr>
|
Chris@16
|
89 struct pick_grouped_node2
|
Chris@16
|
90 {
|
Chris@16
|
91 typedef boost::unordered::detail::grouped_node<A, T> node;
|
Chris@16
|
92
|
Chris@16
|
93 typedef typename boost::unordered::detail::allocator_traits<
|
Chris@16
|
94 typename boost::unordered::detail::rebind_wrap<A, node>::type
|
Chris@16
|
95 >::pointer node_pointer;
|
Chris@16
|
96
|
Chris@16
|
97 typedef boost::unordered::detail::bucket<node_pointer> bucket;
|
Chris@16
|
98 typedef node_pointer link_pointer;
|
Chris@16
|
99 };
|
Chris@16
|
100
|
Chris@16
|
101 template <typename A, typename T>
|
Chris@16
|
102 struct pick_grouped_node2<A, T,
|
Chris@16
|
103 boost::unordered::detail::grouped_ptr_node<T>*,
|
Chris@16
|
104 boost::unordered::detail::ptr_bucket*>
|
Chris@16
|
105 {
|
Chris@16
|
106 typedef boost::unordered::detail::grouped_ptr_node<T> node;
|
Chris@16
|
107 typedef boost::unordered::detail::ptr_bucket bucket;
|
Chris@16
|
108 typedef bucket* link_pointer;
|
Chris@16
|
109 };
|
Chris@16
|
110
|
Chris@16
|
111 template <typename A, typename T>
|
Chris@16
|
112 struct pick_grouped_node
|
Chris@16
|
113 {
|
Chris@16
|
114 typedef boost::unordered::detail::allocator_traits<
|
Chris@16
|
115 typename boost::unordered::detail::rebind_wrap<A,
|
Chris@16
|
116 boost::unordered::detail::grouped_ptr_node<T> >::type
|
Chris@16
|
117 > tentative_node_traits;
|
Chris@16
|
118
|
Chris@16
|
119 typedef boost::unordered::detail::allocator_traits<
|
Chris@16
|
120 typename boost::unordered::detail::rebind_wrap<A,
|
Chris@16
|
121 boost::unordered::detail::ptr_bucket >::type
|
Chris@16
|
122 > tentative_bucket_traits;
|
Chris@16
|
123
|
Chris@16
|
124 typedef pick_grouped_node2<A, T,
|
Chris@16
|
125 typename tentative_node_traits::pointer,
|
Chris@16
|
126 typename tentative_bucket_traits::pointer> pick;
|
Chris@16
|
127
|
Chris@16
|
128 typedef typename pick::node node;
|
Chris@16
|
129 typedef typename pick::bucket bucket;
|
Chris@16
|
130 typedef typename pick::link_pointer link_pointer;
|
Chris@16
|
131 };
|
Chris@16
|
132
|
Chris@16
|
133 template <typename A, typename T, typename H, typename P>
|
Chris@16
|
134 struct multiset
|
Chris@16
|
135 {
|
Chris@16
|
136 typedef boost::unordered::detail::multiset<A, T, H, P> types;
|
Chris@16
|
137
|
Chris@16
|
138 typedef A allocator;
|
Chris@16
|
139 typedef T value_type;
|
Chris@16
|
140 typedef H hasher;
|
Chris@16
|
141 typedef P key_equal;
|
Chris@16
|
142 typedef T key_type;
|
Chris@16
|
143
|
Chris@16
|
144 typedef boost::unordered::detail::allocator_traits<allocator> traits;
|
Chris@16
|
145 typedef boost::unordered::detail::pick_grouped_node<allocator,
|
Chris@16
|
146 value_type> pick;
|
Chris@16
|
147 typedef typename pick::node node;
|
Chris@16
|
148 typedef typename pick::bucket bucket;
|
Chris@16
|
149 typedef typename pick::link_pointer link_pointer;
|
Chris@16
|
150
|
Chris@16
|
151 typedef boost::unordered::detail::grouped_table_impl<types> table;
|
Chris@16
|
152 typedef boost::unordered::detail::set_extractor<value_type> extractor;
|
Chris@16
|
153
|
Chris@101
|
154 typedef typename boost::unordered::detail::pick_policy<T>::type policy;
|
Chris@16
|
155 };
|
Chris@16
|
156
|
Chris@16
|
157 template <typename A, typename K, typename M, typename H, typename P>
|
Chris@16
|
158 struct multimap
|
Chris@16
|
159 {
|
Chris@16
|
160 typedef boost::unordered::detail::multimap<A, K, M, H, P> types;
|
Chris@16
|
161
|
Chris@16
|
162 typedef A allocator;
|
Chris@16
|
163 typedef std::pair<K const, M> value_type;
|
Chris@16
|
164 typedef H hasher;
|
Chris@16
|
165 typedef P key_equal;
|
Chris@16
|
166 typedef K key_type;
|
Chris@16
|
167
|
Chris@16
|
168 typedef boost::unordered::detail::allocator_traits<allocator> traits;
|
Chris@16
|
169 typedef boost::unordered::detail::pick_grouped_node<allocator,
|
Chris@16
|
170 value_type> pick;
|
Chris@16
|
171 typedef typename pick::node node;
|
Chris@16
|
172 typedef typename pick::bucket bucket;
|
Chris@16
|
173 typedef typename pick::link_pointer link_pointer;
|
Chris@16
|
174
|
Chris@16
|
175 typedef boost::unordered::detail::grouped_table_impl<types> table;
|
Chris@16
|
176 typedef boost::unordered::detail::map_extractor<key_type, value_type>
|
Chris@16
|
177 extractor;
|
Chris@16
|
178
|
Chris@101
|
179 typedef typename boost::unordered::detail::pick_policy<K>::type policy;
|
Chris@16
|
180 };
|
Chris@16
|
181
|
Chris@16
|
182 template <typename Types>
|
Chris@16
|
183 struct grouped_table_impl : boost::unordered::detail::table<Types>
|
Chris@16
|
184 {
|
Chris@16
|
185 typedef boost::unordered::detail::table<Types> table;
|
Chris@16
|
186 typedef typename table::value_type value_type;
|
Chris@16
|
187 typedef typename table::bucket bucket;
|
Chris@16
|
188 typedef typename table::policy policy;
|
Chris@16
|
189 typedef typename table::node_pointer node_pointer;
|
Chris@16
|
190 typedef typename table::node_allocator node_allocator;
|
Chris@16
|
191 typedef typename table::node_allocator_traits node_allocator_traits;
|
Chris@16
|
192 typedef typename table::bucket_pointer bucket_pointer;
|
Chris@16
|
193 typedef typename table::link_pointer link_pointer;
|
Chris@16
|
194 typedef typename table::hasher hasher;
|
Chris@16
|
195 typedef typename table::key_equal key_equal;
|
Chris@16
|
196 typedef typename table::key_type key_type;
|
Chris@16
|
197 typedef typename table::node_constructor node_constructor;
|
Chris@16
|
198 typedef typename table::extractor extractor;
|
Chris@16
|
199 typedef typename table::iterator iterator;
|
Chris@16
|
200 typedef typename table::c_iterator c_iterator;
|
Chris@16
|
201
|
Chris@16
|
202 // Constructors
|
Chris@16
|
203
|
Chris@16
|
204 grouped_table_impl(std::size_t n,
|
Chris@16
|
205 hasher const& hf,
|
Chris@16
|
206 key_equal const& eq,
|
Chris@16
|
207 node_allocator const& a)
|
Chris@16
|
208 : table(n, hf, eq, a)
|
Chris@16
|
209 {}
|
Chris@16
|
210
|
Chris@16
|
211 grouped_table_impl(grouped_table_impl const& x)
|
Chris@16
|
212 : table(x, node_allocator_traits::
|
Chris@16
|
213 select_on_container_copy_construction(x.node_alloc()))
|
Chris@16
|
214 {
|
Chris@16
|
215 this->init(x);
|
Chris@16
|
216 }
|
Chris@16
|
217
|
Chris@16
|
218 grouped_table_impl(grouped_table_impl const& x,
|
Chris@16
|
219 node_allocator const& a)
|
Chris@16
|
220 : table(x, a)
|
Chris@16
|
221 {
|
Chris@16
|
222 this->init(x);
|
Chris@16
|
223 }
|
Chris@16
|
224
|
Chris@16
|
225 grouped_table_impl(grouped_table_impl& x,
|
Chris@16
|
226 boost::unordered::detail::move_tag m)
|
Chris@16
|
227 : table(x, m)
|
Chris@16
|
228 {}
|
Chris@16
|
229
|
Chris@16
|
230 grouped_table_impl(grouped_table_impl& x,
|
Chris@16
|
231 node_allocator const& a,
|
Chris@16
|
232 boost::unordered::detail::move_tag m)
|
Chris@16
|
233 : table(x, a, m)
|
Chris@16
|
234 {
|
Chris@16
|
235 this->move_init(x);
|
Chris@16
|
236 }
|
Chris@16
|
237
|
Chris@16
|
238 // Accessors
|
Chris@16
|
239
|
Chris@16
|
240 template <class Key, class Pred>
|
Chris@16
|
241 iterator find_node_impl(
|
Chris@16
|
242 std::size_t key_hash,
|
Chris@16
|
243 Key const& k,
|
Chris@16
|
244 Pred const& eq) const
|
Chris@16
|
245 {
|
Chris@16
|
246 std::size_t bucket_index = this->hash_to_bucket(key_hash);
|
Chris@16
|
247 iterator n = this->begin(bucket_index);
|
Chris@16
|
248
|
Chris@16
|
249 for (;;)
|
Chris@16
|
250 {
|
Chris@16
|
251 if (!n.node_) return n;
|
Chris@16
|
252
|
Chris@16
|
253 std::size_t node_hash = n.node_->hash_;
|
Chris@16
|
254 if (key_hash == node_hash)
|
Chris@16
|
255 {
|
Chris@16
|
256 if (eq(k, this->get_key(*n)))
|
Chris@16
|
257 return n;
|
Chris@16
|
258 }
|
Chris@16
|
259 else
|
Chris@16
|
260 {
|
Chris@16
|
261 if (this->hash_to_bucket(node_hash) != bucket_index)
|
Chris@16
|
262 return iterator();
|
Chris@16
|
263 }
|
Chris@16
|
264
|
Chris@16
|
265 n = iterator(n.node_->group_prev_->next_);
|
Chris@16
|
266 }
|
Chris@16
|
267 }
|
Chris@16
|
268
|
Chris@16
|
269 std::size_t count(key_type const& k) const
|
Chris@16
|
270 {
|
Chris@16
|
271 iterator n = this->find_node(k);
|
Chris@16
|
272 if (!n.node_) return 0;
|
Chris@16
|
273
|
Chris@16
|
274 std::size_t x = 0;
|
Chris@16
|
275 node_pointer it = n.node_;
|
Chris@16
|
276 do {
|
Chris@16
|
277 it = it->group_prev_;
|
Chris@16
|
278 ++x;
|
Chris@16
|
279 } while(it != n.node_);
|
Chris@16
|
280
|
Chris@16
|
281 return x;
|
Chris@16
|
282 }
|
Chris@16
|
283
|
Chris@16
|
284 std::pair<iterator, iterator>
|
Chris@16
|
285 equal_range(key_type const& k) const
|
Chris@16
|
286 {
|
Chris@16
|
287 iterator n = this->find_node(k);
|
Chris@16
|
288 return std::make_pair(
|
Chris@16
|
289 n, n.node_ ? iterator(n.node_->group_prev_->next_) : n);
|
Chris@16
|
290 }
|
Chris@16
|
291
|
Chris@16
|
292 // Equality
|
Chris@16
|
293
|
Chris@16
|
294 bool equals(grouped_table_impl const& other) const
|
Chris@16
|
295 {
|
Chris@16
|
296 if(this->size_ != other.size_) return false;
|
Chris@16
|
297
|
Chris@16
|
298 for(iterator n1 = this->begin(); n1.node_;)
|
Chris@16
|
299 {
|
Chris@16
|
300 iterator n2 = other.find_matching_node(n1);
|
Chris@16
|
301 if (!n2.node_) return false;
|
Chris@16
|
302 iterator end1(n1.node_->group_prev_->next_);
|
Chris@16
|
303 iterator end2(n2.node_->group_prev_->next_);
|
Chris@16
|
304 if (!group_equals(n1, end1, n2, end2)) return false;
|
Chris@16
|
305 n1 = end1;
|
Chris@16
|
306 }
|
Chris@16
|
307
|
Chris@16
|
308 return true;
|
Chris@16
|
309 }
|
Chris@16
|
310
|
Chris@16
|
311 static bool group_equals(iterator n1, iterator end1,
|
Chris@16
|
312 iterator n2, iterator end2)
|
Chris@16
|
313 {
|
Chris@16
|
314 for(;;)
|
Chris@16
|
315 {
|
Chris@16
|
316 if (*n1 != *n2) break;
|
Chris@16
|
317
|
Chris@16
|
318 ++n1;
|
Chris@16
|
319 ++n2;
|
Chris@16
|
320
|
Chris@16
|
321 if (n1 == end1) return n2 == end2;
|
Chris@16
|
322 if (n2 == end2) return false;
|
Chris@16
|
323 }
|
Chris@16
|
324
|
Chris@16
|
325 for(iterator n1a = n1, n2a = n2;;)
|
Chris@16
|
326 {
|
Chris@16
|
327 ++n1a;
|
Chris@16
|
328 ++n2a;
|
Chris@16
|
329
|
Chris@16
|
330 if (n1a == end1)
|
Chris@16
|
331 {
|
Chris@16
|
332 if (n2a == end2) break;
|
Chris@16
|
333 else return false;
|
Chris@16
|
334 }
|
Chris@16
|
335
|
Chris@16
|
336 if (n2a == end2) return false;
|
Chris@16
|
337 }
|
Chris@16
|
338
|
Chris@16
|
339 iterator start = n1;
|
Chris@16
|
340 for(;n1 != end1; ++n1)
|
Chris@16
|
341 {
|
Chris@16
|
342 value_type const& v = *n1;
|
Chris@16
|
343 if (find(start, n1, v)) continue;
|
Chris@16
|
344 std::size_t matches = count_equal(n2, end2, v);
|
Chris@16
|
345 if (!matches) return false;
|
Chris@16
|
346 iterator next = n1;
|
Chris@16
|
347 ++next;
|
Chris@16
|
348 if (matches != 1 + count_equal(next, end1, v)) return false;
|
Chris@16
|
349 }
|
Chris@16
|
350
|
Chris@16
|
351 return true;
|
Chris@16
|
352 }
|
Chris@16
|
353
|
Chris@16
|
354 static bool find(iterator n, iterator end, value_type const& v)
|
Chris@16
|
355 {
|
Chris@16
|
356 for(;n != end; ++n)
|
Chris@16
|
357 if (*n == v)
|
Chris@16
|
358 return true;
|
Chris@16
|
359 return false;
|
Chris@16
|
360 }
|
Chris@16
|
361
|
Chris@16
|
362 static std::size_t count_equal(iterator n, iterator end,
|
Chris@16
|
363 value_type const& v)
|
Chris@16
|
364 {
|
Chris@16
|
365 std::size_t count = 0;
|
Chris@16
|
366 for(;n != end; ++n)
|
Chris@16
|
367 if (*n == v) ++count;
|
Chris@16
|
368 return count;
|
Chris@16
|
369 }
|
Chris@16
|
370
|
Chris@16
|
371 // Emplace/Insert
|
Chris@16
|
372
|
Chris@16
|
373 static inline void add_after_node(
|
Chris@16
|
374 node_pointer n,
|
Chris@16
|
375 node_pointer pos)
|
Chris@16
|
376 {
|
Chris@16
|
377 n->next_ = pos->group_prev_->next_;
|
Chris@16
|
378 n->group_prev_ = pos->group_prev_;
|
Chris@16
|
379 pos->group_prev_->next_ = n;
|
Chris@16
|
380 pos->group_prev_ = n;
|
Chris@16
|
381 }
|
Chris@16
|
382
|
Chris@16
|
383 inline iterator add_node(
|
Chris@16
|
384 node_constructor& a,
|
Chris@16
|
385 std::size_t key_hash,
|
Chris@16
|
386 iterator pos)
|
Chris@16
|
387 {
|
Chris@16
|
388 node_pointer n = a.release();
|
Chris@16
|
389 n->hash_ = key_hash;
|
Chris@16
|
390 if (pos.node_) {
|
Chris@16
|
391 this->add_after_node(n, pos.node_);
|
Chris@16
|
392 if (n->next_) {
|
Chris@16
|
393 std::size_t next_bucket = this->hash_to_bucket(
|
Chris@16
|
394 static_cast<node_pointer>(n->next_)->hash_);
|
Chris@16
|
395 if (next_bucket != this->hash_to_bucket(key_hash)) {
|
Chris@16
|
396 this->get_bucket(next_bucket)->next_ = n;
|
Chris@16
|
397 }
|
Chris@16
|
398 }
|
Chris@16
|
399 }
|
Chris@16
|
400 else {
|
Chris@16
|
401 bucket_pointer b = this->get_bucket(
|
Chris@16
|
402 this->hash_to_bucket(key_hash));
|
Chris@16
|
403
|
Chris@16
|
404 if (!b->next_)
|
Chris@16
|
405 {
|
Chris@16
|
406 link_pointer start_node = this->get_previous_start();
|
Chris@16
|
407
|
Chris@16
|
408 if (start_node->next_) {
|
Chris@16
|
409 this->get_bucket(this->hash_to_bucket(
|
Chris@16
|
410 static_cast<node_pointer>(start_node->next_)->hash_
|
Chris@16
|
411 ))->next_ = n;
|
Chris@16
|
412 }
|
Chris@16
|
413
|
Chris@16
|
414 b->next_ = start_node;
|
Chris@16
|
415 n->next_ = start_node->next_;
|
Chris@16
|
416 start_node->next_ = n;
|
Chris@16
|
417 }
|
Chris@16
|
418 else
|
Chris@16
|
419 {
|
Chris@16
|
420 n->next_ = b->next_->next_;
|
Chris@16
|
421 b->next_->next_ = n;
|
Chris@16
|
422 }
|
Chris@16
|
423 }
|
Chris@16
|
424 ++this->size_;
|
Chris@16
|
425 return iterator(n);
|
Chris@16
|
426 }
|
Chris@16
|
427
|
Chris@16
|
428 iterator emplace_impl(node_constructor& a)
|
Chris@16
|
429 {
|
Chris@16
|
430 key_type const& k = this->get_key(a.value());
|
Chris@16
|
431 std::size_t key_hash = this->hash(k);
|
Chris@16
|
432 iterator position = this->find_node(key_hash, k);
|
Chris@16
|
433
|
Chris@16
|
434 // reserve has basic exception safety if the hash function
|
Chris@16
|
435 // throws, strong otherwise.
|
Chris@16
|
436 this->reserve_for_insert(this->size_ + 1);
|
Chris@16
|
437 return this->add_node(a, key_hash, position);
|
Chris@16
|
438 }
|
Chris@16
|
439
|
Chris@16
|
440 void emplace_impl_no_rehash(node_constructor& a)
|
Chris@16
|
441 {
|
Chris@16
|
442 key_type const& k = this->get_key(a.value());
|
Chris@16
|
443 std::size_t key_hash = this->hash(k);
|
Chris@16
|
444 this->add_node(a, key_hash, this->find_node(key_hash, k));
|
Chris@16
|
445 }
|
Chris@16
|
446
|
Chris@16
|
447 #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
Chris@16
|
448 # if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
Chris@16
|
449 iterator emplace(boost::unordered::detail::emplace_args1<
|
Chris@16
|
450 boost::unordered::detail::please_ignore_this_overload> const&)
|
Chris@16
|
451 {
|
Chris@16
|
452 BOOST_ASSERT(false);
|
Chris@16
|
453 return iterator();
|
Chris@16
|
454 }
|
Chris@16
|
455 # else
|
Chris@16
|
456 iterator emplace(
|
Chris@16
|
457 boost::unordered::detail::please_ignore_this_overload const&)
|
Chris@16
|
458 {
|
Chris@16
|
459 BOOST_ASSERT(false);
|
Chris@16
|
460 return iterator();
|
Chris@16
|
461 }
|
Chris@16
|
462 # endif
|
Chris@16
|
463 #endif
|
Chris@16
|
464
|
Chris@16
|
465 template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
|
Chris@16
|
466 iterator emplace(BOOST_UNORDERED_EMPLACE_ARGS)
|
Chris@16
|
467 {
|
Chris@16
|
468 node_constructor a(this->node_alloc());
|
Chris@16
|
469 a.construct_with_value(BOOST_UNORDERED_EMPLACE_FORWARD);
|
Chris@16
|
470
|
Chris@16
|
471 return iterator(emplace_impl(a));
|
Chris@16
|
472 }
|
Chris@16
|
473
|
Chris@16
|
474 ////////////////////////////////////////////////////////////////////////
|
Chris@16
|
475 // Insert range methods
|
Chris@16
|
476
|
Chris@16
|
477 // if hash function throws, or inserting > 1 element, basic exception
|
Chris@16
|
478 // safety. Strong otherwise
|
Chris@16
|
479 template <class I>
|
Chris@16
|
480 typename boost::unordered::detail::enable_if_forward<I, void>::type
|
Chris@16
|
481 insert_range(I i, I j)
|
Chris@16
|
482 {
|
Chris@16
|
483 if(i == j) return;
|
Chris@16
|
484
|
Chris@16
|
485 std::size_t distance = boost::unordered::detail::distance(i, j);
|
Chris@16
|
486 if(distance == 1) {
|
Chris@16
|
487 node_constructor a(this->node_alloc());
|
Chris@16
|
488 a.construct_with_value2(*i);
|
Chris@16
|
489 emplace_impl(a);
|
Chris@16
|
490 }
|
Chris@16
|
491 else {
|
Chris@16
|
492 // Only require basic exception safety here
|
Chris@16
|
493 this->reserve_for_insert(this->size_ + distance);
|
Chris@16
|
494
|
Chris@16
|
495 node_constructor a(this->node_alloc());
|
Chris@16
|
496 for (; i != j; ++i) {
|
Chris@16
|
497 a.construct_with_value2(*i);
|
Chris@16
|
498 emplace_impl_no_rehash(a);
|
Chris@16
|
499 }
|
Chris@16
|
500 }
|
Chris@16
|
501 }
|
Chris@16
|
502
|
Chris@16
|
503 template <class I>
|
Chris@16
|
504 typename boost::unordered::detail::disable_if_forward<I, void>::type
|
Chris@16
|
505 insert_range(I i, I j)
|
Chris@16
|
506 {
|
Chris@16
|
507 node_constructor a(this->node_alloc());
|
Chris@16
|
508 for (; i != j; ++i) {
|
Chris@16
|
509 a.construct_with_value2(*i);
|
Chris@16
|
510 emplace_impl(a);
|
Chris@16
|
511 }
|
Chris@16
|
512 }
|
Chris@16
|
513
|
Chris@16
|
514 ////////////////////////////////////////////////////////////////////////
|
Chris@16
|
515 // Erase
|
Chris@16
|
516 //
|
Chris@16
|
517 // no throw
|
Chris@16
|
518
|
Chris@16
|
519 std::size_t erase_key(key_type const& k)
|
Chris@16
|
520 {
|
Chris@16
|
521 if(!this->size_) return 0;
|
Chris@16
|
522
|
Chris@16
|
523 std::size_t key_hash = this->hash(k);
|
Chris@16
|
524 std::size_t bucket_index = this->hash_to_bucket(key_hash);
|
Chris@16
|
525 link_pointer prev = this->get_previous_start(bucket_index);
|
Chris@16
|
526 if (!prev) return 0;
|
Chris@16
|
527
|
Chris@16
|
528 for (;;)
|
Chris@16
|
529 {
|
Chris@16
|
530 if (!prev->next_) return 0;
|
Chris@16
|
531 std::size_t node_hash =
|
Chris@16
|
532 static_cast<node_pointer>(prev->next_)->hash_;
|
Chris@16
|
533 if (this->hash_to_bucket(node_hash) != bucket_index)
|
Chris@16
|
534 return 0;
|
Chris@16
|
535 if (node_hash == key_hash &&
|
Chris@16
|
536 this->key_eq()(k, this->get_key(
|
Chris@16
|
537 static_cast<node_pointer>(prev->next_)->value())))
|
Chris@16
|
538 break;
|
Chris@16
|
539 prev = static_cast<node_pointer>(prev->next_)->group_prev_;
|
Chris@16
|
540 }
|
Chris@16
|
541
|
Chris@16
|
542 node_pointer first_node = static_cast<node_pointer>(prev->next_);
|
Chris@16
|
543 link_pointer end = first_node->group_prev_->next_;
|
Chris@16
|
544
|
Chris@101
|
545 std::size_t deleted_count = this->delete_nodes(prev, end);
|
Chris@16
|
546 this->fix_bucket(bucket_index, prev);
|
Chris@101
|
547 return deleted_count;
|
Chris@16
|
548 }
|
Chris@16
|
549
|
Chris@16
|
550 iterator erase(c_iterator r)
|
Chris@16
|
551 {
|
Chris@16
|
552 BOOST_ASSERT(r.node_);
|
Chris@16
|
553 iterator next(r.node_);
|
Chris@16
|
554 ++next;
|
Chris@16
|
555 erase_nodes(r.node_, next.node_);
|
Chris@16
|
556 return next;
|
Chris@16
|
557 }
|
Chris@16
|
558
|
Chris@16
|
559 iterator erase_range(c_iterator r1, c_iterator r2)
|
Chris@16
|
560 {
|
Chris@16
|
561 if (r1 == r2) return iterator(r2.node_);
|
Chris@16
|
562 erase_nodes(r1.node_, r2.node_);
|
Chris@16
|
563 return iterator(r2.node_);
|
Chris@16
|
564 }
|
Chris@16
|
565
|
Chris@101
|
566 link_pointer erase_nodes(node_pointer i, node_pointer j)
|
Chris@16
|
567 {
|
Chris@101
|
568 std::size_t bucket_index = this->hash_to_bucket(i->hash_);
|
Chris@16
|
569
|
Chris@101
|
570 // Split the groups containing 'i' and 'j'.
|
Chris@101
|
571 // And get the pointer to the node before i while
|
Chris@16
|
572 // we're at it.
|
Chris@101
|
573 link_pointer prev = split_groups(i, j);
|
Chris@16
|
574
|
Chris@101
|
575 // If we don't have a 'prev' it means that i is at the
|
Chris@16
|
576 // beginning of a block, so search through the blocks in the
|
Chris@16
|
577 // same bucket.
|
Chris@16
|
578 if (!prev) {
|
Chris@16
|
579 prev = this->get_previous_start(bucket_index);
|
Chris@101
|
580 while (prev->next_ != i)
|
Chris@16
|
581 prev = static_cast<node_pointer>(prev->next_)->group_prev_;
|
Chris@16
|
582 }
|
Chris@16
|
583
|
Chris@16
|
584 // Delete the nodes.
|
Chris@16
|
585 do {
|
Chris@16
|
586 link_pointer group_end =
|
Chris@16
|
587 static_cast<node_pointer>(prev->next_)->group_prev_->next_;
|
Chris@16
|
588 this->delete_nodes(prev, group_end);
|
Chris@16
|
589 bucket_index = this->fix_bucket(bucket_index, prev);
|
Chris@101
|
590 } while(prev->next_ != j);
|
Chris@16
|
591
|
Chris@16
|
592 return prev;
|
Chris@16
|
593 }
|
Chris@16
|
594
|
Chris@101
|
595 static link_pointer split_groups(node_pointer i, node_pointer j)
|
Chris@16
|
596 {
|
Chris@101
|
597 node_pointer prev = i->group_prev_;
|
Chris@101
|
598 if (prev->next_ != i) prev = node_pointer();
|
Chris@16
|
599
|
Chris@101
|
600 if (j) {
|
Chris@101
|
601 node_pointer first = j;
|
Chris@101
|
602 while (first != i && first->group_prev_->next_ == first) {
|
Chris@16
|
603 first = first->group_prev_;
|
Chris@16
|
604 }
|
Chris@16
|
605
|
Chris@101
|
606 boost::swap(first->group_prev_, j->group_prev_);
|
Chris@101
|
607 if (first == i) return prev;
|
Chris@16
|
608 }
|
Chris@16
|
609
|
Chris@16
|
610 if (prev) {
|
Chris@16
|
611 node_pointer first = prev;
|
Chris@16
|
612 while (first->group_prev_->next_ == first) {
|
Chris@16
|
613 first = first->group_prev_;
|
Chris@16
|
614 }
|
Chris@101
|
615 boost::swap(first->group_prev_, i->group_prev_);
|
Chris@16
|
616 }
|
Chris@16
|
617
|
Chris@16
|
618 return prev;
|
Chris@16
|
619 }
|
Chris@16
|
620
|
Chris@16
|
621 ////////////////////////////////////////////////////////////////////////
|
Chris@16
|
622 // fill_buckets
|
Chris@16
|
623
|
Chris@16
|
624 template <class NodeCreator>
|
Chris@16
|
625 static void fill_buckets(iterator n, table& dst,
|
Chris@16
|
626 NodeCreator& creator)
|
Chris@16
|
627 {
|
Chris@16
|
628 link_pointer prev = dst.get_previous_start();
|
Chris@16
|
629
|
Chris@16
|
630 while (n.node_) {
|
Chris@16
|
631 std::size_t key_hash = n.node_->hash_;
|
Chris@16
|
632 iterator group_end(n.node_->group_prev_->next_);
|
Chris@16
|
633
|
Chris@16
|
634 node_pointer first_node = creator.create(*n);
|
Chris@16
|
635 node_pointer end = first_node;
|
Chris@16
|
636 first_node->hash_ = key_hash;
|
Chris@16
|
637 prev->next_ = first_node;
|
Chris@16
|
638 ++dst.size_;
|
Chris@16
|
639
|
Chris@16
|
640 for (++n; n != group_end; ++n)
|
Chris@16
|
641 {
|
Chris@16
|
642 end = creator.create(*n);
|
Chris@16
|
643 end->hash_ = key_hash;
|
Chris@16
|
644 add_after_node(end, first_node);
|
Chris@16
|
645 ++dst.size_;
|
Chris@16
|
646 }
|
Chris@16
|
647
|
Chris@16
|
648 prev = place_in_bucket(dst, prev, end);
|
Chris@16
|
649 }
|
Chris@16
|
650 }
|
Chris@16
|
651
|
Chris@16
|
652 // strong otherwise exception safety
|
Chris@16
|
653 void rehash_impl(std::size_t num_buckets)
|
Chris@16
|
654 {
|
Chris@16
|
655 BOOST_ASSERT(this->buckets_);
|
Chris@16
|
656
|
Chris@16
|
657 this->create_buckets(num_buckets);
|
Chris@16
|
658 link_pointer prev = this->get_previous_start();
|
Chris@16
|
659 while (prev->next_)
|
Chris@16
|
660 prev = place_in_bucket(*this, prev,
|
Chris@16
|
661 static_cast<node_pointer>(prev->next_)->group_prev_);
|
Chris@16
|
662 }
|
Chris@16
|
663
|
Chris@16
|
664 // Iterate through the nodes placing them in the correct buckets.
|
Chris@16
|
665 // pre: prev->next_ is not null.
|
Chris@16
|
666 static link_pointer place_in_bucket(table& dst,
|
Chris@16
|
667 link_pointer prev, node_pointer end)
|
Chris@16
|
668 {
|
Chris@16
|
669 bucket_pointer b = dst.get_bucket(dst.hash_to_bucket(end->hash_));
|
Chris@16
|
670
|
Chris@16
|
671 if (!b->next_) {
|
Chris@16
|
672 b->next_ = prev;
|
Chris@16
|
673 return end;
|
Chris@16
|
674 }
|
Chris@16
|
675 else {
|
Chris@16
|
676 link_pointer next = end->next_;
|
Chris@16
|
677 end->next_ = b->next_->next_;
|
Chris@16
|
678 b->next_->next_ = prev->next_;
|
Chris@16
|
679 prev->next_ = next;
|
Chris@16
|
680 return prev;
|
Chris@16
|
681 }
|
Chris@16
|
682 }
|
Chris@16
|
683 };
|
Chris@16
|
684 }}}
|
Chris@16
|
685
|
Chris@16
|
686 #endif
|