koutil
Loading...
Searching...
No Matches
multi_vector.h
Go to the documentation of this file.
1#ifndef KOUTIL_CONTAINER_MULTI_VECTOR_H
2#define KOUTIL_CONTAINER_MULTI_VECTOR_H
3
4#include "koutil/type/types.h"
5#include <cassert>
6#include <cstddef>
7#include <iterator>
8#include <memory>
9#include <span>
10#include <tuple>
11#include <type_traits>
12#include <utility>
13#include <vector>
14
15namespace koutil::container {
16
22template <typename T>
23concept is_multi_vector_element = !std::is_reference_v<T>;
24
30template <is_multi_vector_element... Types>
31 requires(type::types_remove_t<type::types<Types...>, void>::size != 0)
33private:
34 template <typename T, typename Allocator = std::allocator<T>> class single_vector {
35 public:
36 single_vector(std::size_t n)
37 : m_data(Allocator().allocate(n))
38 , m_capacity(n)
39 , m_size(n) {
40 std::uninitialized_fill_n(m_data, n, T());
41 }
42
43 single_vector(std::size_t n, const T& value)
44 : m_data(Allocator().allocate(n))
45 , m_capacity(n)
46 , m_size(n) {
47 std::uninitialized_fill_n(m_data, n, value);
48 }
49
50 single_vector() = default;
51
53 : m_data(Allocator().allocate(other.m_capacity))
54 , m_capacity(other.m_capacity)
55 , m_size(other.m_size) {
56 std::uninitialized_copy_n(other.m_data, other.m_size, m_data);
57 }
58
60 if (m_capacity != 0) {
61 std::destroy_n(m_data, m_size);
62 Allocator().deallocate(m_data, m_capacity);
63 }
64 }
65
67 : m_data(other.m_data)
68 , m_capacity(other.m_capacity)
69 , m_size(other.m_size) {
70 other.m_capacity = 0;
71 other.m_size = 0;
72 other.m_data = nullptr;
73 }
74
76 if (m_capacity != 0) {
77 std::destroy_n(m_data, m_size);
78 Allocator().deallocate(m_data, m_capacity);
79 }
80
81 m_size = other.m_size;
82 m_capacity = other.m_capacity;
83 m_data = other.m_data;
84
85 other.m_size = 0;
86 other.m_capacity = 0;
87 other.m_data = nullptr;
88
89 return *this;
90 }
91
93 if (&other == this) {
94 return *this;
95 }
96
97 std::destroy_n(m_data, m_size);
98 if (m_capacity != other.m_capacity) {
99 auto alloc = Allocator();
100
101 alloc.deallocate(m_data, m_capacity);
102
103 m_data = new (alloc.allocate(other.m_capacity)) T[other.m_capacity];
104 }
105
106 std::uninitialized_copy_n(other.m_data, other.m_size, m_data);
107
108 m_capacity = other.m_capacity;
109 m_size = other.m_size;
110
111 return *this;
112 }
113
114 void clear() { m_size = 0; }
115
116 void swap(single_vector& other) {
117 std::swap(m_data, other.m_data);
118 std::swap(m_size, other.m_size);
119 std::swap(m_capacity, other.m_capacity);
120 }
121
122 void push_back(const T& value) {
123 try_update_capacity();
124
125 m_data[m_size] = value;
126 m_size += 1;
127 }
128
129 void push_back(T&& value) {
130 try_update_capacity();
131
132 m_data[m_size] = std::move(value);
133 m_size += 1;
134 }
135
136 template <typename Arg> T& emplace_back(Arg&& arg) {
137 try_update_capacity();
138
139 m_data[m_size] = T(std::forward<decltype(arg)>(arg));
140 m_size += 1;
141
142 return m_data[m_size - 1];
143 }
144
145 T* erase(const T* element) {
146 assert(element <= m_data + m_size && element >= m_data);
147
148 // last element
149 if (m_data + m_size == element) {
150 m_size -= 1;
151 return m_data + m_size;
152 }
153
154 m_size -= 1;
155 if (m_size == m_capacity / 2) {
156 m_capacity /= 2;
157 }
158
159 const auto index = static_cast<std::size_t>(element - m_data);
160
161 realloc_without(m_capacity, index);
162
163 return m_data + index;
164 }
165
166 void pop_back() {
167 assert(m_size > 0);
168 m_size -= 1;
169 }
170
171 void resize(std::size_t n) { resize(n, {}); }
172
173 void resize(std::size_t n, const T& value) {
174 if (m_size >= n) {
175 m_size = n;
176 return;
177 }
178
179 if (m_capacity >= n) {
180 std::uninitialized_fill_n(m_data + m_size, m_capacity - m_size, value);
181 } else {
182 realloc_with_value(n, value);
183 }
184 m_size = n;
185 }
186
187 void reserve(std::size_t n) {
188 if (n <= m_capacity) {
189 return;
190 }
191
192 realloc(n);
193 }
194
195 T& at(std::size_t i) { return m_data[i]; }
196
197 [[nodiscard]] const T& at(std::size_t i) const { return m_data[i]; }
198
199 T* data() { return m_data; }
200
201 [[nodiscard]] const T* data() const { return m_data; }
202
203 [[nodiscard]] std::size_t size() const { return m_size; }
204
205 T* begin() { return m_data; }
206
207 const T* begin() const { return m_data; }
208
209 T* end() { return m_data + m_size; }
210
211 const T* end() const { return m_data + m_size; }
212
213 private:
214 T* m_data = nullptr;
215 std::size_t m_capacity = 0;
216 std::size_t m_size = 0;
217
218 [[nodiscard]] std::size_t next_capacity() const {
219 if (m_capacity == 0) {
220 return 1;
221 } else [[likely]] {
222 return m_capacity * 2;
223 }
224 }
225
227 if (m_size + 1 <= m_capacity) {
228 return;
229 }
230 realloc(next_capacity());
231 }
232
233 void realloc(std::size_t capacity) {
234 const std::size_t old_capacity = m_capacity;
235 m_capacity = capacity;
236
237 auto alloc = Allocator();
238 auto* new_data = new (alloc.allocate(m_capacity)) T[m_capacity];
239
240 std::uninitialized_move(m_data, m_data + m_size, new_data);
241
242 std::destroy_n(m_data, m_size);
243 alloc.deallocate(m_data, old_capacity);
244 m_data = new_data;
245 }
246
247 void realloc_with_value(std::size_t capacity, const T& value = {}) {
248 realloc(capacity);
249 std::uninitialized_fill_n(m_data + m_size, m_capacity - m_size, value);
250 }
251
252 void realloc_without(std::size_t capacity, std::size_t index) {
253 const std::size_t old_capacity = m_capacity;
254 m_capacity = capacity;
255
256 auto alloc = Allocator();
257 T* new_data = nullptr;
258
259 if (m_capacity != 0) {
260 new_data = new (alloc.allocate(m_capacity)) T[m_capacity];
261 std::uninitialized_move_n(m_data, index, new_data);
262 std::uninitialized_move_n(m_data + index + 1, m_size - index, new_data);
263 }
264
265 std::destroy_n(m_data, m_size + 1);
266 alloc.deallocate(m_data, old_capacity);
267 m_data = new_data;
268 }
269 };
270
272 template <typename T> using container = single_vector<T>;
273 };
274
277
278 template <type::types_concept T, type::types_container Container>
280
281 template <type::types_concept T, type::types_transform Transform>
283
284 using all_types = type::types<Types...>;
286
288
289 static constexpr auto helper_seq = std::make_index_sequence<types::size>();
290
291public:
297 template <bool is_const> class iterator;
298
300
310 multi_vector() = default;
311 multi_vector(const multi_vector&) = default;
312 multi_vector(multi_vector&&) = default;
313
320 multi_vector(std::size_t count, const value_t& value) { init_vector(count, value); }
321
327 explicit multi_vector(std::size_t count) { init_vector_default(count); }
329 multi_vector& operator=(const multi_vector& other) = default;
331 multi_vector& operator=(multi_vector&&) = default;
333 template <std::size_t I> decltype(auto) get_container() {
334
335 static_assert(!std::is_same_v<type::types_get_t<all_types, I>, void>, "This type was removed");
336
338 constexpr std::size_t count_void = type::types_count<view>::template value<void>;
339 constexpr std::size_t index = view::size - count_void;
340
342
343 auto& container = std::get<index>(m_storage);
344
345 if constexpr (std::is_same_v<element, bool>) {
346 return std::span<bool>(container.begin(), container.end());
347 } else {
348 return std::span { container };
349 }
350 }
352 template <std::size_t I> decltype(auto) get_container() const {
353
354 static_assert(!std::is_same_v<type::types_get_t<all_types, I>, void>, "This type was removed");
355
357 constexpr std::size_t count_void = type::types_count<view>::template value<void>;
358 constexpr std::size_t index = view::size - count_void;
359
361
362 const auto& container = std::get<index>(m_storage);
363
364 if constexpr (std::is_same_v<element, bool>) {
365 return std::span<bool>(container.begin(), container.end());
366 } else {
367 return std::span { container };
368 }
369 }
370
376 value_ref_t front() {
377 assert(!empty());
378 return at(0);
379 }
380
386 const_value_ref_t front() const {
387 assert(!empty());
388 return at(0);
389 }
390
396 value_ref_t back() {
397 assert(!empty());
398 return at(size() - 1);
399 }
400
406 const_value_ref_t back() const {
407 assert(!empty());
408 return at(size() - 1);
409 }
410
417 value_ref_t at(std::size_t pos) {
418 assert(pos < size());
419 return get_all(pos, helper_seq);
420 }
421
428 const_value_ref_t at(std::size_t pos) const {
429 assert(pos < size());
430 return get_all(pos, helper_seq);
431 }
432
439 value_ref_t operator[](std::size_t pos) { return at(pos); }
440
447 const_value_ref_t operator[](std::size_t pos) const { return at(pos); }
448
454 [[nodiscard]] std::size_t size() const { return std::get<0>(m_storage).size(); }
455
461 [[nodiscard]] bool empty() const { return size() == 0; }
462
466 void clear() { clear_all(helper_seq); }
467
473 void swap(multi_vector& other) { std::swap(other.m_storage, m_storage); }
474
480 void resize(std::size_t size) { resize_all(size, helper_seq); }
481
488 void resize(std::size_t size, const value_t& value) { resize_all_with(size, value, helper_seq); }
489
495 void reserve(std::size_t size) { reserve_impl(size, helper_seq); }
496
500 void pop_back() { pop_back_impl(helper_seq); }
501
509 template <typename... Args>
510 requires(sizeof...(Args) == types::size)
511 value_ref_t emplace_back(Args&&... args) {
512 return emplace_back_impl(helper_seq, std::forward<decltype(args)>(args)...);
513 }
514
520 void push_back(const value_t& value) { push_back_impl(value, helper_seq); }
521
527 void push_back(value_t&& value) { push_back_impl(std::move(value), helper_seq); }
528
532 void shrink_to_fit() { shrink_to_fit_impl(helper_seq); }
533
540 iterator_t erase(const_iterator_t pos) {
541 erase_impl(pos);
542
543 const auto dist = static_cast<std::size_t>(pos - begin());
544 if (dist >= size()) {
545 return end();
546 } else {
547 return iterator_t { this, dist };
548 }
549 }
550
556 iterator_t begin() { return iterator_t { this, 0 }; }
557
563 const_iterator_t begin() const { return const_iterator_t { this, 0 }; }
564
570 const_iterator_t cbegin() const { return const_iterator_t { this, 0 }; }
571
577 iterator_t end() { return iterator_t { this, size() }; }
578
584 const_iterator_t end() const { return const_iterator_t { this, size() }; }
585
591 const_iterator_t cend() const { return const_iterator_t { this, size() }; }
592
593private:
594 storage_t m_storage;
595
603 template <std::size_t I = 0> void init_vector(std::size_t count, const value_t& value) {
604 using vector_element = type::types_get_t<types, I>;
605
606 std::get<I>(m_storage) = single_vector<vector_element>(count, std::get<I>(value));
607
608 if constexpr (I + 1 < types::size) {
609 init_vector<I + 1>(count, value);
610 }
611 }
612
619 template <std::size_t I = 0> void init_vector_default(std::size_t count) {
620 using vector_element = type::types_get_t<types, I>;
621
622 std::get<I>(m_storage) = single_vector<vector_element>(count);
623
624 if constexpr (I + 1 < types::size) {
625 init_vector_default<I + 1>(count);
626 }
627 }
628
636 template <std::size_t I> auto& get_single(std::size_t pos) { return std::get<I>(m_storage).at(pos); }
637
645 template <std::size_t I> const auto& get_single(std::size_t pos) const { return std::get<I>(m_storage).at(pos); }
646
654 template <std::size_t... I> value_ref_t get_all(std::size_t pos, std::index_sequence<I...> /*unused*/) {
655 return { get_single<I>(pos)... };
656 }
657
665 template <std::size_t... I> const_value_ref_t get_all(std::size_t pos, std::index_sequence<I...> /*unused*/) const {
666 return { get_single<I>(pos)... };
667 }
668
674 template <std::size_t... I> void clear_all(std::index_sequence<I...> /*unused*/) {
675 (std::get<I>(m_storage).clear(), ...);
676 }
677
684 template <std::size_t... I> void resize_all(std::size_t size, std::index_sequence<I...> /*unused*/) {
685 (std::get<I>(m_storage).resize(size), ...);
686 }
687
695 template <std::size_t... I>
696 void resize_all_with(std::size_t size, const value_t& value, std::index_sequence<I...> /*unused*/) {
697 (std::get<I>(m_storage).resize(size, std::get<I>(value)), ...);
698 }
699
705 template <std::size_t... I> void pop_back_impl(std::index_sequence<I...> /*unused*/) {
706 (std::get<I>(m_storage).pop_back(), ...);
707 }
708
716 template <typename Value, std::size_t... I>
717 void push_back_impl(Value&& value, std::index_sequence<I...> /*unused*/) {
718 (std::get<I>(m_storage).push_back(std::get<I>(std::forward<decltype(value)>(value))), ...);
719 }
720
729 template <typename... Args, std::size_t... I>
730 value_ref_t emplace_back_impl(std::index_sequence<I...> /*unused*/, Args&&... args) {
731 return std::forward_as_tuple(std::get<I>(m_storage).emplace_back(std::forward<decltype(args)>(args))...);
732 }
733
739 template <std::size_t... I> void shrink_to_fit_impl(std::index_sequence<I...> /*unused*/) {
740 (std::get<I>(m_storage).shrink_to_fit(), ...);
741 }
742
749 template <std::size_t... I> void reserve_impl(std::size_t size, std::index_sequence<I...> /*unused*/) {
750 (std::get<I>(m_storage).reserve(size), ...);
751 }
752
759 template <std::size_t I = 0> void erase_impl(const_iterator_t pos) {
760 auto& vec = std::get<I>(m_storage);
761 vec.erase(vec.begin() + pos.m_index);
762
763 if constexpr (I + 1 < types::size) {
764 erase_impl<I + 1>(pos);
765 }
766 }
767};
768
775template <is_multi_vector_element... T>
776 requires(type::types_remove_t<type::types<T...>, void>::size != 0)
777template <bool is_const>
779private:
780 using vec_ptr_t = std::conditional_t<is_const, const multi_vector*, multi_vector*>;
781
782public:
783 using value_type = std::conditional_t<is_const, const_value_ref_t, value_ref_t>;
786 using difference_type = std::ptrdiff_t;
787 using iterator_category = std::random_access_iterator_tag;
788
789 iterator() = default;
790 iterator(const iterator&) = default;
791 iterator(iterator&&) = default;
792 iterator& operator=(const iterator&) = default;
794
795 const_value_type operator*() const { return m_ref->at(m_index); }
796
798 requires(!is_const)
799 {
800 return m_ref->at(m_index);
801 }
802
804 m_index++;
805 return *this;
806 }
807
808 operator iterator<true>() const
809 requires(!is_const)
810 {
811 return iterator<true>(m_ref, m_index);
812 }
813
814 iterator operator++(int) { return { m_ref, m_index++ }; }
815
817 --m_index;
818 return *this;
819 }
820
821 iterator& operator--(int) { return { m_ref, m_index-- }; }
822
823 difference_type operator-(const iterator& other) const {
824 if (m_index < other.m_index) {
825 return -static_cast<difference_type>(other.m_index - m_index);
826 } else {
827 return static_cast<difference_type>(m_index - other.m_index);
828 }
829 }
830
832 m_index += n;
833 return *this;
834 }
835
837 m_index -= n;
838 return *this;
839 }
840
841 iterator operator+(difference_type n) const { return { m_ref, m_index + n }; }
842
843 iterator operator-(difference_type n) const { return { m_ref, m_index - n }; }
844
845 const_value_type operator[](difference_type n) const { return m_ref->at(m_index + n); }
846
848 requires(!is_const)
849 {
850 return m_ref->at(m_index + n);
851 }
852
853 bool operator==(const iterator& other) const = default;
854 bool operator!=(const iterator& other) const = default;
855
856 bool operator<(const iterator& other) const { return m_index < other.m_index; }
857
858 bool operator<=(const iterator& other) const { return m_index <= other.m_index; }
859
860 bool operator>(const iterator& other) const { return m_index > other.m_index; }
861
862 bool operator>=(const iterator& other) const { return m_index >= other.m_index; }
863
864private:
865 vec_ptr_t m_ref = nullptr;
866 std::size_t m_index = 0;
867
868 iterator(vec_ptr_t vec, std::size_t index)
869 : m_ref(vec)
870 , m_index(index) { }
871
872 friend class iterator<true>;
873 friend class multi_vector;
874};
875}
876
877#endif
Nested iterator class for multi_vector.
Definition multi_vector.h:778
bool operator!=(const iterator &other) const =default
bool operator==(const iterator &other) const =default
difference_type operator-(const iterator &other) const
Definition multi_vector.h:823
bool operator<=(const iterator &other) const
Definition multi_vector.h:858
std::ptrdiff_t difference_type
Definition multi_vector.h:786
value_type operator*()
Definition multi_vector.h:797
iterator & operator++()
Definition multi_vector.h:803
iterator & operator--()
Definition multi_vector.h:816
std::conditional_t< is_const, const_value_ref_t, value_ref_t > value_type
Definition multi_vector.h:783
const_value_type operator*() const
Definition multi_vector.h:795
const_value_type operator[](difference_type n) const
Definition multi_vector.h:845
iterator & operator+=(difference_type n)
Definition multi_vector.h:831
iterator & operator-=(difference_type n)
Definition multi_vector.h:836
iterator operator++(int)
Definition multi_vector.h:814
bool operator>=(const iterator &other) const
Definition multi_vector.h:862
std::random_access_iterator_tag iterator_category
Definition multi_vector.h:787
bool operator<(const iterator &other) const
Definition multi_vector.h:856
const_value_ref_t const_value_type
Definition multi_vector.h:784
iterator & operator--(int)
Definition multi_vector.h:821
bool operator>(const iterator &other) const
Definition multi_vector.h:860
std::conditional_t< is_const, const multi_vector *, multi_vector * > vec_ptr_t
Definition multi_vector.h:780
value_type operator[](difference_type n)
Definition multi_vector.h:847
iterator operator+(difference_type n) const
Definition multi_vector.h:841
iterator operator-(difference_type n) const
Definition multi_vector.h:843
value_type reference
Definition multi_vector.h:785
iterator & operator=(const iterator &)=default
iterator(const iterator &)=default
std::size_t m_index
Definition multi_vector.h:866
iterator(vec_ptr_t vec, std::size_t index)
Definition multi_vector.h:868
iterator & operator=(iterator &&)=default
void push_back(const T &value)
Definition multi_vector.h:122
void clear()
Definition multi_vector.h:114
T * begin()
Definition multi_vector.h:205
std::size_t size() const
Definition multi_vector.h:203
void realloc_with_value(std::size_t capacity, const T &value={})
Definition multi_vector.h:247
single_vector & operator=(single_vector &&other)
Definition multi_vector.h:75
T * data()
Definition multi_vector.h:199
const T * begin() const
Definition multi_vector.h:207
T * erase(const T *element)
Definition multi_vector.h:145
T & at(std::size_t i)
Definition multi_vector.h:195
T * m_data
Definition multi_vector.h:214
void realloc_without(std::size_t capacity, std::size_t index)
Definition multi_vector.h:252
T * end()
Definition multi_vector.h:209
single_vector(std::size_t n)
Definition multi_vector.h:36
const T & at(std::size_t i) const
Definition multi_vector.h:197
void swap(single_vector &other)
Definition multi_vector.h:116
void realloc(std::size_t capacity)
Definition multi_vector.h:233
void resize(std::size_t n)
Definition multi_vector.h:171
single_vector & operator=(const single_vector &other)
Definition multi_vector.h:92
void pop_back()
Definition multi_vector.h:166
~single_vector()
Definition multi_vector.h:59
void reserve(std::size_t n)
Definition multi_vector.h:187
std::size_t m_capacity
Definition multi_vector.h:215
std::size_t next_capacity() const
Definition multi_vector.h:218
void try_update_capacity()
Definition multi_vector.h:226
void push_back(T &&value)
Definition multi_vector.h:129
void resize(std::size_t n, const T &value)
Definition multi_vector.h:173
std::size_t m_size
Definition multi_vector.h:216
const T * end() const
Definition multi_vector.h:211
const T * data() const
Definition multi_vector.h:201
single_vector(single_vector &&other)
Definition multi_vector.h:66
T & emplace_back(Arg &&arg)
Definition multi_vector.h:136
single_vector(const single_vector &other)
Definition multi_vector.h:52
single_vector(std::size_t n, const T &value)
Definition multi_vector.h:43
Class representing a multi_vector.
Definition multi_vector.h:32
transform_types_t< to_containers_t< types, single_vector_container >, transforms::tuple > storage_t
Definition multi_vector.h:287
transform_types_t< transform_types_t< types, transforms::reference >, transforms::tuple > value_ref_t
Definition multi_vector.h:301
transform_types_t< transform_types_t< types, transforms::constant_reference >, transforms::tuple > const_value_ref_t
Definition multi_vector.h:302
transform_types_t< types, transforms::tuple > value_t
Definition multi_vector.h:304
type::types_to_containers_t< T, Container > to_containers_t
Definition multi_vector.h:279
types used_types
Definition multi_vector.h:299
multi_vector(multi_vector &&)=default
type::types_transform_t< T, Transform > transform_types_t
Definition multi_vector.h:282
type::types_remove_t< all_types, void > types
Definition multi_vector.h:285
multi_vector(const multi_vector &)=default
Concept to check if a type is a valid multi_vector element.
Definition multi_vector.h:23
Definition comptime_map.h:11
detail::types_get_impl< Types, I >::type types_get_t
Alias for getting a type by index in a types list.
Definition types.h:381
detail::types_to_containers< Types, Container >::type types_to_containers_t
Alias for transforming a types list to a containers list.
Definition types.h:413
detail::types_remove< Types, T >::type types_remove_t
Definition types.h:438
detail::types_transform_impl< Types, Transform >::type types_transform_t
Alias for transforming a types list using a transform template.
Definition types.h:404
detail::types_view< N, Types >::type types_view_t
Definition types.h:440
A namespace containing container templates for types lists.
Definition types.h:132
A template structure to count occurrences of a specific type in a types list.
Definition types.h:146
Provides a std::tuple transform.
Definition types.h:82
A namespace containing transform templates for types lists.
Definition types.h:78
A structure representing a variadic list of types.
Definition types.h:20