33#include <NDEVR/BaseValues.h>
34#include <NDEVR/LibAssert.h>
38 #pragma clang diagnostic push
39 #pragma clang diagnostic ignored "-Wdynamic-class-memaccess"
42 #define NDEVR_HAS_ALIGNED_ALLOC 1
53 inline void* ndevr_aligned_realloc(
void* old_ptr,
59 return _aligned_realloc(old_ptr, new_size, alignment);
67 inline auto ndevr_aligned_malloc(
71 return _aligned_malloc(new_size, alignment);
77 inline auto ndevr_aligned_free(
void* ptr)
79 return _aligned_free(ptr);
82 #define NDEVR_HAS_ALIGNED_ALLOC 0
83#elif defined(__GNUC__) || defined(__clang__)
84 #define NDEVR_HAS_ALIGNED_ALLOC 1
87 #define ndevr_aligned_free ::free
94 inline void* ndevr_aligned_malloc(
99 size_t fixed_size = (new_size + alignment - 1) / alignment * alignment;
100 return ::aligned_alloc(alignment, fixed_size);
110 inline void* ndevr_aligned_realloc(
void* old_ptr,
116 size_t fixed_new_size = (new_size + alignment - 1) / alignment * alignment;
118 void* new_ptr = ::aligned_alloc(alignment, fixed_new_size);
121 memcpy(new_ptr, old_ptr,
getMin(old_size, new_size));
128 #define NDEVR_HAS_ALIGNED_ALLOC 0
132#if NDEVR_HAS_ALIGNED_ALLOC
133#if defined(__cpp_lib_assume_aligned) && __cpp_lib_assume_aligned
134 #define NDEVR_ASSUME_ALIGNED(ALIGN, PTR) \
135 (__builtin_assume_aligned(PTR, ALIGN))
136 #elif defined(_MSC_VER)
137 #define NDEVR_ASSUME_ALIGNED(ALIGN, PTR) \
138 ((__assume((reinterpret_cast<std::uintptr_t>(PTR) & ((ALIGN) - 1)) == 0), (PTR)))
139 #elif defined(__GNUC__) || defined(__clang__)
140 #define NDEVR_ASSUME_ALIGNED(ALIGN, PTR) \
141 (__builtin_assume_aligned(PTR, ALIGN))
143 #define NDEVR_ASSUME_ALIGNED(ALIGN, PTR) \
147 #define NDEVR_ASSUME_ALIGNED(ALIGN, PTR) \
154 template<
size_t t_size>
157 #if NDEVR_HAS_ALIGNED_ALLOC
158 if constexpr (t_size >= 64)
160 else if constexpr (t_size >= 32)
162 else if constexpr (t_size >= 16)
164 else if constexpr (t_size >= 8)
173 template<
class t_type>
180 static constexpr size_t Size() noexcept
189 template<
class t_index_type,
bool is_primitive>
195 template<
class t_index_type>
205 template<
class t_buffer_type,
class t_type>
206 static void Allocate(t_buffer_type&, t_index_type, t_index_type)
noexcept
214 template<
class t_buffer_type,
class t_type>
215 static constexpr void Deallocate(t_buffer_type&, t_index_type, t_index_type)
noexcept
224 template<
class t_buffer_type,
class t_type>
225 static void AllocateElement(t_buffer_type& buff, t_index_type start, t_index_type size,
const t_type&
object)
noexcept
227 buff.setAll(
object, start, size);
235 template<
class t_buffer_type,
class t_type>
236 static void AllocateElement(t_buffer_type& buff, t_index_type index,
const t_type&
object)
noexcept
238 buff.get(index) = object;
246 template<
class t_buffer_type,
class t_type>
247 static void AllocateElement(t_buffer_type& buff, t_index_type index, t_type&&
object)
noexcept
249 buff.get(index) = std::forward<t_type>(
object);
257 template<
class t_index_type>
267 template<
class t_buffer_type,
class t_type>
268 static constexpr void Allocate(t_buffer_type& buff, t_index_type start, t_index_type size)
noexcept
270 if constexpr (!std::is_trivially_default_constructible_v<t_type>)
272 for (t_index_type i = 0; i < size; i++)
273 new (&buff.get(i + start)) t_type();
282 template<
class t_buffer_type,
class t_type>
283 static constexpr void Deallocate(t_buffer_type& buff, t_index_type start, t_index_type size)
noexcept
285 if constexpr (!std::is_trivially_destructible<t_type>::value)
287 t_index_type end = start + size;
288 for (t_index_type i = start; i < end; i++)
289 (&buff.get(i))->~t_type();
299 template<
class t_buffer_type,
class t_type>
300 static constexpr void AllocateElement(t_buffer_type& buff, t_index_type start, t_index_type size,
const t_type&
object)
noexcept
302 t_index_type end = start + size;
303 for (t_index_type i = start; i < end; i++)
304 new (&buff.get(i)) t_type(
object);
312 template<
class t_buffer_type,
class t_type>
313 static constexpr void AllocateElement(t_buffer_type& buff, t_index_type index,
const t_type&
object)
noexcept
315 new (&buff.get(index)) t_type(
object);
323 template<
class t_buffer_type,
class t_type>
324 static constexpr void AllocateElement(t_buffer_type& buff, t_index_type index, t_type&&
object)
noexcept
326 new (&buff.get(index)) t_type(std::move(
object));
333 template<
class t_type,
bool t_is_primitive,
class t_index_type>
343 template<
class t_buffer_type>
344 static constexpr void Allocate(t_buffer_type& buffer, t_index_type start, t_index_type size)
noexcept
354 template<
class t_buffer_type>
355 static constexpr void Deallocate(t_buffer_type& buffer, t_index_type start, t_index_type size)
noexcept
366 template<
class t_buffer_type>
367 static constexpr void AllocateElement(t_buffer_type& buffer, t_index_type start, t_index_type size,
const t_type&
object)
noexcept
378 template<
class t_buffer_type>
379 static constexpr void AllocateElement(t_buffer_type& buffer, t_index_type start, t_index_type size, t_type&
object)
noexcept
389 template<
class t_buffer_type>
390 static constexpr void AllocateElement(t_buffer_type& buffer, t_index_type index,
const t_type&
object)
noexcept
400 template<
class t_buffer_type>
401 static constexpr void AllocateElement(t_buffer_type& buffer, t_index_type index, t_type&&
object)
noexcept
411 return t_is_primitive;
415 #if defined(_MSC_VER) && !defined(__clang__)
416 #define NDEVR_HAS_UMUL128 1
418 #define NDEVR_HAS_UMUL128 0
420 #if defined(__EMSCRIPTEN__)
421 #define NDEVR_ALIGN_TINY 64ULL
422 #define NDEVR_ALIGN_MED 65536ULL
423 #define NDEVR_ALIGN_LARGE 1048576ULL
424 #elif defined(_WIN32)
425 #define NDEVR_ALIGN_TINY 64ULL
426 #define NDEVR_ALIGN_MED 4096ULL
427 #define NDEVR_ALIGN_LARGE 65536ull
428 #define NDEVR_ALIGN_HUGE 2097152ull
429 #elif defined(__ANDROID__)
430 #define NDEVR_ALIGN_TINY 64ULL
431 #define NDEVR_ALIGN_MED 4096ULL
432 #define NDEVR_ALIGN_LARGE 1048576ULL
434 #define NDEVR_ALIGN_TINY 64ULL
435 #define NDEVR_ALIGN_MED 4096ULL
436 #define NDEVR_ALIGN_LARGE 1048576ULL
438#if __cpp_lib_bitops <= 201907L
443 template<
size_t t_value>
444 struct ShiftCount {
static constexpr int value = ((t_value & 1) != 0) ? 0 : (1 +
ShiftCount<(t_value >> 1)>::value); };
446 template<>
struct ShiftCount<0> {
static constexpr int value = 0; };
455 #if NDEVR_HAS_UMUL128
458 static constexpr unsigned __int128
high_bit = (
unsigned __int128)1 << 64;
470 template<
class t_index_type,
size_t t_elem_size>
471 static inline t_index_type
NextCapacityBytes(t_index_type cap_elems, t_index_type need_elems)
noexcept
473 constexpr size_t min_step = size_t(8) * t_elem_size;
475 size_t old_b = size_t(cap_elems) * t_elem_size;
476 size_t need_b = size_t(need_elems) * t_elem_size;
478 size_t base = (old_b < size_t(256)) ? (old_b << 1) : (old_b + (old_b >> 1));
479 size_t grow_b = (base > old_b + min_step) ? base : (old_b + min_step);
484 #ifdef NDEVR_ALIGN_HUGE
485 if (grow_b >= NDEVR_ALIGN_HUGE || t_elem_size >= NDEVR_ALIGN_HUGE)
486 align_b = NDEVR_ALIGN_HUGE;
489 if (grow_b >= NDEVR_ALIGN_LARGE || t_elem_size >= NDEVR_ALIGN_LARGE)
490 align_b = NDEVR_ALIGN_LARGE;
491 else if (grow_b >= NDEVR_ALIGN_MED || t_elem_size >= NDEVR_ALIGN_MED)
492 align_b = NDEVR_ALIGN_MED;
494 align_b = NDEVR_ALIGN_TINY;
495 if constexpr ((t_elem_size & (t_elem_size - size_t(1))) == 0)
497 #if __cpp_lib_bitops > 201907L
498 constexpr int shift = std::countr_zero((
size_t)t_elem_size);
500 constexpr int shift = ShiftCount<t_elem_size>::value;
502 size_t rounded = (grow_b + (align_b - size_t(1))) & ~(align_b -
size_t(1));
503 size_t elems = rounded >> shift;
508 size_t rounded = (grow_b + (align_b - size_t(1))) & ~(align_b -
size_t(1));
509 #if NDEVR_HAS_UMUL128
515 size_t elems = size_t(prod >> 64);
526 template<
class t_type,
size_t t_aligned_size,
bool t_is_primitive,
class t_index_type = u
int04,
bool t_null_term = false,
bool t_allow_reference = false>
537 [[nodiscard]]
static constexpr bool IsNullTerm() noexcept {
return t_null_term; }
567 #if NDEVR_HAS_ALIGNED_ALLOC
568 if constexpr (t_aligned_size > 0)
569 ndevr_aligned_free(
ptr());
579 template<
bool t_managed>
592 template<
bool t_managed>
593 constexpr void createSpace(t_index_type location, t_index_type size)
noexcept
627 [[nodiscard]]
constexpr t_index_type
count(
const t_type& value)
const noexcept
629 t_index_type
count = 0;
632 if (
ptr()[i] == value)
644 template<
class t_comparable_type>
645 [[nodiscard]]
constexpr bool contains(
const t_comparable_type& value, t_index_type start, t_index_type size)
const noexcept
647 for (t_index_type i = start; i < start + size; ++i)
649 if (
ptr()[i] == value)
665 constexpr void addIndex(t_index_type location)
noexcept
669 memmove(
ptr() + location + 1,
ptr() + location,
sizeof(t_type) * (
m_filled_size - location - 1));
679 lib_assert(location <=
m_filled_size,
"Out of bounds remove");
680 memmove(
ptr() + location,
ptr() + location + 1, (
m_filled_size - location - 1) *
sizeof(t_type));
709 void swap(t_index_type index_a, t_index_type index_b)
noexcept
711 std::swap(
ptr()[index_a],
ptr()[index_b]);
736 [[nodiscard]] t_type&
get(t_index_type index)
noexcept
745 [[nodiscard]]
const t_type&
get(t_index_type index)
const noexcept
754 [[nodiscard]]
constexpr decltype(
auto)
ptr()
noexcept
756 if constexpr (t_aligned_size > 0)
757 return (t_type*)NDEVR_ASSUME_ALIGNED(t_aligned_size,
m_buffer);
766 [[nodiscard]]
constexpr decltype(
auto)
ptr()
const noexcept
768 if constexpr (t_aligned_size > 0)
769 return (
const t_type*)NDEVR_ASSUME_ALIGNED(t_aligned_size,
m_buffer);
778 [[nodiscard]]
constexpr decltype(
auto)
begin()
noexcept
787 [[nodiscard]]
constexpr decltype(
auto)
begin()
const noexcept
797 [[nodiscard]]
constexpr decltype(
auto)
begin(t_index_type index)
const noexcept
799 return &(
ptr()[index]);
806 [[nodiscard]]
constexpr decltype(
auto)
begin(t_index_type index)
noexcept
808 return &(
ptr()[index]);
815 [[nodiscard]]
constexpr decltype(
auto)
end()
noexcept
823 [[nodiscard]]
constexpr decltype(
auto)
end()
const noexcept
832 [[nodiscard]]
constexpr decltype(
auto)
end(t_index_type index)
noexcept
840 [[nodiscard]]
constexpr t_index_type
capacity() const noexcept
848 [[nodiscard]]
constexpr t_index_type
filledSize() const noexcept
864 [[nodiscard]]
constexpr size_t memSize() const noexcept
879 #if NDEVR_HAS_ALIGNED_ALLOC
880 if constexpr(t_aligned_size > 0)
881 ndevr_aligned_free(
ptr());
892 if constexpr (t_allow_reference)
896 auto referenced_data =
ptr();
897 #if NDEVR_HAS_ALIGNED_ALLOC
898 if constexpr (t_aligned_size > 0)
899 m_buffer = (t_type*)ndevr_aligned_malloc(
sizeof(t_type) * (t_null_term ? new_size + 1 : new_size), t_aligned_size);
902 m_buffer = (t_type*)malloc(
sizeof(t_type) * (t_null_term ? new_size + 1 : new_size));
907 #if NDEVR_HAS_ALIGNED_ALLOC
908 if constexpr (t_aligned_size > 0)
909 m_buffer = (t_type*)ndevr_aligned_malloc(
sizeof(t_type) * (t_null_term ? new_size + 1 : new_size), t_aligned_size);
912 m_buffer = (t_type*)malloc(
sizeof(t_type) * (t_null_term ? new_size + 1 : new_size));
917 #if NDEVR_HAS_ALIGNED_ALLOC
918 if constexpr (t_aligned_size > 0)
919 m_buffer = (t_type*)ndevr_aligned_malloc(
sizeof(t_type) * (t_null_term ? new_size + 1 : new_size), t_aligned_size);
922 m_buffer = (t_type*)malloc(
sizeof(t_type) * (t_null_term ? new_size + 1 : new_size));
927 #if NDEVR_HAS_ALIGNED_ALLOC
928 if constexpr (t_aligned_size > 0)
930 ,
sizeof(t_type) * (t_null_term ? new_size + 1 : new_size)
934 m_buffer = (t_type*)realloc(
ptr(),
sizeof(t_type) * (t_null_term ? new_size + 1 : new_size));
936 if (
ptr() ==
nullptr)
939 lib_assert(
false,
"Unable to allocate buffer: Perhaps out of system memory!");
950 void setAll(
const t_type&
object, t_index_type offset, t_index_type size)
noexcept
952 for (t_index_type i = offset; i < offset + size; i++)
962 template<
bool is_primitive>
963 void setAll(
const t_type* src, t_index_type offset, t_index_type size)
noexcept
965 if constexpr (is_primitive)
967 memmove(&
ptr()[offset], src, size *
sizeof(t_type));
971 for (t_index_type i = 0; i < size; i++)
973 ptr()[i + offset] = src[i];
984 template<
bool t_is_other_primitive,
class t_other_index_type,
bool t_other_null_term>
987 if constexpr (t_is_other_primitive)
989 memmove(&
ptr()[offset], &(
allocator.ptr()[other_offset]), size *
sizeof(t_type));
993 for (t_index_type i = 0; i < size; i++)
1004 template<
class t_other_allocator>
1007 for (t_index_type i = 0; i < size; i++)
1019 lib_assert(nc >= size,
"Bad allocation prediciton");
1020 lib_assert(nc < Constant<uint04>::Max,
"Bad allocation prediciton");
1041 template<
bool t_auto_set_capacity>
1044 if constexpr (t_auto_set_capacity)
1086 template<
class t_range_buffer>
1089 t_index_type offset = 0;
1090 for (t_index_type i = 0; i < ranges.size(); i++)
1092 auto range = ranges[i];
1093 t_index_type start = range.first;
1094 t_index_type
end = range.second;
1095 t_index_type next = i == ranges.size() - 1 ?
m_filled_size : ranges[i + 1].start;
1096 memmove(&
ptr()[start], &
ptr()[
end], (next - (
end + offset)) *
sizeof(t_type));
1097 offset += (
end - start);
1105 template<
bool t_is_null>
1108 if constexpr (t_is_null)
1119 template<
bool t_is_null>
1122 if constexpr(t_is_null)
1124 #if NDEVR_HAS_ALIGNED_ALLOC
1125 if constexpr (t_aligned_size > 0)
1127 alignas(t_aligned_size)
static constexpr t_type null_object = {};
1128 return const_cast<t_type*
>(&null_object);
1133 static constexpr t_type null_object = {};
1134 return const_cast<t_type*
>(&null_object);
1150 std::swap(value.m_buffer,
m_buffer);
1163 #pragma clang diagnostic pop
constexpr BufferAllocator() noexcept
Default constructor.
void nullTerminatorCheck() noexcept
Writes a null terminator after the last filled element if null termination is enabled.
constexpr decltype(auto) ptr() noexcept
Returns a pointer to the underlying buffer, with optional alignment hint.
constexpr decltype(auto) begin() const noexcept
Returns a const pointer to the beginning of the buffer.
constexpr decltype(auto) end() const noexcept
Returns a const pointer to one past the last filled element.
void setAllFromSource(const t_other_allocator &allocator, t_index_type offset, t_index_type other_offset, t_index_type size) noexcept
Copies elements from a generic source allocator into this buffer using element-wise assignment.
static constexpr bool IsNullTerm() noexcept
Checks whether this allocator uses null termination.
constexpr t_index_type count(const t_type &value) const noexcept
Counts the number of occurrences of a value in the buffer.
void resizeSpace(t_index_type new_size) noexcept
Resizes the allocated memory to the specified number of elements.
sint04 compare(const BufferAllocator &allocator) const noexcept
Performs a byte-level comparison of this buffer with another.
void removeIndex(t_index_type location) noexcept
Removes an element at the specified location by shifting subsequent elements backward.
constexpr decltype(auto) end() noexcept
Returns a pointer to one past the last filled element.
constexpr decltype(auto) begin(t_index_type index) const noexcept
Returns a const pointer to the element at the given index.
void removeLast() noexcept
Removes the last element from the buffer by decrementing the filled size.
constexpr decltype(auto) begin(t_index_type index) noexcept
Returns a pointer to the element at the given index.
BufferAllocator & operator=(BufferAllocator &&value) noexcept
Move assignment operator.
constexpr t_index_type capacity() const noexcept
Returns the total allocated capacity of the buffer in elements.
t_index_type m_filled_size
The number of elements currently stored in the buffer.
t_type & get(t_index_type index) noexcept
Gets a mutable reference to the element at the given index.
constexpr void addIndex(t_index_type location) noexcept
Inserts one uninitialized element at the specified location, shifting subsequent elements.
void autoSetCapacity(t_index_type size) noexcept
Automatically sets the buffer capacity using the growth strategy defined by NextCapacityBytes.
void swap(t_index_type index_a, t_index_type index_b) noexcept
Swaps two elements in the buffer by index.
void setSize(t_index_type size) noexcept
Sets the filled size of the buffer, allocating more space if necessary.
t_type * m_buffer
The buffer that stores the actual data.
constexpr t_index_type filledSize() const noexcept
Returns the number of elements currently stored in the buffer.
t_index_type index_type
The index type used for element addressing.
~BufferAllocator() noexcept
Destructor.
void setAll(const BufferAllocator< t_type, t_aligned_size, t_is_other_primitive, t_other_index_type, t_other_null_term > &allocator, t_index_type offset, t_index_type other_offset, t_index_type size) noexcept
Copies elements from another BufferAllocator into this buffer.
decltype(auto) emptyPtr() const noexcept
Returns a pointer to a static empty object for use when the buffer has no allocation.
constexpr decltype(auto) begin() noexcept
Returns a pointer to the beginning of the buffer.
void removeAllIndex(t_index_type start, t_index_type end) noexcept
Removes a contiguous range of elements from the buffer.
void setAll(const t_type &object, t_index_type offset, t_index_type size) noexcept
Fills a range of elements in the buffer with a single value.
constexpr BufferAllocator(BufferAllocator &&allocator) noexcept
Move constructor.
constexpr decltype(auto) ptr() const noexcept
Returns a const pointer to the underlying buffer, with optional alignment hint.
void setAll(const t_type *src, t_index_type offset, t_index_type size) noexcept
Copies elements from a source array into this buffer.
constexpr void createSpace(t_index_type size) noexcept
Creates additional space at the end of the buffer, optionally auto-managing capacity.
constexpr void addIndex() noexcept
Appends one uninitialized element at the end of the buffer without managed growth.
ObjectAllocator< t_type, t_is_primitive, t_index_type > allocator
The object allocator type for constructing and destructing elements.
const t_type & get(t_index_type index) const noexcept
Gets a const reference to the element at the given index.
constexpr size_t memSize() const noexcept
Returns the total memory size of the filled portion of the buffer in bytes.
constexpr void allocationSizeCheck(t_index_type new_size) noexcept
Checks if the buffer needs to grow and allocates accordingly.
constexpr void reference(t_type *reference, t_index_type new_size)
Sets this allocator to reference external memory without owning it.
void clear() noexcept
Clears the buffer by resetting the filled size to zero without freeing memory.
void removeAllIndices(const t_range_buffer &ranges) noexcept
Removes multiple contiguous ranges of elements from the buffer in a single pass.
sint04 compare(const BufferAllocator &allocator, t_index_type start, t_index_type end) const noexcept
Performs a byte-level comparison of a sub-range of this buffer with another.
void removeLast(t_index_type count) noexcept
Removes a specified number of elements from the end of the buffer.
constexpr bool ownsMemory() const
Checks whether this allocator owns its memory (i.e., has allocated capacity).
t_index_type m_allocated_size
The total allocated capacity in elements.
void addLast() noexcept
Appends one uninitialized element to the end of the buffer without managed growth.
constexpr bool contains(const t_comparable_type &value, t_index_type start, t_index_type size) const noexcept
Checks whether the buffer contains a given value within the specified range.
constexpr void createSpace(t_index_type location, t_index_type size) noexcept
Creates additional space at a specific location, shifting existing elements forward.
constexpr decltype(auto) end(t_index_type index) noexcept
Returns a pointer to the element at the given offset from the end.
static constexpr void AllocateElement(t_buffer_type &buff, t_index_type index, const t_type &object) noexcept
Allocates a single non-primitive element using placement new copy construction.
static constexpr void AllocateElement(t_buffer_type &buff, t_index_type start, t_index_type size, const t_type &object) noexcept
Allocates a range of non-primitive elements using placement new copy construction.
static constexpr void AllocateElement(t_buffer_type &buff, t_index_type index, t_type &&object) noexcept
Allocates a single non-primitive element using placement new move construction.
static constexpr void Allocate(t_buffer_type &buff, t_index_type start, t_index_type size) noexcept
Allocates a range of non-primitive elements using placement new default construction.
static constexpr void Deallocate(t_buffer_type &buff, t_index_type start, t_index_type size) noexcept
Deallocates a range of non-primitive elements by explicitly calling their destructors.
static void AllocateElement(t_buffer_type &buff, t_index_type index, t_type &&object) noexcept
Allocates a single primitive element by move-assigning the given object.
static void AllocateElement(t_buffer_type &buff, t_index_type index, const t_type &object) noexcept
Allocates a single primitive element by copy-assigning the given object.
static constexpr void Deallocate(t_buffer_type &, t_index_type, t_index_type) noexcept
Deallocates space for primitive types.
static void AllocateElement(t_buffer_type &buff, t_index_type start, t_index_type size, const t_type &object) noexcept
Allocates a range of primitive elements by assigning a copy of the given object.
static void Allocate(t_buffer_type &, t_index_type, t_index_type) noexcept
Allocates space for primitive types.
Allows for specific, custom logic for allocating an object.
Allows for specific, custom logic for allocating an object.
static constexpr void Deallocate(t_buffer_type &buffer, t_index_type start, t_index_type size) noexcept
Deallocates a range of elements in the buffer, delegating to the appropriate primitive or non-primiti...
static constexpr void AllocateElement(t_buffer_type &buffer, t_index_type index, t_type &&object) noexcept
Allocates a single element by move-constructing from a given object.
static constexpr bool isPrimitive() noexcept
Checks whether this allocator handles primitive types.
static constexpr void AllocateElement(t_buffer_type &buffer, t_index_type start, t_index_type size, t_type &object) noexcept
Allocates a range of elements by constructing from a given mutable object reference.
static constexpr void AllocateElement(t_buffer_type &buffer, t_index_type start, t_index_type size, const t_type &object) noexcept
Allocates a range of elements by copy-constructing from a given object.
static constexpr void AllocateElement(t_buffer_type &buffer, t_index_type index, const t_type &object) noexcept
Allocates a single element by copy-constructing from a given object.
static constexpr void Allocate(t_buffer_type &buffer, t_index_type start, t_index_type size) noexcept
Allocates a range of elements in the buffer, delegating to the appropriate primitive or non-primitive...
The primary namespace for the NDEVR SDK.
constexpr t_type getMin(const t_type &left, const t_type &right)
Finds the minimum of the given arguments based on the < operator Author: Tyler Parke Date: 2017-11-05...
uint64_t uint08
-Defines an alias representing an 8 byte, unsigned integer
int32_t sint04
-Defines an alias representing a 4 byte, signed integer.
static constexpr size_t DetermineAlignment() noexcept
Determines the optimal memory alignment for an allocation of the given byte size.
constexpr t_to cast(const Angle< t_from > &value)
Casts an Angle from one backing type to another.
static t_index_type NextCapacityBytes(t_index_type cap_elems, t_index_type need_elems) noexcept
Computes the next buffer capacity in elements, using a growth strategy tuned per platform alignment b...
Determines the optimal memory alignment for a given type based on its size.
static constexpr size_t Size() noexcept
Returns the optimal alignment size in bytes for the template type.
Precomputes a magic multiplier for fast compile-time division by the constant D, avoiding expensive r...
static constexpr unsigned __int128 high_bit
High bit used for computing the magic constant.
static constexpr uint08 m
Magic multiplier for GCC/Clang 128-bit integer path.
Compile-time helper that counts the number of trailing zero bits in a value, used for computing shift...