UFO 1.0.0
An Efficient Probabilistic 3D Mapping Framework That Embraces the Unknown
Loading...
Searching...
No Matches
container.hpp
1
42#ifndef UFO_CONTAINER_TREE_CONTAINER_HPP
43#define UFO_CONTAINER_TREE_CONTAINER_HPP
44
45// UFO
46#include <ufo/container/tree/code.hpp>
47#include <ufo/container/tree/container_bucket_iterator.hpp>
48#include <ufo/container/tree/container_iterator.hpp>
49#include <ufo/container/tree/index.hpp>
50#include <ufo/execution/execution.hpp>
51#include <ufo/utility/spinlock.hpp>
52
53// STL
54#include <algorithm>
55#include <array>
56#include <atomic>
57#include <cstddef>
58#include <cstring>
59#include <memory>
60#include <mutex>
61#include <utility>
62
63namespace ufo
64{
65// TODO: Add array of std::atomic_flag to value_type
66
67template <class... Ts>
69{
70 private:
71 static constexpr std::size_t const NUM = 14;
72 static constexpr std::size_t const NUM_BUCKETS = std::size_t(1) << (32 - NUM);
73 static constexpr std::size_t const NUM_BLOCKS_PER_BUCKET = std::size_t(1) << NUM;
74
75 public:
76 //
77 // Tags
78 //
79
80 template <class T>
81 using Data = std::array<T, NUM_BLOCKS_PER_BUCKET>;
82
83 template <class T>
84 struct alignas(32) S {
85 Data<T> data;
86 alignas(8) bool modified = false;
87 };
88
89 template <class T>
90 using bucket_type = S<T>;
91 using size_type = std::size_t;
92 using pos_type = TreeIndex::pos_type;
93
94 using value_type = std::tuple<Data<pos_type>, S<Ts>...>;
95 using Bucket = std::atomic<value_type*>;
96
97 template <class T>
98 using iterator = TreeContainterIterator<T, false, Ts...>;
99 template <class T>
100 using const_iterator = TreeContainterIterator<T, true, Ts...>;
101 template <class T>
102 using reverse_iterator = std::reverse_iterator<iterator<T>>;
103 template <class T>
104 using const_reverse_iterator = std::reverse_iterator<const_iterator<T>>;
105
106 template <class T>
107 using bucket_iterator = TreeContainterBucketIterator<T, false, Ts...>;
108 template <class T>
110 template <class T>
111 using reverse_bucket_iterator = std::reverse_iterator<bucket_iterator<T>>;
112 template <class T>
113 using const_reverse_bucket_iterator = std::reverse_iterator<const_bucket_iterator<T>>;
114
115 public:
116 TreeContainer() = default;
117
118 TreeContainer(TreeContainer const& other)
119 : cap_(other.cap_.load()), num_inactive_(other.num_inactive_.load())
120 {
121 for (std::size_t i{}; NUM_BUCKETS > i; ++i) {
122 if (nullptr == other.buckets_[i]) {
123 break;
124 }
125
126 buckets_[i] = new value_type(*other.buckets_[i]);
127 }
128 }
129
130 template <class... Ts2>
131 TreeContainer(TreeContainer<Ts2...> const& other)
132 : cap_(other.cap_.load()), num_inactive_(other.num_inactive_.load())
133 {
134 // TODO: Implement
135 }
136
137 ~TreeContainer()
138 {
139 for (std::size_t i{}; NUM_BUCKETS > i; ++i) {
140 if (nullptr == buckets_[i]) {
141 break;
142 }
143
144 delete buckets_[i];
145 }
146 }
147
148 TreeContainer& operator=(TreeContainer const& rhs)
149 {
150 for (std::size_t i{}; NUM_BUCKETS > i; ++i) {
151 if (nullptr == rhs.buckets_[i]) {
152 break;
153 }
154
155 if (nullptr == buckets_[i]) {
156 buckets_[i] = new value_type(*rhs.buckets_[i]);
157 } else {
158 bucket(i) = rhs.bucket(i);
159 }
160 }
161
162 cap_ = rhs.cap_.load();
163 num_inactive_ = rhs.num_inactive_.load();
164
165 return *this;
166 }
167
168 template <class... Ts2>
169 TreeContainer& operator=(TreeContainer<Ts2...> const& rhs)
170 {
171 // TODO: Implement
172
173 cap_ = rhs.cap_.load();
174 num_inactive_ = rhs.num_inactive_.load();
175
176 return *this;
177 }
178
179 template <class T>
180 [[nodiscard]] iterator<T> begin()
181 {
182 return iterator<T>(this, 0);
183 }
184
185 template <class T>
186 [[nodiscard]] const_iterator<T> begin() const
187 {
188 return const_iterator<T>(const_cast<TreeContainer*>(this), 0);
189 }
190
191 template <class T>
192 [[nodiscard]] const_iterator<T> cbegin() const
193 {
194 return begin<T>();
195 }
196
197 template <class T>
198 [[nodiscard]] iterator<T> end()
199 {
200 return iterator<T>(this, capacity());
201 }
202
203 template <class T>
204 [[nodiscard]] const_iterator<T> end() const
205 {
206 return const_iterator<T>(const_cast<TreeContainer*>(this), capacity());
207 }
208
209 template <class T>
210 [[nodiscard]] const_iterator<T> cend() const
211 {
212 return end<T>();
213 }
214
215 template <class T>
216 [[nodiscard]] reverse_iterator<T> rbegin()
217 {
218 return std::make_reverse_iterator(end<T>());
219 }
220
221 template <class T>
222 [[nodiscard]] const_reverse_iterator<T> rbegin() const
223 {
224 return std::make_reverse_iterator(end<T>());
225 }
226
227 template <class T>
228 [[nodiscard]] const_reverse_iterator<T> crbegin() const
229 {
230 return rbegin<T>();
231 }
232
233 template <class T>
234 [[nodiscard]] reverse_iterator<T> rend()
235 {
236 return std::make_reverse_iterator(begin<T>());
237 }
238
239 template <class T>
240 [[nodiscard]] const_reverse_iterator<T> rend() const
241 {
242 return std::make_reverse_iterator(begin<T>());
243 }
244
245 template <class T>
246 [[nodiscard]] const_reverse_iterator<T> crend() const
247 {
248 return rend<T>();
249 }
250
251 template <class T>
252 [[nodiscard]] auto iter()
253 {
254 return std::ranges::subrange(begin<T>(), end<T>());
255 }
256
257 template <class T>
258 [[nodiscard]] auto iter() const
259 {
260 return std::ranges::subrange(begin<T>(), end<T>());
261 }
262
263 template <class T>
264 [[nodiscard]] auto riter()
265 {
266 return std::ranges::subrange(rbegin<T>(), rend<T>());
267 }
268
269 template <class T>
270 [[nodiscard]] auto riter() const
271 {
272 return std::ranges::subrange(rbegin<T>(), rend<T>());
273 }
274
275 template <class T>
276 [[nodiscard]] bucket_iterator<T> beginBucket()
277 {
278 return bucket_iterator<T>(this, 0);
279 }
280
281 template <class T>
282 [[nodiscard]] const_bucket_iterator<T> beginBucket() const
283 {
284 return const_bucket_iterator<T>(const_cast<TreeContainer*>(this), 0);
285 }
286
287 template <class T>
288 [[nodiscard]] const_bucket_iterator<T> cbeginBucket() const
289 {
290 return beginBucket<T>();
291 }
292
293 template <class T>
294 [[nodiscard]] bucket_iterator<T> endBucket()
295 {
296 return bucket_iterator<T>(this, numBuckets());
297 }
298
299 template <class T>
300 [[nodiscard]] const_bucket_iterator<T> endBucket() const
301 {
302 return const_bucket_iterator<T>(const_cast<TreeContainer*>(this), numBuckets());
303 }
304
305 template <class T>
306 [[nodiscard]] const_bucket_iterator<T> cendBucket() const
307 {
308 return endBucket<T>();
309 }
310
311 template <class T>
312 [[nodiscard]] reverse_bucket_iterator<T> rbeginBucket()
313 {
314 return std::make_reverse_iterator(endBucket<T>());
315 }
316
317 template <class T>
318 [[nodiscard]] const_reverse_bucket_iterator<T> rbeginBucket() const
319 {
320 return std::make_reverse_iterator(endBucket<T>());
321 }
322
323 template <class T>
324 [[nodiscard]] const_reverse_bucket_iterator<T> crbeginBucket() const
325 {
326 return rbeginBucket<T>();
327 }
328
329 template <class T>
330 [[nodiscard]] reverse_bucket_iterator<T> rendBucket()
331 {
332 return std::make_reverse_iterator(beginBucket<T>());
333 }
334
335 template <class T>
336 [[nodiscard]] const_reverse_bucket_iterator<T> rendBucket() const
337 {
338 return std::make_reverse_iterator(beginBucket<T>());
339 }
340
341 template <class T>
342 [[nodiscard]] const_reverse_bucket_iterator<T> crendBucket() const
343 {
344 return rendBucket<T>();
345 }
346
347 template <class T>
348 [[nodiscard]] auto iterBucket()
349 {
350 return std::ranges::subrange(beginBucket<T>(), endBucket<T>());
351 }
352
353 template <class T>
354 [[nodiscard]] auto iterBucket() const
355 {
356 return std::ranges::subrange(beginBucket<T>(), endBucket<T>());
357 }
358
359 template <class T>
360 [[nodiscard]] auto riterBucket()
361 {
362 return std::ranges::subrange(rbeginBucket<T>(), rendBucket<T>());
363 }
364
365 template <class T>
366 [[nodiscard]] auto riterBucket() const
367 {
368 return std::ranges::subrange(rbeginBucket<T>(), rendBucket<T>());
369 }
370
371 template <class T>
372 [[nodiscard]] S<T>& bucket(std::size_t idx)
373 {
374 return std::get<S<T>>(bucket(idx));
375 }
376
377 template <class T>
378 [[nodiscard]] S<T> const& bucket(std::size_t idx) const
379 {
380 return std::get<S<T>>(bucket(idx));
381 }
382
383 template <std::size_t I>
384 [[nodiscard]] auto& bucket(std::size_t idx)
385 {
386 return std::get<I + 1>(bucket(idx));
387 }
388
389 template <std::size_t I>
390 [[nodiscard]] auto const& bucket(std::size_t idx) const
391 {
392 return std::get<I + 1>(bucket(idx));
393 }
394
395 template <class T>
396 [[nodiscard]] bool& bucketModified(std::size_t idx)
397 {
398 return bucket<T>(idx).modified;
399 }
400
401 template <class T>
402 [[nodiscard]] bool bucketModified(std::size_t idx) const
403 {
404 return bucket<T>(idx).modified;
405 }
406
407 template <std::size_t I>
408 [[nodiscard]] bool& bucketModified(std::size_t idx)
409 {
410 return bucket<I>(idx).modified;
411 }
412
413 template <std::size_t I>
414 [[nodiscard]] bool bucketModified(std::size_t idx) const
415 {
416 return bucket<I>(idx).modified;
417 }
418
419 template <class T>
420 [[nodiscard]] Data<T>& bucketData(std::size_t idx)
421 {
422 auto& x = bucket<T>(idx);
423 x.modified = true;
424 return x.data;
425 }
426
427 template <class T>
428 [[nodiscard]] Data<T> const& bucketData(std::size_t idx) const
429 {
430 return bucket<T>(idx).data;
431 }
432
433 template <std::size_t I>
434 [[nodiscard]] auto& bucketData(std::size_t idx)
435 {
436 auto& x = bucket<I>(idx);
437 x.modified = true;
438 return x.data;
439 }
440
441 template <std::size_t I>
442 [[nodiscard]] auto const& bucketData(std::size_t idx) const
443 {
444 return bucket<I>(idx).data;
445 }
446
447 template <class T>
448 [[nodiscard]] T& get(pos_type pos)
449 {
450 return bucketData<T>(pos)[blockPos(pos)];
451 }
452
453 template <class T>
454 [[nodiscard]] T const& get(pos_type pos) const
455 {
456 return bucketData<T>(pos)[blockPos(pos)];
457 }
458
459 template <std::size_t I>
460 [[nodiscard]] auto& get(pos_type pos)
461 {
462 return bucketData<I>(pos)[blockPos(pos)];
463 }
464
465 template <std::size_t I>
466 [[nodiscard]] auto const& get(pos_type pos) const
467 {
468 return bucketData<I>(pos)[blockPos(pos)];
469 }
470
471 [[nodiscard]] constexpr pos_type numBuckets() const noexcept
472 {
473 return empty() ? 0 : bucketPos(capacity() - 1) + 1;
474 }
475
476 [[nodiscard]] constexpr pos_type numBlocksPerBucket() const noexcept
477 {
478 return NUM_BLOCKS_PER_BUCKET;
479 }
480
481 [[nodiscard]] constexpr pos_type bucketPos(pos_type pos) const noexcept
482 {
483 return pos / NUM_BLOCKS_PER_BUCKET;
484 }
485
486 [[nodiscard]] constexpr pos_type blockPos(pos_type pos) const noexcept
487 {
488 return pos % NUM_BLOCKS_PER_BUCKET;
489 }
490
491 [[nodiscard]] pos_type create()
492 {
493 if (pos_type idx = num_inactive_.load(std::memory_order_relaxed); 0u < idx) {
494 --idx;
495 num_inactive_.store(idx, std::memory_order_relaxed);
496 auto& b = *buckets_[bucketPos(idx)].load(std::memory_order_relaxed);
497 return std::get<0>(b)[blockPos(idx)];
498 }
499
500 pos_type idx = cap_.fetch_add(pos_type(1u), std::memory_order_relaxed);
501
502 pos_type bucket = bucketPos(idx);
503
504 value_type* b = buckets_[bucket];
505 if (nullptr == b) {
506 // Create bucket
507 b = new value_type();
508 buckets_[bucket] = b;
509 }
510
511 return idx;
512 }
513
514 [[nodiscard]] pos_type createThreadSafe()
515 {
516 if (0u < num_inactive_.load(std::memory_order_relaxed)) {
517 std::scoped_lock lock(mutex_);
518 if (pos_type idx = num_inactive_.load(std::memory_order_acquire); 0u < idx) {
519 --idx;
520 num_inactive_.store(idx, std::memory_order_release);
521 auto& b = *buckets_[bucketPos(idx)].load(std::memory_order_relaxed);
522 return std::get<0>(b)[blockPos(idx)];
523 }
524 }
525
526 pos_type idx = cap_.fetch_add(pos_type(1u), std::memory_order_acq_rel);
527
528 pos_type bucket = bucketPos(idx);
529 pos_type block = blockPos(idx);
530
531 value_type* v = buckets_[bucket];
532 if (0 == block) {
533 // This will create bucket if it does not exist
534 if (nullptr == v) {
535 // Create bucket
536 v = new value_type();
537 buckets_[bucket] = v;
538 }
539 } else {
540 // This will wait for someone else to create the bucket if it does not exist
541 for (; nullptr == v; v = buckets_[bucket]) {
542 // Wait
543 }
544 }
545
546 return idx;
547 }
548
549 void eraseBlock(pos_type block)
550 {
551 pos_type idx = num_inactive_.fetch_add(pos_type(1), std::memory_order_acq_rel);
552 auto& b = *buckets_[bucketPos(idx)].load(std::memory_order_relaxed);
553 std::get<0>(b)[blockPos(idx)] = block;
554 }
555
556 void clear()
557 {
558 // Reset all existing buckets to default value
559 for (std::size_t i{}; NUM_BUCKETS > i; ++i) {
560 if (nullptr == buckets_[i]) {
561 break;
562 }
563
564 // TODO: Why does the line below not work?
565 // *(buckets_[i]) = {};
566 }
567
568 cap_ = 0;
569 num_inactive_ = 0;
570 }
571
572 void reserve(pos_type cap)
573 {
574 // FIXME: Can be improved
575 pos_type first = bucketPos(capacity());
576 pos_type last = bucketPos(cap);
577 for (; last >= first; ++first) {
578 if (nullptr == buckets_[first]) {
579 break;
580 }
581 }
582
583 // We know that the rest of the buckets do not exist yet
584
585 for (; last >= first; ++first) {
586 // Create bucket
587 buckets_[first] = new value_type();
588 }
589 }
590
591 void shrinkToFit()
592 {
593 for (std::size_t i = numBuckets(); NUM_BUCKETS > i; ++i) {
594 if (nullptr == buckets_[i]) {
595 break;
596 }
597
598 delete buckets_[i];
599 buckets_[i] = nullptr;
600 }
601 }
602
603 [[nodiscard]] bool empty() const { return 0 == size(); }
604
605 [[nodiscard]] pos_type size() const { return cap_ - num_inactive_; }
606
607 [[nodiscard]] pos_type capacity() const { return cap_; }
608
609 template <class T>
610 [[nodiscard]] static constexpr size_type serializedBucketSize()
611 {
612 return sizeof(S<T>::data);
613 }
614
615 template <class T>
616 [[nodiscard]] constexpr size_type serializedSize() const
617 {
618 return numBuckets() * serializedBucketSize<T>();
619 }
620
621 void swap(TreeContainer& other)
622 {
623 using std::swap;
624 swap(buckets_, other.buckets_);
625
626 pos_type tmp = cap_;
627 cap_ = other.cap_.load();
628 other.cap_ = tmp;
629
630 tmp = num_inactive_;
631 num_inactive_ = other.num_inactive_.load();
632 other.num_inactive_ = tmp;
633 }
634
635 private:
636 [[nodiscard]] value_type& bucket(std::size_t idx)
637 {
638 return *buckets_[bucketPos(idx)].load(std::memory_order_acquire);
639 }
640
641 [[nodiscard]] value_type const& bucket(std::size_t idx) const
642 {
643 return *buckets_[bucketPos(idx)].load(std::memory_order_acquire);
644 }
645
646 private:
647 std::unique_ptr<Bucket[]> buckets_ = std::make_unique<Bucket[]>(NUM_BUCKETS);
648
649 std::atomic<pos_type> cap_{};
650 std::atomic<pos_type> num_inactive_{};
651
652 std::mutex mutex_;
653};
654
655template <class... Ts>
656void swap(TreeContainer<Ts...>& lhs, TreeContainer<Ts...>& rhs)
657{
658 lhs.swap(rhs);
659}
660} // namespace ufo
661
662#endif // UFO_CONTAINER_TREE_CONTAINER_HPP
All vision-related classes and functions.
Definition cloud.hpp:49
constexpr T b(Lab< T, Flags > color) noexcept
Returns the un-weighted blue–yellow axis value.
Definition lab.hpp:326