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_UNIQUE_HPP_INCLUDED
|
Chris@16
|
8 #define BOOST_UNORDERED_DETAIL_UNIQUE_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 #include <boost/throw_exception.hpp>
|
Chris@16
|
18 #include <stdexcept>
|
Chris@16
|
19
|
Chris@16
|
20 namespace boost { namespace unordered { namespace detail {
|
Chris@16
|
21
|
Chris@16
|
22 template <typename A, typename T> struct unique_node;
|
Chris@16
|
23 template <typename T> struct ptr_node;
|
Chris@16
|
24 template <typename Types> struct table_impl;
|
Chris@16
|
25
|
Chris@16
|
26 template <typename A, typename T>
|
Chris@16
|
27 struct unique_node :
|
Chris@16
|
28 boost::unordered::detail::value_base<T>
|
Chris@16
|
29 {
|
Chris@16
|
30 typedef typename ::boost::unordered::detail::rebind_wrap<
|
Chris@101
|
31 A, unique_node<A, T> >::type allocator;
|
Chris@101
|
32 typedef typename ::boost::unordered::detail::
|
Chris@101
|
33 allocator_traits<allocator>::pointer node_pointer;
|
Chris@16
|
34 typedef node_pointer link_pointer;
|
Chris@16
|
35
|
Chris@16
|
36 link_pointer next_;
|
Chris@16
|
37 std::size_t hash_;
|
Chris@16
|
38
|
Chris@16
|
39 unique_node() :
|
Chris@16
|
40 next_(),
|
Chris@16
|
41 hash_(0)
|
Chris@16
|
42 {}
|
Chris@16
|
43
|
Chris@16
|
44 void init(node_pointer)
|
Chris@16
|
45 {
|
Chris@16
|
46 }
|
Chris@16
|
47
|
Chris@16
|
48 private:
|
Chris@16
|
49 unique_node& operator=(unique_node const&);
|
Chris@16
|
50 };
|
Chris@16
|
51
|
Chris@16
|
52 template <typename T>
|
Chris@16
|
53 struct ptr_node :
|
Chris@16
|
54 boost::unordered::detail::ptr_bucket
|
Chris@16
|
55 {
|
Chris@101
|
56 typedef T value_type;
|
Chris@16
|
57 typedef boost::unordered::detail::ptr_bucket bucket_base;
|
Chris@16
|
58 typedef ptr_node<T>* node_pointer;
|
Chris@16
|
59 typedef ptr_bucket* link_pointer;
|
Chris@16
|
60
|
Chris@16
|
61 std::size_t hash_;
|
Chris@101
|
62 boost::unordered::detail::value_base<T> value_base_;
|
Chris@16
|
63
|
Chris@16
|
64 ptr_node() :
|
Chris@16
|
65 bucket_base(),
|
Chris@16
|
66 hash_(0)
|
Chris@16
|
67 {}
|
Chris@16
|
68
|
Chris@16
|
69 void init(node_pointer)
|
Chris@16
|
70 {
|
Chris@16
|
71 }
|
Chris@16
|
72
|
Chris@101
|
73 void* address() { return value_base_.address(); }
|
Chris@101
|
74 value_type& value() { return value_base_.value(); }
|
Chris@101
|
75 value_type* value_ptr() { return value_base_.value_ptr(); }
|
Chris@101
|
76
|
Chris@16
|
77 private:
|
Chris@16
|
78 ptr_node& operator=(ptr_node const&);
|
Chris@16
|
79 };
|
Chris@16
|
80
|
Chris@16
|
81 // If the allocator uses raw pointers use ptr_node
|
Chris@16
|
82 // Otherwise use node.
|
Chris@16
|
83
|
Chris@16
|
84 template <typename A, typename T, typename NodePtr, typename BucketPtr>
|
Chris@16
|
85 struct pick_node2
|
Chris@16
|
86 {
|
Chris@16
|
87 typedef boost::unordered::detail::unique_node<A, T> node;
|
Chris@16
|
88
|
Chris@16
|
89 typedef typename boost::unordered::detail::allocator_traits<
|
Chris@16
|
90 typename boost::unordered::detail::rebind_wrap<A, node>::type
|
Chris@16
|
91 >::pointer node_pointer;
|
Chris@16
|
92
|
Chris@16
|
93 typedef boost::unordered::detail::bucket<node_pointer> bucket;
|
Chris@16
|
94 typedef node_pointer link_pointer;
|
Chris@16
|
95 };
|
Chris@16
|
96
|
Chris@16
|
97 template <typename A, typename T>
|
Chris@16
|
98 struct pick_node2<A, T,
|
Chris@16
|
99 boost::unordered::detail::ptr_node<T>*,
|
Chris@16
|
100 boost::unordered::detail::ptr_bucket*>
|
Chris@16
|
101 {
|
Chris@16
|
102 typedef boost::unordered::detail::ptr_node<T> node;
|
Chris@16
|
103 typedef boost::unordered::detail::ptr_bucket bucket;
|
Chris@16
|
104 typedef bucket* link_pointer;
|
Chris@16
|
105 };
|
Chris@16
|
106
|
Chris@16
|
107 template <typename A, typename T>
|
Chris@16
|
108 struct pick_node
|
Chris@16
|
109 {
|
Chris@16
|
110 typedef boost::unordered::detail::allocator_traits<
|
Chris@16
|
111 typename boost::unordered::detail::rebind_wrap<A,
|
Chris@16
|
112 boost::unordered::detail::ptr_node<T> >::type
|
Chris@16
|
113 > tentative_node_traits;
|
Chris@16
|
114
|
Chris@16
|
115 typedef boost::unordered::detail::allocator_traits<
|
Chris@16
|
116 typename boost::unordered::detail::rebind_wrap<A,
|
Chris@16
|
117 boost::unordered::detail::ptr_bucket >::type
|
Chris@16
|
118 > tentative_bucket_traits;
|
Chris@16
|
119
|
Chris@16
|
120 typedef pick_node2<A, T,
|
Chris@16
|
121 typename tentative_node_traits::pointer,
|
Chris@16
|
122 typename tentative_bucket_traits::pointer> pick;
|
Chris@16
|
123
|
Chris@16
|
124 typedef typename pick::node node;
|
Chris@16
|
125 typedef typename pick::bucket bucket;
|
Chris@16
|
126 typedef typename pick::link_pointer link_pointer;
|
Chris@16
|
127 };
|
Chris@16
|
128
|
Chris@16
|
129 template <typename A, typename T, typename H, typename P>
|
Chris@16
|
130 struct set
|
Chris@16
|
131 {
|
Chris@16
|
132 typedef boost::unordered::detail::set<A, T, H, P> types;
|
Chris@16
|
133
|
Chris@16
|
134 typedef A allocator;
|
Chris@16
|
135 typedef T value_type;
|
Chris@16
|
136 typedef H hasher;
|
Chris@16
|
137 typedef P key_equal;
|
Chris@16
|
138 typedef T key_type;
|
Chris@16
|
139
|
Chris@16
|
140 typedef boost::unordered::detail::allocator_traits<allocator> traits;
|
Chris@16
|
141 typedef boost::unordered::detail::pick_node<allocator, value_type> pick;
|
Chris@16
|
142 typedef typename pick::node node;
|
Chris@16
|
143 typedef typename pick::bucket bucket;
|
Chris@16
|
144 typedef typename pick::link_pointer link_pointer;
|
Chris@16
|
145
|
Chris@16
|
146 typedef boost::unordered::detail::table_impl<types> table;
|
Chris@16
|
147 typedef boost::unordered::detail::set_extractor<value_type> extractor;
|
Chris@16
|
148
|
Chris@101
|
149 typedef typename boost::unordered::detail::pick_policy<T>::type policy;
|
Chris@16
|
150 };
|
Chris@16
|
151
|
Chris@16
|
152 template <typename A, typename K, typename M, typename H, typename P>
|
Chris@16
|
153 struct map
|
Chris@16
|
154 {
|
Chris@16
|
155 typedef boost::unordered::detail::map<A, K, M, H, P> types;
|
Chris@16
|
156
|
Chris@16
|
157 typedef A allocator;
|
Chris@16
|
158 typedef std::pair<K const, M> value_type;
|
Chris@16
|
159 typedef H hasher;
|
Chris@16
|
160 typedef P key_equal;
|
Chris@16
|
161 typedef K key_type;
|
Chris@16
|
162
|
Chris@16
|
163 typedef boost::unordered::detail::allocator_traits<allocator>
|
Chris@16
|
164 traits;
|
Chris@16
|
165 typedef boost::unordered::detail::pick_node<allocator, value_type> pick;
|
Chris@16
|
166 typedef typename pick::node node;
|
Chris@16
|
167 typedef typename pick::bucket bucket;
|
Chris@16
|
168 typedef typename pick::link_pointer link_pointer;
|
Chris@16
|
169
|
Chris@16
|
170 typedef boost::unordered::detail::table_impl<types> table;
|
Chris@16
|
171 typedef boost::unordered::detail::map_extractor<key_type, value_type>
|
Chris@16
|
172 extractor;
|
Chris@16
|
173
|
Chris@101
|
174 typedef typename boost::unordered::detail::pick_policy<K>::type policy;
|
Chris@16
|
175 };
|
Chris@16
|
176
|
Chris@16
|
177 template <typename Types>
|
Chris@16
|
178 struct table_impl : boost::unordered::detail::table<Types>
|
Chris@16
|
179 {
|
Chris@16
|
180 typedef boost::unordered::detail::table<Types> table;
|
Chris@16
|
181 typedef typename table::value_type value_type;
|
Chris@16
|
182 typedef typename table::bucket bucket;
|
Chris@16
|
183 typedef typename table::policy policy;
|
Chris@16
|
184 typedef typename table::node_pointer node_pointer;
|
Chris@16
|
185 typedef typename table::node_allocator node_allocator;
|
Chris@16
|
186 typedef typename table::node_allocator_traits node_allocator_traits;
|
Chris@16
|
187 typedef typename table::bucket_pointer bucket_pointer;
|
Chris@16
|
188 typedef typename table::link_pointer link_pointer;
|
Chris@16
|
189 typedef typename table::hasher hasher;
|
Chris@16
|
190 typedef typename table::key_equal key_equal;
|
Chris@16
|
191 typedef typename table::key_type key_type;
|
Chris@16
|
192 typedef typename table::node_constructor node_constructor;
|
Chris@16
|
193 typedef typename table::extractor extractor;
|
Chris@16
|
194 typedef typename table::iterator iterator;
|
Chris@16
|
195 typedef typename table::c_iterator c_iterator;
|
Chris@16
|
196
|
Chris@16
|
197 typedef std::pair<iterator, bool> emplace_return;
|
Chris@16
|
198
|
Chris@16
|
199 // Constructors
|
Chris@16
|
200
|
Chris@16
|
201 table_impl(std::size_t n,
|
Chris@16
|
202 hasher const& hf,
|
Chris@16
|
203 key_equal const& eq,
|
Chris@16
|
204 node_allocator const& a)
|
Chris@16
|
205 : table(n, hf, eq, a)
|
Chris@16
|
206 {}
|
Chris@16
|
207
|
Chris@16
|
208 table_impl(table_impl const& x)
|
Chris@16
|
209 : table(x, node_allocator_traits::
|
Chris@16
|
210 select_on_container_copy_construction(x.node_alloc()))
|
Chris@16
|
211 {
|
Chris@16
|
212 this->init(x);
|
Chris@16
|
213 }
|
Chris@16
|
214
|
Chris@16
|
215 table_impl(table_impl const& x,
|
Chris@16
|
216 node_allocator const& a)
|
Chris@16
|
217 : table(x, a)
|
Chris@16
|
218 {
|
Chris@16
|
219 this->init(x);
|
Chris@16
|
220 }
|
Chris@16
|
221
|
Chris@16
|
222 table_impl(table_impl& x,
|
Chris@16
|
223 boost::unordered::detail::move_tag m)
|
Chris@16
|
224 : table(x, m)
|
Chris@16
|
225 {}
|
Chris@16
|
226
|
Chris@16
|
227 table_impl(table_impl& x,
|
Chris@16
|
228 node_allocator const& a,
|
Chris@16
|
229 boost::unordered::detail::move_tag m)
|
Chris@16
|
230 : table(x, a, m)
|
Chris@16
|
231 {
|
Chris@16
|
232 this->move_init(x);
|
Chris@16
|
233 }
|
Chris@16
|
234
|
Chris@16
|
235 // Accessors
|
Chris@16
|
236
|
Chris@16
|
237 template <class Key, class Pred>
|
Chris@16
|
238 iterator find_node_impl(
|
Chris@16
|
239 std::size_t key_hash,
|
Chris@16
|
240 Key const& k,
|
Chris@16
|
241 Pred const& eq) const
|
Chris@16
|
242 {
|
Chris@16
|
243 std::size_t bucket_index = this->hash_to_bucket(key_hash);
|
Chris@16
|
244 iterator n = this->begin(bucket_index);
|
Chris@16
|
245
|
Chris@16
|
246 for (;;)
|
Chris@16
|
247 {
|
Chris@16
|
248 if (!n.node_) return n;
|
Chris@16
|
249
|
Chris@16
|
250 std::size_t node_hash = n.node_->hash_;
|
Chris@16
|
251 if (key_hash == node_hash)
|
Chris@16
|
252 {
|
Chris@16
|
253 if (eq(k, this->get_key(*n)))
|
Chris@16
|
254 return n;
|
Chris@16
|
255 }
|
Chris@16
|
256 else
|
Chris@16
|
257 {
|
Chris@16
|
258 if (this->hash_to_bucket(node_hash) != bucket_index)
|
Chris@16
|
259 return iterator();
|
Chris@16
|
260 }
|
Chris@16
|
261
|
Chris@16
|
262 ++n;
|
Chris@16
|
263 }
|
Chris@16
|
264 }
|
Chris@16
|
265
|
Chris@16
|
266 std::size_t count(key_type const& k) const
|
Chris@16
|
267 {
|
Chris@16
|
268 return this->find_node(k).node_ ? 1 : 0;
|
Chris@16
|
269 }
|
Chris@16
|
270
|
Chris@16
|
271 value_type& at(key_type const& k) const
|
Chris@16
|
272 {
|
Chris@16
|
273 if (this->size_) {
|
Chris@16
|
274 iterator it = this->find_node(k);
|
Chris@16
|
275 if (it.node_) return *it;
|
Chris@16
|
276 }
|
Chris@16
|
277
|
Chris@16
|
278 boost::throw_exception(
|
Chris@16
|
279 std::out_of_range("Unable to find key in unordered_map."));
|
Chris@16
|
280 }
|
Chris@16
|
281
|
Chris@16
|
282 std::pair<iterator, iterator>
|
Chris@16
|
283 equal_range(key_type const& k) const
|
Chris@16
|
284 {
|
Chris@16
|
285 iterator n = this->find_node(k);
|
Chris@16
|
286 iterator n2 = n;
|
Chris@16
|
287 if (n2.node_) ++n2;
|
Chris@16
|
288 return std::make_pair(n, n2);
|
Chris@16
|
289 }
|
Chris@16
|
290
|
Chris@16
|
291 // equals
|
Chris@16
|
292
|
Chris@16
|
293 bool equals(table_impl const& other) const
|
Chris@16
|
294 {
|
Chris@16
|
295 if(this->size_ != other.size_) return false;
|
Chris@16
|
296
|
Chris@16
|
297 for(iterator n1 = this->begin(); n1.node_; ++n1)
|
Chris@16
|
298 {
|
Chris@16
|
299 iterator n2 = other.find_matching_node(n1);
|
Chris@16
|
300
|
Chris@16
|
301 if (!n2.node_ || *n1 != *n2)
|
Chris@16
|
302 return false;
|
Chris@16
|
303 }
|
Chris@16
|
304
|
Chris@16
|
305 return true;
|
Chris@16
|
306 }
|
Chris@16
|
307
|
Chris@16
|
308 // Emplace/Insert
|
Chris@16
|
309
|
Chris@16
|
310 inline iterator add_node(
|
Chris@16
|
311 node_constructor& a,
|
Chris@16
|
312 std::size_t key_hash)
|
Chris@16
|
313 {
|
Chris@16
|
314 node_pointer n = a.release();
|
Chris@16
|
315 n->hash_ = key_hash;
|
Chris@16
|
316
|
Chris@16
|
317 bucket_pointer b = this->get_bucket(this->hash_to_bucket(key_hash));
|
Chris@16
|
318
|
Chris@16
|
319 if (!b->next_)
|
Chris@16
|
320 {
|
Chris@16
|
321 link_pointer start_node = this->get_previous_start();
|
Chris@16
|
322
|
Chris@16
|
323 if (start_node->next_) {
|
Chris@16
|
324 this->get_bucket(this->hash_to_bucket(
|
Chris@16
|
325 static_cast<node_pointer>(start_node->next_)->hash_)
|
Chris@16
|
326 )->next_ = n;
|
Chris@16
|
327 }
|
Chris@16
|
328
|
Chris@16
|
329 b->next_ = start_node;
|
Chris@16
|
330 n->next_ = start_node->next_;
|
Chris@16
|
331 start_node->next_ = n;
|
Chris@16
|
332 }
|
Chris@16
|
333 else
|
Chris@16
|
334 {
|
Chris@16
|
335 n->next_ = b->next_->next_;
|
Chris@16
|
336 b->next_->next_ = n;
|
Chris@16
|
337 }
|
Chris@16
|
338
|
Chris@16
|
339 ++this->size_;
|
Chris@16
|
340 return iterator(n);
|
Chris@16
|
341 }
|
Chris@16
|
342
|
Chris@16
|
343 value_type& operator[](key_type const& k)
|
Chris@16
|
344 {
|
Chris@16
|
345 std::size_t key_hash = this->hash(k);
|
Chris@16
|
346 iterator pos = this->find_node(key_hash, k);
|
Chris@16
|
347
|
Chris@16
|
348 if (pos.node_) return *pos;
|
Chris@16
|
349
|
Chris@16
|
350 // Create the node before rehashing in case it throws an
|
Chris@16
|
351 // exception (need strong safety in such a case).
|
Chris@16
|
352 node_constructor a(this->node_alloc());
|
Chris@16
|
353 a.construct_with_value(BOOST_UNORDERED_EMPLACE_ARGS3(
|
Chris@16
|
354 boost::unordered::piecewise_construct,
|
Chris@16
|
355 boost::make_tuple(k),
|
Chris@16
|
356 boost::make_tuple()));
|
Chris@16
|
357
|
Chris@16
|
358 this->reserve_for_insert(this->size_ + 1);
|
Chris@16
|
359 return *add_node(a, key_hash);
|
Chris@16
|
360 }
|
Chris@16
|
361
|
Chris@16
|
362 #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
Chris@16
|
363 # if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
Chris@16
|
364 emplace_return emplace(boost::unordered::detail::emplace_args1<
|
Chris@16
|
365 boost::unordered::detail::please_ignore_this_overload> const&)
|
Chris@16
|
366 {
|
Chris@16
|
367 BOOST_ASSERT(false);
|
Chris@16
|
368 return emplace_return(this->begin(), false);
|
Chris@16
|
369 }
|
Chris@16
|
370 # else
|
Chris@16
|
371 emplace_return emplace(
|
Chris@16
|
372 boost::unordered::detail::please_ignore_this_overload const&)
|
Chris@16
|
373 {
|
Chris@16
|
374 BOOST_ASSERT(false);
|
Chris@16
|
375 return emplace_return(this->begin(), false);
|
Chris@16
|
376 }
|
Chris@16
|
377 # endif
|
Chris@16
|
378 #endif
|
Chris@16
|
379
|
Chris@16
|
380 template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
|
Chris@16
|
381 emplace_return emplace(BOOST_UNORDERED_EMPLACE_ARGS)
|
Chris@16
|
382 {
|
Chris@16
|
383 #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
Chris@16
|
384 return emplace_impl(
|
Chris@16
|
385 extractor::extract(BOOST_UNORDERED_EMPLACE_FORWARD),
|
Chris@16
|
386 BOOST_UNORDERED_EMPLACE_FORWARD);
|
Chris@16
|
387 #else
|
Chris@16
|
388 return emplace_impl(
|
Chris@16
|
389 extractor::extract(args.a0, args.a1),
|
Chris@16
|
390 BOOST_UNORDERED_EMPLACE_FORWARD);
|
Chris@16
|
391 #endif
|
Chris@16
|
392 }
|
Chris@16
|
393
|
Chris@16
|
394 #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
Chris@16
|
395 template <typename A0>
|
Chris@16
|
396 emplace_return emplace(
|
Chris@16
|
397 boost::unordered::detail::emplace_args1<A0> const& args)
|
Chris@16
|
398 {
|
Chris@16
|
399 return emplace_impl(extractor::extract(args.a0), args);
|
Chris@16
|
400 }
|
Chris@16
|
401 #endif
|
Chris@16
|
402
|
Chris@16
|
403 template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
|
Chris@16
|
404 emplace_return emplace_impl(key_type const& k,
|
Chris@16
|
405 BOOST_UNORDERED_EMPLACE_ARGS)
|
Chris@16
|
406 {
|
Chris@16
|
407 std::size_t key_hash = this->hash(k);
|
Chris@16
|
408 iterator pos = this->find_node(key_hash, k);
|
Chris@16
|
409
|
Chris@16
|
410 if (pos.node_) return emplace_return(pos, false);
|
Chris@16
|
411
|
Chris@16
|
412 // Create the node before rehashing in case it throws an
|
Chris@16
|
413 // exception (need strong safety in such a case).
|
Chris@16
|
414 node_constructor a(this->node_alloc());
|
Chris@16
|
415 a.construct_with_value(BOOST_UNORDERED_EMPLACE_FORWARD);
|
Chris@16
|
416
|
Chris@16
|
417 // reserve has basic exception safety if the hash function
|
Chris@16
|
418 // throws, strong otherwise.
|
Chris@16
|
419 this->reserve_for_insert(this->size_ + 1);
|
Chris@16
|
420 return emplace_return(this->add_node(a, key_hash), true);
|
Chris@16
|
421 }
|
Chris@16
|
422
|
Chris@16
|
423 emplace_return emplace_impl_with_node(node_constructor& a)
|
Chris@16
|
424 {
|
Chris@16
|
425 key_type const& k = this->get_key(a.value());
|
Chris@16
|
426 std::size_t key_hash = this->hash(k);
|
Chris@16
|
427 iterator pos = this->find_node(key_hash, k);
|
Chris@16
|
428
|
Chris@16
|
429 if (pos.node_) return emplace_return(pos, false);
|
Chris@16
|
430
|
Chris@16
|
431 // reserve has basic exception safety if the hash function
|
Chris@16
|
432 // throws, strong otherwise.
|
Chris@16
|
433 this->reserve_for_insert(this->size_ + 1);
|
Chris@16
|
434 return emplace_return(this->add_node(a, key_hash), true);
|
Chris@16
|
435 }
|
Chris@16
|
436
|
Chris@16
|
437 template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
|
Chris@16
|
438 emplace_return emplace_impl(no_key, BOOST_UNORDERED_EMPLACE_ARGS)
|
Chris@16
|
439 {
|
Chris@16
|
440 // Don't have a key, so construct the node first in order
|
Chris@16
|
441 // to be able to lookup the position.
|
Chris@16
|
442 node_constructor a(this->node_alloc());
|
Chris@16
|
443 a.construct_with_value(BOOST_UNORDERED_EMPLACE_FORWARD);
|
Chris@16
|
444 return emplace_impl_with_node(a);
|
Chris@16
|
445 }
|
Chris@16
|
446
|
Chris@16
|
447 ////////////////////////////////////////////////////////////////////////
|
Chris@16
|
448 // Insert range methods
|
Chris@16
|
449 //
|
Chris@16
|
450 // if hash function throws, or inserting > 1 element, basic exception
|
Chris@16
|
451 // safety strong otherwise
|
Chris@16
|
452
|
Chris@16
|
453 template <class InputIt>
|
Chris@16
|
454 void insert_range(InputIt i, InputIt j)
|
Chris@16
|
455 {
|
Chris@16
|
456 if(i != j)
|
Chris@16
|
457 return insert_range_impl(extractor::extract(*i), i, j);
|
Chris@16
|
458 }
|
Chris@16
|
459
|
Chris@16
|
460 template <class InputIt>
|
Chris@16
|
461 void insert_range_impl(key_type const& k, InputIt i, InputIt j)
|
Chris@16
|
462 {
|
Chris@16
|
463 node_constructor a(this->node_alloc());
|
Chris@16
|
464
|
Chris@16
|
465 insert_range_impl2(a, k, i, j);
|
Chris@16
|
466
|
Chris@16
|
467 while(++i != j) {
|
Chris@16
|
468 // Note: can't use get_key as '*i' might not be value_type - it
|
Chris@16
|
469 // could be a pair with first_types as key_type without const or
|
Chris@16
|
470 // a different second_type.
|
Chris@16
|
471 //
|
Chris@16
|
472 // TODO: Might be worth storing the value_type instead of the
|
Chris@16
|
473 // key here. Could be more efficient if '*i' is expensive. Could
|
Chris@16
|
474 // be less efficient if copying the full value_type is
|
Chris@16
|
475 // expensive.
|
Chris@16
|
476 insert_range_impl2(a, extractor::extract(*i), i, j);
|
Chris@16
|
477 }
|
Chris@16
|
478 }
|
Chris@16
|
479
|
Chris@16
|
480 template <class InputIt>
|
Chris@16
|
481 void insert_range_impl2(node_constructor& a, key_type const& k,
|
Chris@16
|
482 InputIt i, InputIt j)
|
Chris@16
|
483 {
|
Chris@16
|
484 // No side effects in this initial code
|
Chris@16
|
485 std::size_t key_hash = this->hash(k);
|
Chris@16
|
486 iterator pos = this->find_node(key_hash, k);
|
Chris@16
|
487
|
Chris@16
|
488 if (!pos.node_) {
|
Chris@16
|
489 a.construct_with_value2(*i);
|
Chris@16
|
490 if(this->size_ + 1 > this->max_load_)
|
Chris@16
|
491 this->reserve_for_insert(this->size_ +
|
Chris@16
|
492 boost::unordered::detail::insert_size(i, j));
|
Chris@16
|
493
|
Chris@16
|
494 // Nothing after this point can throw.
|
Chris@16
|
495 this->add_node(a, key_hash);
|
Chris@16
|
496 }
|
Chris@16
|
497 }
|
Chris@16
|
498
|
Chris@16
|
499 template <class InputIt>
|
Chris@16
|
500 void insert_range_impl(no_key, InputIt i, InputIt j)
|
Chris@16
|
501 {
|
Chris@16
|
502 node_constructor a(this->node_alloc());
|
Chris@16
|
503
|
Chris@16
|
504 do {
|
Chris@16
|
505 a.construct_with_value2(*i);
|
Chris@16
|
506 emplace_impl_with_node(a);
|
Chris@16
|
507 } while(++i != j);
|
Chris@16
|
508 }
|
Chris@16
|
509
|
Chris@16
|
510 ////////////////////////////////////////////////////////////////////////
|
Chris@16
|
511 // Erase
|
Chris@16
|
512 //
|
Chris@16
|
513 // no throw
|
Chris@16
|
514
|
Chris@16
|
515 std::size_t erase_key(key_type const& k)
|
Chris@16
|
516 {
|
Chris@16
|
517 if(!this->size_) return 0;
|
Chris@16
|
518
|
Chris@16
|
519 std::size_t key_hash = this->hash(k);
|
Chris@16
|
520 std::size_t bucket_index = this->hash_to_bucket(key_hash);
|
Chris@16
|
521 link_pointer prev = this->get_previous_start(bucket_index);
|
Chris@16
|
522 if (!prev) return 0;
|
Chris@16
|
523
|
Chris@16
|
524 for (;;)
|
Chris@16
|
525 {
|
Chris@16
|
526 if (!prev->next_) return 0;
|
Chris@16
|
527 std::size_t node_hash =
|
Chris@16
|
528 static_cast<node_pointer>(prev->next_)->hash_;
|
Chris@16
|
529 if (this->hash_to_bucket(node_hash) != bucket_index)
|
Chris@16
|
530 return 0;
|
Chris@16
|
531 if (node_hash == key_hash &&
|
Chris@16
|
532 this->key_eq()(k, this->get_key(
|
Chris@16
|
533 static_cast<node_pointer>(prev->next_)->value())))
|
Chris@16
|
534 break;
|
Chris@16
|
535 prev = prev->next_;
|
Chris@16
|
536 }
|
Chris@16
|
537
|
Chris@16
|
538 link_pointer end = static_cast<node_pointer>(prev->next_)->next_;
|
Chris@16
|
539
|
Chris@101
|
540 std::size_t deleted_count = this->delete_nodes(prev, end);
|
Chris@16
|
541 this->fix_bucket(bucket_index, prev);
|
Chris@101
|
542 return deleted_count;
|
Chris@16
|
543 }
|
Chris@16
|
544
|
Chris@16
|
545 iterator erase(c_iterator r)
|
Chris@16
|
546 {
|
Chris@16
|
547 BOOST_ASSERT(r.node_);
|
Chris@16
|
548 iterator next(r.node_);
|
Chris@16
|
549 ++next;
|
Chris@16
|
550 erase_nodes(r.node_, next.node_);
|
Chris@16
|
551 return next;
|
Chris@16
|
552 }
|
Chris@16
|
553
|
Chris@16
|
554 iterator erase_range(c_iterator r1, c_iterator r2)
|
Chris@16
|
555 {
|
Chris@16
|
556 if (r1 == r2) return iterator(r2.node_);
|
Chris@16
|
557 erase_nodes(r1.node_, r2.node_);
|
Chris@16
|
558 return iterator(r2.node_);
|
Chris@16
|
559 }
|
Chris@16
|
560
|
Chris@101
|
561 void erase_nodes(node_pointer i, node_pointer j)
|
Chris@16
|
562 {
|
Chris@101
|
563 std::size_t bucket_index = this->hash_to_bucket(i->hash_);
|
Chris@16
|
564
|
Chris@101
|
565 // Find the node before i.
|
Chris@16
|
566 link_pointer prev = this->get_previous_start(bucket_index);
|
Chris@101
|
567 while(prev->next_ != i) prev = prev->next_;
|
Chris@16
|
568
|
Chris@16
|
569 // Delete the nodes.
|
Chris@16
|
570 do {
|
Chris@16
|
571 this->delete_node(prev);
|
Chris@16
|
572 bucket_index = this->fix_bucket(bucket_index, prev);
|
Chris@101
|
573 } while (prev->next_ != j);
|
Chris@16
|
574 }
|
Chris@16
|
575
|
Chris@16
|
576 ////////////////////////////////////////////////////////////////////////
|
Chris@16
|
577 // fill_buckets
|
Chris@16
|
578
|
Chris@16
|
579 template <class NodeCreator>
|
Chris@16
|
580 static void fill_buckets(iterator n, table& dst,
|
Chris@16
|
581 NodeCreator& creator)
|
Chris@16
|
582 {
|
Chris@16
|
583 link_pointer prev = dst.get_previous_start();
|
Chris@16
|
584
|
Chris@16
|
585 while (n.node_) {
|
Chris@16
|
586 node_pointer node = creator.create(*n);
|
Chris@16
|
587 node->hash_ = n.node_->hash_;
|
Chris@16
|
588 prev->next_ = node;
|
Chris@16
|
589 ++dst.size_;
|
Chris@16
|
590 ++n;
|
Chris@16
|
591
|
Chris@16
|
592 prev = place_in_bucket(dst, prev);
|
Chris@16
|
593 }
|
Chris@16
|
594 }
|
Chris@16
|
595
|
Chris@16
|
596 // strong otherwise exception safety
|
Chris@16
|
597 void rehash_impl(std::size_t num_buckets)
|
Chris@16
|
598 {
|
Chris@16
|
599 BOOST_ASSERT(this->buckets_);
|
Chris@16
|
600
|
Chris@16
|
601 this->create_buckets(num_buckets);
|
Chris@16
|
602 link_pointer prev = this->get_previous_start();
|
Chris@16
|
603 while (prev->next_)
|
Chris@16
|
604 prev = place_in_bucket(*this, prev);
|
Chris@16
|
605 }
|
Chris@16
|
606
|
Chris@16
|
607 // Iterate through the nodes placing them in the correct buckets.
|
Chris@16
|
608 // pre: prev->next_ is not null.
|
Chris@16
|
609 static link_pointer place_in_bucket(table& dst, link_pointer prev)
|
Chris@16
|
610 {
|
Chris@16
|
611 node_pointer n = static_cast<node_pointer>(prev->next_);
|
Chris@16
|
612 bucket_pointer b = dst.get_bucket(dst.hash_to_bucket(n->hash_));
|
Chris@16
|
613
|
Chris@16
|
614 if (!b->next_) {
|
Chris@16
|
615 b->next_ = prev;
|
Chris@16
|
616 return n;
|
Chris@16
|
617 }
|
Chris@16
|
618 else {
|
Chris@16
|
619 prev->next_ = n->next_;
|
Chris@16
|
620 n->next_ = b->next_->next_;
|
Chris@16
|
621 b->next_->next_ = n;
|
Chris@16
|
622 return prev;
|
Chris@16
|
623 }
|
Chris@16
|
624 }
|
Chris@16
|
625 };
|
Chris@16
|
626 }}}
|
Chris@16
|
627
|
Chris@16
|
628 #endif
|