Shadowrun: Awakened 29 September 2011 - Build 871
_concurrent_unordered_internal.h
Go to the documentation of this file.
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.

GNU Lesser General Public License 3 Sourceforge.net