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