Xmipp  v3.23.11-Nereus
queue_bag.h
Go to the documentation of this file.
1 #ifndef XMIPP_QUEUE_BAG_H
2 #define XMIPP_QUEUE_BAG_H
3 
4 #include <vector>
5 #include <type_traits>
6 
7 #define RFS_QUEUE_BAG_RUN_TESTS 0
8 
9 namespace rfs {
10 
11  void testQueueBag();
12 
20  template<typename T>
21  class queue_bag {
22  static_assert(std::is_trivially_copyable<T>::value,
23  "queue_bag is designed only for trivially copyable elements");
24 
25  private:
27  T *elements = nullptr;
28  size_t elementsCapacity = 0;
29 
31  size_t head = 0;
34  size_t tail = 0;
36  size_t size = 0;
37 
38  size_t internalIndex(size_t externalIndex) const {
39  assert(size > 0);
40  assert(externalIndex < size);
41  size_t index = head + externalIndex;
42  if (index >= elementsCapacity) {
43  index -= elementsCapacity;
44  }
45  return index;
46  }
47 
48  public:
49 
50 #if RFS_QUEUE_BAG_RUN_TESTS
51  queue_bag() {
52  testQueueBag();
53  }
54 #endif
55 
58  void addLast(T object) noexcept {
59  if (size == elementsCapacity) {
60  resize(elementsCapacity * 2);
61  }
62 
63  elements[tail++] = object;
64  if (tail == elementsCapacity) {
65  tail = 0;
66  }
67  size++;
68  }
69 
73  void addFirst(T object) noexcept {
74  if (size == elementsCapacity) {
75  resize(elementsCapacity * 2);
76  }
77 
78  if (head == 0) {
79  head = elementsCapacity - 1;
80  } else {
81  head--;
82  }
83  elements[head] = object;
84  size++;
85  }
86 
89  void ensureCapacity(size_t additional) noexcept {
90  size_t needed = size + additional;
91  if (elementsCapacity < needed) {
92  resize(needed);
93  }
94  }
95 
97  void resize(int newSize) noexcept {
98  if (newSize < 32) {
99  newSize = 32;
100  }
101  assert(newSize > elementsCapacity);
102 
103  T *newArray = (T*)malloc(sizeof(T) * newSize);
104  if (head < tail) {
105  // Continuous
106  memcpy(newArray, elements + head, sizeof(T) * size);
107  } else if (size > 0) {
108  // Wrapped
109  size_t rest = elementsCapacity - head;
110  assert(rest + tail == size);
111  memcpy(newArray, elements + head, sizeof(T) * rest);
112  memcpy(newArray + rest, elements, sizeof(T) * tail);
113  }
114 
115  free(elements);
116  elements = newArray;
117  elementsCapacity = newSize;
118  head = 0;
119  tail = size;
120  }
121 
125  T removeFirst() noexcept {
126  assert(size > 0);
127 
128  size_t index = head;
129  head++;
130  if (head == elementsCapacity) {
131  head = 0;
132  }
133  size--;
134 
135  return elements[index];
136  }
137 
141  T removeLast() noexcept {
142  assert(size > 0);
143 
144  if (tail == 0) {
145  tail = elementsCapacity - 1;
146  } else {
147  tail--;
148  }
149  size--;
150  return elements[tail];
151  }
152 
157  T removeIndex(int index) noexcept {
158  assert(index >= 0);
159  assert(index < size);
160 
161  if (index == 0) {
162  return removeFirst();
163  } else if (index + 1 == size) {
164  return removeLast();
165  } else {
166  // Remove last, put it in place of this one
167  size_t elementsIndex = internalIndex(index);
168  T result = elements[elementsIndex];
169  elements[elementsIndex] = removeLast();
170  return result;
171  }
172  }
173 
174  size_t getSize() const noexcept {
175  return size;
176  }
177 
179  bool empty() const noexcept {
180  return size == 0;
181  }
182 
185  const T &first() const noexcept {
186  return elements[internalIndex(0)];
187  }
188 
189  T &first() noexcept {
190  return elements[internalIndex(0)];
191  }
192 
195  const T &last() const noexcept {
196  return elements[internalIndex(size - 1)];
197  }
198 
199  T &last() noexcept {
200  return elements[internalIndex(size - 1)];
201  }
202 
206  const T &operator[](int index) const noexcept {
207  return elements[internalIndex(index)];
208  }
209 
210  T &operator[](int index) noexcept {
211  return elements[internalIndex(index)];
212  }
213 
215  free(elements);
216  }
217  };
218 
220  template<typename T, typename Consumer>
221  void forEach(queue_bag<T>& queue, Consumer consumer) {
222  for (size_t i = 0; i < queue.getSize(); ++i) {
223  if (!consumer(queue[i])) {
224  return;
225  }
226  }
227  }
228 
229  enum class RemoveResult {
230  KeepContinue,
231  KeepBreak,
234  };
235 
241  template<typename T, typename Predicate>
242  size_t removeMatching(queue_bag<T>& queue, Predicate predicate) {
243  size_t removed = 0;
244  size_t i = 0;
245  while (i < queue.getSize()) {
246  RemoveResult res = predicate(queue[i]);
248  queue.removeIndex(i);
249  } else {
250  i++;
251  }
252 
253  if (res == RemoveResult::KeepBreak || res == RemoveResult::RemoveBreak) {
254  break;
255  }
256  }
257  return removed;
258  }
259 
260 #if RFS_QUEUE_BAG_RUN_TESTS
261  inline void testQueueBag() {
262  static bool tested = false;
263  if (tested) {
264  return;
265  }
266  tested = true;
267 
268  queue_bag<int> queue;
269  queue.addFirst(42);
270  int stairs = 20;
271 
272  for (int i = 0; i < stairs; ++i) {
273  queue.addFirst(i);
274  queue.addLast(i);
275  assert(queue.first() == i);
276  assert(queue.last() == i);
277  assert(queue[queue.getSize() / 2] == 42);
278  }
279 
280  for (int i = 0; i < stairs; ++i) {
281  assert(queue[i] == stairs - 1 - i);
282  assert(queue[stairs + 1 + i] == i);
283  }
284 
285  int stairCheckIndex = 0;
286  forEach(queue, [&stairCheckIndex, stairs](const int value){
287  if (stairCheckIndex < stairs) {
288  assert(value == stairs - 1 - stairCheckIndex);
289  } else if (stairCheckIndex == stairs) {
290  assert(value == 42);
291  } else {
292  assert(stairCheckIndex - stairs - 1 == value);
293  }
294  stairCheckIndex++;
295  return true;
296  });
297 
298  for (int i = stairs-1; i >= 0; --i) {
299  assert(queue.removeFirst() == i);
300  assert(queue.removeLast() == i);
301  }
302  assert(queue.removeFirst() == 42);
303  }
304 #endif
305 }
306 
307 #endif //XMIPP_QUEUE_BAG_H
RemoveResult
Definition: queue_bag.h:229
T removeLast() noexcept
Definition: queue_bag.h:141
T removeFirst() noexcept
Definition: queue_bag.h:125
const T & operator[](int index) const noexcept
Definition: queue_bag.h:206
const T & last() const noexcept
Definition: queue_bag.h:195
size_t removeMatching(queue_bag< T > &queue, Predicate predicate)
Definition: queue_bag.h:242
void forEach(queue_bag< T > &queue, Consumer consumer)
Definition: queue_bag.h:221
#define i
T removeIndex(int index) noexcept
Definition: queue_bag.h:157
void resize(int newSize) noexcept
Definition: queue_bag.h:97
void ensureCapacity(size_t additional) noexcept
Definition: queue_bag.h:89
viol index
bool empty() const noexcept
Definition: queue_bag.h:179
size_t getSize() const noexcept
Definition: queue_bag.h:174
free((char *) ob)
T & last() noexcept
Definition: queue_bag.h:199
void addFirst(T object) noexcept
Definition: queue_bag.h:73
T & first() noexcept
Definition: queue_bag.h:189
void addLast(T object) noexcept
Definition: queue_bag.h:58
const T & first() const noexcept
Definition: queue_bag.h:185
void testQueueBag()
T & operator[](int index) noexcept
Definition: queue_bag.h:210
Definition: queue_bag.h:9