25#ifndef JAU_DYN_ARRAY_HPP_
26#define JAU_DYN_ARRAY_HPP_
36#include <condition_variable>
37#include <initializer_list>
50 #define JAU_DARRAY_PRINTF0(...) { fprintf(stderr, __VA_ARGS__); fflush(stderr); }
52 #define JAU_DARRAY_PRINTF0(...)
57 #define JAU_DARRAY_PRINTF(...) { fprintf(stderr, __VA_ARGS__); fflush(stderr); }
59 #define JAU_DARRAY_PRINTF(...)
143 template <
typename Value_type,
typename Size_type = jau::n
size_t,
typename Alloc_type = jau::callocator<Value_type>,
144 bool use_memmove = std::is_trivially_copyable_v<Value_type> || is_container_memmove_compliant_v<Value_type>,
145 bool use_secmem = is_enforcing_secmem_v<Value_type>
155 constexpr static const bool uses_realloc = use_memmove && std::is_base_of_v<jau::callocator<Value_type>, Alloc_type>;
176 typedef std::remove_const_t<Value_type> value_type_mutable;
178 typedef value_type_mutable* pointer_mutable;
180 static constexpr void* voidptr_cast(
const_pointer p) {
return reinterpret_cast<void*
>(
const_cast<pointer_mutable
>( p ) ); }
183 constexpr static const size_type MIN_SIZE_AT_GROW = 10;
189 float growth_factor_;
205 if( size_ > DIFF_MAX ) {
222 template<
class _Alloc_type>
226 if( new_capacity_ > DIFF_MAX ) {
230 value_type * m = alloc_inst.reallocate(begin_, storage_end_-begin_, new_capacity_);
232 free(
const_cast<pointer_mutable
>(begin_));
239 template<
class _Alloc_type>
247 constexpr void freeStore() {
248 if(
nullptr != begin_ ) {
249 alloc_inst.deallocate(begin_, storage_end_-begin_);
253 constexpr void clear_iterator() noexcept {
256 storage_end_ =
nullptr;
260 begin_ = new_storage_;
261 end_ = new_storage_+size_;
262 storage_end_ = new_storage_+capacity_;
267 storage_end_ = begin_+capacity_;
270 constexpr void dtor_one(
iterator pos) {
274 ::explicit_bzero(voidptr_cast(pos),
sizeof(
value_type));
280 JAU_DARRAY_PRINTF0(
"dtor [%zd .. %zd], count %zd\n", (first-begin_), (last-begin_)-1, (last-first)-1);
281 for(; first < last; ++first, ++count ) {
285 ::explicit_bzero(voidptr_cast(last-count), count*
sizeof(
value_type));
291 JAU_DARRAY_PRINTF0(
"ctor_copy_range [%zd .. %zd] -> ??, dist %zd\n", (first-begin_), (last-begin_)-1, (last-first)-1);
309 for(; first < last; ++dest, ++first) {
310 new (
const_cast<pointer_mutable
>(dest))
value_type( *first );
315 JAU_DARRAY_PRINTF0(
"clone_range [0 .. %zd], count %zd\n", (last-first)-1, (last-first)-1);
317 ctor_copy_range(dest, first, last);
321 JAU_DARRAY_PRINTF0(
"clone_range [0 .. %zd], count %zd -> %d\n", (last-begin_)-1, (last-first)-1, (
int)dest_capacity);
322 pointer dest = allocStore(dest_capacity);
323 ctor_copy_range(dest, first, last);
327 JAU_DARRAY_PRINTF0(
"ctor_copy_range_check [%zd .. %zd] -> ??, dist %zd\n", (first-begin_), (last-begin_)-1, (last-first)-1);
331 for(; first < last; ++dest, ++first) {
332 new (
const_cast<pointer_mutable
>(dest))
value_type( *first );
336 JAU_DARRAY_PRINTF0(
"clone_range_check [%zd .. %zd], count %zd -> %d\n", (first-begin_), (last-begin_)-1, (last-first)-1, (
int)dest_capacity);
337 if( dest_capacity <
size_type(last-first) ) {
341 pointer dest = allocStore(dest_capacity);
342 ctor_copy_range_check(dest, first, last);
346 template<
class InputIt >
347 constexpr static void ctor_copy_range_foreign(
pointer dest, InputIt first, InputIt last) {
352 for(; first != last; ++dest, ++first) {
353 new (
const_cast<pointer_mutable
>(dest))
value_type( *first );
356 template<
class InputIt >
357 constexpr pointer clone_range_foreign(
const size_type dest_capacity, InputIt first, InputIt last) {
358 if( dest_capacity <
size_type(last-first) ) {
362 pointer dest = allocStore(dest_capacity);
363 ctor_copy_range_foreign(dest, first, last);
367 constexpr void realloc_storage_move(
const size_type new_capacity) {
369 pointer new_storage = allocStore(new_capacity);
373 for(; first < end_; ++dest, ++first) {
374 new (
const_cast<pointer_mutable
>(dest))
value_type( std::move( *first ) );
379 set_iterator(new_storage,
size(), new_capacity);
381 pointer new_storage = reallocStore<allocator_type>(new_capacity);
382 set_iterator(new_storage,
size(), new_capacity);
384 pointer new_storage = allocStore(new_capacity);
385 ::memmove(voidptr_cast(new_storage),
386 begin_, (uint8_t*)end_-(uint8_t*)begin_);
388 set_iterator(new_storage,
size(), new_capacity);
391 constexpr void grow_storage_move(
const size_type new_capacity) {
398 const size_type grown_capacity = std::max<size_type>(
399 std::max<size_type>( MIN_SIZE_AT_GROW, new_capacity ),
402 realloc_storage_move( grown_capacity );
404 constexpr void grow_storage_move() {
415 ::memmove(voidptr_cast(dest),
420 JAU_DARRAY_PRINTF0(
"move_elements.mmm.left [%zd .. %zd] -> %zd, dist %zd\n", (first-begin_), ((first + count)-begin_)-1, (dest-begin_), (first-dest));
421 ::explicit_bzero(voidptr_cast(dest+count), (first-dest)*
sizeof(
value_type));
424 JAU_DARRAY_PRINTF0(
"move_elements.mmm.right [%zd .. %zd] -> %zd, dist %zd, size %zu\n", (first-begin_), ((first + count)-begin_)-1, (dest-begin_), (dest-first), (dest-first)*
sizeof(
value_type));
439 PRAGMA_DISABLE_WARNING_STRINGOP_OVERFLOW
440 ::explicit_bzero(voidptr_cast(first), (dest-first)*
sizeof(
value_type));
448 JAU_DARRAY_PRINTF0(
"move_elements.def.left [%zd .. %zd] -> %zd, dist %zd\n", (first-begin_), (last-begin_)-1, (dest-begin_), (first-dest));
449 for(; first < last; ++dest, ++first ) {
450 new (
const_cast<pointer_mutable
>(dest))
value_type( std::move( *first ) );
456 JAU_DARRAY_PRINTF0(
"move_elements.def.right [%zd .. %zd] -> %zd, dist %zd\n", (first-begin_), (last-begin_)-1, (dest-begin_), (dest-first));
458 for(--last; first <= last; --dest, --last ) {
459 new (
const_cast<pointer_mutable
>(dest))
value_type( std::move( *last ) );
475 : alloc_inst(), begin_(
nullptr ), end_(
nullptr ), storage_end_(
nullptr ),
487 : alloc_inst( alloc ), begin_( allocStore(
capacity) ), end_( begin_ ), storage_end_( begin_ +
capacity ),
500 : alloc_inst( x.alloc_inst ), begin_( clone_range(x.begin_, x.end_) ), end_( begin_ + x.
size() ),
501 storage_end_( begin_ + x.
size() ), growth_factor_( x.growth_factor_ ) {
514 : alloc_inst( alloc ), begin_( clone_range(x.begin_, x.end_) ), end_( begin_ + x.
size() ),
532 : alloc_inst( alloc ), begin_( clone_range( _capacity, x.begin_, x.end_) ), end_( begin_ + x.
size() ),
533 storage_end_( begin_ + _capacity ), growth_factor_(
growth_factor ) {
547 dtor_range(begin_, end_);
548 growth_factor_ = x.growth_factor_;
549 if( x_size_ > capacity_ ) {
551 begin_ = clone_range(x_size_, x.begin_, x.end_);
552 set_iterator(x_size_, x_size_);
554 ctor_copy_range(begin_, x.begin_, x.end_);
555 set_iterator(x_size_, capacity_);
566 : alloc_inst( std::move(x.alloc_inst) ), begin_( std::move(x.begin_) ), end_( std::move(x.end_) ),
567 storage_end_( std::move(x.storage_end_) ), growth_factor_( std::move(x.growth_factor_) )
576 : alloc_inst( std::move(alloc) ), begin_( std::move(x.begin_) ), end_( std::move(x.end_) ),
577 storage_end_( std::move(x.storage_end_) ), growth_factor_(
growth_factor )
593 alloc_inst = std::move(x.alloc_inst);
594 begin_ = std::move(x.begin_);
595 end_ = std::move(x.end_);
596 storage_end_ = std::move(x.storage_end_);
597 growth_factor_ = std::move( x.growth_factor_ );
624 : alloc_inst( alloc ), begin_( clone_range_check(_capacity, first, last) ), end_(begin_ +
size_type(last - first) ),
625 storage_end_( begin_ + _capacity ), growth_factor_(
growth_factor ) {
643 template<
class InputIt >
646 : alloc_inst( alloc ), begin_( clone_range_foreign(_capacity, first, last) ), end_(begin_ +
size_type(last - first) ),
647 storage_end_( begin_ + _capacity ), growth_factor_(
growth_factor ) {
660 template<
class InputIt >
662 : alloc_inst( alloc ), begin_( clone_range_foreign(
size_type(last - first), first, last) ), end_(begin_ +
size_type(last - first) ),
680 : alloc_inst( alloc ), begin_( clone_range_foreign(initlist.
size(), initlist.
begin(), initlist.
end()) ),
714 constexpr iterator storage_end() noexcept {
return storage_end_; }
716 constexpr const_iterator storage_end() const noexcept {
return storage_end_; }
718 constexpr const_iterator cstorage_end() const noexcept {
return storage_end_; }
732 return growth_factor_;
745 return std::max<size_type>( std::max<size_type>( MIN_SIZE_AT_GROW, a_capacity+1 ),
752 constexpr bool empty() const noexcept {
return begin_ == end_; }
815 if( 0 <= i && i <
size() ) {
825 if( 0 <= i && i <
size() ) {
842 if( new_capacity > capacity_ ) {
843 grow_storage_move(new_capacity);
855 if( capacity_ > size_ ) {
856 realloc_storage_move(size_);
866 template<
class InputIt >
867 constexpr void assign( InputIt first, InputIt last ) {
871 dtor_range(begin_, end_);
872 if( x_size_ > capacity_ ) {
874 begin_ = clone_range_foreign(x_size_, first, last);
875 set_iterator(x_size_, x_size_);
877 ctor_copy_range_foreign(begin_, first, last);
878 set_iterator(x_size_, capacity_);
890 dtor_range(begin_, end_);
891 if( x_size_ > capacity_ ) {
893 begin_ = clone_range_check(x_size_, first, last);
894 set_iterator(x_size_, x_size_);
896 ctor_copy_range_check(begin_, first, last);
897 set_iterator(x_size_, capacity_);
905 dtor_range(begin_, end_);
909 storage_end_ =
nullptr;
922 std::swap(growth_factor_, x.growth_factor_);
931 if( begin_ != end_ ) {
941 if( begin_ <= pos && pos < end_ ) {
944 if( 0 < right_count ) {
945 move_elements(
const_cast<value_type*
>(pos), pos+1, right_count);
949 return begin_ <= const_cast<iterator>(pos) &&
const_cast<iterator>(pos) <= end_ ?
const_cast<iterator>(pos) : end_;
957 const size_type count = dtor_range(first, last);
960 if( 0 < right_count ) {
961 move_elements(first, last, right_count);
965 return begin_ <= const_cast<iterator>(first) &&
const_cast<iterator>(first) <= end_ ?
const_cast<iterator>(first) : end_;
973 return erase(begin_ + pos_idx);
981 return erase(begin_ + first_idx, begin_ + last_idx);
997 if( begin_ <= pos && pos <= end_ ) {
998 if( end_ == storage_end_ ) {
1000 grow_storage_move();
1001 pos = begin_ + pos_idx;
1004 if( 0 < right_count ) {
1005 move_elements(
const_cast<iterator>(pos+1), pos, right_count);
1007 new (
const_cast<pointer_mutable
>(pos))
value_type( x );
1010 return begin_ <= pos && pos <= end_ ? const_cast<iterator>(pos) : end_;
1022 return insert(begin_ + pos_idx, x);
1038 if( begin_ <= pos && pos <= end_ ) {
1040 if( end_ == storage_end_ ) {
1041 grow_storage_move();
1043 iterator pos_new = begin_ + pos_idx;
1045 if( 0 < right_count ) {
1046 move_elements(pos_new+1, pos_new, right_count);
1048 new (
const_cast<pointer_mutable
>(pos_new))
value_type( std::move( x ) );
1051 return begin_ <= pos_new && pos_new <= end_ ? pos_new : end_;
1069 template<
typename... Args>
1071 if( begin_ <= pos && pos <= end_ ) {
1073 if( end_ == storage_end_ ) {
1074 grow_storage_move();
1076 iterator pos_new = begin_ + pos_idx;
1078 if( 0 < right_count ) {
1079 move_elements(pos_new+1, pos_new, right_count);
1081 new (
const_cast<pointer_mutable
>(pos_new))
value_type( std::forward<Args>(args)... );
1084 return begin_ <= pos_new && pos_new <= end_ ? pos_new : end_;
1098 template<
class InputIt >
1100 if( begin_ <= pos && pos <= end_ ) {
1103 if( end_ + new_elem_count >= storage_end_ ) {
1104 grow_storage_move(
size() + new_elem_count);
1106 iterator pos_new = begin_ + pos_idx;
1108 if( 0 < right_count ) {
1109 move_elements(pos_new + new_elem_count, pos_new, right_count);
1111 ctor_copy_range_foreign(pos_new, first, last);
1112 end_ += new_elem_count;
1114 return begin_ <= pos_new && pos_new <= end_ ? pos_new : end_;
1125 if( end_ == storage_end_ ) {
1126 grow_storage_move();
1128 new (
const_cast<pointer_mutable
>(end_))
value_type( x );
1137 if( end_ == storage_end_ ) {
1138 grow_storage_move();
1140 new (
const_cast<pointer_mutable
>(end_))
value_type( std::move(x) );
1157 insert(begin_, std::move(x));
1170 template<
typename... Args>
1172 if( end_ == storage_end_ ) {
1173 grow_storage_move();
1175 new (
const_cast<pointer_mutable
>(end_))
value_type( std::forward<Args>(args)... );
1187 template<
class InputIt >
1191 if( end_ + count >= storage_end_ ) {
1192 grow_storage_move(
size() + count);
1194 ctor_copy_range_foreign(end_, first, last);
1204 template <
typename... Args>
1207 const size_type count =
sizeof...(Args);
1211 if( end_ + count >= storage_end_ ) {
1212 grow_storage_move(
size() + count);
1215 (
new (
const_cast<pointer_mutable
>(end_++))
value_type( args ), ... );
1227 template <
typename... Args>
1230 const size_type count =
sizeof...(Args);
1234 if( end_ + count >= storage_end_ ) {
1235 grow_storage_move(
size() + count);
1238 (
new (
const_cast<pointer_mutable
>(end_++))
value_type( std::move(args) ), ... );
1273 for(
auto it = begin_; it != end_; ) {
1274 if( comparator( *it, x ) ) {
1307 for(
auto it = end_-1; begin_ <= it; --it) {
1308 if( comparator( *it, x ) ) {
1311 if( !all_matching ) {
1323 if( 1 < ++i ) { res.append(
", "); }
1336 ", type[integral "+
std::to_string(std::is_integral_v<Value_type>)+
1337 ", trivialCpy "+
std::to_string(std::is_trivially_copyable_v<Value_type>)+
1370 template <
typename First,
typename... Next,
1372 std::enable_if_t< std::conjunction_v<std::is_same<First, Next>... >,
bool> =
true>
1392 template <
typename First,
typename... Next>
1396 d.
push_back( std::forward<First>(arg1) );
1403 template<
typename Value_type,
typename Size_type,
typename Alloc_type>
1412 template<
typename Value_type,
typename Size_type,
typename Alloc_type>
1414 if( &rhs == &lhs ) {
1419 template<
typename Value_type,
typename Size_type,
typename Alloc_type>
1424 template<
typename Value_type,
typename Size_type,
typename Alloc_type>
1428 template<
typename Value_type,
typename Size_type,
typename Alloc_type>
1430 {
return lhs < rhs; }
1432 template<
typename Value_type,
typename Size_type,
typename Alloc_type>
1434 {
return !(lhs < rhs); }
1436 template<
typename Value_type,
typename Size_type,
typename Alloc_type>
1438 {
return !(rhs < lhs); }
1440 template<
typename Value_type,
typename Size_type,
typename Alloc_type>
1452 template<
class,
class =
void >
Implementation of a dynamic linear array storage, aka vector.
constexpr void push_front(value_type &&x)
Like std::vector::push_front(), move.
const allocator_type & get_allocator_ref() const noexcept
constexpr iterator insert(const_iterator pos, InputIt first, InputIt last)
Like std::vector::insert(), inserting the value_type range [first, last).
constexpr void push_back(InputIt first, InputIt last)
Like std::vector::push_back(), but appends the value_type range [first, last).
const value_type * const_iterator
bool darray_tag
Used to determine whether this type is a darray or has a darray, see ::is_darray_type<T>
const_reference operator[](size_type i) const noexcept
Like std::vector::operator[](size_type), immutable reference.
constexpr void swap(darray &x) noexcept
Like std::vector::swap().
constexpr void assign(InputIt first, InputIt last)
Like std::vector::assign()
constexpr darray & operator=(const darray &x)
Like std::vector::operator=(&), assignment.
bool(* equal_comparator)(const value_type &a, const value_type &b)
Generic value_type equal comparator to be user defined for e.g.
constexpr void assign(const_iterator first, const_iterator last)
Like std::vector::assign(), but non-template overload using const_iterator.
static constexpr const bool uses_secmem
constexpr reference front()
Like std::vector::front(), mutable access.
constexpr darray(std::initializer_list< value_type > initlist, const allocator_type &alloc=allocator_type())
Create a new instance from an initializer list.
constexpr const_iterator begin() const noexcept
constexpr iterator erase(iterator first, const_iterator last)
Like std::vector::erase(), removes the elements in the range [first, last).
constexpr iterator end() noexcept
constexpr size_type capacity() const noexcept
Return the current capacity.
constexpr const_iterator cend() const noexcept
constexpr size_type size() const noexcept
Like std::vector::size().
void reserve(size_type new_capacity)
Like std::vector::reserve(), increases this instance's capacity to new_capacity.
const_reference at(size_type i) const
Like std::vector::at(size_type), immutable reference.
constexpr void push_back(value_type &&x)
Like std::vector::push_back(), move.
const value_type * const_pointer
constexpr const_iterator end() const noexcept
constexpr void push_back(const value_type &x)
Like std::vector::push_back(), copy.
constexpr darray(darray &&x) noexcept
constexpr reference emplace_back(Args &&... args)
Like std::vector::emplace_back(), construct a new element in place at the end().
constexpr darray(const darray &x)
Creates a new instance, copying all elements from the given darray.
Alloc_type allocator_type
constexpr iterator erase(const size_type first_idx, const size_type last_idx)
Similar to std::vector::erase() using indices, removes the elements in the range [first_idx,...
constexpr size_type erase_matching(const value_type &x, const bool all_matching, equal_comparator comparator)
Erase either the first matching element or all matching elements.
constexpr darray(InputIt first, InputIt last, const allocator_type &alloc=allocator_type())
Creates a new instance, copying all elements from the given template input-iterator value_type range ...
reference operator[](size_type i) noexcept
Like std::vector::operator[](size_type), mutable reference.
constexpr iterator insert(const size_type pos_idx, const value_type &x)
Similar to std::vector::insert() using an index, copy.
std::string toString() const noexcept
constexpr bool empty() const noexcept
Like std::vector::empty().
constexpr const_pointer data() const noexcept
Like std::vector::data(), const immutable pointer.
constexpr darray & operator=(darray &&x) noexcept
Like std::vector::operator=(&&), move.
constexpr const_iterator cbegin() const noexcept
constexpr bool capacity_reached() const noexcept
Returns true if capacity has been reached and the next push_back() will grow the storage and invalida...
constexpr pointer data() noexcept
Like std::vector::data(), mutable pointer.
constexpr darray() noexcept
Default constructor, giving zero capacity and zero memory footprint.
constexpr darray(size_type capacity, const float growth_factor=DEFAULT_GROWTH_FACTOR, const allocator_type &alloc=allocator_type())
Creating an empty instance with initial capacity and other (default) properties.
constexpr float growth_factor() const noexcept
constexpr darray(darray &&x, const float growth_factor, const allocator_type &alloc) noexcept
constexpr iterator insert(const_iterator pos, const value_type &x)
Like std::vector::insert(), copy.
constexpr iterator begin() noexcept
constexpr void push_back_list(const Args &... args)
Like push_back(), but for more multiple const r-value to copy.
constexpr void push_back_list(Args &&... args)
Like push_back(), but for more multiple r-value references to move.
static constexpr const bool uses_realloc
constexpr iterator erase(const_iterator pos)
Like std::vector::erase(), removes the elements at pos.
std::make_signed< size_type >::type difference_type
constexpr void clear() noexcept
Like std::vector::clear(), but ending with zero capacity.
allocator_type get_allocator() const noexcept
constexpr iterator erase(const size_type pos_idx)
Similar to std::vector::erase() using an index, removes the elements at pos_idx.
constexpr bool push_back_unique(const value_type &x, equal_comparator comparator)
Like std::vector::push_back(), but only if the newly added element does not yet exist.
constexpr void shrink_to_fit()
Like std::vector::shrink_to_fit(), but ensured constexpr.
constexpr iterator insert(const_iterator pos, value_type &&x)
Like std::vector::insert(), move.
constexpr const_reference front() const
Like std::vector::front(), immutable access.
reference at(size_type i)
Like std::vector::at(size_type), mutable reference.
static constexpr const bool uses_memmove
constexpr iterator emplace(const_iterator pos, Args &&... args)
Like std::vector::emplace(), construct a new element in place.
const value_type & const_reference
constexpr darray(const size_type _capacity, const_iterator first, const_iterator last, const float growth_factor=DEFAULT_GROWTH_FACTOR, const allocator_type &alloc=allocator_type())
Creates a new instance with custom initial storage capacity, copying all elements from the given cons...
constexpr size_type max_size() const noexcept
Returns std::numeric_limits<difference_type>::max() as the maximum array size.
std::string get_info() const noexcept
static constexpr const float DEFAULT_GROWTH_FACTOR
Default growth factor using the golden ratio 1.618.
constexpr size_type get_grown_capacity() const noexcept
Return the current capacity() multiplied by the growth factor, minimum is max(capacity()+1,...
constexpr reference back()
Like std::vector::back(), mutable access.
constexpr darray(const size_type _capacity, InputIt first, InputIt last, const float growth_factor=DEFAULT_GROWTH_FACTOR, const allocator_type &alloc=allocator_type())
Creates a new instance with custom initial storage capacity, copying all elements from the given temp...
constexpr void pop_back() noexcept
Like std::vector::pop_back().
constexpr const_reference back() const
Like std::vector::back(), immutable access.
constexpr void push_front(const value_type &x)
Like std::vector::push_front(), copy.
constexpr darray(const darray &x, const size_type _capacity, const float growth_factor, const allocator_type &alloc)
Creates a new instance with custom initial storage capacity, copying all elements from the given darr...
constexpr darray(const darray &x, const float growth_factor, const allocator_type &alloc)
Creates a new instance, copying all elements from the given darray.
#define JAU_DARRAY_PRINTF(...)
#define JAU_DARRAY_PRINTF0(...)
constexpr UnaryFunction for_each_const(T &data, UnaryFunction f, std::enable_if_t< is_cow_type< T >::value, bool >=true) noexcept
std::string to_string(const endian_t v) noexcept
Return std::string representation of the given endian.
std::string to_string(const alphabet &v) noexcept
#define PRAGMA_DISABLE_WARNING_PUSH
#define PRAGMA_DISABLE_WARNING_POP
#define PRAGMA_DISABLE_WARNING_NULL_DEREFERENCE
std::ostream & operator<<(std::ostream &out, const cow_darray< Value_type, Size_type, Alloc_type > &c)
void swap(darray< Value_type, Size_type, Alloc_type > &rhs, darray< Value_type, Size_type, Alloc_type > &lhs) noexcept
bool operator>=(const cow_darray< Value_type, Size_type, Alloc_type > &rhs, const cow_darray< Value_type, Size_type, Alloc_type > &lhs)
constexpr darray< First > make_darray(First &&arg1, Next &&... argsN)
Construct a darray<T> instance, initialized by move semantics from the variadic (template pack) argum...
bool operator>(const cow_darray< Value_type, Size_type, Alloc_type > &rhs, const cow_darray< Value_type, Size_type, Alloc_type > &lhs)
bool operator<(const cow_darray< Value_type, Size_type, Alloc_type > &rhs, const cow_darray< Value_type, Size_type, Alloc_type > &lhs)
void swap(cow_darray< Value_type, Size_type, Alloc_type > &rhs, cow_darray< Value_type, Size_type, Alloc_type > &lhs) noexcept
bool operator<=(const cow_darray< Value_type, Size_type, Alloc_type > &rhs, const cow_darray< Value_type, Size_type, Alloc_type > &lhs)
@ free
Denotes a func::free_target_t.
constexpr T max(const T x, const T y) noexcept
Returns the maximum of two integrals (w/ branching) in O(1)
std::string to_hexstring(value_type const &v) noexcept
Produce a lower-case hexadecimal string representation of the given pointer.
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
bool operator==(const callocator< T1 > &lhs, const callocator< T2 > &rhs) noexcept
bool operator!=(const callocator< T1 > &lhs, const callocator< T2 > &rhs) noexcept
A simple allocator using POSIX C functions: ::malloc(), ::free() and ::realloc().
template< class T > is_darray_type<T>::value compile-time Type Trait, determining whether the given t...