![]() |
Shadowrun: Awakened 29 September 2011 - Build 871
|
00001 /* 00002 Copyright 2005-2010 Intel Corporation. All Rights Reserved. 00003 00004 This file is part of Threading Building Blocks. 00005 00006 Threading Building Blocks is free software; you can redistribute it 00007 and/or modify it under the terms of the GNU General Public License 00008 version 2 as published by the Free Software Foundation. 00009 00010 Threading Building Blocks is distributed in the hope that it will be 00011 useful, but WITHOUT ANY WARRANTY; without even the implied warranty 00012 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License 00016 along with Threading Building Blocks; if not, write to the Free Software 00017 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00018 00019 As a special exception, you may use this file as part of a free software 00020 library without restriction. Specifically, if other files instantiate 00021 templates or use macros or inline functions from this file, or you compile 00022 this file and link it with other files to produce an executable, this 00023 file does not by itself cause the resulting executable to be covered by 00024 the GNU General Public License. This exception does not however 00025 invalidate any other reasons why the executable file might be covered by 00026 the GNU General Public License. 00027 */ 00028 00029 /* Container implementations in this header are based on PPL implementations 00030 provided by Microsoft. */ 00031 00032 #ifndef __TBB_concurrent_unordered_internal_H 00033 #define __TBB_concurrent_unordered_internal_H 00034 00035 #include "tbb_stddef.h" 00036 00037 #if !TBB_USE_EXCEPTIONS && _MSC_VER 00038 // Suppress "C++ exception handler used, but unwind semantics are not enabled" warning in STL headers 00039 #pragma warning (push) 00040 #pragma warning (disable: 4530) 00041 #endif 00042 00043 #include <iterator> 00044 #include <utility> // Need std::pair 00045 #include <functional> 00046 #include <string> // For tbb_hasher 00047 #include <cstring> // Need std::memset 00048 00049 #if !TBB_USE_EXCEPTIONS && _MSC_VER 00050 #pragma warning (pop) 00051 #endif 00052 00053 #include "tbb_machine.h" 00054 #include "tbb_exception.h" 00055 #include "tbb_allocator.h" 00056 00057 namespace tbb { 00058 namespace interface5 { 00060 namespace internal { 00061 00062 template <typename T, typename Allocator> 00063 class split_ordered_list; 00064 template <typename Traits> 00065 class concurrent_unordered_base; 00066 00067 // Forward list iterators (without skipping dummy elements) 00068 template<class Solist, typename Value> 00069 class flist_iterator : public std::iterator<std::forward_iterator_tag, Value> 00070 { 00071 template <typename T, typename Allocator> 00072 friend class split_ordered_list; 00073 template <typename Traits> 00074 friend class concurrent_unordered_base; 00075 template<class M, typename V> 00076 friend class flist_iterator; 00077 00078 typedef typename Solist::nodeptr_t nodeptr_t; 00079 public: 00080 typedef typename Solist::value_type value_type; 00081 typedef typename Solist::difference_type difference_type; 00082 typedef typename Solist::pointer pointer; 00083 typedef typename Solist::reference reference; 00084 00085 flist_iterator() : my_node_ptr(0) {} 00086 flist_iterator( const flist_iterator<Solist, typename Solist::value_type> &other ) 00087 : my_node_ptr(other.my_node_ptr) {} 00088 00089 reference operator*() const { return my_node_ptr->my_element; } 00090 pointer operator->() const { return &**this; } 00091 00092 flist_iterator& operator++() { 00093 my_node_ptr = my_node_ptr->my_next; 00094 return *this; 00095 } 00096 00097 flist_iterator operator++(int) { 00098 flist_iterator tmp = *this; 00099 ++*this; 00100 return tmp; 00101 } 00102 00103 protected: 00104 flist_iterator(nodeptr_t pnode) : my_node_ptr(pnode) {} 00105 nodeptr_t get_node_ptr() const { return my_node_ptr; } 00106 00107 nodeptr_t my_node_ptr; 00108 00109 template<typename M, typename T, typename U> 00110 friend bool operator==( const flist_iterator<M,T> &i, const flist_iterator<M,U> &j ); 00111 template<typename M, typename T, typename U> 00112 friend bool operator!=( const flist_iterator<M,T>& i, const flist_iterator<M,U>& j ); 00113 }; 00114 00115 template<typename Solist, typename T, typename U> 00116 bool operator==( const flist_iterator<Solist,T> &i, const flist_iterator<Solist,U> &j ) { 00117 return i.my_node_ptr == j.my_node_ptr; 00118 } 00119 template<typename Solist, typename T, typename U> 00120 bool operator!=( const flist_iterator<Solist,T>& i, const flist_iterator<Solist,U>& j ) { 00121 return i.my_node_ptr != j.my_node_ptr; 00122 } 00123 00124 // Split-order list iterators, needed to skip dummy elements 00125 template<class Solist, typename Value> 00126 class solist_iterator : public flist_iterator<Solist, Value> 00127 { 00128 typedef flist_iterator<Solist, Value> base_type; 00129 typedef typename Solist::nodeptr_t nodeptr_t; 00130 using base_type::get_node_ptr; 00131 template <typename T, typename Allocator> 00132 friend class split_ordered_list; 00133 template<class M, typename V> 00134 friend class solist_iterator; 00135 template<typename M, typename T, typename U> 00136 friend bool operator==( const solist_iterator<M,T> &i, const solist_iterator<M,U> &j ); 00137 template<typename M, typename T, typename U> 00138 friend bool operator!=( const solist_iterator<M,T>& i, const solist_iterator<M,U>& j ); 00139 00140 const Solist *my_list_ptr; 00141 solist_iterator(nodeptr_t pnode, const Solist *plist) : base_type(pnode), my_list_ptr(plist) {} 00142 00143 public: 00144 typedef typename Solist::value_type value_type; 00145 typedef typename Solist::difference_type difference_type; 00146 typedef typename Solist::pointer pointer; 00147 typedef typename Solist::reference reference; 00148 00149 solist_iterator() {} 00150 solist_iterator(const solist_iterator<Solist, typename Solist::value_type> &other ) 00151 : base_type(other), my_list_ptr(other.my_list_ptr) {} 00152 00153 reference operator*() const { 00154 return this->base_type::operator*(); 00155 } 00156 00157 pointer operator->() const { 00158 return (&**this); 00159 } 00160 00161 solist_iterator& operator++() { 00162 do ++(*(base_type *)this); 00163 while (get_node_ptr() != NULL && get_node_ptr()->is_dummy()); 00164 00165 return (*this); 00166 } 00167 00168 solist_iterator operator++(int) { 00169 solist_iterator tmp = *this; 00170 do ++*this; 00171 while (get_node_ptr() != NULL && get_node_ptr()->is_dummy()); 00172 00173 return (tmp); 00174 } 00175 }; 00176 00177 template<typename Solist, typename T, typename U> 00178 bool operator==( const solist_iterator<Solist,T> &i, const solist_iterator<Solist,U> &j ) { 00179 return i.my_node_ptr == j.my_node_ptr && i.my_list_ptr == j.my_list_ptr; 00180 } 00181 template<typename Solist, typename T, typename U> 00182 bool operator!=( const solist_iterator<Solist,T>& i, const solist_iterator<Solist,U>& j ) { 00183 return i.my_node_ptr != j.my_node_ptr || i.my_list_ptr != j.my_list_ptr; 00184 } 00185 00186 // Forward type and class definitions 00187 typedef size_t sokey_t; 00188 00189 // Forward list in which elements are sorted in a split-order 00190 template <typename T, typename Allocator> 00191 class split_ordered_list 00192 { 00193 public: 00194 typedef split_ordered_list<T, Allocator> self_type; 00195 typedef typename Allocator::template rebind<T>::other allocator_type; 00196 struct node; 00197 typedef node *nodeptr_t; 00198 00199 typedef typename allocator_type::size_type size_type; 00200 typedef typename allocator_type::difference_type difference_type; 00201 typedef typename allocator_type::pointer pointer; 00202 typedef typename allocator_type::const_pointer const_pointer; 00203 typedef typename allocator_type::reference reference; 00204 typedef typename allocator_type::const_reference const_reference; 00205 typedef typename allocator_type::value_type value_type; 00206 00207 typedef solist_iterator<self_type, const value_type> const_iterator; 00208 typedef solist_iterator<self_type, value_type> iterator; 00209 typedef flist_iterator<self_type, const value_type> raw_const_iterator; 00210 typedef flist_iterator<self_type, value_type> raw_iterator; 00211 00212 // Node that holds the element in a split-ordered list 00213 struct node : tbb::internal::no_assign 00214 { 00215 // Initialize the node with the given order key 00216 void init(sokey_t order_key) { 00217 my_order_key = order_key; 00218 my_next = NULL; 00219 } 00220 00221 // Return the order key (needed for hashing) 00222 sokey_t get_order_key() const { // TODO: remove 00223 return my_order_key; 00224 } 00225 00226 // Inserts the new element in the list in an atomic fashion 00227 nodeptr_t atomic_set_next(nodeptr_t new_node, nodeptr_t current_node) 00228 { 00229 // Try to change the next pointer on the current element to a new element, only if it still points to the cached next 00230 nodeptr_t exchange_node = (nodeptr_t) __TBB_CompareAndSwapW((void *) &my_next, (uintptr_t)new_node, (uintptr_t)current_node); 00231 00232 if (exchange_node == current_node) // TODO: why this branch? 00233 { 00234 // Operation succeeded, return the new node 00235 return new_node; 00236 } 00237 else 00238 { 00239 // Operation failed, return the "interfering" node 00240 return exchange_node; 00241 } 00242 } 00243 00244 // Checks if this element in the list is a dummy, order enforcing node. Dummy nodes are used by buckets 00245 // in the hash table to quickly index into the right subsection of the split-ordered list. 00246 bool is_dummy() const { 00247 return (my_order_key & 0x1) == 0; 00248 } 00249 00250 00251 nodeptr_t my_next; // Next element in the list 00252 value_type my_element; // Element storage 00253 sokey_t my_order_key; // Order key for this element 00254 }; 00255 00256 // Allocate a new node with the given order key and value 00257 nodeptr_t create_node(sokey_t order_key, const T &value) { 00258 nodeptr_t pnode = my_node_allocator.allocate(1); 00259 00260 __TBB_TRY { 00261 new(static_cast<void*>(&pnode->my_element)) T(value); 00262 pnode->init(order_key); 00263 } __TBB_CATCH(...) { 00264 my_node_allocator.deallocate(pnode, 1); 00265 __TBB_RETHROW(); 00266 } 00267 00268 return (pnode); 00269 } 00270 00271 // Allocate a new node with the given order key; used to allocate dummy nodes 00272 nodeptr_t create_node(sokey_t order_key) { 00273 nodeptr_t pnode = my_node_allocator.allocate(1); 00274 00275 __TBB_TRY { 00276 new(static_cast<void*>(&pnode->my_element)) T(); 00277 pnode->init(order_key); 00278 } __TBB_CATCH(...) { 00279 my_node_allocator.deallocate(pnode, 1); 00280 __TBB_RETHROW(); 00281 } 00282 00283 return (pnode); 00284 } 00285 00286 split_ordered_list(allocator_type a = allocator_type()) 00287 : my_node_allocator(a), my_element_count(0) 00288 { 00289 // Immediately allocate a dummy node with order key of 0. This node 00290 // will always be the head of the list. 00291 my_head = create_node(0); 00292 } 00293 00294 ~split_ordered_list() 00295 { 00296 // Clear the list 00297 clear(); 00298 00299 // Remove the head element which is not cleared by clear() 00300 nodeptr_t pnode = my_head; 00301 my_head = NULL; 00302 00303 __TBB_ASSERT(pnode != NULL && pnode->my_next == NULL, "Invalid head list node"); 00304 00305 destroy_node(pnode); 00306 } 00307 00308 // Common forward list functions 00309 00310 allocator_type get_allocator() const { 00311 return (my_node_allocator); 00312 } 00313 00314 void clear() { 00315 nodeptr_t pnext; 00316 nodeptr_t pnode = my_head; 00317 00318 __TBB_ASSERT(my_head != NULL, "Invalid head list node"); 00319 pnext = pnode->my_next; 00320 pnode->my_next = NULL; 00321 pnode = pnext; 00322 00323 while (pnode != NULL) 00324 { 00325 pnext = pnode->my_next; 00326 destroy_node(pnode); 00327 pnode = pnext; 00328 } 00329 00330 my_element_count = 0; 00331 } 00332 00333 // Returns a first non-dummy element in the SOL 00334 iterator begin() { 00335 return first_real_iterator(raw_begin()); 00336 } 00337 00338 // Returns a first non-dummy element in the SOL 00339 const_iterator begin() const { 00340 return first_real_iterator(raw_begin()); 00341 } 00342 00343 iterator end() { 00344 return (iterator(0, this)); 00345 } 00346 00347 const_iterator end() const { 00348 return (const_iterator(0, this)); 00349 } 00350 00351 const_iterator cbegin() const { 00352 return (((const self_type *)this)->begin()); 00353 } 00354 00355 const_iterator cend() const { 00356 return (((const self_type *)this)->end()); 00357 } 00358 00359 // Checks if the number of elements (non-dummy) is 0 00360 bool empty() const { 00361 return (my_element_count == 0); 00362 } 00363 00364 // Returns the number of non-dummy elements in the list 00365 size_type size() const { 00366 return my_element_count; 00367 } 00368 00369 // Returns the maximum size of the list, determined by the allocator 00370 size_type max_size() const { 00371 return my_node_allocator.max_size(); 00372 } 00373 00374 // Swaps 'this' list with the passed in one 00375 void swap(self_type& other) 00376 { 00377 if (this == &other) 00378 { 00379 // Nothing to do 00380 return; 00381 } 00382 00383 std::swap(my_element_count, other.my_element_count); 00384 std::swap(my_head, other.my_head); 00385 } 00386 00387 // Split-order list functions 00388 00389 // Returns a first element in the SOL, which is always a dummy 00390 raw_iterator raw_begin() { 00391 return raw_iterator(my_head); 00392 } 00393 00394 // Returns a first element in the SOL, which is always a dummy 00395 raw_const_iterator raw_begin() const { 00396 return raw_const_iterator(my_head); 00397 } 00398 00399 raw_iterator raw_end() { 00400 return raw_iterator(0); 00401 } 00402 00403 raw_const_iterator raw_end() const { 00404 return raw_const_iterator(0); 00405 } 00406 00407 static sokey_t get_order_key(const raw_const_iterator& it) { 00408 return it.get_node_ptr()->get_order_key(); 00409 } 00410 00411 static sokey_t get_safe_order_key(const raw_const_iterator& it) { 00412 if( !it.get_node_ptr() ) return sokey_t(~0U); 00413 return it.get_node_ptr()->get_order_key(); 00414 } 00415 00416 // Returns a public iterator version of the internal iterator. Public iterator must not 00417 // be a dummy private iterator. 00418 iterator get_iterator(raw_iterator it) { 00419 __TBB_ASSERT(it.get_node_ptr() == NULL || !it.get_node_ptr()->is_dummy(), "Invalid user node (dummy)"); 00420 return iterator(it.get_node_ptr(), this); 00421 } 00422 00423 // Returns a public iterator version of the internal iterator. Public iterator must not 00424 // be a dummy private iterator. 00425 const_iterator get_iterator(raw_const_iterator it) const { 00426 __TBB_ASSERT(it.get_node_ptr() == NULL || !it.get_node_ptr()->is_dummy(), "Invalid user node (dummy)"); 00427 return const_iterator(it.get_node_ptr(), this); 00428 } 00429 00430 // Returns a non-const version of the raw_iterator 00431 raw_iterator get_iterator(raw_const_iterator it) { 00432 return raw_iterator(it.get_node_ptr()); 00433 } 00434 00435 // Returns a non-const version of the iterator 00436 static iterator get_iterator(const_iterator it) { 00437 return iterator(it.my_node_ptr, it.my_list_ptr); 00438 } 00439 00440 // Returns a public iterator version of a first non-dummy internal iterator at or after 00441 // the passed in internal iterator. 00442 iterator first_real_iterator(raw_iterator it) 00443 { 00444 // Skip all dummy, internal only iterators 00445 while (it != raw_end() && it.get_node_ptr()->is_dummy()) 00446 ++it; 00447 00448 return iterator(it.get_node_ptr(), this); 00449 } 00450 00451 // Returns a public iterator version of a first non-dummy internal iterator at or after 00452 // the passed in internal iterator. 00453 const_iterator first_real_iterator(raw_const_iterator it) const 00454 { 00455 // Skip all dummy, internal only iterators 00456 while (it != raw_end() && it.get_node_ptr()->is_dummy()) 00457 ++it; 00458 00459 return const_iterator(it.get_node_ptr(), this); 00460 } 00461 00462 // Erase an element using the allocator 00463 void destroy_node(nodeptr_t pnode) { 00464 my_node_allocator.destroy(pnode); 00465 my_node_allocator.deallocate(pnode, 1); 00466 } 00467 00468 // Try to insert a new element in the list. If insert fails, return the node that 00469 // was inserted instead. 00470 nodeptr_t try_insert(nodeptr_t previous, nodeptr_t new_node, nodeptr_t current_node) { 00471 new_node->my_next = current_node; 00472 return previous->atomic_set_next(new_node, current_node); 00473 } 00474 00475 // Insert a new element between passed in iterators 00476 std::pair<iterator, bool> try_insert(raw_iterator it, raw_iterator next, const value_type &value, sokey_t order_key, size_type *new_count) 00477 { 00478 nodeptr_t pnode = create_node(order_key, value); 00479 nodeptr_t inserted_node = try_insert(it.get_node_ptr(), pnode, next.get_node_ptr()); 00480 00481 if (inserted_node == pnode) 00482 { 00483 // If the insert succeeded, check that the order is correct and increment the element count 00484 check_range(); 00485 *new_count = __TBB_FetchAndAddW((uintptr_t*)&my_element_count, uintptr_t(1)); 00486 return std::pair<iterator, bool>(iterator(pnode, this), true); 00487 } 00488 else 00489 { 00490 // If the insert failed (element already there), then delete the new one 00491 destroy_node(pnode); 00492 return std::pair<iterator, bool>(end(), false); 00493 } 00494 } 00495 00496 // Insert a new dummy element, starting search at a parent dummy element 00497 raw_iterator insert_dummy(raw_iterator it, sokey_t order_key) 00498 { 00499 raw_iterator last = raw_end(); 00500 raw_iterator where = it; 00501 00502 __TBB_ASSERT(where != last, "Invalid head node"); 00503 00504 ++where; 00505 00506 // Create a dummy element up front, even though it may be discarded (due to concurrent insertion) 00507 nodeptr_t dummy_node = create_node(order_key); 00508 00509 for (;;) 00510 { 00511 __TBB_ASSERT(it != last, "Invalid head list node"); 00512 00513 // If the head iterator is at the end of the list, or past the point where this dummy 00514 // node needs to be inserted, then try to insert it. 00515 if (where == last || get_order_key(where) > order_key) 00516 { 00517 __TBB_ASSERT(get_order_key(it) < order_key, "Invalid node order in the list"); 00518 00519 // Try to insert it in the right place 00520 nodeptr_t inserted_node = try_insert(it.get_node_ptr(), dummy_node, where.get_node_ptr()); 00521 00522 if (inserted_node == dummy_node) 00523 { 00524 // Insertion succeeded, check the list for order violations 00525 check_range(); 00526 return raw_iterator(dummy_node); 00527 } 00528 else 00529 { 00530 // Insertion failed: either dummy node was inserted by another thread, or 00531 // a real element was inserted at exactly the same place as dummy node. 00532 // Proceed with the search from the previous location where order key was 00533 // known to be larger (note: this is legal only because there is no safe 00534 // concurrent erase operation supported). 00535 where = it; 00536 ++where; 00537 continue; 00538 } 00539 } 00540 else if (get_order_key(where) == order_key) 00541 { 00542 // Another dummy node with the same value found, discard the new one. 00543 destroy_node(dummy_node); 00544 return where; 00545 } 00546 00547 // Move the iterator forward 00548 it = where; 00549 ++where; 00550 } 00551 00552 } 00553 00554 // This erase function can handle both real and dummy nodes 00555 void erase_node(raw_iterator previous, raw_const_iterator& where) 00556 { 00557 nodeptr_t pnode = (where++).get_node_ptr(); 00558 nodeptr_t prevnode = previous.get_node_ptr(); 00559 __TBB_ASSERT(prevnode->my_next == pnode, "Erase must take consecutive iterators"); 00560 prevnode->my_next = pnode->my_next; 00561 00562 destroy_node(pnode); 00563 } 00564 00565 // Erase the element (previous node needs to be passed because this is a forward only list) 00566 iterator erase_node(raw_iterator previous, const_iterator where) 00567 { 00568 raw_const_iterator it = where; 00569 erase_node(previous, it); 00570 my_element_count--; 00571 00572 return get_iterator(first_real_iterator(it)); 00573 } 00574 00575 // Move all elements from the passed in split-ordered list to this one 00576 void move_all(self_type& source) 00577 { 00578 raw_const_iterator first = source.raw_begin(); 00579 raw_const_iterator last = source.raw_end(); 00580 00581 if (first == last) 00582 return; 00583 00584 nodeptr_t previous_node = my_head; 00585 raw_const_iterator begin_iterator = first++; 00586 00587 // Move all elements one by one, including dummy ones 00588 for (raw_const_iterator it = first; it != last;) 00589 { 00590 nodeptr_t pnode = it.get_node_ptr(); 00591 00592 nodeptr_t dummy_node = pnode->is_dummy() ? create_node(pnode->get_order_key()) : create_node(pnode->get_order_key(), pnode->my_element); 00593 previous_node = try_insert(previous_node, dummy_node, NULL); 00594 __TBB_ASSERT(previous_node != NULL, "Insertion must succeed"); 00595 raw_const_iterator where = it++; 00596 source.erase_node(get_iterator(begin_iterator), where); 00597 } 00598 check_range(); 00599 } 00600 00601 00602 private: 00603 00604 // Check the list for order violations 00605 void check_range() 00606 { 00607 #if TBB_USE_ASSERT 00608 for (raw_iterator it = raw_begin(); it != raw_end(); ++it) 00609 { 00610 raw_iterator next_iterator = it; 00611 ++next_iterator; 00612 00613 __TBB_ASSERT(next_iterator == end() || next_iterator.get_node_ptr()->get_order_key() >= it.get_node_ptr()->get_order_key(), "!!! List order inconsistency !!!"); 00614 } 00615 #endif 00616 } 00617 00618 typename allocator_type::template rebind<node>::other my_node_allocator; // allocator object for nodes 00619 size_type my_element_count; // Total item count, not counting dummy nodes 00620 nodeptr_t my_head; // pointer to head node 00621 }; 00622 00623 // Template class for hash compare 00624 template<typename Key, typename Hasher, typename Key_equality> 00625 class hash_compare 00626 { 00627 public: 00628 hash_compare() {} 00629 00630 hash_compare(Hasher a_hasher) : my_hash_object(a_hasher) {} 00631 00632 hash_compare(Hasher a_hasher, Key_equality a_keyeq) : my_hash_object(a_hasher), my_key_compare_object(a_keyeq) {} 00633 00634 size_t operator()(const Key& key) const { 00635 return ((size_t)my_hash_object(key)); 00636 } 00637 00638 bool operator()(const Key& key1, const Key& key2) const { 00639 return (!my_key_compare_object(key1, key2)); 00640 } 00641 00642 Hasher my_hash_object; // The hash object 00643 Key_equality my_key_compare_object; // The equality comparator object 00644 }; 00645 00646 #if _MSC_VER 00647 #pragma warning(push) 00648 #pragma warning(disable: 4127) // warning 4127 -- while (true) has a constant expression in it (for allow_multimapping) 00649 #endif 00650 00651 template <typename Traits> 00652 class concurrent_unordered_base : public Traits 00653 { 00654 protected: 00655 // Type definitions 00656 typedef concurrent_unordered_base<Traits> self_type; 00657 typedef typename Traits::value_type value_type; 00658 typedef typename Traits::key_type key_type; 00659 typedef typename Traits::hash_compare hash_compare; 00660 typedef typename Traits::value_compare value_compare; 00661 typedef typename Traits::allocator_type allocator_type; 00662 typedef typename allocator_type::pointer pointer; 00663 typedef typename allocator_type::const_pointer const_pointer; 00664 typedef typename allocator_type::reference reference; 00665 typedef typename allocator_type::const_reference const_reference; 00666 typedef typename allocator_type::size_type size_type; 00667 typedef typename allocator_type::difference_type difference_type; 00668 typedef split_ordered_list<value_type, typename Traits::allocator_type> solist_t; 00669 typedef typename solist_t::nodeptr_t nodeptr_t; 00670 // Iterators that walk the entire split-order list, including dummy nodes 00671 typedef typename solist_t::raw_iterator raw_iterator; 00672 typedef typename solist_t::raw_const_iterator raw_const_iterator; 00673 typedef typename solist_t::iterator iterator; // TODO: restore const iterator for unordered_sets 00674 typedef typename solist_t::const_iterator const_iterator; 00675 typedef iterator local_iterator; 00676 typedef const_iterator const_local_iterator; 00677 using Traits::my_hash_compare; 00678 using Traits::get_key; 00679 using Traits::allow_multimapping; 00680 00681 private: 00682 typedef std::pair<iterator, iterator> pairii_t; 00683 typedef std::pair<const_iterator, const_iterator> paircc_t; 00684 00685 static size_type const pointers_per_table = sizeof(size_type) * 8; // One bucket segment per bit 00686 static const size_type initial_bucket_number = 8; // Initial number of buckets 00687 static const size_type initial_bucket_load = 4; // Initial maximum number of elements per bucket 00688 00689 protected: 00690 // Constructors/Destructors 00691 concurrent_unordered_base(size_type n_of_buckets = initial_bucket_number, 00692 const hash_compare& hc = hash_compare(), const allocator_type& a = allocator_type()) 00693 : Traits(hc), my_number_of_buckets(n_of_buckets), my_solist(a), 00694 my_allocator(a), my_maximum_bucket_size((float) initial_bucket_load) 00695 { 00696 internal_init(); 00697 } 00698 00699 concurrent_unordered_base(const concurrent_unordered_base& right, const allocator_type& a) 00700 : Traits(right.my_hash_compare), my_solist(a), my_allocator(a) 00701 { 00702 internal_copy(right); 00703 } 00704 00705 concurrent_unordered_base(const concurrent_unordered_base& right) 00706 : Traits(right.my_hash_compare), my_solist(right.get_allocator()), my_allocator(right.get_allocator()) 00707 { 00708 internal_init(); 00709 internal_copy(right); 00710 } 00711 00712 concurrent_unordered_base& operator=(const concurrent_unordered_base& right) { 00713 if (this != &right) 00714 internal_copy(right); 00715 return (*this); 00716 } 00717 00718 ~concurrent_unordered_base() { 00719 // Delete all node segments 00720 internal_clear(); 00721 } 00722 00723 public: 00724 allocator_type get_allocator() const { 00725 return my_solist.get_allocator(); 00726 } 00727 00728 // Size and capacity function 00729 bool empty() const { 00730 return my_solist.empty(); 00731 } 00732 00733 size_type size() const { 00734 return my_solist.size(); 00735 } 00736 00737 size_type max_size() const { 00738 return my_solist.max_size(); 00739 } 00740 00741 // Iterators 00742 iterator begin() { 00743 return my_solist.begin(); 00744 } 00745 00746 const_iterator begin() const { 00747 return my_solist.begin(); 00748 } 00749 00750 iterator end() { 00751 return my_solist.end(); 00752 } 00753 00754 const_iterator end() const { 00755 return my_solist.end(); 00756 } 00757 00758 const_iterator cbegin() const { 00759 return my_solist.cbegin(); 00760 } 00761 00762 const_iterator cend() const { 00763 return my_solist.cend(); 00764 } 00765 00766 // Parallel traversal support 00767 class const_range_type : tbb::internal::no_assign { 00768 const concurrent_unordered_base &my_table; 00769 raw_const_iterator my_begin_node; 00770 raw_const_iterator my_end_node; 00771 mutable raw_const_iterator my_midpoint_node; 00772 public: 00774 typedef typename concurrent_unordered_base::size_type size_type; 00775 typedef typename concurrent_unordered_base::value_type value_type; 00776 typedef typename concurrent_unordered_base::reference reference; 00777 typedef typename concurrent_unordered_base::difference_type difference_type; 00778 typedef typename concurrent_unordered_base::const_iterator iterator; 00779 00781 bool empty() const {return my_begin_node == my_end_node;} 00782 00784 bool is_divisible() const { 00785 return my_midpoint_node != my_end_node; 00786 } 00788 const_range_type( const_range_type &r, split ) : 00789 my_table(r.my_table), my_end_node(r.my_end_node) 00790 { 00791 r.my_end_node = my_begin_node = r.my_midpoint_node; 00792 __TBB_ASSERT( !empty(), "Splitting despite the range is not divisible" ); 00793 __TBB_ASSERT( !r.empty(), "Splitting despite the range is not divisible" ); 00794 set_midpoint(); 00795 r.set_midpoint(); 00796 } 00798 const_range_type( const concurrent_unordered_base &a_table ) : 00799 my_table(a_table), my_begin_node(a_table.my_solist.begin()), 00800 my_end_node(a_table.my_solist.end()) 00801 { 00802 set_midpoint(); 00803 } 00804 iterator begin() const { return my_table.my_solist.get_iterator(my_begin_node); } 00805 iterator end() const { return my_table.my_solist.get_iterator(my_end_node); } 00807 size_type grainsize() const { return 1; } 00808 00810 void set_midpoint() const { 00811 if( my_begin_node == my_end_node ) // not divisible 00812 my_midpoint_node = my_end_node; 00813 else { 00814 sokey_t begin_key = solist_t::get_safe_order_key(my_begin_node); 00815 sokey_t end_key = solist_t::get_safe_order_key(my_end_node); 00816 size_t mid_bucket = __TBB_ReverseBits( begin_key + (end_key-begin_key)/2 ) % my_table.my_number_of_buckets; 00817 while ( !my_table.is_initialized(mid_bucket) ) mid_bucket = my_table.get_parent(mid_bucket); 00818 my_midpoint_node = my_table.my_solist.first_real_iterator(my_table.get_bucket( mid_bucket )); 00819 if( my_midpoint_node == my_begin_node ) 00820 my_midpoint_node = my_end_node; 00821 #if TBB_USE_ASSERT 00822 else { 00823 sokey_t mid_key = solist_t::get_safe_order_key(my_midpoint_node); 00824 __TBB_ASSERT( begin_key < mid_key, "my_begin_node is after my_midpoint_node" ); 00825 __TBB_ASSERT( mid_key <= end_key, "my_midpoint_node is after my_end_node" ); 00826 } 00827 #endif // TBB_USE_ASSERT 00828 } 00829 } 00830 }; 00831 00832 class range_type : public const_range_type { 00833 public: 00834 typedef typename concurrent_unordered_base::iterator iterator; 00836 range_type( range_type &r, split ) : const_range_type( r, split() ) {} 00838 range_type( const concurrent_unordered_base &a_table ) : const_range_type(a_table) {} 00839 00840 iterator begin() const { return solist_t::get_iterator( const_range_type::begin() ); } 00841 iterator end() const { return solist_t::get_iterator( const_range_type::end() ); } 00842 }; 00843 00844 range_type range() { 00845 return range_type( *this ); 00846 } 00847 00848 const_range_type range() const { 00849 return const_range_type( *this ); 00850 } 00851 00852 // Modifiers 00853 std::pair<iterator, bool> insert(const value_type& value) { 00854 return internal_insert(value); 00855 } 00856 00857 iterator insert(const_iterator, const value_type& value) { 00858 // Ignore hint 00859 return insert(value).first; 00860 } 00861 00862 template<class Iterator> 00863 void insert(Iterator first, Iterator last) { 00864 for (Iterator it = first; it != last; ++it) 00865 insert(*it); 00866 } 00867 00868 iterator unsafe_erase(const_iterator where) { 00869 return internal_erase(where); 00870 } 00871 00872 iterator unsafe_erase(const_iterator first, const_iterator last) { 00873 while (first != last) 00874 unsafe_erase(first++); 00875 return my_solist.get_iterator(first); 00876 } 00877 00878 size_type unsafe_erase(const key_type& key) { 00879 pairii_t where = equal_range(key); 00880 size_type item_count = internal_distance(where.first, where.second); 00881 unsafe_erase(where.first, where.second); 00882 return item_count; 00883 } 00884 00885 void swap(concurrent_unordered_base& right) { 00886 if (this != &right) { 00887 std::swap(my_hash_compare, right.my_hash_compare); // TODO: check what ADL meant here 00888 my_solist.swap(right.my_solist); 00889 internal_swap_buckets(right); 00890 std::swap(my_number_of_buckets, right.my_number_of_buckets); 00891 std::swap(my_maximum_bucket_size, right.my_maximum_bucket_size); 00892 } 00893 } 00894 00895 // Observers 00896 void clear() { 00897 // Clear list 00898 my_solist.clear(); 00899 00900 // Clear buckets 00901 internal_clear(); 00902 } 00903 00904 // Lookup 00905 iterator find(const key_type& key) { 00906 return internal_find(key); 00907 } 00908 00909 const_iterator find(const key_type& key) const { 00910 return const_cast<self_type*>(this)->internal_find(key); 00911 } 00912 00913 size_type count(const key_type& key) const { 00914 paircc_t answer = equal_range(key); 00915 size_type item_count = internal_distance(answer.first, answer.second); 00916 return item_count; 00917 } 00918 00919 std::pair<iterator, iterator> equal_range(const key_type& key) { 00920 return internal_equal_range(key); 00921 } 00922 00923 std::pair<const_iterator, const_iterator> equal_range(const key_type& key) const { 00924 return internal_equal_range(key); 00925 } 00926 00927 // Bucket interface - for debugging 00928 size_type unsafe_bucket_count() const { 00929 return my_number_of_buckets; 00930 } 00931 00932 size_type unsafe_max_bucket_count() const { 00933 return segment_size(pointers_per_table-1); 00934 } 00935 00936 size_type unsafe_bucket_size(size_type bucket) { 00937 size_type item_count = 0; 00938 if (is_initialized(bucket)) { 00939 raw_iterator it = get_bucket(bucket); 00940 ++it; 00941 for (; it != my_solist.raw_end() && !it.get_node_ptr()->is_dummy(); ++it) 00942 ++item_count; 00943 } 00944 return item_count; 00945 } 00946 00947 size_type unsafe_bucket(const key_type& key) const { 00948 sokey_t order_key = (sokey_t) my_hash_compare(key); 00949 size_type bucket = order_key % my_number_of_buckets; 00950 return bucket; 00951 } 00952 00953 // If the bucket is initialized, return a first non-dummy element in it 00954 local_iterator unsafe_begin(size_type bucket) { 00955 if (!is_initialized(bucket)) 00956 return end(); 00957 00958 raw_iterator it = get_bucket(bucket); 00959 return my_solist.first_real_iterator(it); 00960 } 00961 00962 // If the bucket is initialized, return a first non-dummy element in it 00963 const_local_iterator unsafe_begin(size_type bucket) const 00964 { 00965 if (!is_initialized(bucket)) 00966 return end(); 00967 00968 raw_const_iterator it = get_bucket(bucket); 00969 return my_solist.first_real_iterator(it); 00970 } 00971 00972 // @REVIEW: Takes O(n) 00973 // Returns the iterator after the last non-dummy element in the bucket 00974 local_iterator unsafe_end(size_type bucket) 00975 { 00976 if (!is_initialized(bucket)) 00977 return end(); 00978 00979 raw_iterator it = get_bucket(bucket); 00980 00981 // Find the end of the bucket, denoted by the dummy element 00982 do ++it; 00983 while(it != my_solist.raw_end() && !it.get_node_ptr()->is_dummy()); 00984 00985 // Return the first real element past the end of the bucket 00986 return my_solist.first_real_iterator(it); 00987 } 00988 00989 // @REVIEW: Takes O(n) 00990 // Returns the iterator after the last non-dummy element in the bucket 00991 const_local_iterator unsafe_end(size_type bucket) const 00992 { 00993 if (!is_initialized(bucket)) 00994 return end(); 00995 00996 raw_const_iterator it = get_bucket(bucket); 00997 00998 // Find the end of the bucket, denoted by the dummy element 00999 do ++it; 01000 while(it != my_solist.raw_end() && !it.get_node_ptr()->is_dummy()); 01001 01002 // Return the first real element past the end of the bucket 01003 return my_solist.first_real_iterator(it); 01004 } 01005 01006 const_local_iterator unsafe_cbegin(size_type bucket) const { 01007 return ((const self_type *) this)->begin(); 01008 } 01009 01010 const_local_iterator unsafe_cend(size_type bucket) const { 01011 return ((const self_type *) this)->end(); 01012 } 01013 01014 // Hash policy 01015 float load_factor() const { 01016 return (float) size() / (float) unsafe_bucket_count(); 01017 } 01018 01019 float max_load_factor() const { 01020 return my_maximum_bucket_size; 01021 } 01022 01023 void max_load_factor(float newmax) { 01024 if (newmax != newmax || newmax < 0) 01025 tbb::internal::throw_exception(tbb::internal::eid_invalid_load_factor); 01026 my_maximum_bucket_size = newmax; 01027 } 01028 01029 // This function is a noop, because the underlying split-ordered list 01030 // is already sorted, so an increase in the bucket number will be 01031 // reflected next time this bucket is touched. 01032 void rehash(size_type buckets) { 01033 size_type current_buckets = my_number_of_buckets; 01034 01035 if (current_buckets > buckets) 01036 return; 01037 else if ( (buckets & (buckets-1)) != 0 ) 01038 tbb::internal::throw_exception(tbb::internal::eid_invalid_buckets_number); 01039 my_number_of_buckets = buckets; 01040 } 01041 01042 private: 01043 01044 // Initialize the hash and keep the first bucket open 01045 void internal_init() { 01046 // Allocate an array of segment pointers 01047 memset(my_buckets, 0, pointers_per_table * sizeof(void *)); 01048 01049 // Insert the first element in the split-ordered list 01050 raw_iterator dummy_node = my_solist.raw_begin(); 01051 set_bucket(0, dummy_node); 01052 } 01053 01054 void internal_clear() { 01055 for (size_type index = 0; index < pointers_per_table; ++index) { 01056 if (my_buckets[index] != NULL) { 01057 size_type sz = segment_size(index); 01058 for (size_type index2 = 0; index2 < sz; ++index2) 01059 my_allocator.destroy(&my_buckets[index][index2]); 01060 my_allocator.deallocate(my_buckets[index], sz); 01061 my_buckets[index] = 0; 01062 } 01063 } 01064 } 01065 01066 void internal_copy(const self_type& right) { 01067 clear(); 01068 01069 my_maximum_bucket_size = right.my_maximum_bucket_size; 01070 my_number_of_buckets = right.my_number_of_buckets; 01071 01072 __TBB_TRY { 01073 insert(right.begin(), right.end()); 01074 my_hash_compare = right.my_hash_compare; 01075 } __TBB_CATCH(...) { 01076 my_solist.clear(); 01077 __TBB_RETHROW(); 01078 } 01079 } 01080 01081 void internal_swap_buckets(concurrent_unordered_base& right) 01082 { 01083 // Swap all node segments 01084 for (size_type index = 0; index < pointers_per_table; ++index) 01085 { 01086 raw_iterator * iterator_pointer = my_buckets[index]; 01087 my_buckets[index] = right.my_buckets[index]; 01088 right.my_buckets[index] = iterator_pointer; 01089 } 01090 } 01091 01092 // Hash APIs 01093 size_type internal_distance(const_iterator first, const_iterator last) const 01094 { 01095 size_type num = 0; 01096 01097 for (const_iterator it = first; it != last; ++it) 01098 ++num; 01099 01100 return num; 01101 } 01102 01103 // Insert an element in the hash given its value 01104 std::pair<iterator, bool> internal_insert(const value_type& value) 01105 { 01106 sokey_t order_key = (sokey_t) my_hash_compare(get_key(value)); 01107 size_type bucket = order_key % my_number_of_buckets; 01108 01109 // If bucket is empty, initialize it first 01110 if (!is_initialized(bucket)) 01111 init_bucket(bucket); 01112 01113 size_type new_count; 01114 order_key = split_order_key_regular(order_key); 01115 raw_iterator it = get_bucket(bucket); 01116 raw_iterator last = my_solist.raw_end(); 01117 raw_iterator where = it; 01118 01119 __TBB_ASSERT(where != last, "Invalid head node"); 01120 01121 // First node is a dummy node 01122 ++where; 01123 01124 for (;;) 01125 { 01126 if (where == last || solist_t::get_order_key(where) > order_key) 01127 { 01128 // Try to insert it in the right place 01129 std::pair<iterator, bool> result = my_solist.try_insert(it, where, value, order_key, &new_count); 01130 01131 if (result.second) 01132 { 01133 // Insertion succeeded, adjust the table size, if needed 01134 adjust_table_size(new_count, my_number_of_buckets); 01135 return result; 01136 } 01137 else 01138 { 01139 // Insertion failed: either the same node was inserted by another thread, or 01140 // another element was inserted at exactly the same place as this node. 01141 // Proceed with the search from the previous location where order key was 01142 // known to be larger (note: this is legal only because there is no safe 01143 // concurrent erase operation supported). 01144 where = it; 01145 ++where; 01146 continue; 01147 } 01148 } 01149 else if (!allow_multimapping && solist_t::get_order_key(where) == order_key && my_hash_compare(get_key(*where), get_key(value)) == 0) 01150 { 01151 // Element already in the list, return it 01152 return std::pair<iterator, bool>(my_solist.get_iterator(where), false); 01153 } 01154 01155 // Move the iterator forward 01156 it = where; 01157 ++where; 01158 } 01159 } 01160 01161 // Find the element in the split-ordered list 01162 iterator internal_find(const key_type& key) 01163 { 01164 sokey_t order_key = (sokey_t) my_hash_compare(key); 01165 size_type bucket = order_key % my_number_of_buckets; 01166 01167 // If bucket is empty, initialize it first 01168 if (!is_initialized(bucket)) 01169 init_bucket(bucket); 01170 01171 order_key = split_order_key_regular(order_key); 01172 raw_iterator last = my_solist.raw_end(); 01173 01174 for (raw_iterator it = get_bucket(bucket); it != last; ++it) 01175 { 01176 if (solist_t::get_order_key(it) > order_key) 01177 { 01178 // If the order key is smaller than the current order key, the element 01179 // is not in the hash. 01180 return end(); 01181 } 01182 else if (solist_t::get_order_key(it) == order_key) 01183 { 01184 // The fact that order keys match does not mean that the element is found. 01185 // Key function comparison has to be performed to check whether this is the 01186 // right element. If not, keep searching while order key is the same. 01187 if (!my_hash_compare(get_key(*it), key)) 01188 return my_solist.get_iterator(it); 01189 } 01190 } 01191 01192 return end(); 01193 } 01194 01195 // Erase an element from the list. This is not a concurrency safe function. 01196 iterator internal_erase(const_iterator it) 01197 { 01198 key_type key = get_key(*it); 01199 sokey_t order_key = (sokey_t) my_hash_compare(key); 01200 size_type bucket = order_key % my_number_of_buckets; 01201 01202 // If bucket is empty, initialize it first 01203 if (!is_initialized(bucket)) 01204 init_bucket(bucket); 01205 01206 order_key = split_order_key_regular(order_key); 01207 01208 raw_iterator previous = get_bucket(bucket); 01209 raw_iterator last = my_solist.raw_end(); 01210 raw_iterator where = previous; 01211 01212 __TBB_ASSERT(where != last, "Invalid head node"); 01213 01214 // First node is a dummy node 01215 ++where; 01216 01217 for (;;) { 01218 if (where == last) 01219 return end(); 01220 else if (my_solist.get_iterator(where) == it) 01221 return my_solist.erase_node(previous, it); 01222 01223 // Move the iterator forward 01224 previous = where; 01225 ++where; 01226 } 01227 } 01228 01229 // Return the [begin, end) pair of iterators with the same key values. 01230 // This operation makes sense only if mapping is many-to-one. 01231 pairii_t internal_equal_range(const key_type& key) 01232 { 01233 sokey_t order_key = (sokey_t) my_hash_compare(key); 01234 size_type bucket = order_key % my_number_of_buckets; 01235 01236 // If bucket is empty, initialize it first 01237 if (!is_initialized(bucket)) 01238 init_bucket(bucket); 01239 01240 order_key = split_order_key_regular(order_key); 01241 raw_iterator end_it = my_solist.raw_end(); 01242 01243 for (raw_iterator it = get_bucket(bucket); it != end_it; ++it) 01244 { 01245 if (solist_t::get_order_key(it) > order_key) 01246 { 01247 // There is no element with the given key 01248 return pairii_t(end(), end()); 01249 } 01250 else if (solist_t::get_order_key(it) == order_key && !my_hash_compare(get_key(*it), key)) 01251 { 01252 iterator first = my_solist.get_iterator(it); 01253 iterator last = first; 01254 01255 while( last != end() && !my_hash_compare(get_key(*last), key) ) 01256 ++last; 01257 return pairii_t(first, last); 01258 } 01259 } 01260 01261 return pairii_t(end(), end()); 01262 } 01263 01264 // Return the [begin, end) pair of const iterators with the same key values. 01265 // This operation makes sense only if mapping is many-to-one. 01266 paircc_t internal_equal_range(const key_type& key) const 01267 { 01268 sokey_t order_key = (sokey_t) my_hash_compare(key); 01269 size_type bucket = order_key % my_number_of_buckets; 01270 01271 // If bucket is empty, initialize it first 01272 if (!is_initialized(bucket)) 01273 return paircc_t(end(), end()); 01274 01275 order_key = split_order_key_regular(order_key); 01276 raw_const_iterator end_it = my_solist.raw_end(); 01277 01278 for (raw_const_iterator it = get_bucket(bucket); it != end_it; ++it) 01279 { 01280 if (solist_t::get_order_key(it) > order_key) 01281 { 01282 // There is no element with the given key 01283 return paircc_t(end(), end()); 01284 } 01285 else if (solist_t::get_order_key(it) == order_key && !my_hash_compare(get_key(*it), key)) 01286 { 01287 const_iterator first = my_solist.get_iterator(it); 01288 const_iterator last = first; 01289 01290 while( last != end() && !my_hash_compare(get_key(*last), key ) ) 01291 ++last; 01292 return paircc_t(first, last); 01293 } 01294 } 01295 01296 return paircc_t(end(), end()); 01297 } 01298 01299 // Bucket APIs 01300 void init_bucket(size_type bucket) 01301 { 01302 // Bucket 0 has no parent. Initialize it and return. 01303 if (bucket == 0) { 01304 internal_init(); 01305 return; 01306 } 01307 01308 size_type parent_bucket = get_parent(bucket); 01309 01310 // All parent_bucket buckets have to be initialized before this bucket is 01311 if (!is_initialized(parent_bucket)) 01312 init_bucket(parent_bucket); 01313 01314 raw_iterator parent = get_bucket(parent_bucket); 01315 01316 // Create a dummy first node in this bucket 01317 raw_iterator dummy_node = my_solist.insert_dummy(parent, split_order_key_dummy(bucket)); 01318 set_bucket(bucket, dummy_node); 01319 } 01320 01321 void adjust_table_size(size_type total_elements, size_type current_size) 01322 { 01323 // Grow the table by a factor of 2 if possible and needed 01324 if ( ((float) total_elements / (float) current_size) > my_maximum_bucket_size ) 01325 { 01326 // Double the size of the hash only if size has not changed inbetween loads 01327 __TBB_CompareAndSwapW((uintptr_t*)&my_number_of_buckets, 2 * current_size, current_size ); 01328 } 01329 } 01330 01331 size_type get_parent(size_type bucket) const 01332 { 01333 // Unsets bucket's most significant turned-on bit 01334 size_type msb = __TBB_Log2((uintptr_t)bucket); 01335 return bucket & ~(size_type(1) << msb); 01336 } 01337 01338 01339 // Dynamic sized array (segments) 01341 static size_type segment_index_of( size_type index ) { 01342 return size_type( __TBB_Log2( index|1 ) ); 01343 } 01344 01346 static size_type segment_base( size_type k ) { 01347 return (size_type(1)<<k & ~size_type(1)); 01348 } 01349 01351 static size_type segment_size( size_type k ) { 01352 return k? size_type(1)<<k : 2; 01353 } 01354 01355 raw_iterator get_bucket(size_type bucket) const { 01356 size_type segment = segment_index_of(bucket); 01357 bucket -= segment_base(segment); 01358 __TBB_ASSERT( my_buckets[segment], "bucket must be in an allocated segment" ); 01359 return my_buckets[segment][bucket]; 01360 } 01361 01362 void set_bucket(size_type bucket, raw_iterator dummy_head) { 01363 size_type segment = segment_index_of(bucket); 01364 bucket -= segment_base(segment); 01365 01366 if (my_buckets[segment] == NULL) { 01367 size_type sz = segment_size(segment); 01368 raw_iterator * new_segment = my_allocator.allocate(sz); 01369 std::memset(new_segment, 0, sz*sizeof(raw_iterator)); 01370 01371 if (__TBB_CompareAndSwapW((void *) &my_buckets[segment], (uintptr_t)new_segment, 0) != 0) 01372 my_allocator.deallocate(new_segment, sz); 01373 } 01374 01375 my_buckets[segment][bucket] = dummy_head; 01376 } 01377 01378 bool is_initialized(size_type bucket) const { 01379 size_type segment = segment_index_of(bucket); 01380 bucket -= segment_base(segment); 01381 01382 if (my_buckets[segment] == NULL) 01383 return false; 01384 01385 raw_iterator it = my_buckets[segment][bucket]; 01386 return (it.get_node_ptr() != NULL); 01387 } 01388 01389 // Utilities for keys 01390 01391 // A regular order key has its original hash value reversed and the last bit set 01392 sokey_t split_order_key_regular(sokey_t order_key) const { 01393 return __TBB_ReverseBits(order_key) | 0x1; 01394 } 01395 01396 // A dummy order key has its original hash value reversed and the last bit unset 01397 sokey_t split_order_key_dummy(sokey_t order_key) const { 01398 return __TBB_ReverseBits(order_key) & ~(0x1); 01399 } 01400 01401 // Shared variables 01402 size_type my_number_of_buckets; // Current table size 01403 solist_t my_solist; // List where all the elements are kept 01404 typename allocator_type::template rebind<raw_iterator>::other my_allocator; // Allocator object for segments 01405 float my_maximum_bucket_size; // Maximum size of the bucket 01406 raw_iterator *my_buckets[pointers_per_table]; // The segment table 01407 }; 01408 #if _MSC_VER 01409 #pragma warning(pop) // warning 4127 -- while (true) has a constant expression in it 01410 #endif 01411 01413 static const size_t hash_multiplier = sizeof(size_t)==4? 2654435769U : 11400714819323198485ULL; 01414 } // namespace internal 01417 template<typename T> 01418 inline size_t tbb_hasher( const T& t ) { 01419 return static_cast<size_t>( t ) * internal::hash_multiplier; 01420 } 01421 template<typename P> 01422 inline size_t tbb_hasher( P* ptr ) { 01423 size_t const h = reinterpret_cast<size_t>( ptr ); 01424 return (h >> 3) ^ h; 01425 } 01426 template<typename E, typename S, typename A> 01427 inline size_t tbb_hasher( const std::basic_string<E,S,A>& s ) { 01428 size_t h = 0; 01429 for( const E* c = s.c_str(); *c; ++c ) 01430 h = static_cast<size_t>(*c) ^ (h * internal::hash_multiplier); 01431 return h; 01432 } 01433 template<typename F, typename S> 01434 inline size_t tbb_hasher( const std::pair<F,S>& p ) { 01435 return tbb_hasher(p.first) ^ tbb_hasher(p.second); 01436 } 01437 } // namespace interface5 01438 using interface5::tbb_hasher; 01439 } // namespace tbb 01440 #endif// __TBB_concurrent_unordered_internal_H
Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.