UFO 1.0.0
An Efficient Probabilistic 3D Mapping Framework That Embraces the Unknown
Loading...
Searching...
No Matches
small_vector.hpp
1
42#ifndef UFO_CONTAINER_SMALL_VECTOR_HPP
43#define UFO_CONTAINER_SMALL_VECTOR_HPP
44
45// UFO
46#include <ufo/utility/io/buffer.hpp>
47#include <ufo/utility/iterator_wrapper.hpp>
48
49// STL
50#include <cstdlib>
51#include <iterator>
52#include <memory>
53#include <numeric>
54#include <type_traits>
55
56namespace ufo
57{
58template <typename T, std::size_t T_NUM, std::size_t N, typename SIZE_T = T>
60{
61 // TODO: Make it possible to have smaller SIZE_T than T
62 static constexpr std::size_t SIZES_SIZE = sizeof(SIZE_T) / sizeof(T);
63 static constexpr std::size_t SIZES_OFFSET = N * SIZES_SIZE;
64
65 public:
66 using size_type = SIZE_T;
67 using difference_type = std::ptrdiff_t;
68 using reference = std::conditional_t<1 == T_NUM, T&, std::array<T, T_NUM>&>;
69 using const_reference =
70 std::conditional_t<1 == T_NUM, T const&, std::array<T, T_NUM> const&>;
71 using pointer = std::conditional_t<1 == T_NUM, T*, std::array<T, T_NUM>*>;
72 using const_pointer =
73 std::conditional_t<1 == T_NUM, T const*, std::array<T, T_NUM> const*>;
74 using iterator = std::conditional_t<1 == T_NUM, T*, std::array<T, T_NUM>*>;
75 using const_iterator =
76 std::conditional_t<1 == T_NUM, T const*, std::array<T, T_NUM> const*>;
77 using reverse_iterator = std::reverse_iterator<iterator>;
78 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
79 using Query = IteratorWrapper<iterator>;
80 using ConstQuery = IteratorWrapper<const_iterator>;
81 using ReverseQuery = IteratorWrapper<reverse_iterator>;
82 using ReverseConstQuery = IteratorWrapper<const_reverse_iterator>;
83
84 public:
85 //
86 // Constructors
87 //
88
89 //
90 // Destructor
91 //
92
93 //
94 // Assignment operator
95 //
96
97 //
98 // iterators
99 //
100
101 [[nodiscard]] iterator begin() { return begin(0); }
102
103 [[nodiscard]] const_iterator begin() const { return begin(0); }
104
105 [[nodiscard]] const_iterator cbegin() const { return cbegin(); }
106
107 [[nodiscard]] iterator end() { return end(N - 1); }
108
109 [[nodiscard]] const_iterator end() const { return end(N - 1); }
110
111 [[nodiscard]] const_iterator cend() const { return end(); }
112
113 [[nodiscard]] iterator begin(std::size_t pos)
114 {
115 return reinterpret_cast<iterator>(data_ ? data_.get() + offset(pos) : nullptr);
116 }
117
118 [[nodiscard]] const_iterator begin(std::size_t pos) const
119 {
120 return reinterpret_cast<const_iterator>(data_ ? data_.get() + offset(pos) : nullptr);
121 }
122
123 [[nodiscard]] const_iterator cbegin(std::size_t pos) const { return begin(pos); }
124
125 [[nodiscard]] iterator end(std::size_t pos)
126 {
127 return reinterpret_cast<iterator>(data_ ? data_.get() + offset(pos + 1) : nullptr);
128 }
129
130 [[nodiscard]] const_iterator end(std::size_t pos) const
131 {
132 return reinterpret_cast<const_iterator>(data_ ? data_.get() + offset(pos + 1)
133 : nullptr);
134 }
135
136 [[nodiscard]] const_iterator cend(std::size_t pos) const { return end(pos); }
137
138 [[nodiscard]] reverse_iterator rbegin() { return std::make_reverse_iterator(end()); }
139
140 [[nodiscard]] const_iterator rbegin() const
141 {
142 return std::make_reverse_iterator(end());
143 }
144
145 [[nodiscard]] const_iterator crbegin() const { return crbegin(); }
146
147 [[nodiscard]] iterator rend() { return std::make_reverse_iterator(begin()); }
148
149 [[nodiscard]] const_iterator rend() const
150 {
151 return std::make_reverse_iterator(begin());
152 }
153
154 [[nodiscard]] const_iterator crend() const { return rend(); }
155
156 [[nodiscard]] iterator rbegin(std::size_t pos)
157 {
158 return std::make_reverse_iterator(end(pos));
159 }
160
161 [[nodiscard]] const_iterator rbegin(std::size_t pos) const
162 {
163 return std::make_reverse_iterator(end(pos));
164 }
165
166 [[nodiscard]] const_iterator crbegin(std::size_t pos) const { return rbegin(pos); }
167
168 [[nodiscard]] iterator rend(std::size_t pos)
169 {
170 return std::make_reverse_iterator(begin(pos));
171 }
172
173 [[nodiscard]] const_iterator rend(std::size_t pos) const
174 {
175 return std::make_reverse_iterator(begin(pos));
176 }
177
178 [[nodiscard]] const_iterator crend(std::size_t pos) const { return rend(pos); }
179
180 //
181 // Query
182 //
183
184 [[nodiscard]] Query query() { return {begin(), end()}; }
185
186 [[nodiscard]] Query query(std::size_t pos) { return {begin(pos), end(pos)}; }
187
188 [[nodiscard]] ConstQuery query() const { return {begin(), end()}; }
189
190 [[nodiscard]] ConstQuery query(std::size_t pos) const { return {begin(pos), end(pos)}; }
191
192 [[nodiscard]] ReverseQuery rquery() { return {rbegin(), rend()}; }
193
194 [[nodiscard]] ReverseQuery rquery(std::size_t pos) { return {rbegin(pos), rend(pos)}; }
195
196 [[nodiscard]] ReverseConstQuery rquery() const { return {rbegin(), rend()}; }
197
198 [[nodiscard]] ReverseConstQuery rquery(std::size_t pos) const
199 {
200 return {rbegin(pos), rend(pos)};
201 }
202
203 //
204 // Data
205 //
206
207 T* data() { return data(0); }
208
209 T const* data() const { return data(0); }
210
211 T* data(std::size_t pos) { return data_.get() + offset(pos); }
212
213 T const* data(std::size_t pos) const { return data_.get() + offset(pos); }
214
215 //
216 // Operator()()
217 //
218
219 reference operator()(std::size_t idx) { return operator()(0, idx); }
220
221 const_reference operator()(std::size_t idx) const { return operator()(0, idx); }
222
223 reference operator()(std::size_t pos, std::size_t idx)
224 {
225 return reinterpret_cast<reference>(data_[offset(pos) + T_NUM * idx]);
226 }
227
228 const_reference operator()(std::size_t pos, std::size_t idx) const
229 {
230 return reinterpret_cast<const_reference>(data_[offset(pos) + T_NUM * idx]);
231 }
232
233 //
234 // Clear
235 //
236
237 void clear()
238 {
239 if (data_) {
240 data_.reset();
241 }
242 }
243
244 void clear(std::size_t pos)
245 {
246 if (size() == size(pos)) {
247 clear();
248 } else {
249 resize(pos);
250 }
251 }
252
253 //
254 // Empty
255 //
256
257 [[nodiscard]] bool empty() const { return nullptr == data_; }
258
259 [[nodiscard]] bool empty(std::size_t pos) const { return 0 == size(pos); }
260
261 //
262 // Size
263 //
264
265 [[nodiscard]] std::size_t size() const
266 {
267 auto s = sizes();
268 return std::accumulate(std::cbegin(s), std::cend(s), std::size_t(0));
269 }
270
271 [[nodiscard]] std::size_t size(std::size_t pos) const
272 {
273 return data_ ? *(reinterpret_cast<size_type const*>(data_.get()) + pos) : 0;
274 }
275
276 [[nodiscard]] std::array<size_type, N> sizes() const
277 {
278 if (empty()) {
279 return std::array<size_type, N>{};
280 }
281
282 size_type const* it = reinterpret_cast<size_type const*>(data_.get());
283
284 std::array<size_type, N> s;
285 std::copy(it, it + N, s.data());
286 return s;
287 }
288
289 //
290 // Allocated size
291 //
292
293 // [[nodiscard]] std::size_t allocatedSize() const
294 // {
295 // return SIZES_OFFSET + T_NUM * size();
296 // }
297
298 // [[nodiscard]] std::size_t allocatedSize(std::size_t pos) const
299 // {
300 // return SIZES_OFFSET + T_NUM * size(pos);
301 // }
302
303 //
304 // Offset
305 //
306
307 [[nodiscard]] std::size_t offset(std::size_t pos) const
308 {
309 size_type const* it = reinterpret_cast<size_type const*>(data_.get());
310 return data_ ? SIZES_OFFSET + T_NUM * std::accumulate(it, it + pos, std::size_t(0))
311 : 0;
312 }
313
314 //
315 // Resize
316 //
317
318 void resize(std::size_t count)
319 {
320 if (0 == count) {
321 clear();
322 return;
323 } else if (size() == count) {
324 return;
325 }
326
327 T* p_cur = data_.release();
328 T* p_new = allocate(p_cur, count);
329
330 if (!p_new) {
331 data_.reset(p_cur);
332 throw std::bad_alloc();
333 }
334
335 data_.reset(p_new);
336
337 auto it = reinterpret_cast<SIZE_T*>(data_.get());
338 *it = static_cast<SIZE_T>(count);
339 std::fill(it + 1, it + N, SIZE_T(0));
340 }
341
342 void resize(std::size_t pos, std::size_t count)
343 {
344 auto cur_sizes = sizes();
345 auto cur_size =
346 std::accumulate(std::cbegin(cur_sizes), std::cend(cur_sizes), std::size_t(0));
347 auto cur_count = cur_sizes[pos];
348
349 if (cur_count == count) {
350 return;
351 } else if (0 == count && cur_size == cur_count) {
352 clear();
353 return;
354 }
355
356 if (count < cur_count && N - 1 != pos) {
357#if __cplusplus >= 202002L
358 std::copy(std::to_address(begin(pos + 1)), std::to_address(end()),
359 std::to_address(begin(pos) + count));
360#else
361 std::copy(begin(pos + 1), end(), begin(pos) + count);
362#endif
363 }
364
365 bool was_empty = empty();
366
367 T* p_cur = data_.release();
368 T* p_new = allocate(p_cur, cur_size + count - cur_count);
369
370 if (!p_new) {
371 data_.reset(p_cur);
372 throw std::bad_alloc();
373 }
374
375 data_.reset(p_new);
376
377 if (was_empty) {
378 auto it = reinterpret_cast<SIZE_T*>(data_.get());
379 std::fill(it, it + N, SIZE_T(0));
380 } else {
381 if (count > cur_count && N - 1 != pos) {
382#if __cplusplus >= 202002L
383 std::copy_backward(std::to_address(begin(pos + 1)), std::to_address(end()),
384 std::to_address(end() + (count - cur_count)));
385#else
386 std::copy_backward(begin(pos + 1), end(), end() + (count - cur_count));
387#endif
388 }
389 }
390
391 reinterpret_cast<SIZE_T&>(data_[SIZES_SIZE * pos]) = static_cast<SIZE_T>(count);
392 }
393
394 //
395 // Memory usage
396 //
397
398 [[nodiscard]] std::size_t memoryUsage()
399 {
400 return empty() ? 0 : N * sizeof(SIZE_T) + size() * T_NUM * sizeof(T);
401 }
402
403 [[nodiscard]] std::size_t memoryUsage(std::size_t pos)
404 {
405 return empty(pos) ? 0 : size(pos) * T_NUM * sizeof(T);
406 }
407
408 //
409 // Input/output (read/write)
410 //
411
412 std::size_t serializedSize() const { return sizeof(std::uint32_t) + memoryUsage(); }
413
414 void read(ReadBuffer& in)
415 {
416 std::uint32_t s;
417 in.read(&s, sizeof(s));
418 resize(s);
419 if (s) {
420 in.read(data_.get(), memoryUsage());
421 }
422 }
423
424 void read(ReadBuffer& in, std::size_t pos)
425 {
426 std::uint32_t s;
427 in.read(&s, sizeof(s));
428 resize(pos, s);
429 if (s) {
430 in.read(data(pos), memoryUsage(pos));
431 }
432 }
433
434 void write(WriteBuffer& out)
435 {
436 std::uint32_t s = size();
437 out.write(&s, sizeof(s));
438 if (s) {
439 out.write(data_.get(), memoryUsage());
440 }
441 }
442
443 void write(WriteBuffer& out, std::size_t pos)
444 {
445 std::uint32_t s = size(pos);
446 out.write(&s, sizeof(s));
447 if (s) {
448 out.write(data(pos), memoryUsage(pos));
449 }
450 }
451
452 protected:
453 //
454 // Allocate
455 //
456
457 T* allocate(T* p, std::size_t s)
458 {
459 return static_cast<T*>(realloc(p, N * sizeof(SIZE_T) + s * T_NUM * sizeof(T)));
460 }
461
462 protected:
463 struct free_delete {
464 void operator()(void* x) { free(x); }
465 };
466
467 std::unique_ptr<T[], free_delete> data_;
468};
469
470//
471// Specialization for pair
472//
473
474// template <typename T1, typename T2, std::size_t N, typename size_type>
475// class SmallVector<std::pair<T1, T2>, 1, N, size_type>
476// {
477// public:
478// //
479// // TODO: Implement
480// //
481
482// protected:
483// //
484// // TODO: Implement
485// //
486
487// protected:
488// struct free_delete {
489// void operator()(void *x) { free(x); }
490// };
491
492// std::uniquelhs.ptr_<std::pair<T1, T2>[], free_delete> data_;
493// };
494} // namespace ufo
495
496namespace std
497{
498template <typename T, size_t T_NUM, size_t N, typename SIZE_T = T>
499ostream& operator<<(ostream& out, ufo::SmallVector<T, T_NUM, N, SIZE_T> const& vec)
500{
501 for (size_t i{}; N != i; ++i) {
502 if (vec.empty(i)) {
503 out << "[] ";
504 } else {
505 out << "[";
506 for (auto const& e : vec.query(i)) {
507 if constexpr (1 == T_NUM) {
508 out << +e << ' ';
509 } else {
510 out << '(';
511 for (auto x : e) {
512 out << +x << ' ';
513 }
514 out << "\b) ";
515 }
516 }
517 out << "\b] ";
518 }
519 }
520
521 out << '\b';
522
523 return out;
524}
525} // namespace std
526
527#endif // UFO_CONTAINER_SMALL_VECTOR_HPP
STL namespace.
All vision-related classes and functions.
Definition cloud.hpp:49