IceShard 1
A personal game engine project, with development focused on 2D/2.5D games.
Loading...
Searching...
No Matches
array.hxx
Go to the documentation of this file.
1
3
4#pragma once
9#include <ice/span.hxx>
10
11namespace ice
12{
13
20 template<typename Type, ice::ContainerLogic Logic = ice::Constant_DefaultContainerLogic<Type>>
21 struct Array
24 {
25 static_assert(
27 "Collection element type is not allowed with 'Trivial' logic!"
28 );
29
30 using ValueType = Type;
31 using ConstContainerValueType = Type const;
32 using Iterator = Type*;
33 using ReverseIterator = std::reverse_iterator<Type*>;
34 using ConstIterator = Type const*;
35 using ConstReverseIterator = std::reverse_iterator<Type const*>;
38
43
44 inline explicit Array(ice::Allocator& alloc) noexcept;
45 inline ~Array() noexcept;
46
47 inline Array(Array&& other) noexcept;
48 inline Array(Array const& other) noexcept
49 requires std::copy_constructible<Type>;
50
51 inline Array(
53 ice::Span<Type const> values
54 ) noexcept requires std::copy_constructible<Type>;
55
56 inline auto operator=(Array&& other) noexcept -> Array&;
57 inline auto operator=(Array const& other) noexcept -> Array&
58 requires std::copy_constructible<Type>;
59
60 // API Requirements Of: Container
61 constexpr auto size() const noexcept -> SizeType { return { _count, sizeof(ValueType) }; }
62
63 // API Requirements Of: Resizable Container
64 template<typename Self>
65 constexpr auto data(this Self& self) noexcept -> ice::container::ValuePtr<Self> { return self._data; }
66 constexpr auto capacity() const noexcept -> SizeType { return { _capacity, sizeof(ValueType) }; }
67 constexpr void set_capacity(SizeType new_capacity) noexcept;
68 constexpr void resize(SizeType new_size) noexcept;
69 constexpr void clear() noexcept;
70
71 // API Manipulation
72 template<typename ItemType = Type>
73 requires std::convertible_to<ItemType, Type> && std::is_constructible_v<Type, ItemType>
74 inline void push_back(ItemType&& item) noexcept;
75
76 template<ice::concepts::IterableContainer ContainerT>
77 requires (ice::concepts::CompatibleContainer<Type, ContainerT>)
78 inline void push_back(ContainerT const& other) noexcept;
79
80 inline void pop_back(ice::ncount count = 1_count) noexcept;
81
82 inline void remove_at(ice::nindex index) noexcept;
83
84 // API Requirements Of: Data and Memory
85 constexpr auto data_view(this Array const& self) noexcept -> ice::Data;
86 constexpr auto memory_view(this Array& self) noexcept -> ice::Memory;
87
88 // Operators and implicit conversions
89 inline operator ice::Span<Type>() noexcept;
90 inline operator ice::Span<Type const>() const noexcept;
91 };
92
93 template<typename Type, ice::ContainerLogic Logic>
94 auto data_view(ice::Array<Type, Logic> const& arr) noexcept -> ice::Data = delete;
95
96 template<typename Type, ice::ContainerLogic Logic>
97 inline Array<Type, Logic>::Array(ice::Allocator& alloc) noexcept
98 : _allocator{ &alloc }
99 , _capacity{ 0 }
100 , _count{ 0 }
101 , _data{ nullptr }
102 { }
103
104 template<typename Type, ice::ContainerLogic Logic>
106 {
107 if constexpr (Logic == ContainerLogic::Complex)
108 {
110 }
111
112 _allocator->deallocate(memory_view());
113 }
114
115 template<typename Type, ice::ContainerLogic Logic>
116 inline Array<Type, Logic>::Array(Array&& other) noexcept
117 : _allocator{ other._allocator }
118 , _capacity{ ice::exchange(other._capacity, 0) }
119 , _count{ ice::exchange(other._count, 0) }
120 , _data{ ice::exchange(other._data, nullptr) }
121 { }
122
123 template<typename Type, ice::ContainerLogic Logic>
124 inline Array<Type, Logic>::Array(Array const& other) noexcept
125 requires std::copy_constructible<Type>
126 : _allocator{ other._allocator }
127 , _capacity{ 0 }
128 , _count{ 0 }
129 , _data{ nullptr }
130 {
131 if (other._count > 0)
132 {
133 set_capacity(other.size());
134
135 if constexpr (Logic == ContainerLogic::Complex)
136 {
138 memory_view(),
139 other.data(),
140 other.size()
141 );
142 }
143 else
144 {
146 memory_view(),
147 other.data_view()
148 );
149 }
150
151 _count = other._count;
152 }
153 }
154
155 template<typename Type, ice::ContainerLogic Logic>
159 ) noexcept requires std::copy_constructible<Type>
160 : _allocator{ &alloc }
161 , _capacity{ 0 }
162 , _count{ 0 }
163 , _data{ nullptr }
164 {
165 if (values.not_empty())
166 {
167 set_capacity(values.size());
168
169 if constexpr (Logic == ContainerLogic::Complex)
170 {
172 memory_view(),
173 values.data(),
174 values.size()
175 );
176 }
177 else
178 {
179 ice::memcpy(memory_view(), values.data_view());
180 }
181
182 _count = values.size().u32();
183 }
184 }
185
186 template<typename Type, ice::ContainerLogic Logic>
187 inline auto Array<Type, Logic>::operator=(Array&& other) noexcept -> Array&
188 {
189 if (this != &other)
190 {
191 set_capacity(0);
192
193 _allocator = other._allocator;
194 _capacity = ice::exchange(other._capacity, 0);
195 _data = ice::exchange(other._data, nullptr);
196 _count = ice::exchange(other._count, 0);
197 }
198 return *this;
199 }
200
201 template<typename Type, ice::ContainerLogic Logic>
202 inline auto Array<Type, Logic>::operator=(Array const& other) noexcept -> Array&
203 requires std::copy_constructible<Type>
204 {
205 if (this != &other)
206 {
207 this->clear();
208 this->reserve(other.capacity());
209
210 if (other.size() > 0)
211 {
212 if constexpr (Logic == ContainerLogic::Complex)
213 {
215 memory_view(),
216 other.data(),
217 other.size()
218 );
219 }
220 else
221 {
223 memory_view(),
224 other.data_view()
225 );
226 }
227 }
228
229 _count = other._count;
230 }
231 return *this;
232 }
233
234 template<typename Type, ice::ContainerLogic Logic>
235 inline constexpr void ice::Array<Type, Logic>::set_capacity(SizeType new_capacity) noexcept
236 {
237 if (new_capacity == _capacity)
238 {
239 return;
240 }
241
242 if (new_capacity < _count)
243 {
244 if constexpr (Logic == ContainerLogic::Complex)
245 {
246 ice::mem_destruct_n_at(_data + new_capacity, _count - new_capacity);
247 }
248
249 _count = new_capacity.u32();
250 }
251
252 ValueType* new_data = nullptr;
253 if (new_capacity > 0)
254 {
255 ice::AllocResult new_buffer = _allocator->allocate(ice::meminfo_of<ValueType> * new_capacity);
256 ICE_ASSERT_CORE(new_buffer.memory != nullptr);
257 if (_count > 0)
258 {
259 if constexpr (Logic == ContainerLogic::Complex)
260 {
263 }
264 else
265 {
266 ice::memcpy(new_buffer, data_view());
267 }
268 }
269 new_data = reinterpret_cast<ValueType*>(new_buffer.memory);
270 }
271
272 _allocator->deallocate(memory_view());
273 _data = new_data;
274 _capacity = new_capacity.u32();
275 }
276
277 template<typename Type, ice::ContainerLogic Logic>
278 inline constexpr void ice::Array<Type, Logic>::resize(SizeType new_size) noexcept
279 {
280 if (_capacity < new_size)
281 {
282 set_capacity(new_size);
283 }
284
285 if (new_size > _count)
286 {
287 SizeType const missing_items = new_size - _count;
288 ice::Memory const uninitialized_memory = ice::ptr_add(memory_view(), size());
289
291 uninitialized_memory,
292 missing_items
293 );
294 }
295 else if constexpr (Logic == ContainerLogic::Complex)
296 {
297 static_assert(Logic != ContainerLogic::Trivial);
298 ice::ncount const destroyed_items = _count - new_size;
299
301 _data + new_size,
302 destroyed_items
303 );
304 }
305
306 _count = new_size.u32();
307 }
308
309 template<typename Type, ice::ContainerLogic Logic>
310 inline constexpr void ice::Array<Type, Logic>::clear() noexcept
311 {
312 if constexpr (Logic == ContainerLogic::Complex)
313 {
315 }
316 _count = 0;
317 }
318
319 template<typename Type, ice::ContainerLogic Logic>
320 template<typename ItemType>
321 requires std::convertible_to<ItemType, Type> && std::is_constructible_v<Type, ItemType>
322 inline void Array<Type, Logic>::push_back(ItemType&& item) noexcept
323 {
324 if (size() == capacity())
325 {
326 this->grow();
327 }
328
329 if constexpr (Logic == ContainerLogic::Complex)
330 {
331 ice::mem_construct_at<Type>(this->end(), ice::forward<ItemType>(item));
332 }
333 else
334 {
335 _data[_count] = Type{ ice::forward<ItemType>(item) };
336 }
337
338 _count += 1;
339 }
340
341 template<typename Type, ice::ContainerLogic Logic>
342 template<ice::concepts::IterableContainer ContainerT>
344 inline void ice::Array<Type, Logic>::push_back(ContainerT const& other) noexcept
345 {
346 ice::ncount const current_size = size();
347 ice::ncount const required_capacity = other.size() + current_size;
348 if (required_capacity > _capacity)
349 {
350 this->grow(required_capacity);
351 }
352
353 ice::Memory target_memory = ice::ptr_add(memory_view(), current_size);
355 {
356 ice::memcpy(target_memory, other.data_view());
357 }
358 else
359 {
361 target_memory, other.begin(), other.end()
362 );
363 }
364
365 _count = required_capacity.u32();
366 }
367
368 template<typename Type, ice::ContainerLogic Logic>
370 {
371 ice::ncount const current_count = size();
372 ice::ncount const final_count = current_count - ice::min(count, current_count);
373 if constexpr (Logic == ContainerLogic::Complex)
374 {
375 ice::mem_destruct_n_at(data() + final_count, current_count - final_count);
376 }
377
378 _count = final_count.u32();
379 }
380
381 template <typename Type, ice::ContainerLogic Logic>
382 inline void Array<Type, Logic>::remove_at(ice::nindex index) noexcept
383 {
384 if (_count > 1 && index.is_valid())
385 {
386 _data[index.native()] = ice::move(_data[_count - 1]);
387 }
388 this->pop_back();
389 }
390
391 template<typename Type, ice::ContainerLogic Logic>
392 inline constexpr auto Array<Type, Logic>::data_view(this Array const& self) noexcept -> ice::Data
393 {
394 return ice::Data{
395 .location = self.data(),
396 .size = self.size(),
397 .alignment = ice::align_of<ValueType>
398 };
399 }
400
401 template<typename Type, ice::ContainerLogic Logic>
402 inline constexpr auto Array<Type, Logic>::memory_view(this Array& self) noexcept -> ice::Memory
403 {
404 return ice::Memory{
405 .location = self.data(),
406 .size = self.capacity(),
407 .alignment = ice::align_of<ValueType>
408 };
409 }
410
411 template<typename Type, ice::ContainerLogic Logic>
413 {
414 return Span{ _data, _count };
415 }
416
417 template<typename Type, ice::ContainerLogic Logic>
419 {
420 return Span{ _data, _count };
421 }
422
423
424} // namespace ice
#define ICE_ASSERT_CORE(expression)
Definition assert_core.hxx:43
A concept that ensures only types that can be trivially copyable can be 'forced' to use trifial Logic...
Definition container_logic.hxx:25
Definition container_concepts.hxx:175
Definition container_concepts.hxx:59
Definition container_concepts.hxx:12
ValueType< ContainerT > * ValuePtr
Definition container_concepts.hxx:155
constexpr auto min(arr_t< Size, T > left, arr_t< Size, U > right) noexcept -> arr_t< Size, T >
Definition array_operations.hxx:60
arr_t< Size, T > arr
Definition array.hxx:178
SPDX-License-Identifier: MIT.
Definition array.hxx:12
auto mem_move_construct_n_at(ice::Memory memory, T *objects, ice::u64 count) noexcept -> T *
Definition mem_initializers.hxx:58
ContainerLogic
The logic implemented by a collectiont type when working with data. (Copying, Moving,...
Definition container_logic.hxx:13
@ Complex
The collection handles complex data types and properly implements copy and move semantics.
Definition container_logic.hxx:19
@ Trivial
The collection only handles plain old data and is allowed to memcopy values.
Definition container_logic.hxx:16
void mem_destruct_n_at(T *location, ice::u64 count) noexcept
Definition mem_initializers.hxx:113
auto data_view(ice::Array< Type, Logic > const &arr) noexcept -> ice::Data=delete
auto alloc(ice::usize size) noexcept -> ice::AllocResult
constexpr ice::ualign align_of
Definition mem_info.hxx:15
auto mem_copy_construct_it_at(ice::Memory memory, ItT begin, ItT end) noexcept -> T *
Definition mem_initializers.hxx:92
auto mem_default_construct_n_at(ice::Memory memory, ice::u64 count) noexcept -> T *
Definition mem_initializers.hxx:46
auto ptr_add(void *pointer, ice::usize offset) noexcept -> void *
Definition mem_arithmetic.hxx:34
auto mem_copy_construct_n_at(ice::Memory memory, T const *objects, ice::u64 count) noexcept -> T *
Definition mem_initializers.hxx:80
constexpr auto count(T const (&)[Size]) noexcept -> ice::u32
Definition base.hxx:43
std::uint32_t u32
Definition types.hxx:26
constexpr ice::meminfo meminfo_of
Definition mem_info.hxx:18
ice::AllocatorBase< ice::build::is_debug||ice::build::is_develop > Allocator
Definition mem_types.hxx:25
auto mem_construct_at(void *memory_ptr, Args &&... args) noexcept -> T *
Definition mem_initializers.hxx:12
auto memcpy(void *dest, void const *source, ice::usize size) noexcept -> void *
Definition mem.hxx:44
void * memory
Definition mem.hxx:45
A simple container storing items in continuous memory.
Definition array.hxx:24
ice::u32 _capacity
Definition array.hxx:40
constexpr void set_capacity(SizeType new_capacity) noexcept
Definition array.hxx:235
constexpr auto data_view(this Array const &self) noexcept -> ice::Data
Definition array.hxx:392
ice::u32 _count
Definition array.hxx:41
Type ValueType
Definition array.hxx:30
constexpr void resize(SizeType new_size) noexcept
Definition array.hxx:278
auto operator=(Array &&other) noexcept -> Array &
Definition array.hxx:187
void push_back(ItemType &&item) noexcept
Definition array.hxx:322
ValueType * _data
Definition array.hxx:42
Type const ConstContainerValueType
Definition array.hxx:31
constexpr auto data(this Self &self) noexcept -> ice::container::ValuePtr< Self >
Definition array.hxx:65
constexpr auto memory_view(this Array &self) noexcept -> ice::Memory
Definition array.hxx:402
constexpr auto capacity() const noexcept -> SizeType
Definition array.hxx:66
ice::ncount SizeType
Definition array.hxx:36
constexpr void clear() noexcept
Definition array.hxx:310
Type const * ConstIterator
Definition array.hxx:34
ice::concepts::ContiguousContainerTag ContainerTag
Definition array.hxx:37
ice::Allocator * _allocator
Definition array.hxx:39
Type * Iterator
Definition array.hxx:32
void pop_back(ice::ncount count=1_count) noexcept
Definition array.hxx:369
~Array() noexcept
Definition array.hxx:105
void remove_at(ice::nindex index) noexcept
Definition array.hxx:382
std::reverse_iterator< Type const * > ConstReverseIterator
Definition array.hxx:35
Array(ice::Allocator &alloc) noexcept
Definition array.hxx:97
std::reverse_iterator< Type * > ReverseIterator
Definition array.hxx:33
constexpr auto size() const noexcept -> SizeType
Definition array.hxx:61
Definition mem_data.hxx:17
Definition mem_memory.hxx:13
A view into an array of objects laid out in contiguous memory.
Definition span.hxx:17
Definition container_concepts.hxx:56
Definition contiguous_container.hxx:14
constexpr auto end(this Self &&self) noexcept -> ice::container::Iterator< Self >
Definition contiguous_container.hxx:81
Definition resizable_container.hxx:11
constexpr void reserve(this Self &self, ice::ncount min_capacity) noexcept
Definition resizable_container.hxx:25
constexpr void grow(this Self &self, ice::ncount min_capacity=ice::ncount_none) noexcept
Definition resizable_container.hxx:34
Definition ncount.hxx:14
Definition nindex.hxx:13
constexpr auto u32() const noexcept
Definition nvalue.hxx:113