File indexing completed on 2025-01-18 10:12:47
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #ifndef __TBB__flow_graph_item_buffer_impl_H
0018 #define __TBB__flow_graph_item_buffer_impl_H
0019
0020 #ifndef __TBB_flow_graph_H
0021 #error Do not #include this internal file directly; use public TBB headers instead.
0022 #endif
0023
0024 #include "tbb/internal/_flow_graph_types_impl.h" // for aligned_pair
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034 using internal::aligned_pair;
0035 using internal::alignment_of;
0036
0037 namespace internal {
0038
0039 template <typename T, typename A=cache_aligned_allocator<T> >
0040 class item_buffer {
0041 public:
0042 typedef T item_type;
0043 enum buffer_item_state { no_item=0, has_item=1, reserved_item=2 };
0044 protected:
0045 typedef size_t size_type;
0046 typedef typename aligned_pair<item_type, buffer_item_state>::type buffer_item_type;
0047 typedef typename tbb::internal::allocator_rebind<A, buffer_item_type>::type allocator_type;
0048 buffer_item_type *my_array;
0049 size_type my_array_size;
0050 static const size_type initial_buffer_size = 4;
0051 size_type my_head;
0052 size_type my_tail;
0053
0054 bool buffer_empty() const { return my_head == my_tail; }
0055
0056 buffer_item_type &item(size_type i) {
0057 __TBB_ASSERT(!(size_type(&(my_array[i&(my_array_size-1)].second))%alignment_of<buffer_item_state>::value),NULL);
0058 __TBB_ASSERT(!(size_type(&(my_array[i&(my_array_size-1)].first))%alignment_of<item_type>::value), NULL);
0059 return my_array[i & (my_array_size - 1) ];
0060 }
0061
0062 const buffer_item_type &item(size_type i) const {
0063 __TBB_ASSERT(!(size_type(&(my_array[i&(my_array_size-1)].second))%alignment_of<buffer_item_state>::value), NULL);
0064 __TBB_ASSERT(!(size_type(&(my_array[i&(my_array_size-1)].first))%alignment_of<item_type>::value), NULL);
0065 return my_array[i & (my_array_size-1)];
0066 }
0067
0068 bool my_item_valid(size_type i) const { return (i < my_tail) && (i >= my_head) && (item(i).second != no_item); }
0069 bool my_item_reserved(size_type i) const { return item(i).second == reserved_item; }
0070
0071
0072 const item_type &get_my_item(size_t i) const {
0073 __TBB_ASSERT(my_item_valid(i),"attempt to get invalid item");
0074 item_type *itm = (tbb::internal::punned_cast<item_type *>(&(item(i).first)));
0075 return *(const item_type *)itm;
0076 }
0077
0078
0079 void set_my_item(size_t i, const item_type &o) {
0080 if(item(i).second != no_item) {
0081 destroy_item(i);
0082 }
0083 new(&(item(i).first)) item_type(o);
0084 item(i).second = has_item;
0085 }
0086
0087
0088 void fetch_item(size_t i, item_type &o) {
0089 __TBB_ASSERT(my_item_valid(i), "Trying to fetch an empty slot");
0090 o = get_my_item(i);
0091 destroy_item(i);
0092 }
0093
0094
0095
0096
0097 void move_item(size_t to, size_t from) {
0098 __TBB_ASSERT(!my_item_valid(to), "Trying to move to a non-empty slot");
0099 __TBB_ASSERT(my_item_valid(from), "Trying to move from an empty slot");
0100 set_my_item(to, get_my_item(from));
0101 destroy_item(from);
0102
0103 }
0104
0105
0106 bool place_item(size_t here, const item_type &me) {
0107 #if !TBB_DEPRECATED_SEQUENCER_DUPLICATES
0108 if(my_item_valid(here)) return false;
0109 #endif
0110 set_my_item(here, me);
0111 return true;
0112 }
0113
0114
0115 void swap_items(size_t i, size_t j) {
0116 __TBB_ASSERT(my_item_valid(i) && my_item_valid(j), "attempt to swap invalid item(s)");
0117 item_type temp = get_my_item(i);
0118 set_my_item(i, get_my_item(j));
0119 set_my_item(j, temp);
0120 }
0121
0122 void destroy_item(size_type i) {
0123 __TBB_ASSERT(my_item_valid(i), "destruction of invalid item");
0124 (tbb::internal::punned_cast<item_type *>(&(item(i).first)))->~item_type();
0125 item(i).second = no_item;
0126 }
0127
0128
0129 const item_type& front() const
0130 {
0131 __TBB_ASSERT(my_item_valid(my_head), "attempt to fetch head non-item");
0132 return get_my_item(my_head);
0133 }
0134
0135
0136 const item_type& back() const
0137 {
0138 __TBB_ASSERT(my_item_valid(my_tail - 1), "attempt to fetch head non-item");
0139 return get_my_item(my_tail - 1);
0140 }
0141
0142
0143 void reserve_item(size_type i) { __TBB_ASSERT(my_item_valid(i) && !my_item_reserved(i), "item cannot be reserved"); item(i).second = reserved_item; }
0144 void release_item(size_type i) { __TBB_ASSERT(my_item_reserved(i), "item is not reserved"); item(i).second = has_item; }
0145
0146 void destroy_front() { destroy_item(my_head); ++my_head; }
0147 void destroy_back() { destroy_item(my_tail-1); --my_tail; }
0148
0149
0150
0151 size_type size(size_t new_tail = 0) { return (new_tail ? new_tail : my_tail) - my_head; }
0152 size_type capacity() { return my_array_size; }
0153
0154
0155 bool buffer_full() { return size() >= capacity(); }
0156
0157
0158 void grow_my_array( size_t minimum_size ) {
0159
0160 __TBB_ASSERT(capacity() >= my_tail - my_head, "total items exceed capacity");
0161 size_type new_size = my_array_size ? 2*my_array_size : initial_buffer_size;
0162 while( new_size<minimum_size )
0163 new_size*=2;
0164
0165 buffer_item_type* new_array = allocator_type().allocate(new_size);
0166
0167
0168 for( size_type i=0; i<new_size; ++i ) { new_array[i].second = no_item; }
0169
0170 for( size_type i=my_head; i<my_tail; ++i) {
0171 if(my_item_valid(i)) {
0172
0173 char *new_space = (char *)&(new_array[i&(new_size-1)].first);
0174 (void)new(new_space) item_type(get_my_item(i));
0175 new_array[i&(new_size-1)].second = item(i).second;
0176 }
0177 }
0178
0179 clean_up_buffer(false);
0180
0181 my_array = new_array;
0182 my_array_size = new_size;
0183 }
0184
0185 bool push_back(item_type &v) {
0186 if(buffer_full()) {
0187 grow_my_array(size() + 1);
0188 }
0189 set_my_item(my_tail, v);
0190 ++my_tail;
0191 return true;
0192 }
0193
0194 bool pop_back(item_type &v) {
0195 if (!my_item_valid(my_tail-1)) {
0196 return false;
0197 }
0198 v = this->back();
0199 destroy_back();
0200 return true;
0201 }
0202
0203 bool pop_front(item_type &v) {
0204 if(!my_item_valid(my_head)) {
0205 return false;
0206 }
0207 v = this->front();
0208 destroy_front();
0209 return true;
0210 }
0211
0212
0213
0214 void clean_up_buffer(bool reset_pointers) {
0215 if (my_array) {
0216 for( size_type i=my_head; i<my_tail; ++i ) {
0217 if(my_item_valid(i))
0218 destroy_item(i);
0219 }
0220 allocator_type().deallocate(my_array,my_array_size);
0221 }
0222 my_array = NULL;
0223 if(reset_pointers) {
0224 my_head = my_tail = my_array_size = 0;
0225 }
0226 }
0227
0228 public:
0229
0230 item_buffer( ) : my_array(NULL), my_array_size(0),
0231 my_head(0), my_tail(0) {
0232 grow_my_array(initial_buffer_size);
0233 }
0234
0235 ~item_buffer() {
0236 clean_up_buffer(true);
0237 }
0238
0239 void reset() { clean_up_buffer(true); grow_my_array(initial_buffer_size); }
0240
0241 };
0242
0243
0244
0245
0246 template<typename T, typename A=cache_aligned_allocator<T> >
0247 class reservable_item_buffer : public item_buffer<T, A> {
0248 protected:
0249 using item_buffer<T, A>::my_item_valid;
0250 using item_buffer<T, A>::my_head;
0251
0252 public:
0253 reservable_item_buffer() : item_buffer<T, A>(), my_reserved(false) {}
0254 void reset() {my_reserved = false; item_buffer<T,A>::reset(); }
0255 protected:
0256
0257 bool reserve_front(T &v) {
0258 if(my_reserved || !my_item_valid(this->my_head)) return false;
0259 my_reserved = true;
0260
0261 v = this->front();
0262 this->reserve_item(this->my_head);
0263 return true;
0264 }
0265
0266 void consume_front() {
0267 __TBB_ASSERT(my_reserved, "Attempt to consume a non-reserved item");
0268 this->destroy_front();
0269 my_reserved = false;
0270 }
0271
0272 void release_front() {
0273 __TBB_ASSERT(my_reserved, "Attempt to release a non-reserved item");
0274 this->release_item(this->my_head);
0275 my_reserved = false;
0276 }
0277
0278 bool my_reserved;
0279 };
0280
0281 }
0282
0283 #endif