multiset.hpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
3  */
4 
5 #ifndef UAVCAN_UTIL_MULTISET_HPP_INCLUDED
6 #define UAVCAN_UTIL_MULTISET_HPP_INCLUDED
7 
8 #include <cassert>
9 #include <cstdlib>
11 #include <uavcan/build_config.hpp>
15 
16 #if !defined(UAVCAN_CPP_VERSION) || !defined(UAVCAN_CPP11)
17 # error UAVCAN_CPP_VERSION
18 #endif
19 
20 namespace uavcan
21 {
28 template <typename T>
30 {
32  {
33  T* ptr;
34 
35 #if UAVCAN_CPP_VERSION >= UAVCAN_CPP11
36  alignas(T) unsigned char pool[sizeof(T)];
37 #else
38  union
39  {
40  unsigned char pool[sizeof(T)];
41  /*
42  * Such alignment does not guarantee safety for all types (only for libuavcan internal ones);
43  * however, increasing it is too memory inefficient. So it is recommended to use C++11, where
44  * this issue is resolved with alignas() (see above).
45  */
46  void* _aligner1_;
47  long long _aligner2_;
48  };
49 #endif
50 
51  Item()
52  : ptr(UAVCAN_NULLPTR)
53  {
54  fill_n(pool, sizeof(pool), static_cast<unsigned char>(0));
55  }
56 
57  ~Item() { destroy(); }
58 
59  bool isConstructed() const { return ptr != UAVCAN_NULLPTR; }
60 
61  void destroy()
62  {
63  if (ptr != UAVCAN_NULLPTR)
64  {
65  ptr->~T();
66  ptr = UAVCAN_NULLPTR;
67  fill_n(pool, sizeof(pool), static_cast<unsigned char>(0));
68  }
69  }
70  };
71 
72 private:
73  struct Chunk : LinkedListNode<Chunk>
74  {
75  enum { NumItems = (MemPoolBlockSize - sizeof(LinkedListNode<Chunk>)) / sizeof(Item) };
76  Item items[NumItems];
77 
79  {
80  StaticAssert<(static_cast<unsigned>(NumItems) > 0)>::check();
82  UAVCAN_ASSERT(!items[0].isConstructed());
83  }
84 
85  static Chunk* instantiate(IPoolAllocator& allocator)
86  {
87  void* const praw = allocator.allocate(sizeof(Chunk));
88  if (praw == UAVCAN_NULLPTR)
89  {
90  return UAVCAN_NULLPTR;
91  }
92  return new (praw) Chunk();
93  }
94 
95  static void destroy(Chunk*& obj, IPoolAllocator& allocator)
96  {
97  if (obj != UAVCAN_NULLPTR)
98  {
99  obj->~Chunk();
100  allocator.deallocate(obj);
101  obj = UAVCAN_NULLPTR;
102  }
103  }
104 
106  {
107  for (unsigned i = 0; i < static_cast<unsigned>(NumItems); i++)
108  {
109  if (!items[i].isConstructed())
110  {
111  return items + i;
112  }
113  }
114  return UAVCAN_NULLPTR;
115  }
116  };
117 
118  /*
119  * Data
120  */
123 
124  /*
125  * Methods
126  */
127  Item* findOrCreateFreeSlot();
128 
129  void compact();
130 
131  enum RemoveStrategy { RemoveOne, RemoveAll };
132 
133  template <typename Predicate>
134  void removeWhere(Predicate predicate, RemoveStrategy strategy);
135 
137  {
138  bool operator()(const T&) const { return true; }
139  };
140 
142  {
143  unsigned index;
144  IndexPredicate(unsigned target_index)
145  : index(target_index)
146  { }
147 
148  bool operator()(const T&)
149  {
150  return index-- == 0;
151  }
152  };
153 
155  {
156  const T& reference;
157 
158  ComparingPredicate(const T& ref)
159  : reference(ref)
160  { }
161 
162  bool operator()(const T& sample)
163  {
164  return reference == sample;
165  }
166  };
167 
168  template<typename Operator>
170  {
171  Operator oper;
172 
174  : oper(o)
175  { }
176 
177  bool operator()(T& item)
178  {
179  oper(item);
180  return false;
181  }
182 
183  bool operator()(const T& item) const
184  {
185  oper(item);
186  return false;
187  }
188  };
189 
190 public:
192  : allocator_(allocator)
193  { }
194 
196  {
197  clear();
198  }
199 
205  T* emplace()
206  {
207  Item* const item = findOrCreateFreeSlot();
208  if (item == UAVCAN_NULLPTR)
209  {
210  return UAVCAN_NULLPTR;
211  }
212  UAVCAN_ASSERT(item->ptr == UAVCAN_NULLPTR);
213  item->ptr = new (item->pool) T();
214  return item->ptr;
215  }
216 
217  template <typename P1>
218  T* emplace(P1 p1)
219  {
220  Item* const item = findOrCreateFreeSlot();
221  if (item == UAVCAN_NULLPTR)
222  {
223  return UAVCAN_NULLPTR;
224  }
225  UAVCAN_ASSERT(item->ptr == UAVCAN_NULLPTR);
226  item->ptr = new (item->pool) T(p1);
227  return item->ptr;
228  }
229 
230  template <typename P1, typename P2>
231  T* emplace(P1 p1, P2 p2)
232  {
233  Item* const item = findOrCreateFreeSlot();
234  if (item == UAVCAN_NULLPTR)
235  {
236  return UAVCAN_NULLPTR;
237  }
238  UAVCAN_ASSERT(item->ptr == UAVCAN_NULLPTR);
239  item->ptr = new (item->pool) T(p1, p2);
240  return item->ptr;
241  }
242 
243  template <typename P1, typename P2, typename P3>
244  T* emplace(P1 p1, P2 p2, P3 p3)
245  {
246  Item* const item = findOrCreateFreeSlot();
247  if (item == UAVCAN_NULLPTR)
248  {
249  return UAVCAN_NULLPTR;
250  }
251  UAVCAN_ASSERT(item->ptr == UAVCAN_NULLPTR);
252  item->ptr = new (item->pool) T(p1, p2, p3);
253  return item->ptr;
254  }
255 
261  template <typename Predicate>
262  void removeAllWhere(Predicate predicate) { removeWhere<Predicate>(predicate, RemoveAll); }
263 
264  template <typename Predicate>
265  void removeFirstWhere(Predicate predicate) { removeWhere<Predicate>(predicate, RemoveOne); }
266 
267  void removeFirst(const T& ref) { removeFirstWhere(ComparingPredicate(ref)); }
268 
269  void removeAll(const T& ref) { removeAllWhere(ComparingPredicate(ref)); }
270 
271  void clear() { removeAllWhere(YesPredicate()); }
272 
278  template <typename Predicate>
279  T* find(Predicate predicate);
280 
281  template <typename Predicate>
282  const T* find(Predicate predicate) const
283  {
284  return const_cast<Multiset*>(this)->find<Predicate>(predicate);
285  }
286 
293  template <typename Operator>
294  void forEach(Operator oper)
295  {
296  OperatorToFalsePredicateAdapter<Operator> adapter(oper);
297  (void)find<OperatorToFalsePredicateAdapter<Operator>&>(adapter);
298  }
299 
300  template <typename Operator>
301  void forEach(Operator oper) const
302  {
303  const OperatorToFalsePredicateAdapter<Operator> adapter(oper);
304  (void)find<const OperatorToFalsePredicateAdapter<Operator>&>(adapter);
305  }
306 
313  T* getByIndex(unsigned index)
314  {
315  IndexPredicate predicate(index);
316  return find<IndexPredicate&>(predicate);
317  }
318 
319  const T* getByIndex(unsigned index) const
320  {
321  return const_cast<Multiset*>(this)->getByIndex(index);
322  }
323 
327  bool isEmpty() const { return find(YesPredicate()) == UAVCAN_NULLPTR; }
328 
333  unsigned getSize() const;
334 };
335 
336 // ----------------------------------------------------------------------------
337 
338 /*
339  * Multiset<>
340  */
341 template <typename T>
343 {
344  // Search
345  {
346  Chunk* p = list_.get();
347  while (p)
348  {
349  Item* const dyn = p->findFreeSlot();
350  if (dyn != UAVCAN_NULLPTR)
351  {
352  return dyn;
353  }
354  p = p->getNextListNode();
355  }
356  }
357 
358  // Create new chunk
359  Chunk* const chunk = Chunk::instantiate(allocator_);
360  if (chunk == UAVCAN_NULLPTR)
361  {
362  return UAVCAN_NULLPTR;
363  }
364  list_.insert(chunk);
365  return &chunk->items[0];
366 }
367 
368 template <typename T>
370 {
371  Chunk* p = list_.get();
372  while (p)
373  {
374  Chunk* const next = p->getNextListNode();
375  bool remove_this = true;
376  for (int i = 0; i < Chunk::NumItems; i++)
377  {
378  if (p->items[i].isConstructed())
379  {
380  remove_this = false;
381  break;
382  }
383  }
384  if (remove_this)
385  {
386  list_.remove(p);
387  Chunk::destroy(p, allocator_);
388  }
389  p = next;
390  }
391 }
392 
393 template <typename T>
394 template <typename Predicate>
395 void Multiset<T>::removeWhere(Predicate predicate, const RemoveStrategy strategy)
396 {
397  unsigned num_removed = 0;
398 
399  Chunk* p = list_.get();
400  while (p != UAVCAN_NULLPTR)
401  {
402  Chunk* const next_chunk = p->getNextListNode(); // For the case if the current entry gets modified
403 
404  if ((num_removed > 0) && (strategy == RemoveOne))
405  {
406  break;
407  }
408 
409  for (int i = 0; i < Chunk::NumItems; i++)
410  {
411  Item& item = p->items[i];
412  if (item.isConstructed())
413  {
414  if (predicate(*item.ptr))
415  {
416  num_removed++;
417  item.destroy();
418  if (strategy == RemoveOne)
419  {
420  break;
421  }
422  }
423  }
424  }
425 
426  p = next_chunk;
427  }
428 
429  if (num_removed > 0)
430  {
431  compact();
432  }
433 }
434 
435 template <typename T>
436 template <typename Predicate>
437 T* Multiset<T>::find(Predicate predicate)
438 {
439  Chunk* p = list_.get();
440  while (p != UAVCAN_NULLPTR)
441  {
442  Chunk* const next_chunk = p->getNextListNode(); // For the case if the current entry gets modified
443 
444  for (int i = 0; i < Chunk::NumItems; i++)
445  {
446  if (p->items[i].isConstructed())
447  {
448  if (predicate(*p->items[i].ptr))
449  {
450  return p->items[i].ptr;
451  }
452  }
453  }
454 
455  p = next_chunk;
456  }
457  return UAVCAN_NULLPTR;
458 }
459 
460 template <typename T>
461 unsigned Multiset<T>::getSize() const
462 {
463  unsigned num = 0;
464  Chunk* p = list_.get();
465  while (p)
466  {
467  for (int i = 0; i < Chunk::NumItems; i++)
468  {
469  num += p->items[i].isConstructed() ? 1U : 0U;
470  }
471  p = p->getNextListNode();
472  }
473  return num;
474 }
475 
476 }
477 
478 #endif // Include guard
void removeAllWhere(Predicate predicate)
Definition: multiset.hpp:262
IndexPredicate(unsigned target_index)
Definition: multiset.hpp:144
void removeFirst(const T &ref)
Definition: multiset.hpp:267
virtual void deallocate(const void *ptr)=0
IPoolAllocator & allocator_
Definition: multiset.hpp:122
static const unsigned MemPoolBlockSize
Safe default that should be OK for any platform.
void forEach(Operator oper) const
Definition: multiset.hpp:301
bool isEmpty() const
Definition: multiset.hpp:327
T * emplace(P1 p1, P2 p2, P3 p3)
Definition: multiset.hpp:244
bool operator()(const T &sample)
Definition: multiset.hpp:162
T * emplace(P1 p1, P2 p2)
Definition: multiset.hpp:231
bool operator()(const T &) const
Definition: multiset.hpp:138
LinkedListRoot< Chunk > list_
Definition: multiset.hpp:121
void removeWhere(Predicate predicate, RemoveStrategy strategy)
Definition: multiset.hpp:395
bool isConstructed() const
Definition: multiset.hpp:59
void removeAll(const T &ref)
Definition: multiset.hpp:269
T * emplace(P1 p1)
Definition: multiset.hpp:218
const T * find(Predicate predicate) const
Definition: multiset.hpp:282
T * find(Predicate predicate)
Definition: multiset.hpp:437
const T * getByIndex(unsigned index) const
Definition: multiset.hpp:319
static Chunk * instantiate(IPoolAllocator &allocator)
Definition: multiset.hpp:85
Multiset(IPoolAllocator &allocator)
Definition: multiset.hpp:191
virtual void * allocate(std::size_t size)=0
UAVCAN_EXPORT void fill_n(OutputIt first, std::size_t n, const T &value)
Definition: templates.hpp:268
unsigned getSize() const
Definition: multiset.hpp:461
void forEach(Operator oper)
Definition: multiset.hpp:294
T * getByIndex(unsigned index)
Definition: multiset.hpp:313
Item * findOrCreateFreeSlot()
Definition: multiset.hpp:342
static void destroy(Chunk *&obj, IPoolAllocator &allocator)
Definition: multiset.hpp:95
void removeFirstWhere(Predicate predicate)
Definition: multiset.hpp:265


uavcan_communicator
Author(s):
autogenerated on Wed Jan 11 2023 03:59:39