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
uavcan::Multiset::removeFirstWhere
void removeFirstWhere(Predicate predicate)
Definition: multiset.hpp:265
uavcan::Multiset::Item::isConstructed
bool isConstructed() const
Definition: multiset.hpp:59
uavcan::Multiset::OperatorToFalsePredicateAdapter::oper
Operator oper
Definition: multiset.hpp:171
check
ROSCPP_DECL bool check()
uavcan::Multiset::clear
void clear()
Definition: multiset.hpp:271
UAVCAN_NULLPTR
#define UAVCAN_NULLPTR
Definition: libuavcan/libuavcan/include/uavcan/build_config.hpp:51
uavcan::Multiset::removeAllWhere
void removeAllWhere(Predicate predicate)
Definition: multiset.hpp:262
uavcan::Multiset::Chunk::Chunk
Chunk()
Definition: multiset.hpp:78
uavcan::Noncopyable
Definition: templates.hpp:46
uavcan::Multiset::Chunk::instantiate
static Chunk * instantiate(IPoolAllocator &allocator)
Definition: multiset.hpp:85
templates.hpp
uavcan::Multiset::IndexPredicate::index
unsigned index
Definition: multiset.hpp:143
uavcan::Multiset::findOrCreateFreeSlot
Item * findOrCreateFreeSlot()
Definition: multiset.hpp:342
uavcan::Multiset::Multiset
Multiset(IPoolAllocator &allocator)
Definition: multiset.hpp:191
uavcan::Multiset::emplace
T * emplace(P1 p1, P2 p2, P3 p3)
Definition: multiset.hpp:244
dynamic_memory.hpp
uavcan::Multiset::Chunk
Definition: multiset.hpp:73
uavcan::Multiset::isEmpty
bool isEmpty() const
Definition: multiset.hpp:327
uavcan::Multiset::YesPredicate::operator()
bool operator()(const T &) const
Definition: multiset.hpp:138
uavcan::Multiset::ComparingPredicate::operator()
bool operator()(const T &sample)
Definition: multiset.hpp:162
uavcan::Multiset::getByIndex
const T * getByIndex(unsigned index) const
Definition: multiset.hpp:319
uavcan::Multiset::getSize
unsigned getSize() const
Definition: multiset.hpp:461
uavcan::IPoolAllocator::allocate
virtual void * allocate(std::size_t size)=0
uavcan::Multiset::~Multiset
~Multiset()
Definition: multiset.hpp:195
uavcan::fill_n
UAVCAN_EXPORT void fill_n(OutputIt first, std::size_t n, const T &value)
Definition: templates.hpp:268
uavcan::Multiset::IndexPredicate
Definition: multiset.hpp:141
uavcan::Multiset::find
const T * find(Predicate predicate) const
Definition: multiset.hpp:282
placement_new.hpp
uavcan::Multiset::list_
LinkedListRoot< Chunk > list_
Definition: multiset.hpp:121
uavcan::Multiset::ComparingPredicate::ComparingPredicate
ComparingPredicate(const T &ref)
Definition: multiset.hpp:158
uavcan::Multiset::removeFirst
void removeFirst(const T &ref)
Definition: multiset.hpp:267
uavcan::Multiset::find
T * find(Predicate predicate)
Definition: multiset.hpp:437
uavcan::Multiset::Item::ptr
T * ptr
Definition: multiset.hpp:33
uavcan::Multiset::removeAll
void removeAll(const T &ref)
Definition: multiset.hpp:269
uavcan::IPoolAllocator::deallocate
virtual void deallocate(const void *ptr)=0
uavcan::IsDynamicallyAllocatable::check
static void check()
Definition: libuavcan/libuavcan/include/uavcan/build_config.hpp:246
uavcan::Multiset::OperatorToFalsePredicateAdapter::operator()
bool operator()(T &item)
Definition: multiset.hpp:177
uavcan::Multiset::OperatorToFalsePredicateAdapter::OperatorToFalsePredicateAdapter
OperatorToFalsePredicateAdapter(Operator o)
Definition: multiset.hpp:173
uavcan::IPoolAllocator
Definition: dynamic_memory.hpp:21
uavcan::Multiset::allocator_
IPoolAllocator & allocator_
Definition: multiset.hpp:122
uavcan::Multiset::IndexPredicate::IndexPredicate
IndexPredicate(unsigned target_index)
Definition: multiset.hpp:144
UAVCAN_EXPORT
#define UAVCAN_EXPORT
Definition: libuavcan/libuavcan/include/uavcan/build_config.hpp:108
uavcan::Multiset::ComparingPredicate::reference
const T & reference
Definition: multiset.hpp:156
uavcan::Multiset::getByIndex
T * getByIndex(unsigned index)
Definition: multiset.hpp:313
uavcan::Multiset::Chunk::destroy
static void destroy(Chunk *&obj, IPoolAllocator &allocator)
Definition: multiset.hpp:95
uavcan::Multiset::forEach
void forEach(Operator oper) const
Definition: multiset.hpp:301
build_config.hpp
uavcan::MemPoolBlockSize
static const unsigned MemPoolBlockSize
Safe default that should be OK for any platform.
Definition: libuavcan/libuavcan/include/uavcan/build_config.hpp:228
uavcan::Multiset::Item::Item
Item()
Definition: multiset.hpp:51
uavcan::Multiset::forEach
void forEach(Operator oper)
Definition: multiset.hpp:294
uavcan::Multiset::removeWhere
void removeWhere(Predicate predicate, RemoveStrategy strategy)
Definition: multiset.hpp:395
linked_list.hpp
uavcan::Multiset::Item
Definition: multiset.hpp:31
uavcan::Multiset::Item::~Item
~Item()
Definition: multiset.hpp:57
uavcan::Multiset::emplace
T * emplace(P1 p1)
Definition: multiset.hpp:218
uavcan::Multiset::Chunk::findFreeSlot
Item * findFreeSlot()
Definition: multiset.hpp:105
uavcan::LinkedListRoot
Definition: linked_list.hpp:44
uavcan::Multiset::IndexPredicate::operator()
bool operator()(const T &)
Definition: multiset.hpp:148
uavcan::Multiset::ComparingPredicate
Definition: multiset.hpp:154
uavcan::LinkedListNode
Definition: linked_list.hpp:20
uavcan
Definition: libuavcan/libuavcan/include/uavcan/build_config.hpp:204
uavcan::Multiset::OperatorToFalsePredicateAdapter
Definition: multiset.hpp:169
uavcan::Multiset::compact
void compact()
Definition: multiset.hpp:369
uavcan::Multiset::Item::destroy
void destroy()
Definition: multiset.hpp:61
uavcan::Multiset::YesPredicate
Definition: multiset.hpp:136
uavcan::Multiset::OperatorToFalsePredicateAdapter::operator()
bool operator()(const T &item) const
Definition: multiset.hpp:183
uavcan::Multiset
Definition: multiset.hpp:29
uavcan::Multiset< CanFilterConfig >::RemoveStrategy
RemoveStrategy
Definition: multiset.hpp:131
uavcan::Multiset::emplace
T * emplace()
Definition: multiset.hpp:205
UAVCAN_ASSERT
#define UAVCAN_ASSERT(x)
Definition: libuavcan/libuavcan/include/uavcan/build_config.hpp:184
uavcan::Multiset::emplace
T * emplace(P1 p1, P2 p2)
Definition: multiset.hpp:231


uavcan_communicator
Author(s):
autogenerated on Fri Dec 13 2024 03:10:02