2021-09-17 22:01:53 +02:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <util/types.hpp>
|
2022-10-03 11:40:39 +02:00
|
|
|
#include <functional>
|
2023-08-12 13:31:17 +02:00
|
|
|
#include <algorithm>
|
2025-11-21 00:07:06 +01:00
|
|
|
#include <cstdlib>
|
2021-09-17 22:01:53 +02:00
|
|
|
|
2025-07-20 18:59:32 +02:00
|
|
|
#include "reverse_ptr.hpp"
|
|
|
|
|
|
2021-09-17 22:01:53 +02:00
|
|
|
namespace rsx
|
|
|
|
|
{
|
2025-11-21 00:07:06 +01:00
|
|
|
namespace aligned_allocator
|
|
|
|
|
{
|
|
|
|
|
template <size_t Align>
|
2025-12-03 00:25:17 +01:00
|
|
|
requires (Align != 0) && ((Align & (Align - 1)) == 0)
|
|
|
|
|
size_t align_up(size_t size)
|
|
|
|
|
{
|
|
|
|
|
return (size + (Align - 1)) & ~(Align - 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <size_t Align>
|
|
|
|
|
requires (Align != 0) && ((Align & (Align - 1)) == 0)
|
2025-11-21 00:07:06 +01:00
|
|
|
void* malloc(size_t size)
|
|
|
|
|
{
|
2025-12-03 00:25:17 +01:00
|
|
|
#if defined(_WIN32)
|
2025-11-21 00:07:06 +01:00
|
|
|
return _aligned_malloc(size, Align);
|
2025-12-03 00:25:17 +01:00
|
|
|
#elif defined(__APPLE__)
|
|
|
|
|
constexpr size_t NativeAlign = std::max(Align, sizeof(void*));
|
|
|
|
|
return std::aligned_alloc(NativeAlign, align_up<NativeAlign>(size));
|
2025-11-21 00:07:06 +01:00
|
|
|
#else
|
2025-12-03 00:25:17 +01:00
|
|
|
return std::aligned_alloc(Align, align_up<Align>(size));
|
2025-11-21 00:07:06 +01:00
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template <size_t Align>
|
2025-12-03 00:25:17 +01:00
|
|
|
requires (Align != 0) && ((Align & (Align - 1)) == 0)
|
2025-11-21 00:07:06 +01:00
|
|
|
void* realloc(void* prev_ptr, [[maybe_unused]] size_t prev_size, size_t new_size)
|
|
|
|
|
{
|
2025-12-03 00:25:17 +01:00
|
|
|
if (align_up<Align>(prev_size) >= new_size)
|
2025-11-28 19:54:45 +01:00
|
|
|
{
|
2025-11-28 21:04:30 +01:00
|
|
|
return prev_ptr;
|
2025-11-28 19:54:45 +01:00
|
|
|
}
|
2025-11-28 21:04:30 +01:00
|
|
|
|
|
|
|
|
ensure(reinterpret_cast<usz>(prev_ptr) % Align == 0, "Pointer not aligned to Align");
|
2025-12-03 00:25:17 +01:00
|
|
|
#if defined(_WIN32)
|
2025-11-21 00:07:06 +01:00
|
|
|
return _aligned_realloc(prev_ptr, new_size, Align);
|
|
|
|
|
#else
|
2025-12-03 00:25:17 +01:00
|
|
|
#if defined(__APPLE__)
|
|
|
|
|
constexpr size_t NativeAlign = std::max(Align, sizeof(void*));
|
|
|
|
|
void* ret = std::aligned_alloc(NativeAlign, align_up<NativeAlign>(new_size));
|
|
|
|
|
#else
|
|
|
|
|
void* ret = std::aligned_alloc(Align, align_up<Align>(new_size));
|
|
|
|
|
#endif
|
2025-11-21 00:07:06 +01:00
|
|
|
std::memcpy(ret, prev_ptr, std::min(prev_size, new_size));
|
2025-11-28 19:54:45 +01:00
|
|
|
std::free(prev_ptr);
|
2025-11-21 00:07:06 +01:00
|
|
|
return ret;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void free(void* ptr)
|
|
|
|
|
{
|
2025-11-21 01:03:42 +01:00
|
|
|
#ifdef _WIN32
|
2025-11-21 00:07:06 +01:00
|
|
|
_aligned_free(ptr);
|
|
|
|
|
#else
|
|
|
|
|
std::free(ptr);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-13 01:24:56 +02:00
|
|
|
template <typename C, typename T>
|
|
|
|
|
concept span_like =
|
|
|
|
|
requires(C& c) {
|
|
|
|
|
{ c.data() } -> std::convertible_to<const T*>;
|
|
|
|
|
{ c.size() } -> std::integral;
|
|
|
|
|
};
|
|
|
|
|
|
2025-11-22 18:25:47 +01:00
|
|
|
template <typename T, typename U>
|
|
|
|
|
concept is_trivially_comparable_v =
|
|
|
|
|
requires (T t1, U t2) {
|
|
|
|
|
{ t1 == t2 } -> std::same_as<bool>;
|
|
|
|
|
};
|
|
|
|
|
|
2025-11-21 00:07:06 +01:00
|
|
|
template <typename Ty, size_t Align=alignof(Ty)>
|
2025-11-11 13:11:41 +01:00
|
|
|
requires std::is_trivially_destructible_v<Ty> && std::is_trivially_copyable_v<Ty>
|
2021-09-17 22:01:53 +02:00
|
|
|
struct simple_array
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
using iterator = Ty*;
|
|
|
|
|
using const_iterator = const Ty*;
|
2025-07-20 18:59:32 +02:00
|
|
|
using reverse_iterator = reverse_pointer<Ty>;
|
|
|
|
|
using const_reverse_iterator = reverse_pointer<const Ty>;
|
2021-09-17 22:01:53 +02:00
|
|
|
using value_type = Ty;
|
|
|
|
|
|
|
|
|
|
private:
|
2024-02-25 01:28:06 +01:00
|
|
|
static constexpr u32 _local_capacity = std::max<u32>(64u / sizeof(Ty), 1u);
|
2025-11-21 00:07:06 +01:00
|
|
|
alignas(Align) char _local_storage[_local_capacity * sizeof(Ty)];
|
2024-02-25 01:28:06 +01:00
|
|
|
|
|
|
|
|
u32 _capacity = _local_capacity;
|
2024-02-25 16:03:32 +01:00
|
|
|
Ty* _data = _local_capacity ? reinterpret_cast<Ty*>(_local_storage) : nullptr;
|
2021-09-17 22:01:53 +02:00
|
|
|
u32 _size = 0;
|
|
|
|
|
|
2025-05-01 23:38:51 +02:00
|
|
|
inline u32 offset(const_iterator pos)
|
2021-09-17 22:01:53 +02:00
|
|
|
{
|
2025-05-01 23:38:51 +02:00
|
|
|
return (_data) ? u32(pos - _data) : 0u;
|
2021-09-17 22:01:53 +02:00
|
|
|
}
|
|
|
|
|
|
2024-02-25 01:28:06 +01:00
|
|
|
bool is_local_storage() const
|
|
|
|
|
{
|
2024-02-25 16:03:32 +01:00
|
|
|
return _data == reinterpret_cast<const Ty*>(_local_storage);
|
2024-02-25 01:28:06 +01:00
|
|
|
}
|
|
|
|
|
|
2021-09-17 22:01:53 +02:00
|
|
|
public:
|
|
|
|
|
simple_array() = default;
|
|
|
|
|
|
2022-05-26 22:04:15 +02:00
|
|
|
simple_array(u32 initial_size)
|
|
|
|
|
{
|
|
|
|
|
reserve(initial_size);
|
|
|
|
|
_size = initial_size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
simple_array(u32 initial_size, const Ty val)
|
2021-09-17 22:01:53 +02:00
|
|
|
{
|
|
|
|
|
reserve(initial_size);
|
|
|
|
|
_size = initial_size;
|
|
|
|
|
|
|
|
|
|
for (u32 n = 0; n < initial_size; ++n)
|
|
|
|
|
{
|
|
|
|
|
_data[n] = val;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
simple_array(const std::initializer_list<Ty>& args)
|
|
|
|
|
{
|
|
|
|
|
reserve(::size32(args));
|
|
|
|
|
|
|
|
|
|
for (const auto& arg : args)
|
|
|
|
|
{
|
|
|
|
|
push_back(arg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
simple_array(const simple_array& other)
|
|
|
|
|
{
|
2024-02-25 01:28:06 +01:00
|
|
|
resize(other._size);
|
2021-09-17 22:01:53 +02:00
|
|
|
|
2024-02-25 01:28:06 +01:00
|
|
|
if (_size)
|
|
|
|
|
{
|
|
|
|
|
std::memcpy(_data, other._data, size_bytes());
|
|
|
|
|
}
|
2021-09-17 22:01:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
simple_array(simple_array&& other) noexcept
|
|
|
|
|
{
|
|
|
|
|
swap(other);
|
|
|
|
|
}
|
|
|
|
|
|
2025-08-13 01:24:56 +02:00
|
|
|
template <typename Container>
|
|
|
|
|
requires span_like<Container, Ty>
|
|
|
|
|
simple_array(const Container& container)
|
|
|
|
|
{
|
|
|
|
|
resize(container.size());
|
|
|
|
|
|
|
|
|
|
if (_size)
|
|
|
|
|
{
|
|
|
|
|
std::memcpy(_data, container.data(), size_bytes());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-17 22:01:53 +02:00
|
|
|
simple_array& operator=(const simple_array& other)
|
|
|
|
|
{
|
|
|
|
|
if (&other != this)
|
|
|
|
|
{
|
2024-02-25 01:28:06 +01:00
|
|
|
resize(other._size);
|
|
|
|
|
|
|
|
|
|
if (_size)
|
|
|
|
|
{
|
|
|
|
|
std::memcpy(_data, other._data, size_bytes());
|
|
|
|
|
}
|
2021-09-17 22:01:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
simple_array& operator=(simple_array&& other) noexcept
|
|
|
|
|
{
|
|
|
|
|
swap(other);
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~simple_array()
|
|
|
|
|
{
|
|
|
|
|
if (_data)
|
|
|
|
|
{
|
2024-02-25 01:28:06 +01:00
|
|
|
if (!is_local_storage())
|
|
|
|
|
{
|
2025-11-21 00:07:06 +01:00
|
|
|
aligned_allocator::free(_data);
|
2024-02-25 01:28:06 +01:00
|
|
|
}
|
|
|
|
|
|
2021-09-17 22:01:53 +02:00
|
|
|
_data = nullptr;
|
|
|
|
|
_size = _capacity = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-25 01:28:06 +01:00
|
|
|
void swap(simple_array<Ty>& that) noexcept
|
2021-09-17 22:01:53 +02:00
|
|
|
{
|
2024-02-25 01:28:06 +01:00
|
|
|
if (!_size && !that._size)
|
|
|
|
|
{
|
|
|
|
|
// NOP. Surprisingly common
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto _this_is_local = is_local_storage();
|
|
|
|
|
const auto _that_is_local = that.is_local_storage();
|
|
|
|
|
|
|
|
|
|
if (!_this_is_local && !_that_is_local)
|
|
|
|
|
{
|
|
|
|
|
std::swap(_capacity, that._capacity);
|
|
|
|
|
std::swap(_size, that._size);
|
|
|
|
|
std::swap(_data, that._data);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!_size)
|
|
|
|
|
{
|
|
|
|
|
*this = that;
|
|
|
|
|
that.clear();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!that._size)
|
|
|
|
|
{
|
|
|
|
|
that = *this;
|
|
|
|
|
clear();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_this_is_local != _that_is_local)
|
|
|
|
|
{
|
|
|
|
|
// Mismatched usage of the stack storage.
|
|
|
|
|
rsx::simple_array<Ty> tmp{ *this };
|
|
|
|
|
*this = that;
|
|
|
|
|
that = tmp;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-11 13:11:41 +01:00
|
|
|
// Use memcpy to allow compiler optimizations
|
|
|
|
|
Ty _stack_alloc[_local_capacity];
|
|
|
|
|
std::memcpy(_stack_alloc, that._data, that.size_bytes());
|
|
|
|
|
std::memcpy(that._data, _data, size_bytes());
|
|
|
|
|
std::memcpy(_data, _stack_alloc, that.size_bytes());
|
2024-02-25 01:28:06 +01:00
|
|
|
std::swap(_size, that._size);
|
2021-09-17 22:01:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void reserve(u32 size)
|
|
|
|
|
{
|
|
|
|
|
if (_capacity >= size)
|
2024-02-25 01:28:06 +01:00
|
|
|
{
|
2021-09-17 22:01:53 +02:00
|
|
|
return;
|
2024-02-25 01:28:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (is_local_storage())
|
|
|
|
|
{
|
|
|
|
|
// Switch to heap storage
|
2025-11-21 00:07:06 +01:00
|
|
|
ensure(_data = static_cast<Ty*>(aligned_allocator::malloc<Align>(sizeof(Ty) * size)));
|
2025-04-25 09:21:39 +02:00
|
|
|
std::memcpy(static_cast<void*>(_data), _local_storage, size_bytes());
|
2024-02-25 01:28:06 +01:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Extend heap storage
|
2025-11-21 00:07:06 +01:00
|
|
|
ensure(_data = static_cast<Ty*>(aligned_allocator::realloc<Align>(_data, size_bytes(), sizeof(Ty) * size))); // "realloc() failed!"
|
2024-02-25 01:28:06 +01:00
|
|
|
}
|
2021-09-17 22:01:53 +02:00
|
|
|
|
|
|
|
|
_capacity = size;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-27 19:34:11 +02:00
|
|
|
template <typename T> requires UnsignedInt<T>
|
|
|
|
|
void resize(T size)
|
2021-09-17 22:01:53 +02:00
|
|
|
{
|
2022-09-27 19:34:11 +02:00
|
|
|
const auto new_size = static_cast<u32>(size);
|
|
|
|
|
reserve(new_size);
|
|
|
|
|
_size = new_size;
|
2021-09-17 22:01:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void push_back(const Ty& val)
|
|
|
|
|
{
|
|
|
|
|
if (_size >= _capacity)
|
|
|
|
|
{
|
|
|
|
|
reserve(_capacity + 16);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_data[_size++] = val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void push_back(Ty&& val)
|
|
|
|
|
{
|
|
|
|
|
if (_size >= _capacity)
|
|
|
|
|
{
|
|
|
|
|
reserve(_capacity + 16);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_data[_size++] = val;
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-27 19:51:22 +01:00
|
|
|
template <typename... Args>
|
|
|
|
|
void emplace_back(Args&&... args)
|
|
|
|
|
{
|
|
|
|
|
if (_size >= _capacity)
|
|
|
|
|
{
|
|
|
|
|
reserve(_capacity + 16);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::construct_at(&_data[_size++], std::forward<Args&&>(args)...);
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-17 22:01:53 +02:00
|
|
|
Ty pop_back()
|
|
|
|
|
{
|
|
|
|
|
return _data[--_size];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
iterator insert(iterator pos, const Ty& val)
|
|
|
|
|
{
|
|
|
|
|
ensure(pos >= _data);
|
|
|
|
|
const auto _loc = offset(pos);
|
|
|
|
|
|
|
|
|
|
if (_size >= _capacity)
|
|
|
|
|
{
|
|
|
|
|
reserve(_capacity + 16);
|
|
|
|
|
pos = _data + _loc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_loc >= _size)
|
|
|
|
|
{
|
|
|
|
|
_data[_size++] = val;
|
|
|
|
|
return pos;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-04 19:45:22 +01:00
|
|
|
AUDIT(_loc < _size);
|
2021-09-17 22:01:53 +02:00
|
|
|
|
|
|
|
|
const auto remaining = (_size - _loc);
|
|
|
|
|
memmove(pos + 1, pos, remaining * sizeof(Ty));
|
|
|
|
|
|
|
|
|
|
*pos = val;
|
|
|
|
|
_size++;
|
|
|
|
|
|
|
|
|
|
return pos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
iterator insert(iterator pos, Ty&& val)
|
|
|
|
|
{
|
|
|
|
|
ensure(pos >= _data);
|
|
|
|
|
const auto _loc = offset(pos);
|
|
|
|
|
|
|
|
|
|
if (_size >= _capacity)
|
|
|
|
|
{
|
|
|
|
|
reserve(_capacity + 16);
|
|
|
|
|
pos = _data + _loc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_loc >= _size)
|
|
|
|
|
{
|
|
|
|
|
_data[_size++] = val;
|
|
|
|
|
return pos;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-04 19:45:22 +01:00
|
|
|
AUDIT(_loc < _size);
|
2021-09-17 22:01:53 +02:00
|
|
|
|
|
|
|
|
const u32 remaining = (_size - _loc);
|
|
|
|
|
memmove(pos + 1, pos, remaining * sizeof(Ty));
|
|
|
|
|
|
|
|
|
|
*pos = val;
|
|
|
|
|
_size++;
|
|
|
|
|
|
|
|
|
|
return pos;
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-15 21:04:57 +02:00
|
|
|
void operator += (const rsx::simple_array<Ty>& that)
|
|
|
|
|
{
|
|
|
|
|
const auto old_size = _size;
|
|
|
|
|
resize(_size + that._size);
|
|
|
|
|
std::memcpy(data() + old_size, that.data(), that.size_bytes());
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-17 22:01:53 +02:00
|
|
|
void clear()
|
|
|
|
|
{
|
|
|
|
|
_size = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool empty() const
|
|
|
|
|
{
|
|
|
|
|
return _size == 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 size() const
|
|
|
|
|
{
|
|
|
|
|
return _size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u64 size_bytes() const
|
|
|
|
|
{
|
|
|
|
|
return _size * sizeof(Ty);
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-15 13:21:25 +02:00
|
|
|
u32 size_bytes32() const
|
|
|
|
|
{
|
|
|
|
|
return _size * sizeof(Ty);
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-17 22:01:53 +02:00
|
|
|
u32 capacity() const
|
|
|
|
|
{
|
|
|
|
|
return _capacity;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ty& operator[] (u32 index)
|
|
|
|
|
{
|
|
|
|
|
return _data[index];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Ty& operator[] (u32 index) const
|
|
|
|
|
{
|
|
|
|
|
return _data[index];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ty* data()
|
|
|
|
|
{
|
|
|
|
|
return _data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Ty* data() const
|
|
|
|
|
{
|
|
|
|
|
return _data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ty& back()
|
|
|
|
|
{
|
|
|
|
|
return _data[_size - 1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Ty& back() const
|
|
|
|
|
{
|
|
|
|
|
return _data[_size - 1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ty& front()
|
|
|
|
|
{
|
|
|
|
|
return _data[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const Ty& front() const
|
|
|
|
|
{
|
|
|
|
|
return _data[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
iterator begin()
|
|
|
|
|
{
|
|
|
|
|
return _data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
iterator end()
|
|
|
|
|
{
|
|
|
|
|
return _data ? _data + _size : nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const_iterator begin() const
|
|
|
|
|
{
|
|
|
|
|
return _data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const_iterator end() const
|
|
|
|
|
{
|
|
|
|
|
return _data ? _data + _size : nullptr;
|
|
|
|
|
}
|
2022-10-02 01:58:55 +02:00
|
|
|
|
2025-07-20 18:59:32 +02:00
|
|
|
const_iterator cbegin() const
|
|
|
|
|
{
|
|
|
|
|
return _data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const_iterator cend() const
|
|
|
|
|
{
|
|
|
|
|
return _data ? _data + _size : nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
reverse_iterator rbegin()
|
|
|
|
|
{
|
2025-07-27 02:06:46 +02:00
|
|
|
return reverse_iterator(end() - 1);
|
2025-07-20 18:59:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
reverse_iterator rend()
|
|
|
|
|
{
|
2025-07-27 02:06:46 +02:00
|
|
|
return reverse_iterator(begin() - 1);
|
2025-07-20 18:59:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const_reverse_iterator rbegin() const
|
|
|
|
|
{
|
2025-07-27 02:06:46 +02:00
|
|
|
return crbegin();
|
2025-07-20 18:59:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const_reverse_iterator rend() const
|
|
|
|
|
{
|
2025-07-27 02:06:46 +02:00
|
|
|
return crend();
|
2025-07-20 18:59:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const_reverse_iterator crbegin() const
|
|
|
|
|
{
|
2025-07-27 02:06:46 +02:00
|
|
|
return const_reverse_iterator(cend() - 1);
|
2025-07-20 18:59:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const_reverse_iterator crend() const
|
|
|
|
|
{
|
2025-07-27 02:06:46 +02:00
|
|
|
return const_reverse_iterator(cbegin() - 1);
|
2025-07-20 18:59:32 +02:00
|
|
|
}
|
|
|
|
|
|
2022-10-02 01:58:55 +02:00
|
|
|
bool any(std::predicate<const Ty&> auto predicate) const
|
|
|
|
|
{
|
|
|
|
|
for (auto it = begin(); it != end(); ++it)
|
|
|
|
|
{
|
|
|
|
|
if (std::invoke(predicate, *it))
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-22 18:25:47 +01:00
|
|
|
/**
|
|
|
|
|
* Note that find and find_if return pointers to objects and not iterators for simplified usage.
|
|
|
|
|
* It is functionally equivalent to retrieve a nullptr meaning empty object stored and nullptr meaning not found for all practical uses of this container.
|
|
|
|
|
*/
|
|
|
|
|
template <typename T = Ty>
|
|
|
|
|
requires is_trivially_comparable_v<Ty, T>
|
|
|
|
|
Ty* find(const T& value)
|
|
|
|
|
{
|
|
|
|
|
for (auto it = begin(); it != end(); ++it)
|
|
|
|
|
{
|
|
|
|
|
if (*it == value)
|
|
|
|
|
{
|
|
|
|
|
return &(*it);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Remove when we switch to C++23
|
|
|
|
|
template <typename T = Ty>
|
|
|
|
|
requires is_trivially_comparable_v<Ty, T>
|
|
|
|
|
const Ty* find(const T& value) const
|
|
|
|
|
{
|
|
|
|
|
return const_cast<simple_array<Ty, Align>*>(this)->find(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ty* find_if(std::predicate<const Ty&> auto predicate)
|
|
|
|
|
{
|
|
|
|
|
for (auto it = begin(); it != end(); ++it)
|
|
|
|
|
{
|
|
|
|
|
if (std::invoke(predicate, *it))
|
|
|
|
|
{
|
|
|
|
|
return &(*it);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Remove with C++23
|
|
|
|
|
const Ty* find_if(std::predicate<const Ty&> auto predicate) const
|
|
|
|
|
{
|
|
|
|
|
return const_cast<simple_array<Ty, Align>*>(this)->find_if(predicate);
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-03 02:17:26 +01:00
|
|
|
bool erase_if(std::predicate<const Ty&> auto predicate)
|
2022-10-02 01:58:55 +02:00
|
|
|
{
|
|
|
|
|
if (!_size)
|
|
|
|
|
{
|
2024-11-03 02:17:26 +01:00
|
|
|
return false;
|
2022-10-02 01:58:55 +02:00
|
|
|
}
|
|
|
|
|
|
2024-11-03 02:17:26 +01:00
|
|
|
bool ret = false;
|
2025-04-26 18:19:28 +02:00
|
|
|
for (auto ptr = _data, last = _data + _size - 1; ptr <= last;)
|
2022-10-02 01:58:55 +02:00
|
|
|
{
|
2024-11-03 02:17:26 +01:00
|
|
|
if (predicate(*ptr))
|
2022-10-02 01:58:55 +02:00
|
|
|
{
|
2025-04-13 22:01:05 +02:00
|
|
|
ret = true;
|
|
|
|
|
|
2025-04-26 18:19:28 +02:00
|
|
|
if (ptr == last)
|
2025-04-13 22:01:05 +02:00
|
|
|
{
|
2025-04-26 18:19:28 +02:00
|
|
|
// Popping the last entry from list. Just set the new size and exit
|
|
|
|
|
_size--;
|
|
|
|
|
break;
|
2025-04-13 22:01:05 +02:00
|
|
|
}
|
|
|
|
|
|
2025-04-26 18:19:28 +02:00
|
|
|
// Move item to the end of the list and shrink by 1
|
|
|
|
|
std::memcpy(ptr, last, sizeof(Ty));
|
2025-04-26 19:39:02 +02:00
|
|
|
_size--;
|
|
|
|
|
last--;
|
2025-04-26 18:19:28 +02:00
|
|
|
|
|
|
|
|
// Retest the same ptr which now has the previous tail item
|
|
|
|
|
continue;
|
2022-10-02 01:58:55 +02:00
|
|
|
}
|
2025-04-26 18:19:28 +02:00
|
|
|
|
|
|
|
|
ptr++;
|
2022-10-02 01:58:55 +02:00
|
|
|
}
|
2024-11-03 02:17:26 +01:00
|
|
|
|
|
|
|
|
return ret;
|
2022-10-02 01:58:55 +02:00
|
|
|
}
|
2022-12-05 20:28:43 +01:00
|
|
|
|
2025-02-09 21:28:37 +01:00
|
|
|
simple_array<Ty>& sort(std::predicate<const Ty&, const Ty&> auto predicate)
|
2022-12-05 20:28:43 +01:00
|
|
|
{
|
|
|
|
|
if (_size < 2)
|
|
|
|
|
{
|
2025-02-09 21:28:37 +01:00
|
|
|
return *this;
|
2022-12-05 20:28:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::sort(begin(), end(), predicate);
|
2025-02-09 21:28:37 +01:00
|
|
|
return *this;
|
2022-12-05 20:28:43 +01:00
|
|
|
}
|
2024-02-25 01:28:06 +01:00
|
|
|
|
2024-03-20 17:28:59 +01:00
|
|
|
template <typename F, typename U = std::invoke_result_t<F, const Ty&>>
|
2025-02-09 21:28:37 +01:00
|
|
|
requires (std::is_invocable_v<F, const Ty&> && std::is_trivially_destructible_v<U>)
|
2024-02-25 01:28:06 +01:00
|
|
|
simple_array<U> map(F&& xform) const
|
|
|
|
|
{
|
2024-06-12 02:10:28 +02:00
|
|
|
simple_array<U> result;
|
|
|
|
|
result.reserve(size());
|
|
|
|
|
|
2024-02-25 01:28:06 +01:00
|
|
|
for (auto it = begin(); it != end(); ++it)
|
|
|
|
|
{
|
|
|
|
|
result.push_back(xform(*it));
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
2025-01-17 01:17:57 +01:00
|
|
|
|
2025-02-09 21:28:37 +01:00
|
|
|
template <typename F, typename U = std::invoke_result_t<F, const Ty&>>
|
|
|
|
|
requires (std::is_invocable_v<F, const Ty&> && !std::is_trivially_destructible_v<U>)
|
|
|
|
|
std::vector<U> map(F&& xform) const
|
|
|
|
|
{
|
|
|
|
|
std::vector<U> result;
|
|
|
|
|
result.reserve(size());
|
|
|
|
|
|
|
|
|
|
for (auto it = begin(); it != end(); ++it)
|
|
|
|
|
{
|
|
|
|
|
result.push_back(xform(*it));
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-17 01:17:57 +01:00
|
|
|
template <typename F, typename U>
|
|
|
|
|
requires std::is_invocable_r_v<U, F, const U&, const Ty&>
|
|
|
|
|
U reduce(U initial_value, F&& reducer) const
|
|
|
|
|
{
|
|
|
|
|
U accumulate = initial_value;
|
|
|
|
|
for (auto it = begin(); it != end(); ++it)
|
|
|
|
|
{
|
|
|
|
|
accumulate = reducer(accumulate, *it);
|
|
|
|
|
}
|
|
|
|
|
return accumulate;
|
|
|
|
|
}
|
2021-09-17 22:01:53 +02:00
|
|
|
};
|
|
|
|
|
}
|