williamr@2
|
1 |
/* Copyright 2003-2007 Joaquín M López Muñoz.
|
williamr@2
|
2 |
* Distributed under the Boost Software License, Version 1.0.
|
williamr@2
|
3 |
* (See accompanying file LICENSE_1_0.txt or copy at
|
williamr@2
|
4 |
* http://www.boost.org/LICENSE_1_0.txt)
|
williamr@2
|
5 |
*
|
williamr@2
|
6 |
* See http://www.boost.org/libs/multi_index for library home page.
|
williamr@2
|
7 |
*/
|
williamr@2
|
8 |
|
williamr@2
|
9 |
#ifndef BOOST_MULTI_INDEX_HASHED_INDEX_HPP
|
williamr@2
|
10 |
#define BOOST_MULTI_INDEX_HASHED_INDEX_HPP
|
williamr@2
|
11 |
|
williamr@2
|
12 |
#if defined(_MSC_VER)&&(_MSC_VER>=1200)
|
williamr@2
|
13 |
#pragma once
|
williamr@2
|
14 |
#endif
|
williamr@2
|
15 |
|
williamr@2
|
16 |
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
|
williamr@2
|
17 |
#include <algorithm>
|
williamr@2
|
18 |
#include <boost/call_traits.hpp>
|
williamr@2
|
19 |
#include <boost/detail/allocator_utilities.hpp>
|
williamr@2
|
20 |
#include <boost/detail/no_exceptions_support.hpp>
|
williamr@2
|
21 |
#include <boost/detail/workaround.hpp>
|
williamr@2
|
22 |
#include <boost/limits.hpp>
|
williamr@2
|
23 |
#include <boost/mpl/push_front.hpp>
|
williamr@2
|
24 |
#include <boost/multi_index/detail/access_specifier.hpp>
|
williamr@2
|
25 |
#include <boost/multi_index/detail/auto_space.hpp>
|
williamr@2
|
26 |
#include <boost/multi_index/detail/bucket_array.hpp>
|
williamr@2
|
27 |
#include <boost/multi_index/detail/hash_index_iterator.hpp>
|
williamr@2
|
28 |
#include <boost/multi_index/detail/modify_key_adaptor.hpp>
|
williamr@2
|
29 |
#include <boost/multi_index/detail/safe_ctr_proxy.hpp>
|
williamr@2
|
30 |
#include <boost/multi_index/detail/safe_mode.hpp>
|
williamr@2
|
31 |
#include <boost/multi_index/detail/scope_guard.hpp>
|
williamr@2
|
32 |
#include <boost/multi_index/hashed_index_fwd.hpp>
|
williamr@2
|
33 |
#include <boost/tuple/tuple.hpp>
|
williamr@2
|
34 |
#include <cstddef>
|
williamr@2
|
35 |
#include <functional>
|
williamr@2
|
36 |
#include <utility>
|
williamr@2
|
37 |
|
williamr@2
|
38 |
#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
|
williamr@2
|
39 |
#include <boost/serialization/nvp.hpp>
|
williamr@2
|
40 |
#endif
|
williamr@2
|
41 |
|
williamr@2
|
42 |
#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)
|
williamr@2
|
43 |
#define BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT \
|
williamr@2
|
44 |
detail::scope_guard BOOST_JOIN(check_invariant_,__LINE__)= \
|
williamr@2
|
45 |
detail::make_obj_guard(*this,&hashed_index::check_invariant_); \
|
williamr@2
|
46 |
BOOST_JOIN(check_invariant_,__LINE__).touch();
|
williamr@2
|
47 |
#else
|
williamr@2
|
48 |
#define BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT
|
williamr@2
|
49 |
#endif
|
williamr@2
|
50 |
|
williamr@2
|
51 |
namespace boost{
|
williamr@2
|
52 |
|
williamr@2
|
53 |
namespace multi_index{
|
williamr@2
|
54 |
|
williamr@2
|
55 |
namespace detail{
|
williamr@2
|
56 |
|
williamr@2
|
57 |
/* hashed_index adds a layer of hashed indexing to a given Super */
|
williamr@2
|
58 |
|
williamr@2
|
59 |
/* Most of the implementation of unique and non-unique indices is
|
williamr@2
|
60 |
* shared. We tell from one another on instantiation time by using
|
williamr@2
|
61 |
* these tags.
|
williamr@2
|
62 |
*/
|
williamr@2
|
63 |
|
williamr@2
|
64 |
struct hashed_unique_tag{};
|
williamr@2
|
65 |
struct hashed_non_unique_tag{};
|
williamr@2
|
66 |
|
williamr@2
|
67 |
template<
|
williamr@2
|
68 |
typename KeyFromValue,typename Hash,typename Pred,
|
williamr@2
|
69 |
typename SuperMeta,typename TagList,typename Category
|
williamr@2
|
70 |
>
|
williamr@2
|
71 |
class hashed_index:
|
williamr@2
|
72 |
BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS SuperMeta::type
|
williamr@2
|
73 |
|
williamr@2
|
74 |
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
williamr@2
|
75 |
#if BOOST_WORKAROUND(BOOST_MSVC,<1300)
|
williamr@2
|
76 |
,public safe_ctr_proxy_impl<
|
williamr@2
|
77 |
hashed_index_iterator<
|
williamr@2
|
78 |
hashed_index_node<typename SuperMeta::type::node_type>,
|
williamr@2
|
79 |
bucket_array<typename SuperMeta::type::final_allocator_type> >,
|
williamr@2
|
80 |
hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category> >
|
williamr@2
|
81 |
#else
|
williamr@2
|
82 |
,public safe_mode::safe_container<
|
williamr@2
|
83 |
hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category> >
|
williamr@2
|
84 |
#endif
|
williamr@2
|
85 |
#endif
|
williamr@2
|
86 |
|
williamr@2
|
87 |
{
|
williamr@2
|
88 |
#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)&&\
|
williamr@2
|
89 |
BOOST_WORKAROUND(__MWERKS__,<=0x3003)
|
williamr@2
|
90 |
/* The "ISO C++ Template Parser" option in CW8.3 has a problem with the
|
williamr@2
|
91 |
* lifetime of const references bound to temporaries --precisely what
|
williamr@2
|
92 |
* scopeguards are.
|
williamr@2
|
93 |
*/
|
williamr@2
|
94 |
|
williamr@2
|
95 |
#pragma parse_mfunc_templ off
|
williamr@2
|
96 |
#endif
|
williamr@2
|
97 |
|
williamr@2
|
98 |
typedef typename SuperMeta::type super;
|
williamr@2
|
99 |
|
williamr@2
|
100 |
protected:
|
williamr@2
|
101 |
typedef hashed_index_node<
|
williamr@2
|
102 |
typename super::node_type> node_type;
|
williamr@2
|
103 |
typedef bucket_array<
|
williamr@2
|
104 |
typename super::final_allocator_type> bucket_array_type;
|
williamr@2
|
105 |
|
williamr@2
|
106 |
public:
|
williamr@2
|
107 |
/* types */
|
williamr@2
|
108 |
|
williamr@2
|
109 |
typedef typename KeyFromValue::result_type key_type;
|
williamr@2
|
110 |
typedef typename node_type::value_type value_type;
|
williamr@2
|
111 |
typedef KeyFromValue key_from_value;
|
williamr@2
|
112 |
typedef Hash hasher;
|
williamr@2
|
113 |
typedef Pred key_equal;
|
williamr@2
|
114 |
typedef tuple<std::size_t,
|
williamr@2
|
115 |
key_from_value,hasher,key_equal> ctor_args;
|
williamr@2
|
116 |
typedef typename super::final_allocator_type allocator_type;
|
williamr@2
|
117 |
typedef typename allocator_type::pointer pointer;
|
williamr@2
|
118 |
typedef typename allocator_type::const_pointer const_pointer;
|
williamr@2
|
119 |
typedef typename allocator_type::reference reference;
|
williamr@2
|
120 |
typedef typename allocator_type::const_reference const_reference;
|
williamr@2
|
121 |
typedef std::size_t size_type;
|
williamr@2
|
122 |
typedef std::ptrdiff_t difference_type;
|
williamr@2
|
123 |
|
williamr@2
|
124 |
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
williamr@2
|
125 |
#if BOOST_WORKAROUND(BOOST_MSVC,<1300)
|
williamr@2
|
126 |
typedef safe_mode::safe_iterator<
|
williamr@2
|
127 |
hashed_index_iterator<
|
williamr@2
|
128 |
node_type,bucket_array_type>,
|
williamr@2
|
129 |
safe_ctr_proxy<
|
williamr@2
|
130 |
hashed_index_iterator<
|
williamr@2
|
131 |
node_type,bucket_array_type> > > iterator;
|
williamr@2
|
132 |
#else
|
williamr@2
|
133 |
typedef safe_mode::safe_iterator<
|
williamr@2
|
134 |
hashed_index_iterator<
|
williamr@2
|
135 |
node_type,bucket_array_type>,
|
williamr@2
|
136 |
hashed_index> iterator;
|
williamr@2
|
137 |
#endif
|
williamr@2
|
138 |
#else
|
williamr@2
|
139 |
typedef hashed_index_iterator<
|
williamr@2
|
140 |
node_type,bucket_array_type> iterator;
|
williamr@2
|
141 |
#endif
|
williamr@2
|
142 |
|
williamr@2
|
143 |
typedef iterator const_iterator;
|
williamr@2
|
144 |
|
williamr@2
|
145 |
typedef iterator local_iterator;
|
williamr@2
|
146 |
typedef const_iterator const_local_iterator;
|
williamr@2
|
147 |
typedef TagList tag_list;
|
williamr@2
|
148 |
|
williamr@2
|
149 |
protected:
|
williamr@2
|
150 |
typedef typename super::final_node_type final_node_type;
|
williamr@2
|
151 |
typedef tuples::cons<
|
williamr@2
|
152 |
ctor_args,
|
williamr@2
|
153 |
typename super::ctor_args_list> ctor_args_list;
|
williamr@2
|
154 |
typedef typename mpl::push_front<
|
williamr@2
|
155 |
typename super::index_type_list,
|
williamr@2
|
156 |
hashed_index>::type index_type_list;
|
williamr@2
|
157 |
typedef typename mpl::push_front<
|
williamr@2
|
158 |
typename super::iterator_type_list,
|
williamr@2
|
159 |
iterator>::type iterator_type_list;
|
williamr@2
|
160 |
typedef typename mpl::push_front<
|
williamr@2
|
161 |
typename super::const_iterator_type_list,
|
williamr@2
|
162 |
const_iterator>::type const_iterator_type_list;
|
williamr@2
|
163 |
typedef typename super::copy_map_type copy_map_type;
|
williamr@2
|
164 |
|
williamr@2
|
165 |
#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
|
williamr@2
|
166 |
typedef typename super::index_saver_type index_saver_type;
|
williamr@2
|
167 |
typedef typename super::index_loader_type index_loader_type;
|
williamr@2
|
168 |
#endif
|
williamr@2
|
169 |
|
williamr@2
|
170 |
private:
|
williamr@2
|
171 |
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
williamr@2
|
172 |
#if BOOST_WORKAROUND(BOOST_MSVC,<1300)
|
williamr@2
|
173 |
typedef safe_ctr_proxy_impl<
|
williamr@2
|
174 |
hashed_index_iterator<
|
williamr@2
|
175 |
node_type,
|
williamr@2
|
176 |
bucket_array_type>,
|
williamr@2
|
177 |
hashed_index> safe_super;
|
williamr@2
|
178 |
#else
|
williamr@2
|
179 |
typedef safe_mode::safe_container<
|
williamr@2
|
180 |
hashed_index> safe_super;
|
williamr@2
|
181 |
#endif
|
williamr@2
|
182 |
#endif
|
williamr@2
|
183 |
|
williamr@2
|
184 |
typedef typename call_traits<value_type>::param_type value_param_type;
|
williamr@2
|
185 |
typedef typename call_traits<
|
williamr@2
|
186 |
key_type>::param_type key_param_type;
|
williamr@2
|
187 |
|
williamr@2
|
188 |
public:
|
williamr@2
|
189 |
|
williamr@2
|
190 |
/* construct/destroy/copy
|
williamr@2
|
191 |
* Default and copy ctors are in the protected section as indices are
|
williamr@2
|
192 |
* not supposed to be created on their own. No range ctor either.
|
williamr@2
|
193 |
*/
|
williamr@2
|
194 |
|
williamr@2
|
195 |
hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& operator=(
|
williamr@2
|
196 |
const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x)
|
williamr@2
|
197 |
{
|
williamr@2
|
198 |
this->final()=x.final();
|
williamr@2
|
199 |
return *this;
|
williamr@2
|
200 |
}
|
williamr@2
|
201 |
|
williamr@2
|
202 |
allocator_type get_allocator()const
|
williamr@2
|
203 |
{
|
williamr@2
|
204 |
return this->final().get_allocator();
|
williamr@2
|
205 |
}
|
williamr@2
|
206 |
|
williamr@2
|
207 |
/* size and capacity */
|
williamr@2
|
208 |
|
williamr@2
|
209 |
bool empty()const{return this->final_empty_();}
|
williamr@2
|
210 |
size_type size()const{return this->final_size_();}
|
williamr@2
|
211 |
size_type max_size()const{return this->final_max_size_();}
|
williamr@2
|
212 |
|
williamr@2
|
213 |
/* iterators */
|
williamr@2
|
214 |
|
williamr@2
|
215 |
iterator begin()
|
williamr@2
|
216 |
{
|
williamr@2
|
217 |
return make_iterator(
|
williamr@2
|
218 |
node_type::from_impl(buckets.at(first_bucket)->next()));
|
williamr@2
|
219 |
}
|
williamr@2
|
220 |
|
williamr@2
|
221 |
const_iterator begin()const
|
williamr@2
|
222 |
{
|
williamr@2
|
223 |
return make_iterator(
|
williamr@2
|
224 |
node_type::from_impl(buckets.at(first_bucket)->next()));
|
williamr@2
|
225 |
}
|
williamr@2
|
226 |
|
williamr@2
|
227 |
iterator end(){return make_iterator(header());}
|
williamr@2
|
228 |
const_iterator end()const{return make_iterator(header());}
|
williamr@2
|
229 |
|
williamr@2
|
230 |
/* modifiers */
|
williamr@2
|
231 |
|
williamr@2
|
232 |
std::pair<iterator,bool> insert(value_param_type x)
|
williamr@2
|
233 |
{
|
williamr@2
|
234 |
BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
|
williamr@2
|
235 |
std::pair<final_node_type*,bool> p=this->final_insert_(x);
|
williamr@2
|
236 |
return std::pair<iterator,bool>(make_iterator(p.first),p.second);
|
williamr@2
|
237 |
}
|
williamr@2
|
238 |
|
williamr@2
|
239 |
iterator insert(iterator position,value_param_type x)
|
williamr@2
|
240 |
{
|
williamr@2
|
241 |
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
|
williamr@2
|
242 |
BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
|
williamr@2
|
243 |
BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
|
williamr@2
|
244 |
std::pair<final_node_type*,bool> p=this->final_insert_(
|
williamr@2
|
245 |
x,static_cast<final_node_type*>(position.get_node()));
|
williamr@2
|
246 |
return make_iterator(p.first);
|
williamr@2
|
247 |
}
|
williamr@2
|
248 |
|
williamr@2
|
249 |
template<typename InputIterator>
|
williamr@2
|
250 |
void insert(InputIterator first,InputIterator last)
|
williamr@2
|
251 |
{
|
williamr@2
|
252 |
BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
|
williamr@2
|
253 |
iterator hint=end();
|
williamr@2
|
254 |
for(;first!=last;++first)hint=insert(hint,*first);
|
williamr@2
|
255 |
}
|
williamr@2
|
256 |
|
williamr@2
|
257 |
iterator erase(iterator position)
|
williamr@2
|
258 |
{
|
williamr@2
|
259 |
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
|
williamr@2
|
260 |
BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
|
williamr@2
|
261 |
BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
|
williamr@2
|
262 |
BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
|
williamr@2
|
263 |
this->final_erase_(static_cast<final_node_type*>(position++.get_node()));
|
williamr@2
|
264 |
return position;
|
williamr@2
|
265 |
}
|
williamr@2
|
266 |
|
williamr@2
|
267 |
size_type erase(key_param_type k)
|
williamr@2
|
268 |
{
|
williamr@2
|
269 |
BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
|
williamr@2
|
270 |
|
williamr@2
|
271 |
size_type s=0;
|
williamr@2
|
272 |
std::size_t buc=buckets.position(hash(k));
|
williamr@2
|
273 |
hashed_index_node_impl* x=buckets.at(buc);
|
williamr@2
|
274 |
hashed_index_node_impl* y=x->next();
|
williamr@2
|
275 |
while(y!=x){
|
williamr@2
|
276 |
if(eq(k,key(node_type::from_impl(y)->value()))){
|
williamr@2
|
277 |
bool b;
|
williamr@2
|
278 |
do{
|
williamr@2
|
279 |
hashed_index_node_impl* z=y->next();
|
williamr@2
|
280 |
b=z!=x&&eq(
|
williamr@2
|
281 |
key(node_type::from_impl(y)->value()),
|
williamr@2
|
282 |
key(node_type::from_impl(z)->value()));
|
williamr@2
|
283 |
this->final_erase_(
|
williamr@2
|
284 |
static_cast<final_node_type*>(node_type::from_impl(y)));
|
williamr@2
|
285 |
y=z;
|
williamr@2
|
286 |
++s;
|
williamr@2
|
287 |
}while(b);
|
williamr@2
|
288 |
break;
|
williamr@2
|
289 |
}
|
williamr@2
|
290 |
y=y->next();
|
williamr@2
|
291 |
}
|
williamr@2
|
292 |
return s;
|
williamr@2
|
293 |
}
|
williamr@2
|
294 |
|
williamr@2
|
295 |
iterator erase(iterator first,iterator last)
|
williamr@2
|
296 |
{
|
williamr@2
|
297 |
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(first);
|
williamr@2
|
298 |
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(last);
|
williamr@2
|
299 |
BOOST_MULTI_INDEX_CHECK_IS_OWNER(first,*this);
|
williamr@2
|
300 |
BOOST_MULTI_INDEX_CHECK_IS_OWNER(last,*this);
|
williamr@2
|
301 |
BOOST_MULTI_INDEX_CHECK_VALID_RANGE(first,last);
|
williamr@2
|
302 |
BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
|
williamr@2
|
303 |
while(first!=last){
|
williamr@2
|
304 |
first=erase(first);
|
williamr@2
|
305 |
}
|
williamr@2
|
306 |
return first;
|
williamr@2
|
307 |
}
|
williamr@2
|
308 |
|
williamr@2
|
309 |
bool replace(iterator position,value_param_type x)
|
williamr@2
|
310 |
{
|
williamr@2
|
311 |
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
|
williamr@2
|
312 |
BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
|
williamr@2
|
313 |
BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
|
williamr@2
|
314 |
BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
|
williamr@2
|
315 |
return this->final_replace_(
|
williamr@2
|
316 |
x,static_cast<final_node_type*>(position.get_node()));
|
williamr@2
|
317 |
}
|
williamr@2
|
318 |
|
williamr@2
|
319 |
template<typename Modifier>
|
williamr@2
|
320 |
bool modify(iterator position,Modifier mod)
|
williamr@2
|
321 |
{
|
williamr@2
|
322 |
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
|
williamr@2
|
323 |
BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
|
williamr@2
|
324 |
BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
|
williamr@2
|
325 |
BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
|
williamr@2
|
326 |
|
williamr@2
|
327 |
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
williamr@2
|
328 |
/* MSVC++ 6.0 optimizer on safe mode code chokes if this
|
williamr@2
|
329 |
* this is not added. Left it for all compilers as it does no
|
williamr@2
|
330 |
* harm.
|
williamr@2
|
331 |
*/
|
williamr@2
|
332 |
|
williamr@2
|
333 |
position.detach();
|
williamr@2
|
334 |
#endif
|
williamr@2
|
335 |
|
williamr@2
|
336 |
return this->final_modify_(
|
williamr@2
|
337 |
mod,static_cast<final_node_type*>(position.get_node()));
|
williamr@2
|
338 |
}
|
williamr@2
|
339 |
|
williamr@2
|
340 |
template<typename Modifier>
|
williamr@2
|
341 |
bool modify_key(iterator position,Modifier mod)
|
williamr@2
|
342 |
{
|
williamr@2
|
343 |
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
|
williamr@2
|
344 |
BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
|
williamr@2
|
345 |
BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
|
williamr@2
|
346 |
BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
|
williamr@2
|
347 |
return modify(
|
williamr@2
|
348 |
position,modify_key_adaptor<Modifier,value_type,KeyFromValue>(mod,key));
|
williamr@2
|
349 |
}
|
williamr@2
|
350 |
|
williamr@2
|
351 |
void clear()
|
williamr@2
|
352 |
{
|
williamr@2
|
353 |
BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
|
williamr@2
|
354 |
this->final_clear_();
|
williamr@2
|
355 |
}
|
williamr@2
|
356 |
|
williamr@2
|
357 |
void swap(hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x)
|
williamr@2
|
358 |
{
|
williamr@2
|
359 |
BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
|
williamr@2
|
360 |
this->final_swap_(x.final());
|
williamr@2
|
361 |
}
|
williamr@2
|
362 |
|
williamr@2
|
363 |
/* observers */
|
williamr@2
|
364 |
|
williamr@2
|
365 |
key_from_value key_extractor()const{return key;}
|
williamr@2
|
366 |
hasher hash_function()const{return hash;}
|
williamr@2
|
367 |
key_equal key_eq()const{return eq;}
|
williamr@2
|
368 |
|
williamr@2
|
369 |
/* lookup */
|
williamr@2
|
370 |
|
williamr@2
|
371 |
/* Internally, these ops rely on const_iterator being the same
|
williamr@2
|
372 |
* type as iterator.
|
williamr@2
|
373 |
*/
|
williamr@2
|
374 |
|
williamr@2
|
375 |
template<typename CompatibleKey>
|
williamr@2
|
376 |
iterator find(const CompatibleKey& k)const
|
williamr@2
|
377 |
{
|
williamr@2
|
378 |
return find(k,hash,eq);
|
williamr@2
|
379 |
}
|
williamr@2
|
380 |
|
williamr@2
|
381 |
template<
|
williamr@2
|
382 |
typename CompatibleKey,typename CompatibleHash,typename CompatiblePred
|
williamr@2
|
383 |
>
|
williamr@2
|
384 |
iterator find(
|
williamr@2
|
385 |
const CompatibleKey& k,
|
williamr@2
|
386 |
const CompatibleHash& hash,const CompatiblePred& eq)const
|
williamr@2
|
387 |
{
|
williamr@2
|
388 |
std::size_t buc=buckets.position(hash(k));
|
williamr@2
|
389 |
hashed_index_node_impl* x=buckets.at(buc);
|
williamr@2
|
390 |
hashed_index_node_impl* y=x->next();
|
williamr@2
|
391 |
while(y!=x){
|
williamr@2
|
392 |
if(eq(k,key(node_type::from_impl(y)->value()))){
|
williamr@2
|
393 |
return make_iterator(node_type::from_impl(y));
|
williamr@2
|
394 |
}
|
williamr@2
|
395 |
y=y->next();
|
williamr@2
|
396 |
}
|
williamr@2
|
397 |
return end();
|
williamr@2
|
398 |
}
|
williamr@2
|
399 |
|
williamr@2
|
400 |
template<typename CompatibleKey>
|
williamr@2
|
401 |
size_type count(const CompatibleKey& k)const
|
williamr@2
|
402 |
{
|
williamr@2
|
403 |
return count(k,hash,eq);
|
williamr@2
|
404 |
}
|
williamr@2
|
405 |
|
williamr@2
|
406 |
template<
|
williamr@2
|
407 |
typename CompatibleKey,typename CompatibleHash,typename CompatiblePred
|
williamr@2
|
408 |
>
|
williamr@2
|
409 |
size_type count(
|
williamr@2
|
410 |
const CompatibleKey& k,
|
williamr@2
|
411 |
const CompatibleHash& hash,const CompatiblePred& eq)const
|
williamr@2
|
412 |
{
|
williamr@2
|
413 |
size_type res=0;
|
williamr@2
|
414 |
std::size_t buc=buckets.position(hash(k));
|
williamr@2
|
415 |
hashed_index_node_impl* x=buckets.at(buc);
|
williamr@2
|
416 |
hashed_index_node_impl* y=x->next();
|
williamr@2
|
417 |
while(y!=x){
|
williamr@2
|
418 |
if(eq(k,key(node_type::from_impl(y)->value()))){
|
williamr@2
|
419 |
do{
|
williamr@2
|
420 |
++res;
|
williamr@2
|
421 |
y=y->next();
|
williamr@2
|
422 |
}while(y!=x&&eq(k,key(node_type::from_impl(y)->value())));
|
williamr@2
|
423 |
break;
|
williamr@2
|
424 |
}
|
williamr@2
|
425 |
y=y->next();
|
williamr@2
|
426 |
}
|
williamr@2
|
427 |
return res;
|
williamr@2
|
428 |
}
|
williamr@2
|
429 |
|
williamr@2
|
430 |
template<typename CompatibleKey>
|
williamr@2
|
431 |
std::pair<iterator,iterator> equal_range(const CompatibleKey& k)const
|
williamr@2
|
432 |
{
|
williamr@2
|
433 |
return equal_range(k,hash,eq);
|
williamr@2
|
434 |
}
|
williamr@2
|
435 |
|
williamr@2
|
436 |
template<
|
williamr@2
|
437 |
typename CompatibleKey,typename CompatibleHash,typename CompatiblePred
|
williamr@2
|
438 |
>
|
williamr@2
|
439 |
std::pair<iterator,iterator> equal_range(
|
williamr@2
|
440 |
const CompatibleKey& k,
|
williamr@2
|
441 |
const CompatibleHash& hash,const CompatiblePred& eq)const
|
williamr@2
|
442 |
{
|
williamr@2
|
443 |
std::size_t buc=buckets.position(hash(k));
|
williamr@2
|
444 |
hashed_index_node_impl* x=buckets.at(buc);
|
williamr@2
|
445 |
hashed_index_node_impl* y=x->next();
|
williamr@2
|
446 |
while(y!=x){
|
williamr@2
|
447 |
if(eq(k,key(node_type::from_impl(y)->value()))){
|
williamr@2
|
448 |
hashed_index_node_impl* y0=y;
|
williamr@2
|
449 |
do{
|
williamr@2
|
450 |
y=y->next();
|
williamr@2
|
451 |
}while(y!=x&&eq(k,key(node_type::from_impl(y)->value())));
|
williamr@2
|
452 |
if(y==x){
|
williamr@2
|
453 |
do{
|
williamr@2
|
454 |
++y;
|
williamr@2
|
455 |
}while(y==y->next());
|
williamr@2
|
456 |
y=y->next();
|
williamr@2
|
457 |
}
|
williamr@2
|
458 |
return std::pair<iterator,iterator>(
|
williamr@2
|
459 |
make_iterator(node_type::from_impl(y0)),
|
williamr@2
|
460 |
make_iterator(node_type::from_impl(y)));
|
williamr@2
|
461 |
}
|
williamr@2
|
462 |
y=y->next();
|
williamr@2
|
463 |
}
|
williamr@2
|
464 |
return std::pair<iterator,iterator>(end(),end());
|
williamr@2
|
465 |
}
|
williamr@2
|
466 |
|
williamr@2
|
467 |
/* bucket interface */
|
williamr@2
|
468 |
|
williamr@2
|
469 |
size_type bucket_count()const{return buckets.size();}
|
williamr@2
|
470 |
size_type max_bucket_count()const{return static_cast<size_type>(-1);}
|
williamr@2
|
471 |
|
williamr@2
|
472 |
size_type bucket_size(size_type n)const
|
williamr@2
|
473 |
{
|
williamr@2
|
474 |
size_type res=0;
|
williamr@2
|
475 |
hashed_index_node_impl* x=buckets.at(n);
|
williamr@2
|
476 |
hashed_index_node_impl* y=x->next();
|
williamr@2
|
477 |
while(y!=x){
|
williamr@2
|
478 |
++res;
|
williamr@2
|
479 |
y=y->next();
|
williamr@2
|
480 |
}
|
williamr@2
|
481 |
return res;
|
williamr@2
|
482 |
}
|
williamr@2
|
483 |
|
williamr@2
|
484 |
size_type bucket(key_param_type k)const
|
williamr@2
|
485 |
{
|
williamr@2
|
486 |
return buckets.position(hash(k));
|
williamr@2
|
487 |
}
|
williamr@2
|
488 |
|
williamr@2
|
489 |
local_iterator begin(size_type n)
|
williamr@2
|
490 |
{
|
williamr@2
|
491 |
return const_cast<const hashed_index*>(this)->begin(n);
|
williamr@2
|
492 |
}
|
williamr@2
|
493 |
|
williamr@2
|
494 |
const_local_iterator begin(size_type n)const
|
williamr@2
|
495 |
{
|
williamr@2
|
496 |
hashed_index_node_impl* x=buckets.at(n);
|
williamr@2
|
497 |
hashed_index_node_impl* y=x->next();
|
williamr@2
|
498 |
if(y==x)return end();
|
williamr@2
|
499 |
return make_iterator(node_type::from_impl(y));
|
williamr@2
|
500 |
}
|
williamr@2
|
501 |
|
williamr@2
|
502 |
local_iterator end(size_type n)
|
williamr@2
|
503 |
{
|
williamr@2
|
504 |
return const_cast<const hashed_index*>(this)->end(n);
|
williamr@2
|
505 |
}
|
williamr@2
|
506 |
|
williamr@2
|
507 |
const_local_iterator end(size_type n)const
|
williamr@2
|
508 |
{
|
williamr@2
|
509 |
hashed_index_node_impl* x=buckets.at(n);
|
williamr@2
|
510 |
if(x==x->next())return end();
|
williamr@2
|
511 |
do{
|
williamr@2
|
512 |
++x;
|
williamr@2
|
513 |
}while(x==x->next());
|
williamr@2
|
514 |
return make_iterator(node_type::from_impl(x->next()));
|
williamr@2
|
515 |
}
|
williamr@2
|
516 |
|
williamr@2
|
517 |
/* hash policy */
|
williamr@2
|
518 |
|
williamr@2
|
519 |
float load_factor()const{return static_cast<float>(size())/bucket_count();}
|
williamr@2
|
520 |
float max_load_factor()const{return mlf;}
|
williamr@2
|
521 |
void max_load_factor(float z){mlf=z;calculate_max_load();}
|
williamr@2
|
522 |
|
williamr@2
|
523 |
void rehash(size_type n)
|
williamr@2
|
524 |
{
|
williamr@2
|
525 |
BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
|
williamr@2
|
526 |
if(size()<max_load&&n<=bucket_count())return;
|
williamr@2
|
527 |
|
williamr@2
|
528 |
size_type bc =(std::numeric_limits<size_type>::max)();
|
williamr@2
|
529 |
float fbc=static_cast<float>(1+size()/mlf);
|
williamr@2
|
530 |
if(bc>fbc){
|
williamr@2
|
531 |
bc=static_cast<size_type>(fbc);
|
williamr@2
|
532 |
if(bc<n)bc=n;
|
williamr@2
|
533 |
}
|
williamr@2
|
534 |
unchecked_rehash(bc);
|
williamr@2
|
535 |
}
|
williamr@2
|
536 |
|
williamr@2
|
537 |
BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
williamr@2
|
538 |
hashed_index(const ctor_args_list& args_list,const allocator_type& al):
|
williamr@2
|
539 |
super(args_list.get_tail(),al),
|
williamr@2
|
540 |
key(tuples::get<1>(args_list.get_head())),
|
williamr@2
|
541 |
hash(tuples::get<2>(args_list.get_head())),
|
williamr@2
|
542 |
eq(tuples::get<3>(args_list.get_head())),
|
williamr@2
|
543 |
buckets(al,header()->impl(),tuples::get<0>(args_list.get_head())),
|
williamr@2
|
544 |
mlf(1.0),
|
williamr@2
|
545 |
first_bucket(buckets.size())
|
williamr@2
|
546 |
{
|
williamr@2
|
547 |
calculate_max_load();
|
williamr@2
|
548 |
}
|
williamr@2
|
549 |
|
williamr@2
|
550 |
hashed_index(
|
williamr@2
|
551 |
const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x):
|
williamr@2
|
552 |
super(x),
|
williamr@2
|
553 |
|
williamr@2
|
554 |
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
williamr@2
|
555 |
safe_super(),
|
williamr@2
|
556 |
#endif
|
williamr@2
|
557 |
|
williamr@2
|
558 |
key(x.key),
|
williamr@2
|
559 |
hash(x.hash),
|
williamr@2
|
560 |
eq(x.eq),
|
williamr@2
|
561 |
buckets(x.get_allocator(),header()->impl(),x.buckets.size()),
|
williamr@2
|
562 |
mlf(x.mlf),
|
williamr@2
|
563 |
max_load(x.max_load),
|
williamr@2
|
564 |
first_bucket(x.first_bucket)
|
williamr@2
|
565 |
{
|
williamr@2
|
566 |
/* Copy ctor just takes the internal configuration objects from x. The rest
|
williamr@2
|
567 |
* is done in subsequent call to copy_().
|
williamr@2
|
568 |
*/
|
williamr@2
|
569 |
}
|
williamr@2
|
570 |
|
williamr@2
|
571 |
~hashed_index()
|
williamr@2
|
572 |
{
|
williamr@2
|
573 |
/* the container is guaranteed to be empty by now */
|
williamr@2
|
574 |
}
|
williamr@2
|
575 |
|
williamr@2
|
576 |
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
williamr@2
|
577 |
iterator make_iterator(node_type* node)
|
williamr@2
|
578 |
{
|
williamr@2
|
579 |
return iterator(node,&buckets,this);
|
williamr@2
|
580 |
}
|
williamr@2
|
581 |
|
williamr@2
|
582 |
const_iterator make_iterator(node_type* node)const
|
williamr@2
|
583 |
{
|
williamr@2
|
584 |
return const_iterator(
|
williamr@2
|
585 |
node,
|
williamr@2
|
586 |
&const_cast<bucket_array_type&>(buckets),
|
williamr@2
|
587 |
const_cast<hashed_index*>(this));
|
williamr@2
|
588 |
}
|
williamr@2
|
589 |
#else
|
williamr@2
|
590 |
iterator make_iterator(node_type* node)
|
williamr@2
|
591 |
{
|
williamr@2
|
592 |
return iterator(node,&buckets);
|
williamr@2
|
593 |
}
|
williamr@2
|
594 |
|
williamr@2
|
595 |
const_iterator make_iterator(node_type* node)const
|
williamr@2
|
596 |
{
|
williamr@2
|
597 |
return const_iterator(node,&const_cast<bucket_array_type&>(buckets));
|
williamr@2
|
598 |
}
|
williamr@2
|
599 |
#endif
|
williamr@2
|
600 |
|
williamr@2
|
601 |
void copy_(
|
williamr@2
|
602 |
const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x,
|
williamr@2
|
603 |
const copy_map_type& map)
|
williamr@2
|
604 |
{
|
williamr@2
|
605 |
for(hashed_index_node_impl* begin_org=x.buckets.begin(),
|
williamr@2
|
606 |
* begin_cpy=buckets.begin(),
|
williamr@2
|
607 |
* end_org=x.buckets.end();
|
williamr@2
|
608 |
begin_org!=end_org;++begin_org,++begin_cpy){
|
williamr@2
|
609 |
|
williamr@2
|
610 |
hashed_index_node_impl* next_org=begin_org->next();
|
williamr@2
|
611 |
hashed_index_node_impl* cpy=begin_cpy;
|
williamr@2
|
612 |
while(next_org!=begin_org){
|
williamr@2
|
613 |
cpy->next()=
|
williamr@2
|
614 |
static_cast<node_type*>(
|
williamr@2
|
615 |
map.find(
|
williamr@2
|
616 |
static_cast<final_node_type*>(
|
williamr@2
|
617 |
node_type::from_impl(next_org))))->impl();
|
williamr@2
|
618 |
next_org=next_org->next();
|
williamr@2
|
619 |
cpy=cpy->next();
|
williamr@2
|
620 |
}
|
williamr@2
|
621 |
cpy->next()=begin_cpy;
|
williamr@2
|
622 |
}
|
williamr@2
|
623 |
|
williamr@2
|
624 |
super::copy_(x,map);
|
williamr@2
|
625 |
}
|
williamr@2
|
626 |
|
williamr@2
|
627 |
node_type* insert_(value_param_type v,node_type* x)
|
williamr@2
|
628 |
{
|
williamr@2
|
629 |
reserve(size()+1);
|
williamr@2
|
630 |
|
williamr@2
|
631 |
std::size_t buc=find_bucket(v);
|
williamr@2
|
632 |
hashed_index_node_impl* pos=buckets.at(buc);
|
williamr@2
|
633 |
if(!link_point(v,pos,Category()))return node_type::from_impl(pos);
|
williamr@2
|
634 |
|
williamr@2
|
635 |
node_type* res=static_cast<node_type*>(super::insert_(v,x));
|
williamr@2
|
636 |
if(res==x){
|
williamr@2
|
637 |
link(x,pos);
|
williamr@2
|
638 |
if(first_bucket>buc)first_bucket=buc;
|
williamr@2
|
639 |
}
|
williamr@2
|
640 |
return res;
|
williamr@2
|
641 |
}
|
williamr@2
|
642 |
|
williamr@2
|
643 |
node_type* insert_(value_param_type v,node_type* position,node_type* x)
|
williamr@2
|
644 |
{
|
williamr@2
|
645 |
reserve(size()+1);
|
williamr@2
|
646 |
|
williamr@2
|
647 |
std::size_t buc=find_bucket(v);
|
williamr@2
|
648 |
hashed_index_node_impl* pos=buckets.at(buc);
|
williamr@2
|
649 |
if(!link_point(v,pos,Category()))return node_type::from_impl(pos);
|
williamr@2
|
650 |
|
williamr@2
|
651 |
node_type* res=static_cast<node_type*>(super::insert_(v,position,x));
|
williamr@2
|
652 |
if(res==x){
|
williamr@2
|
653 |
link(x,pos);
|
williamr@2
|
654 |
if(first_bucket>buc)first_bucket=buc;
|
williamr@2
|
655 |
}
|
williamr@2
|
656 |
return res;
|
williamr@2
|
657 |
}
|
williamr@2
|
658 |
|
williamr@2
|
659 |
void erase_(node_type* x)
|
williamr@2
|
660 |
{
|
williamr@2
|
661 |
unlink(x);
|
williamr@2
|
662 |
first_bucket=buckets.first_nonempty(first_bucket);
|
williamr@2
|
663 |
super::erase_(x);
|
williamr@2
|
664 |
|
williamr@2
|
665 |
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
williamr@2
|
666 |
detach_iterators(x);
|
williamr@2
|
667 |
#endif
|
williamr@2
|
668 |
}
|
williamr@2
|
669 |
|
williamr@2
|
670 |
void delete_all_nodes_()
|
williamr@2
|
671 |
{
|
williamr@2
|
672 |
for(hashed_index_node_impl* x=buckets.begin(),*x_end=buckets.end();
|
williamr@2
|
673 |
x!=x_end;++x){
|
williamr@2
|
674 |
hashed_index_node_impl* y=x->next();
|
williamr@2
|
675 |
while(y!=x){
|
williamr@2
|
676 |
hashed_index_node_impl* z=y->next();
|
williamr@2
|
677 |
this->final_delete_node_(
|
williamr@2
|
678 |
static_cast<final_node_type*>(node_type::from_impl(y)));
|
williamr@2
|
679 |
y=z;
|
williamr@2
|
680 |
}
|
williamr@2
|
681 |
}
|
williamr@2
|
682 |
}
|
williamr@2
|
683 |
|
williamr@2
|
684 |
void clear_()
|
williamr@2
|
685 |
{
|
williamr@2
|
686 |
super::clear_();
|
williamr@2
|
687 |
buckets.clear();
|
williamr@2
|
688 |
first_bucket=buckets.size();
|
williamr@2
|
689 |
|
williamr@2
|
690 |
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
williamr@2
|
691 |
safe_super::detach_dereferenceable_iterators();
|
williamr@2
|
692 |
#endif
|
williamr@2
|
693 |
}
|
williamr@2
|
694 |
|
williamr@2
|
695 |
void swap_(
|
williamr@2
|
696 |
hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x)
|
williamr@2
|
697 |
{
|
williamr@2
|
698 |
std::swap(key,x.key);
|
williamr@2
|
699 |
std::swap(hash,x.hash);
|
williamr@2
|
700 |
std::swap(eq,x.eq);
|
williamr@2
|
701 |
buckets.swap(x.buckets);
|
williamr@2
|
702 |
std::swap(mlf,x.mlf);
|
williamr@2
|
703 |
std::swap(max_load,x.max_load);
|
williamr@2
|
704 |
std::swap(first_bucket,x.first_bucket);
|
williamr@2
|
705 |
|
williamr@2
|
706 |
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
williamr@2
|
707 |
safe_super::swap(x);
|
williamr@2
|
708 |
#endif
|
williamr@2
|
709 |
|
williamr@2
|
710 |
super::swap_(x);
|
williamr@2
|
711 |
}
|
williamr@2
|
712 |
|
williamr@2
|
713 |
bool replace_(value_param_type v,node_type* x)
|
williamr@2
|
714 |
{
|
williamr@2
|
715 |
if(eq(key(v),key(x->value()))){
|
williamr@2
|
716 |
return super::replace_(v,x);
|
williamr@2
|
717 |
}
|
williamr@2
|
718 |
|
williamr@2
|
719 |
hashed_index_node_impl* y=prev(x);
|
williamr@2
|
720 |
unlink_next(y);
|
williamr@2
|
721 |
|
williamr@2
|
722 |
BOOST_TRY{
|
williamr@2
|
723 |
std::size_t buc=find_bucket(v);
|
williamr@2
|
724 |
hashed_index_node_impl* pos=buckets.at(buc);
|
williamr@2
|
725 |
if(link_point(v,pos,Category())&&super::replace_(v,x)){
|
williamr@2
|
726 |
link(x,pos);
|
williamr@2
|
727 |
if(first_bucket>buc){
|
williamr@2
|
728 |
first_bucket=buc;
|
williamr@2
|
729 |
}
|
williamr@2
|
730 |
else if(first_bucket<buc){
|
williamr@2
|
731 |
first_bucket=buckets.first_nonempty(first_bucket);
|
williamr@2
|
732 |
}
|
williamr@2
|
733 |
return true;
|
williamr@2
|
734 |
}
|
williamr@2
|
735 |
link(x,y);
|
williamr@2
|
736 |
return false;
|
williamr@2
|
737 |
}
|
williamr@2
|
738 |
BOOST_CATCH(...){
|
williamr@2
|
739 |
link(x,y);
|
williamr@2
|
740 |
BOOST_RETHROW;
|
williamr@2
|
741 |
}
|
williamr@2
|
742 |
BOOST_CATCH_END
|
williamr@2
|
743 |
}
|
williamr@2
|
744 |
|
williamr@2
|
745 |
bool modify_(node_type* x)
|
williamr@2
|
746 |
{
|
williamr@2
|
747 |
unlink(x);
|
williamr@2
|
748 |
|
williamr@2
|
749 |
std::size_t buc;
|
williamr@2
|
750 |
hashed_index_node_impl* pos;
|
williamr@2
|
751 |
BOOST_TRY
|
williamr@2
|
752 |
{
|
williamr@2
|
753 |
buc=find_bucket(x->value());
|
williamr@2
|
754 |
pos=buckets.at(buc);
|
williamr@2
|
755 |
if(!link_point(x->value(),pos,Category())){
|
williamr@2
|
756 |
first_bucket=buckets.first_nonempty(first_bucket);
|
williamr@2
|
757 |
super::erase_(x);
|
williamr@2
|
758 |
|
williamr@2
|
759 |
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
williamr@2
|
760 |
detach_iterators(x);
|
williamr@2
|
761 |
#endif
|
williamr@2
|
762 |
return false;
|
williamr@2
|
763 |
}
|
williamr@2
|
764 |
|
williamr@2
|
765 |
}
|
williamr@2
|
766 |
BOOST_CATCH(...){
|
williamr@2
|
767 |
first_bucket=buckets.first_nonempty(first_bucket);
|
williamr@2
|
768 |
super::erase_(x);
|
williamr@2
|
769 |
|
williamr@2
|
770 |
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
williamr@2
|
771 |
detach_iterators(x);
|
williamr@2
|
772 |
#endif
|
williamr@2
|
773 |
|
williamr@2
|
774 |
BOOST_RETHROW;
|
williamr@2
|
775 |
}
|
williamr@2
|
776 |
BOOST_CATCH_END
|
williamr@2
|
777 |
|
williamr@2
|
778 |
BOOST_TRY{
|
williamr@2
|
779 |
if(super::modify_(x)){
|
williamr@2
|
780 |
link(x,pos);
|
williamr@2
|
781 |
if(first_bucket>buc){
|
williamr@2
|
782 |
first_bucket=buc;
|
williamr@2
|
783 |
}
|
williamr@2
|
784 |
else if(first_bucket<buc){
|
williamr@2
|
785 |
first_bucket=buckets.first_nonempty(first_bucket);
|
williamr@2
|
786 |
}
|
williamr@2
|
787 |
return true;
|
williamr@2
|
788 |
}
|
williamr@2
|
789 |
|
williamr@2
|
790 |
first_bucket=buckets.first_nonempty(first_bucket);
|
williamr@2
|
791 |
|
williamr@2
|
792 |
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
williamr@2
|
793 |
detach_iterators(x);
|
williamr@2
|
794 |
#endif
|
williamr@2
|
795 |
return false;
|
williamr@2
|
796 |
}
|
williamr@2
|
797 |
BOOST_CATCH(...){
|
williamr@2
|
798 |
first_bucket=buckets.first_nonempty(first_bucket);
|
williamr@2
|
799 |
|
williamr@2
|
800 |
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
williamr@2
|
801 |
detach_iterators(x);
|
williamr@2
|
802 |
#endif
|
williamr@2
|
803 |
|
williamr@2
|
804 |
BOOST_RETHROW;
|
williamr@2
|
805 |
}
|
williamr@2
|
806 |
BOOST_CATCH_END
|
williamr@2
|
807 |
}
|
williamr@2
|
808 |
|
williamr@2
|
809 |
#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
|
williamr@2
|
810 |
/* serialization */
|
williamr@2
|
811 |
|
williamr@2
|
812 |
template<typename Archive>
|
williamr@2
|
813 |
void save_(
|
williamr@2
|
814 |
Archive& ar,const unsigned int version,const index_saver_type& sm)const
|
williamr@2
|
815 |
{
|
williamr@2
|
816 |
ar<<serialization::make_nvp("position",buckets);
|
williamr@2
|
817 |
super::save_(ar,version,sm);
|
williamr@2
|
818 |
}
|
williamr@2
|
819 |
|
williamr@2
|
820 |
template<typename Archive>
|
williamr@2
|
821 |
void load_(Archive& ar,const unsigned int version,const index_loader_type& lm)
|
williamr@2
|
822 |
{
|
williamr@2
|
823 |
ar>>serialization::make_nvp("position",buckets);
|
williamr@2
|
824 |
super::load_(ar,version,lm);
|
williamr@2
|
825 |
}
|
williamr@2
|
826 |
#endif
|
williamr@2
|
827 |
|
williamr@2
|
828 |
#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)
|
williamr@2
|
829 |
/* invariant stuff */
|
williamr@2
|
830 |
|
williamr@2
|
831 |
bool invariant_()const
|
williamr@2
|
832 |
{
|
williamr@2
|
833 |
if(size()==0||begin()==end()){
|
williamr@2
|
834 |
if(size()!=0||begin()!=end())return false;
|
williamr@2
|
835 |
}
|
williamr@2
|
836 |
else{
|
williamr@2
|
837 |
size_type s0=0;
|
williamr@2
|
838 |
for(const_iterator it=begin(),it_end=end();it!=it_end;++it,++s0){}
|
williamr@2
|
839 |
if(s0!=size())return false;
|
williamr@2
|
840 |
|
williamr@2
|
841 |
size_type s1=0;
|
williamr@2
|
842 |
for(size_type buc=0;buc<bucket_count();++buc){
|
williamr@2
|
843 |
size_type ss1=0;
|
williamr@2
|
844 |
for(const_local_iterator it=begin(buc),it_end=end(buc);
|
williamr@2
|
845 |
it!=it_end;++it,++ss1){
|
williamr@2
|
846 |
if(find_bucket(*it)!=buc)return false;
|
williamr@2
|
847 |
}
|
williamr@2
|
848 |
if(ss1!=bucket_size(buc))return false;
|
williamr@2
|
849 |
s1+=ss1;
|
williamr@2
|
850 |
}
|
williamr@2
|
851 |
if(s1!=size())return false;
|
williamr@2
|
852 |
}
|
williamr@2
|
853 |
|
williamr@2
|
854 |
if(first_bucket!=buckets.first_nonempty(0))return false;
|
williamr@2
|
855 |
|
williamr@2
|
856 |
return super::invariant_();
|
williamr@2
|
857 |
}
|
williamr@2
|
858 |
|
williamr@2
|
859 |
/* This forwarding function eases things for the boost::mem_fn construct
|
williamr@2
|
860 |
* in BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT. Actually,
|
williamr@2
|
861 |
* final_check_invariant is already an inherited member function of index.
|
williamr@2
|
862 |
*/
|
williamr@2
|
863 |
void check_invariant_()const{this->final_check_invariant_();}
|
williamr@2
|
864 |
#endif
|
williamr@2
|
865 |
|
williamr@2
|
866 |
private:
|
williamr@2
|
867 |
node_type* header()const{return this->final_header();}
|
williamr@2
|
868 |
|
williamr@2
|
869 |
std::size_t find_bucket(value_param_type v)const
|
williamr@2
|
870 |
{
|
williamr@2
|
871 |
return bucket(key(v));
|
williamr@2
|
872 |
}
|
williamr@2
|
873 |
|
williamr@2
|
874 |
bool link_point(
|
williamr@2
|
875 |
value_param_type v,hashed_index_node_impl*& pos,hashed_unique_tag)
|
williamr@2
|
876 |
{
|
williamr@2
|
877 |
hashed_index_node_impl* x=pos->next();
|
williamr@2
|
878 |
while(x!=pos){
|
williamr@2
|
879 |
if(eq(key(v),key(node_type::from_impl(x)->value()))){
|
williamr@2
|
880 |
pos=x;
|
williamr@2
|
881 |
return false;
|
williamr@2
|
882 |
}
|
williamr@2
|
883 |
x=x->next();
|
williamr@2
|
884 |
}
|
williamr@2
|
885 |
return true;
|
williamr@2
|
886 |
}
|
williamr@2
|
887 |
|
williamr@2
|
888 |
bool link_point(
|
williamr@2
|
889 |
value_param_type v,hashed_index_node_impl*& pos,hashed_non_unique_tag)
|
williamr@2
|
890 |
{
|
williamr@2
|
891 |
hashed_index_node_impl* prev=pos;
|
williamr@2
|
892 |
hashed_index_node_impl* x=pos->next();
|
williamr@2
|
893 |
while(x!=pos){
|
williamr@2
|
894 |
if(eq(key(v),key(node_type::from_impl(x)->value()))){
|
williamr@2
|
895 |
pos=prev;
|
williamr@2
|
896 |
return true;
|
williamr@2
|
897 |
}
|
williamr@2
|
898 |
prev=x;
|
williamr@2
|
899 |
x=x->next();
|
williamr@2
|
900 |
}
|
williamr@2
|
901 |
return true;
|
williamr@2
|
902 |
}
|
williamr@2
|
903 |
|
williamr@2
|
904 |
void link(node_type* x,hashed_index_node_impl* pos)
|
williamr@2
|
905 |
{
|
williamr@2
|
906 |
hashed_index_node_impl::link(x->impl(),pos);
|
williamr@2
|
907 |
};
|
williamr@2
|
908 |
|
williamr@2
|
909 |
void link(hashed_index_node_impl* x,hashed_index_node_impl* pos)
|
williamr@2
|
910 |
{
|
williamr@2
|
911 |
hashed_index_node_impl::link(x,pos);
|
williamr@2
|
912 |
};
|
williamr@2
|
913 |
|
williamr@2
|
914 |
void unlink(node_type* x)
|
williamr@2
|
915 |
{
|
williamr@2
|
916 |
hashed_index_node_impl::unlink(x->impl());
|
williamr@2
|
917 |
};
|
williamr@2
|
918 |
|
williamr@2
|
919 |
static hashed_index_node_impl* prev(node_type* x)
|
williamr@2
|
920 |
{
|
williamr@2
|
921 |
return hashed_index_node_impl::prev(x->impl());
|
williamr@2
|
922 |
}
|
williamr@2
|
923 |
|
williamr@2
|
924 |
static void unlink_next(hashed_index_node_impl* x)
|
williamr@2
|
925 |
{
|
williamr@2
|
926 |
hashed_index_node_impl::unlink_next(x);
|
williamr@2
|
927 |
}
|
williamr@2
|
928 |
|
williamr@2
|
929 |
void calculate_max_load()
|
williamr@2
|
930 |
{
|
williamr@2
|
931 |
float fml=static_cast<float>(mlf*bucket_count());
|
williamr@2
|
932 |
max_load=(std::numeric_limits<size_type>::max)();
|
williamr@2
|
933 |
if(max_load>fml)max_load=static_cast<size_type>(fml);
|
williamr@2
|
934 |
}
|
williamr@2
|
935 |
|
williamr@2
|
936 |
void reserve(size_type n)
|
williamr@2
|
937 |
{
|
williamr@2
|
938 |
if(n>max_load){
|
williamr@2
|
939 |
size_type bc =(std::numeric_limits<size_type>::max)();
|
williamr@2
|
940 |
float fbc=static_cast<float>(1+n/mlf);
|
williamr@2
|
941 |
if(bc>fbc)bc =static_cast<size_type>(fbc);
|
williamr@2
|
942 |
unchecked_rehash(bc);
|
williamr@2
|
943 |
}
|
williamr@2
|
944 |
}
|
williamr@2
|
945 |
|
williamr@2
|
946 |
void unchecked_rehash(size_type n)
|
williamr@2
|
947 |
{
|
williamr@2
|
948 |
bucket_array_type buckets1(get_allocator(),header()->impl(),n);
|
williamr@2
|
949 |
auto_space<std::size_t,allocator_type> hashes(get_allocator(),size());
|
williamr@2
|
950 |
|
williamr@2
|
951 |
std::size_t i=0;
|
williamr@2
|
952 |
hashed_index_node_impl* x=buckets.begin();
|
williamr@2
|
953 |
hashed_index_node_impl* x_end=buckets.end();
|
williamr@2
|
954 |
for(;x!=x_end;++x){
|
williamr@2
|
955 |
hashed_index_node_impl* y=x->next();
|
williamr@2
|
956 |
while(y!=x){
|
williamr@2
|
957 |
hashes.data()[i++]=hash(key(node_type::from_impl(y)->value()));
|
williamr@2
|
958 |
y=y->next();
|
williamr@2
|
959 |
}
|
williamr@2
|
960 |
}
|
williamr@2
|
961 |
|
williamr@2
|
962 |
i=0;
|
williamr@2
|
963 |
x=buckets.begin();
|
williamr@2
|
964 |
for(;x!=x_end;++x){
|
williamr@2
|
965 |
hashed_index_node_impl* y=x->next();
|
williamr@2
|
966 |
while(y!=x){
|
williamr@2
|
967 |
hashed_index_node_impl* z=y->next();
|
williamr@2
|
968 |
std::size_t buc1=buckets1.position(hashes.data()[i++]);
|
williamr@2
|
969 |
hashed_index_node_impl* x1=buckets1.at(buc1);
|
williamr@2
|
970 |
link(y,x1);
|
williamr@2
|
971 |
y=z;
|
williamr@2
|
972 |
}
|
williamr@2
|
973 |
}
|
williamr@2
|
974 |
|
williamr@2
|
975 |
buckets.swap(buckets1);
|
williamr@2
|
976 |
calculate_max_load();
|
williamr@2
|
977 |
first_bucket=buckets.first_nonempty(0);
|
williamr@2
|
978 |
}
|
williamr@2
|
979 |
|
williamr@2
|
980 |
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
williamr@2
|
981 |
void detach_iterators(node_type* x)
|
williamr@2
|
982 |
{
|
williamr@2
|
983 |
iterator it=make_iterator(x);
|
williamr@2
|
984 |
safe_mode::detach_equivalent_iterators(it);
|
williamr@2
|
985 |
}
|
williamr@2
|
986 |
#endif
|
williamr@2
|
987 |
|
williamr@2
|
988 |
key_from_value key;
|
williamr@2
|
989 |
hasher hash;
|
williamr@2
|
990 |
key_equal eq;
|
williamr@2
|
991 |
bucket_array_type buckets;
|
williamr@2
|
992 |
float mlf;
|
williamr@2
|
993 |
size_type max_load;
|
williamr@2
|
994 |
std::size_t first_bucket;
|
williamr@2
|
995 |
|
williamr@2
|
996 |
#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)&&\
|
williamr@2
|
997 |
BOOST_WORKAROUND(__MWERKS__,<=0x3003)
|
williamr@2
|
998 |
#pragma parse_mfunc_templ reset
|
williamr@2
|
999 |
#endif
|
williamr@2
|
1000 |
};
|
williamr@2
|
1001 |
|
williamr@2
|
1002 |
/* specialized algorithms */
|
williamr@2
|
1003 |
|
williamr@2
|
1004 |
template<
|
williamr@2
|
1005 |
typename KeyFromValue,typename Hash,typename Pred,
|
williamr@2
|
1006 |
typename SuperMeta,typename TagList,typename Category
|
williamr@2
|
1007 |
>
|
williamr@2
|
1008 |
void swap(
|
williamr@2
|
1009 |
hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x,
|
williamr@2
|
1010 |
hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& y)
|
williamr@2
|
1011 |
{
|
williamr@2
|
1012 |
x.swap(y);
|
williamr@2
|
1013 |
}
|
williamr@2
|
1014 |
|
williamr@2
|
1015 |
} /* namespace multi_index::detail */
|
williamr@2
|
1016 |
|
williamr@2
|
1017 |
/* sequenced index specifiers */
|
williamr@2
|
1018 |
|
williamr@2
|
1019 |
template<typename Arg1,typename Arg2,typename Arg3,typename Arg4>
|
williamr@2
|
1020 |
struct hashed_unique
|
williamr@2
|
1021 |
{
|
williamr@2
|
1022 |
typedef typename detail::hashed_index_args<
|
williamr@2
|
1023 |
Arg1,Arg2,Arg3,Arg4> index_args;
|
williamr@2
|
1024 |
typedef typename index_args::tag_list_type::type tag_list_type;
|
williamr@2
|
1025 |
typedef typename index_args::key_from_value_type key_from_value_type;
|
williamr@2
|
1026 |
typedef typename index_args::hash_type hash_type;
|
williamr@2
|
1027 |
typedef typename index_args::pred_type pred_type;
|
williamr@2
|
1028 |
|
williamr@2
|
1029 |
template<typename Super>
|
williamr@2
|
1030 |
struct node_class
|
williamr@2
|
1031 |
{
|
williamr@2
|
1032 |
typedef detail::hashed_index_node<Super> type;
|
williamr@2
|
1033 |
};
|
williamr@2
|
1034 |
|
williamr@2
|
1035 |
template<typename SuperMeta>
|
williamr@2
|
1036 |
struct index_class
|
williamr@2
|
1037 |
{
|
williamr@2
|
1038 |
typedef detail::hashed_index<
|
williamr@2
|
1039 |
key_from_value_type,hash_type,pred_type,
|
williamr@2
|
1040 |
SuperMeta,tag_list_type,detail::hashed_unique_tag> type;
|
williamr@2
|
1041 |
};
|
williamr@2
|
1042 |
};
|
williamr@2
|
1043 |
|
williamr@2
|
1044 |
template<typename Arg1,typename Arg2,typename Arg3,typename Arg4>
|
williamr@2
|
1045 |
struct hashed_non_unique
|
williamr@2
|
1046 |
{
|
williamr@2
|
1047 |
typedef typename detail::hashed_index_args<
|
williamr@2
|
1048 |
Arg1,Arg2,Arg3,Arg4> index_args;
|
williamr@2
|
1049 |
typedef typename index_args::tag_list_type::type tag_list_type;
|
williamr@2
|
1050 |
typedef typename index_args::key_from_value_type key_from_value_type;
|
williamr@2
|
1051 |
typedef typename index_args::hash_type hash_type;
|
williamr@2
|
1052 |
typedef typename index_args::pred_type pred_type;
|
williamr@2
|
1053 |
|
williamr@2
|
1054 |
template<typename Super>
|
williamr@2
|
1055 |
struct node_class
|
williamr@2
|
1056 |
{
|
williamr@2
|
1057 |
typedef detail::hashed_index_node<Super> type;
|
williamr@2
|
1058 |
};
|
williamr@2
|
1059 |
|
williamr@2
|
1060 |
template<typename SuperMeta>
|
williamr@2
|
1061 |
struct index_class
|
williamr@2
|
1062 |
{
|
williamr@2
|
1063 |
typedef detail::hashed_index<
|
williamr@2
|
1064 |
key_from_value_type,hash_type,pred_type,
|
williamr@2
|
1065 |
SuperMeta,tag_list_type,detail::hashed_non_unique_tag> type;
|
williamr@2
|
1066 |
};
|
williamr@2
|
1067 |
};
|
williamr@2
|
1068 |
|
williamr@2
|
1069 |
} /* namespace multi_index */
|
williamr@2
|
1070 |
|
williamr@2
|
1071 |
} /* namespace boost */
|
williamr@2
|
1072 |
|
williamr@2
|
1073 |
#undef BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT
|
williamr@2
|
1074 |
|
williamr@2
|
1075 |
#endif
|