2 Copyright 2005-2011 Intel Corporation. All Rights Reserved.
4 This file is part of Threading Building Blocks.
6 Threading Building Blocks is free software; you can redistribute it
7 and/or modify it under the terms of the GNU General Public License
8 version 2 as published by the Free Software Foundation.
10 Threading Building Blocks is distributed in the hope that it will be
11 useful, but WITHOUT ANY WARRANTY; without even the implied warranty
12 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with Threading Building Blocks; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 As a special exception, you may use this file as part of a free software
20 library without restriction. Specifically, if other files instantiate
21 templates or use macros or inline functions from this file, or you compile
22 this file and link it with other files to produce an executable, this
23 file does not by itself cause the resulting executable to be covered by
24 the GNU General Public License. This exception does not however
25 invalidate any other reasons why the executable file might be covered by
26 the GNU General Public License.
29 // tagged buffer that can expand, and can support as many deletions as additions
30 // list-based, with elements of list held in std::vector (for destruction management),
31 // multiplicative hashing (like ets). No synchronization built-in.
34 #ifndef __TBB__flow_graph_tagged_buffer_impl_H
35 #define __TBB__flow_graph_tagged_buffer_impl_H
37 #ifndef __TBB_flow_graph_H
38 #error Do not #include this internal file directly; use public TBB headers instead.
41 template<typename TagType, typename ValueType, size_t NoTagMark>
42 struct buffer_element {
46 buffer_element() : t(NoTagMark), next(NULL) {}
54 typename Allocator=tbb::cache_aligned_allocator< buffer_element<TagType,ValueType,NoTagMark> >
58 static const size_t INITIAL_SIZE = 8; // initial size of the hash pointer table
59 static const TagType NO_TAG = TagType(NoTagMark);
60 typedef ValueType value_type;
61 typedef buffer_element<TagType,ValueType, NO_TAG> element_type;
62 typedef value_type *pointer_type;
63 typedef std::vector<element_type, Allocator> list_array_type;
64 typedef typename Allocator::template rebind<element_type*>::other pointer_array_allocator_type;
65 typedef typename Allocator::template rebind<list_array_type>::other list_array_allocator;
71 std::vector<element_type, Allocator> *lists;
72 element_type* free_list;
74 size_t mask() { return my_size - 1; }
77 static size_t hash(TagType t) {
81 #if __TBB_WORDSIZE == 4
82 return uintptr_t(t)*0x9E3779B9;
84 return uintptr_t(t)*0x9E3779B97F4A7C15;
89 void set_up_free_list( element_type **p_free_list, list_array_type *la, size_t sz) {
90 for(size_t i=0; i < sz - 1; ++i ) { // construct free list
91 (*la)[i].next = &((*la)[i+1]);
94 (*la)[sz-1].next = NULL;
95 *p_free_list = &((*la)[0]);
99 // make the pointer array larger
100 element_type **new_array;
101 element_type **old_array = array;
102 size_t old_size = my_size;
104 new_array = pointer_array_allocator_type().allocate(my_size);
105 for(size_t i=0; i < my_size; ++i) new_array[i] = NULL;
106 list_array_type *new_list_array = new list_array_type(old_size, element_type(), Allocator());
107 set_up_free_list(&free_list, new_list_array, old_size );
109 for(size_t i=0; i < old_size; ++i) {
110 for( element_type* op = old_array[i]; op; op = op->next) {
111 internal_tagged_insert(new_array, my_size, op->t, op->v);
114 pointer_array_allocator_type().deallocate(old_array, old_size);
116 delete lists; // destroy and deallocate instead
118 lists = new_list_array;
121 void internal_tagged_insert( element_type **ar, size_t sz, TagType t, value_type v) {
122 size_t l_mask = sz-1;
123 size_t h = hash(t) & l_mask;
124 __TBB_ASSERT(free_list, "Error: free list not set up.");
125 element_type* my_elem = free_list; free_list = free_list->next;
128 my_elem->next = ar[h];
133 tagged_buffer() : my_size(INITIAL_SIZE), nelements(0) {
134 array = pointer_array_allocator_type().allocate(my_size);
135 for(size_t i = 0; i < my_size; ++i) array[i] = NULL;
136 lists = new list_array_type(INITIAL_SIZE/2, element_type(), Allocator());
137 set_up_free_list(&free_list, lists, INITIAL_SIZE/2);
142 pointer_array_allocator_type().deallocate(array, my_size);
149 bool tagged_insert(TagType t, value_type v) {
151 if(tagged_find_ref(t, p)) {
152 *p = v; // replace the value
156 if(nelements*2 > my_size) grow_array();
157 internal_tagged_insert(array, my_size, t, v);
161 // returns reference to array element.v
162 bool tagged_find_ref(TagType t, pointer_type &v) {
163 size_t i = hash(t) & mask();
164 for(element_type* p = array[i]; p; p = p->next) {
173 bool tagged_find( TagType t, value_type &v) {
175 if(tagged_find_ref(t, p)) {
183 void tagged_delete(TagType t) {
184 size_t h = hash(t) & mask();
185 element_type* prev = NULL;
186 for(element_type* p = array[h]; p; prev = p, p = p->next) {
189 if(prev) prev->next = p->next;
190 else array[h] = p->next;
197 __TBB_ASSERT(false, "tag not found for delete");
200 // search for v in the array; if found {set t, return true} else return false
201 // we use this in join_node_FE to find if a tag's items are all available.
202 bool find_value_tag( TagType &t, value_type v) {
203 for(size_t i= 0; i < my_size / 2; ++i) { // remember the vector is half the size of the hash array
204 if( (*lists)[i].t != NO_TAG && (*lists)[i].v == v) {
212 #endif // __TBB__flow_graph_tagged_buffer_impl_H