OLD | NEW |
| (Empty) |
1 // Internal policy header for TR1 unordered_set and unordered_map -*- C++ -*- | |
2 | |
3 // Copyright (C) 2007, 2008, 2009 Free Software Foundation, Inc. | |
4 // | |
5 // This file is part of the GNU ISO C++ Library. This library is free | |
6 // software; you can redistribute it and/or modify it under the | |
7 // terms of the GNU General Public License as published by the | |
8 // Free Software Foundation; either version 3, or (at your option) | |
9 // any later version. | |
10 | |
11 // This library is distributed in the hope that it will be useful, | |
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 // GNU General Public License for more details. | |
15 | |
16 // Under Section 7 of GPL version 3, you are granted additional | |
17 // permissions described in the GCC Runtime Library Exception, version | |
18 // 3.1, as published by the Free Software Foundation. | |
19 | |
20 // You should have received a copy of the GNU General Public License and | |
21 // a copy of the GCC Runtime Library Exception along with this program; | |
22 // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see | |
23 // <http://www.gnu.org/licenses/>. | |
24 | |
25 /** @file tr1_impl/hashtable_policy.h | |
26 * This is an internal header file, included by other library headers. | |
27 * You should not attempt to use it directly. | |
28 */ | |
29 | |
30 namespace std | |
31 { | |
32 _GLIBCXX_BEGIN_NAMESPACE_TR1 | |
33 | |
34 namespace __detail | |
35 { | |
36 // Helper function: return distance(first, last) for forward | |
37 // iterators, or 0 for input iterators. | |
38 template<class _Iterator> | |
39 inline typename std::iterator_traits<_Iterator>::difference_type | |
40 __distance_fw(_Iterator __first, _Iterator __last, | |
41 std::input_iterator_tag) | |
42 { return 0; } | |
43 | |
44 template<class _Iterator> | |
45 inline typename std::iterator_traits<_Iterator>::difference_type | |
46 __distance_fw(_Iterator __first, _Iterator __last, | |
47 std::forward_iterator_tag) | |
48 { return std::distance(__first, __last); } | |
49 | |
50 template<class _Iterator> | |
51 inline typename std::iterator_traits<_Iterator>::difference_type | |
52 __distance_fw(_Iterator __first, _Iterator __last) | |
53 { | |
54 typedef typename std::iterator_traits<_Iterator>::iterator_category _Tag; | |
55 return __distance_fw(__first, __last, _Tag()); | |
56 } | |
57 | |
58 template<typename _RAIter, typename _Tp> | |
59 _RAIter | |
60 __lower_bound(_RAIter __first, _RAIter __last, const _Tp& __val) | |
61 { | |
62 typedef typename std::iterator_traits<_RAIter>::difference_type _DType; | |
63 | |
64 _DType __len = __last - __first; | |
65 while (__len > 0) | |
66 { | |
67 _DType __half = __len >> 1; | |
68 _RAIter __middle = __first + __half; | |
69 if (*__middle < __val) | |
70 { | |
71 __first = __middle; | |
72 ++__first; | |
73 __len = __len - __half - 1; | |
74 } | |
75 else | |
76 __len = __half; | |
77 } | |
78 return __first; | |
79 } | |
80 | |
81 // Auxiliary types used for all instantiations of _Hashtable: nodes | |
82 // and iterators. | |
83 | |
84 // Nodes, used to wrap elements stored in the hash table. A policy | |
85 // template parameter of class template _Hashtable controls whether | |
86 // nodes also store a hash code. In some cases (e.g. strings) this | |
87 // may be a performance win. | |
88 template<typename _Value, bool __cache_hash_code> | |
89 struct _Hash_node; | |
90 | |
91 template<typename _Value> | |
92 struct _Hash_node<_Value, true> | |
93 { | |
94 _Value _M_v; | |
95 std::size_t _M_hash_code; | |
96 _Hash_node* _M_next; | |
97 | |
98 #ifdef _GLIBCXX_INCLUDE_AS_CXX0X | |
99 template<typename... _Args> | |
100 _Hash_node(_Args&&... __args) | |
101 : _M_v(std::forward<_Args>(__args)...), | |
102 _M_hash_code(), _M_next() { } | |
103 #endif | |
104 }; | |
105 | |
106 template<typename _Value> | |
107 struct _Hash_node<_Value, false> | |
108 { | |
109 _Value _M_v; | |
110 _Hash_node* _M_next; | |
111 | |
112 #ifdef _GLIBCXX_INCLUDE_AS_CXX0X | |
113 template<typename... _Args> | |
114 _Hash_node(_Args&&... __args) | |
115 : _M_v(std::forward<_Args>(__args)...), | |
116 _M_next() { } | |
117 #endif | |
118 }; | |
119 | |
120 // Local iterators, used to iterate within a bucket but not between | |
121 // buckets. | |
122 template<typename _Value, bool __cache> | |
123 struct _Node_iterator_base | |
124 { | |
125 _Node_iterator_base(_Hash_node<_Value, __cache>* __p) | |
126 : _M_cur(__p) { } | |
127 | |
128 void | |
129 _M_incr() | |
130 { _M_cur = _M_cur->_M_next; } | |
131 | |
132 _Hash_node<_Value, __cache>* _M_cur; | |
133 }; | |
134 | |
135 template<typename _Value, bool __cache> | |
136 inline bool | |
137 operator==(const _Node_iterator_base<_Value, __cache>& __x, | |
138 const _Node_iterator_base<_Value, __cache>& __y) | |
139 { return __x._M_cur == __y._M_cur; } | |
140 | |
141 template<typename _Value, bool __cache> | |
142 inline bool | |
143 operator!=(const _Node_iterator_base<_Value, __cache>& __x, | |
144 const _Node_iterator_base<_Value, __cache>& __y) | |
145 { return __x._M_cur != __y._M_cur; } | |
146 | |
147 template<typename _Value, bool __constant_iterators, bool __cache> | |
148 struct _Node_iterator | |
149 : public _Node_iterator_base<_Value, __cache> | |
150 { | |
151 typedef _Value value_type; | |
152 typedef typename | |
153 __gnu_cxx::__conditional_type<__constant_iterators, | |
154 const _Value*, _Value*>::__type | |
155 pointer; | |
156 typedef typename | |
157 __gnu_cxx::__conditional_type<__constant_iterators, | |
158 const _Value&, _Value&>::__type | |
159 reference; | |
160 typedef std::ptrdiff_t difference_type; | |
161 typedef std::forward_iterator_tag iterator_category; | |
162 | |
163 _Node_iterator() | |
164 : _Node_iterator_base<_Value, __cache>(0) { } | |
165 | |
166 explicit | |
167 _Node_iterator(_Hash_node<_Value, __cache>* __p) | |
168 : _Node_iterator_base<_Value, __cache>(__p) { } | |
169 | |
170 reference | |
171 operator*() const | |
172 { return this->_M_cur->_M_v; } | |
173 | |
174 pointer | |
175 operator->() const | |
176 { return &this->_M_cur->_M_v; } | |
177 | |
178 _Node_iterator& | |
179 operator++() | |
180 { | |
181 this->_M_incr(); | |
182 return *this; | |
183 } | |
184 | |
185 _Node_iterator | |
186 operator++(int) | |
187 { | |
188 _Node_iterator __tmp(*this); | |
189 this->_M_incr(); | |
190 return __tmp; | |
191 } | |
192 }; | |
193 | |
194 template<typename _Value, bool __constant_iterators, bool __cache> | |
195 struct _Node_const_iterator | |
196 : public _Node_iterator_base<_Value, __cache> | |
197 { | |
198 typedef _Value value_type; | |
199 typedef const _Value* pointer; | |
200 typedef const _Value& reference; | |
201 typedef std::ptrdiff_t difference_type; | |
202 typedef std::forward_iterator_tag iterator_category; | |
203 | |
204 _Node_const_iterator() | |
205 : _Node_iterator_base<_Value, __cache>(0) { } | |
206 | |
207 explicit | |
208 _Node_const_iterator(_Hash_node<_Value, __cache>* __p) | |
209 : _Node_iterator_base<_Value, __cache>(__p) { } | |
210 | |
211 _Node_const_iterator(const _Node_iterator<_Value, __constant_iterators, | |
212 __cache>& __x) | |
213 : _Node_iterator_base<_Value, __cache>(__x._M_cur) { } | |
214 | |
215 reference | |
216 operator*() const | |
217 { return this->_M_cur->_M_v; } | |
218 | |
219 pointer | |
220 operator->() const | |
221 { return &this->_M_cur->_M_v; } | |
222 | |
223 _Node_const_iterator& | |
224 operator++() | |
225 { | |
226 this->_M_incr(); | |
227 return *this; | |
228 } | |
229 | |
230 _Node_const_iterator | |
231 operator++(int) | |
232 { | |
233 _Node_const_iterator __tmp(*this); | |
234 this->_M_incr(); | |
235 return __tmp; | |
236 } | |
237 }; | |
238 | |
239 template<typename _Value, bool __cache> | |
240 struct _Hashtable_iterator_base | |
241 { | |
242 _Hashtable_iterator_base(_Hash_node<_Value, __cache>* __node, | |
243 _Hash_node<_Value, __cache>** __bucket) | |
244 : _M_cur_node(__node), _M_cur_bucket(__bucket) { } | |
245 | |
246 void | |
247 _M_incr() | |
248 { | |
249 _M_cur_node = _M_cur_node->_M_next; | |
250 if (!_M_cur_node) | |
251 _M_incr_bucket(); | |
252 } | |
253 | |
254 void | |
255 _M_incr_bucket(); | |
256 | |
257 _Hash_node<_Value, __cache>* _M_cur_node; | |
258 _Hash_node<_Value, __cache>** _M_cur_bucket; | |
259 }; | |
260 | |
261 // Global iterators, used for arbitrary iteration within a hash | |
262 // table. Larger and more expensive than local iterators. | |
263 template<typename _Value, bool __cache> | |
264 void | |
265 _Hashtable_iterator_base<_Value, __cache>:: | |
266 _M_incr_bucket() | |
267 { | |
268 ++_M_cur_bucket; | |
269 | |
270 // This loop requires the bucket array to have a non-null sentinel. | |
271 while (!*_M_cur_bucket) | |
272 ++_M_cur_bucket; | |
273 _M_cur_node = *_M_cur_bucket; | |
274 } | |
275 | |
276 template<typename _Value, bool __cache> | |
277 inline bool | |
278 operator==(const _Hashtable_iterator_base<_Value, __cache>& __x, | |
279 const _Hashtable_iterator_base<_Value, __cache>& __y) | |
280 { return __x._M_cur_node == __y._M_cur_node; } | |
281 | |
282 template<typename _Value, bool __cache> | |
283 inline bool | |
284 operator!=(const _Hashtable_iterator_base<_Value, __cache>& __x, | |
285 const _Hashtable_iterator_base<_Value, __cache>& __y) | |
286 { return __x._M_cur_node != __y._M_cur_node; } | |
287 | |
288 template<typename _Value, bool __constant_iterators, bool __cache> | |
289 struct _Hashtable_iterator | |
290 : public _Hashtable_iterator_base<_Value, __cache> | |
291 { | |
292 typedef _Value value_type; | |
293 typedef typename | |
294 __gnu_cxx::__conditional_type<__constant_iterators, | |
295 const _Value*, _Value*>::__type | |
296 pointer; | |
297 typedef typename | |
298 __gnu_cxx::__conditional_type<__constant_iterators, | |
299 const _Value&, _Value&>::__type | |
300 reference; | |
301 typedef std::ptrdiff_t difference_type; | |
302 typedef std::forward_iterator_tag iterator_category; | |
303 | |
304 _Hashtable_iterator() | |
305 : _Hashtable_iterator_base<_Value, __cache>(0, 0) { } | |
306 | |
307 _Hashtable_iterator(_Hash_node<_Value, __cache>* __p, | |
308 _Hash_node<_Value, __cache>** __b) | |
309 : _Hashtable_iterator_base<_Value, __cache>(__p, __b) { } | |
310 | |
311 explicit | |
312 _Hashtable_iterator(_Hash_node<_Value, __cache>** __b) | |
313 : _Hashtable_iterator_base<_Value, __cache>(*__b, __b) { } | |
314 | |
315 reference | |
316 operator*() const | |
317 { return this->_M_cur_node->_M_v; } | |
318 | |
319 pointer | |
320 operator->() const | |
321 { return &this->_M_cur_node->_M_v; } | |
322 | |
323 _Hashtable_iterator& | |
324 operator++() | |
325 { | |
326 this->_M_incr(); | |
327 return *this; | |
328 } | |
329 | |
330 _Hashtable_iterator | |
331 operator++(int) | |
332 { | |
333 _Hashtable_iterator __tmp(*this); | |
334 this->_M_incr(); | |
335 return __tmp; | |
336 } | |
337 }; | |
338 | |
339 template<typename _Value, bool __constant_iterators, bool __cache> | |
340 struct _Hashtable_const_iterator | |
341 : public _Hashtable_iterator_base<_Value, __cache> | |
342 { | |
343 typedef _Value value_type; | |
344 typedef const _Value* pointer; | |
345 typedef const _Value& reference; | |
346 typedef std::ptrdiff_t difference_type; | |
347 typedef std::forward_iterator_tag iterator_category; | |
348 | |
349 _Hashtable_const_iterator() | |
350 : _Hashtable_iterator_base<_Value, __cache>(0, 0) { } | |
351 | |
352 _Hashtable_const_iterator(_Hash_node<_Value, __cache>* __p, | |
353 _Hash_node<_Value, __cache>** __b) | |
354 : _Hashtable_iterator_base<_Value, __cache>(__p, __b) { } | |
355 | |
356 explicit | |
357 _Hashtable_const_iterator(_Hash_node<_Value, __cache>** __b) | |
358 : _Hashtable_iterator_base<_Value, __cache>(*__b, __b) { } | |
359 | |
360 _Hashtable_const_iterator(const _Hashtable_iterator<_Value, | |
361 __constant_iterators, __cache>& __x) | |
362 : _Hashtable_iterator_base<_Value, __cache>(__x._M_cur_node, | |
363 __x._M_cur_bucket) { } | |
364 | |
365 reference | |
366 operator*() const | |
367 { return this->_M_cur_node->_M_v; } | |
368 | |
369 pointer | |
370 operator->() const | |
371 { return &this->_M_cur_node->_M_v; } | |
372 | |
373 _Hashtable_const_iterator& | |
374 operator++() | |
375 { | |
376 this->_M_incr(); | |
377 return *this; | |
378 } | |
379 | |
380 _Hashtable_const_iterator | |
381 operator++(int) | |
382 { | |
383 _Hashtable_const_iterator __tmp(*this); | |
384 this->_M_incr(); | |
385 return __tmp; | |
386 } | |
387 }; | |
388 | |
389 | |
390 // Many of class template _Hashtable's template parameters are policy | |
391 // classes. These are defaults for the policies. | |
392 | |
393 // Default range hashing function: use division to fold a large number | |
394 // into the range [0, N). | |
395 struct _Mod_range_hashing | |
396 { | |
397 typedef std::size_t first_argument_type; | |
398 typedef std::size_t second_argument_type; | |
399 typedef std::size_t result_type; | |
400 | |
401 result_type | |
402 operator()(first_argument_type __num, second_argument_type __den) const | |
403 { return __num % __den; } | |
404 }; | |
405 | |
406 // Default ranged hash function H. In principle it should be a | |
407 // function object composed from objects of type H1 and H2 such that | |
408 // h(k, N) = h2(h1(k), N), but that would mean making extra copies of | |
409 // h1 and h2. So instead we'll just use a tag to tell class template | |
410 // hashtable to do that composition. | |
411 struct _Default_ranged_hash { }; | |
412 | |
413 // Default value for rehash policy. Bucket size is (usually) the | |
414 // smallest prime that keeps the load factor small enough. | |
415 struct _Prime_rehash_policy | |
416 { | |
417 _Prime_rehash_policy(float __z = 1.0) | |
418 : _M_max_load_factor(__z), _M_growth_factor(2.f), _M_next_resize(0) { } | |
419 | |
420 float | |
421 max_load_factor() const | |
422 { return _M_max_load_factor; } | |
423 | |
424 // Return a bucket size no smaller than n. | |
425 std::size_t | |
426 _M_next_bkt(std::size_t __n) const; | |
427 | |
428 // Return a bucket count appropriate for n elements | |
429 std::size_t | |
430 _M_bkt_for_elements(std::size_t __n) const; | |
431 | |
432 // __n_bkt is current bucket count, __n_elt is current element count, | |
433 // and __n_ins is number of elements to be inserted. Do we need to | |
434 // increase bucket count? If so, return make_pair(true, n), where n | |
435 // is the new bucket count. If not, return make_pair(false, 0). | |
436 std::pair<bool, std::size_t> | |
437 _M_need_rehash(std::size_t __n_bkt, std::size_t __n_elt, | |
438 std::size_t __n_ins) const; | |
439 | |
440 enum { _S_n_primes = sizeof(unsigned long) != 8 ? 256 : 256 + 48 }; | |
441 | |
442 float _M_max_load_factor; | |
443 float _M_growth_factor; | |
444 mutable std::size_t _M_next_resize; | |
445 }; | |
446 | |
447 extern const unsigned long __prime_list[]; | |
448 | |
449 // XXX This is a hack. There's no good reason for any of | |
450 // _Prime_rehash_policy's member functions to be inline. | |
451 | |
452 // Return a prime no smaller than n. | |
453 inline std::size_t | |
454 _Prime_rehash_policy:: | |
455 _M_next_bkt(std::size_t __n) const | |
456 { | |
457 const unsigned long* __p = __lower_bound(__prime_list, __prime_list | |
458 + _S_n_primes, __n); | |
459 _M_next_resize = | |
460 static_cast<std::size_t>(__builtin_ceil(*__p * _M_max_load_factor)); | |
461 return *__p; | |
462 } | |
463 | |
464 // Return the smallest prime p such that alpha p >= n, where alpha | |
465 // is the load factor. | |
466 inline std::size_t | |
467 _Prime_rehash_policy:: | |
468 _M_bkt_for_elements(std::size_t __n) const | |
469 { | |
470 const float __min_bkts = __n / _M_max_load_factor; | |
471 const unsigned long* __p = __lower_bound(__prime_list, __prime_list | |
472 + _S_n_primes, __min_bkts); | |
473 _M_next_resize = | |
474 static_cast<std::size_t>(__builtin_ceil(*__p * _M_max_load_factor)); | |
475 return *__p; | |
476 } | |
477 | |
478 // Finds the smallest prime p such that alpha p > __n_elt + __n_ins. | |
479 // If p > __n_bkt, return make_pair(true, p); otherwise return | |
480 // make_pair(false, 0). In principle this isn't very different from | |
481 // _M_bkt_for_elements. | |
482 | |
483 // The only tricky part is that we're caching the element count at | |
484 // which we need to rehash, so we don't have to do a floating-point | |
485 // multiply for every insertion. | |
486 | |
487 inline std::pair<bool, std::size_t> | |
488 _Prime_rehash_policy:: | |
489 _M_need_rehash(std::size_t __n_bkt, std::size_t __n_elt, | |
490 std::size_t __n_ins) const | |
491 { | |
492 if (__n_elt + __n_ins > _M_next_resize) | |
493 { | |
494 float __min_bkts = ((float(__n_ins) + float(__n_elt)) | |
495 / _M_max_load_factor); | |
496 if (__min_bkts > __n_bkt) | |
497 { | |
498 __min_bkts = std::max(__min_bkts, _M_growth_factor * __n_bkt); | |
499 const unsigned long* __p = | |
500 __lower_bound(__prime_list, __prime_list + _S_n_primes, | |
501 __min_bkts); | |
502 _M_next_resize = static_cast<std::size_t> | |
503 (__builtin_ceil(*__p * _M_max_load_factor)); | |
504 return std::make_pair(true, *__p); | |
505 } | |
506 else | |
507 { | |
508 _M_next_resize = static_cast<std::size_t> | |
509 (__builtin_ceil(__n_bkt * _M_max_load_factor)); | |
510 return std::make_pair(false, 0); | |
511 } | |
512 } | |
513 else | |
514 return std::make_pair(false, 0); | |
515 } | |
516 | |
517 // Base classes for std::tr1::_Hashtable. We define these base | |
518 // classes because in some cases we want to do different things | |
519 // depending on the value of a policy class. In some cases the | |
520 // policy class affects which member functions and nested typedefs | |
521 // are defined; we handle that by specializing base class templates. | |
522 // Several of the base class templates need to access other members | |
523 // of class template _Hashtable, so we use the "curiously recurring | |
524 // template pattern" for them. | |
525 | |
526 // class template _Map_base. If the hashtable has a value type of the | |
527 // form pair<T1, T2> and a key extraction policy that returns the | |
528 // first part of the pair, the hashtable gets a mapped_type typedef. | |
529 // If it satisfies those criteria and also has unique keys, then it | |
530 // also gets an operator[]. | |
531 template<typename _Key, typename _Value, typename _Ex, bool __unique, | |
532 typename _Hashtable> | |
533 struct _Map_base { }; | |
534 | |
535 template<typename _Key, typename _Pair, typename _Hashtable> | |
536 struct _Map_base<_Key, _Pair, std::_Select1st<_Pair>, false, _Hashtable> | |
537 { | |
538 typedef typename _Pair::second_type mapped_type; | |
539 }; | |
540 | |
541 template<typename _Key, typename _Pair, typename _Hashtable> | |
542 struct _Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable> | |
543 { | |
544 typedef typename _Pair::second_type mapped_type; | |
545 | |
546 mapped_type& | |
547 operator[](const _Key& __k); | |
548 | |
549 #ifdef _GLIBCXX_INCLUDE_AS_CXX0X | |
550 // _GLIBCXX_RESOLVE_LIB_DEFECTS | |
551 // DR 761. unordered_map needs an at() member function. | |
552 mapped_type& | |
553 at(const _Key& __k); | |
554 | |
555 const mapped_type& | |
556 at(const _Key& __k) const; | |
557 #endif | |
558 }; | |
559 | |
560 template<typename _Key, typename _Pair, typename _Hashtable> | |
561 typename _Map_base<_Key, _Pair, std::_Select1st<_Pair>, | |
562 true, _Hashtable>::mapped_type& | |
563 _Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>:: | |
564 operator[](const _Key& __k) | |
565 { | |
566 _Hashtable* __h = static_cast<_Hashtable*>(this); | |
567 typename _Hashtable::_Hash_code_type __code = __h->_M_hash_code(__k); | |
568 std::size_t __n = __h->_M_bucket_index(__k, __code, | |
569 __h->_M_bucket_count); | |
570 | |
571 typename _Hashtable::_Node* __p = | |
572 __h->_M_find_node(__h->_M_buckets[__n], __k, __code); | |
573 if (!__p) | |
574 return __h->_M_insert_bucket(std::make_pair(__k, mapped_type()), | |
575 __n, __code)->second; | |
576 return (__p->_M_v).second; | |
577 } | |
578 | |
579 #ifdef _GLIBCXX_INCLUDE_AS_CXX0X | |
580 template<typename _Key, typename _Pair, typename _Hashtable> | |
581 typename _Map_base<_Key, _Pair, std::_Select1st<_Pair>, | |
582 true, _Hashtable>::mapped_type& | |
583 _Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>:: | |
584 at(const _Key& __k) | |
585 { | |
586 _Hashtable* __h = static_cast<_Hashtable*>(this); | |
587 typename _Hashtable::_Hash_code_type __code = __h->_M_hash_code(__k); | |
588 std::size_t __n = __h->_M_bucket_index(__k, __code, | |
589 __h->_M_bucket_count); | |
590 | |
591 typename _Hashtable::_Node* __p = | |
592 __h->_M_find_node(__h->_M_buckets[__n], __k, __code); | |
593 if (!__p) | |
594 __throw_out_of_range(__N("_Map_base::at")); | |
595 return (__p->_M_v).second; | |
596 } | |
597 | |
598 template<typename _Key, typename _Pair, typename _Hashtable> | |
599 const typename _Map_base<_Key, _Pair, std::_Select1st<_Pair>, | |
600 true, _Hashtable>::mapped_type& | |
601 _Map_base<_Key, _Pair, std::_Select1st<_Pair>, true, _Hashtable>:: | |
602 at(const _Key& __k) const | |
603 { | |
604 const _Hashtable* __h = static_cast<const _Hashtable*>(this); | |
605 typename _Hashtable::_Hash_code_type __code = __h->_M_hash_code(__k); | |
606 std::size_t __n = __h->_M_bucket_index(__k, __code, | |
607 __h->_M_bucket_count); | |
608 | |
609 typename _Hashtable::_Node* __p = | |
610 __h->_M_find_node(__h->_M_buckets[__n], __k, __code); | |
611 if (!__p) | |
612 __throw_out_of_range(__N("_Map_base::at")); | |
613 return (__p->_M_v).second; | |
614 } | |
615 #endif | |
616 | |
617 // class template _Rehash_base. Give hashtable the max_load_factor | |
618 // functions iff the rehash policy is _Prime_rehash_policy. | |
619 template<typename _RehashPolicy, typename _Hashtable> | |
620 struct _Rehash_base { }; | |
621 | |
622 template<typename _Hashtable> | |
623 struct _Rehash_base<_Prime_rehash_policy, _Hashtable> | |
624 { | |
625 float | |
626 max_load_factor() const | |
627 { | |
628 const _Hashtable* __this = static_cast<const _Hashtable*>(this); | |
629 return __this->__rehash_policy().max_load_factor(); | |
630 } | |
631 | |
632 void | |
633 max_load_factor(float __z) | |
634 { | |
635 _Hashtable* __this = static_cast<_Hashtable*>(this); | |
636 __this->__rehash_policy(_Prime_rehash_policy(__z)); | |
637 } | |
638 }; | |
639 | |
640 // Class template _Hash_code_base. Encapsulates two policy issues that | |
641 // aren't quite orthogonal. | |
642 // (1) the difference between using a ranged hash function and using | |
643 // the combination of a hash function and a range-hashing function. | |
644 // In the former case we don't have such things as hash codes, so | |
645 // we have a dummy type as placeholder. | |
646 // (2) Whether or not we cache hash codes. Caching hash codes is | |
647 // meaningless if we have a ranged hash function. | |
648 // We also put the key extraction and equality comparison function | |
649 // objects here, for convenience. | |
650 | |
651 // Primary template: unused except as a hook for specializations. | |
652 template<typename _Key, typename _Value, | |
653 typename _ExtractKey, typename _Equal, | |
654 typename _H1, typename _H2, typename _Hash, | |
655 bool __cache_hash_code> | |
656 struct _Hash_code_base; | |
657 | |
658 // Specialization: ranged hash function, no caching hash codes. H1 | |
659 // and H2 are provided but ignored. We define a dummy hash code type. | |
660 template<typename _Key, typename _Value, | |
661 typename _ExtractKey, typename _Equal, | |
662 typename _H1, typename _H2, typename _Hash> | |
663 struct _Hash_code_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2, | |
664 _Hash, false> | |
665 { | |
666 protected: | |
667 _Hash_code_base(const _ExtractKey& __ex, const _Equal& __eq, | |
668 const _H1&, const _H2&, const _Hash& __h) | |
669 : _M_extract(__ex), _M_eq(__eq), _M_ranged_hash(__h) { } | |
670 | |
671 typedef void* _Hash_code_type; | |
672 | |
673 _Hash_code_type | |
674 _M_hash_code(const _Key& __key) const | |
675 { return 0; } | |
676 | |
677 std::size_t | |
678 _M_bucket_index(const _Key& __k, _Hash_code_type, | |
679 std::size_t __n) const | |
680 { return _M_ranged_hash(__k, __n); } | |
681 | |
682 std::size_t | |
683 _M_bucket_index(const _Hash_node<_Value, false>* __p, | |
684 std::size_t __n) const | |
685 { return _M_ranged_hash(_M_extract(__p->_M_v), __n); } | |
686 | |
687 bool | |
688 _M_compare(const _Key& __k, _Hash_code_type, | |
689 _Hash_node<_Value, false>* __n) const | |
690 { return _M_eq(__k, _M_extract(__n->_M_v)); } | |
691 | |
692 void | |
693 _M_store_code(_Hash_node<_Value, false>*, _Hash_code_type) const | |
694 { } | |
695 | |
696 void | |
697 _M_copy_code(_Hash_node<_Value, false>*, | |
698 const _Hash_node<_Value, false>*) const | |
699 { } | |
700 | |
701 void | |
702 _M_swap(_Hash_code_base& __x) | |
703 { | |
704 std::swap(_M_extract, __x._M_extract); | |
705 std::swap(_M_eq, __x._M_eq); | |
706 std::swap(_M_ranged_hash, __x._M_ranged_hash); | |
707 } | |
708 | |
709 protected: | |
710 _ExtractKey _M_extract; | |
711 _Equal _M_eq; | |
712 _Hash _M_ranged_hash; | |
713 }; | |
714 | |
715 | |
716 // No specialization for ranged hash function while caching hash codes. | |
717 // That combination is meaningless, and trying to do it is an error. | |
718 | |
719 | |
720 // Specialization: ranged hash function, cache hash codes. This | |
721 // combination is meaningless, so we provide only a declaration | |
722 // and no definition. | |
723 template<typename _Key, typename _Value, | |
724 typename _ExtractKey, typename _Equal, | |
725 typename _H1, typename _H2, typename _Hash> | |
726 struct _Hash_code_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2, | |
727 _Hash, true>; | |
728 | |
729 // Specialization: hash function and range-hashing function, no | |
730 // caching of hash codes. H is provided but ignored. Provides | |
731 // typedef and accessor required by TR1. | |
732 template<typename _Key, typename _Value, | |
733 typename _ExtractKey, typename _Equal, | |
734 typename _H1, typename _H2> | |
735 struct _Hash_code_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2, | |
736 _Default_ranged_hash, false> | |
737 { | |
738 typedef _H1 hasher; | |
739 | |
740 hasher | |
741 hash_function() const | |
742 { return _M_h1; } | |
743 | |
744 protected: | |
745 _Hash_code_base(const _ExtractKey& __ex, const _Equal& __eq, | |
746 const _H1& __h1, const _H2& __h2, | |
747 const _Default_ranged_hash&) | |
748 : _M_extract(__ex), _M_eq(__eq), _M_h1(__h1), _M_h2(__h2) { } | |
749 | |
750 typedef std::size_t _Hash_code_type; | |
751 | |
752 _Hash_code_type | |
753 _M_hash_code(const _Key& __k) const | |
754 { return _M_h1(__k); } | |
755 | |
756 std::size_t | |
757 _M_bucket_index(const _Key&, _Hash_code_type __c, | |
758 std::size_t __n) const | |
759 { return _M_h2(__c, __n); } | |
760 | |
761 std::size_t | |
762 _M_bucket_index(const _Hash_node<_Value, false>* __p, | |
763 std::size_t __n) const | |
764 { return _M_h2(_M_h1(_M_extract(__p->_M_v)), __n); } | |
765 | |
766 bool | |
767 _M_compare(const _Key& __k, _Hash_code_type, | |
768 _Hash_node<_Value, false>* __n) const | |
769 { return _M_eq(__k, _M_extract(__n->_M_v)); } | |
770 | |
771 void | |
772 _M_store_code(_Hash_node<_Value, false>*, _Hash_code_type) const | |
773 { } | |
774 | |
775 void | |
776 _M_copy_code(_Hash_node<_Value, false>*, | |
777 const _Hash_node<_Value, false>*) const | |
778 { } | |
779 | |
780 void | |
781 _M_swap(_Hash_code_base& __x) | |
782 { | |
783 std::swap(_M_extract, __x._M_extract); | |
784 std::swap(_M_eq, __x._M_eq); | |
785 std::swap(_M_h1, __x._M_h1); | |
786 std::swap(_M_h2, __x._M_h2); | |
787 } | |
788 | |
789 protected: | |
790 _ExtractKey _M_extract; | |
791 _Equal _M_eq; | |
792 _H1 _M_h1; | |
793 _H2 _M_h2; | |
794 }; | |
795 | |
796 // Specialization: hash function and range-hashing function, | |
797 // caching hash codes. H is provided but ignored. Provides | |
798 // typedef and accessor required by TR1. | |
799 template<typename _Key, typename _Value, | |
800 typename _ExtractKey, typename _Equal, | |
801 typename _H1, typename _H2> | |
802 struct _Hash_code_base<_Key, _Value, _ExtractKey, _Equal, _H1, _H2, | |
803 _Default_ranged_hash, true> | |
804 { | |
805 typedef _H1 hasher; | |
806 | |
807 hasher | |
808 hash_function() const | |
809 { return _M_h1; } | |
810 | |
811 protected: | |
812 _Hash_code_base(const _ExtractKey& __ex, const _Equal& __eq, | |
813 const _H1& __h1, const _H2& __h2, | |
814 const _Default_ranged_hash&) | |
815 : _M_extract(__ex), _M_eq(__eq), _M_h1(__h1), _M_h2(__h2) { } | |
816 | |
817 typedef std::size_t _Hash_code_type; | |
818 | |
819 _Hash_code_type | |
820 _M_hash_code(const _Key& __k) const | |
821 { return _M_h1(__k); } | |
822 | |
823 std::size_t | |
824 _M_bucket_index(const _Key&, _Hash_code_type __c, | |
825 std::size_t __n) const | |
826 { return _M_h2(__c, __n); } | |
827 | |
828 std::size_t | |
829 _M_bucket_index(const _Hash_node<_Value, true>* __p, | |
830 std::size_t __n) const | |
831 { return _M_h2(__p->_M_hash_code, __n); } | |
832 | |
833 bool | |
834 _M_compare(const _Key& __k, _Hash_code_type __c, | |
835 _Hash_node<_Value, true>* __n) const | |
836 { return __c == __n->_M_hash_code && _M_eq(__k, _M_extract(__n->_M_v)); } | |
837 | |
838 void | |
839 _M_store_code(_Hash_node<_Value, true>* __n, _Hash_code_type __c) const | |
840 { __n->_M_hash_code = __c; } | |
841 | |
842 void | |
843 _M_copy_code(_Hash_node<_Value, true>* __to, | |
844 const _Hash_node<_Value, true>* __from) const | |
845 { __to->_M_hash_code = __from->_M_hash_code; } | |
846 | |
847 void | |
848 _M_swap(_Hash_code_base& __x) | |
849 { | |
850 std::swap(_M_extract, __x._M_extract); | |
851 std::swap(_M_eq, __x._M_eq); | |
852 std::swap(_M_h1, __x._M_h1); | |
853 std::swap(_M_h2, __x._M_h2); | |
854 } | |
855 | |
856 protected: | |
857 _ExtractKey _M_extract; | |
858 _Equal _M_eq; | |
859 _H1 _M_h1; | |
860 _H2 _M_h2; | |
861 }; | |
862 } // namespace __detail | |
863 | |
864 _GLIBCXX_END_NAMESPACE_TR1 | |
865 } | |
OLD | NEW |