mirror of https://github.com/PCSX2/pcsx2.git
Common: Update FixedArray.h from DuckStation
This commit is contained in:
parent
299fd3d5ad
commit
907ae642d0
|
@ -1,13 +1,18 @@
|
||||||
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
|
// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com>, 2024 PCSX2 Dev Team
|
||||||
// SPDX-License-Identifier: LGPL-3.0+
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/Assertions.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstring>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
template <typename T, std::size_t SIZE>
|
template <typename T, std::size_t SIZE, std::size_t ALIGNMENT = 0>
|
||||||
class HeapArray
|
class FixedHeapArray
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
using value_type = T;
|
using value_type = T;
|
||||||
|
@ -17,23 +22,23 @@ public:
|
||||||
using const_reference = const T&;
|
using const_reference = const T&;
|
||||||
using pointer = T*;
|
using pointer = T*;
|
||||||
using const_pointer = const T*;
|
using const_pointer = const T*;
|
||||||
using this_type = HeapArray<T, SIZE>;
|
using this_type = FixedHeapArray<T, SIZE>;
|
||||||
|
|
||||||
HeapArray() { m_data = new T[SIZE]; }
|
FixedHeapArray() { allocate(); }
|
||||||
|
|
||||||
HeapArray(const this_type& copy)
|
FixedHeapArray(const this_type& copy)
|
||||||
{
|
{
|
||||||
m_data = new T[SIZE];
|
allocate();
|
||||||
std::copy(copy.cbegin(), copy.cend(), begin());
|
std::copy(copy.cbegin(), copy.cend(), begin());
|
||||||
}
|
}
|
||||||
|
|
||||||
HeapArray(this_type&& move)
|
FixedHeapArray(this_type&& move)
|
||||||
{
|
{
|
||||||
m_data = move.m_data;
|
m_data = move.m_data;
|
||||||
move.m_data = nullptr;
|
move.m_data = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
~HeapArray() { delete[] m_data; }
|
~FixedHeapArray() { deallocate(); }
|
||||||
|
|
||||||
size_type size() const { return SIZE; }
|
size_type size() const { return SIZE; }
|
||||||
size_type capacity() const { return SIZE; }
|
size_type capacity() const { return SIZE; }
|
||||||
|
@ -76,7 +81,7 @@ public:
|
||||||
|
|
||||||
this_type& operator=(this_type&& move)
|
this_type& operator=(this_type&& move)
|
||||||
{
|
{
|
||||||
delete[] m_data;
|
deallocate();
|
||||||
m_data = move.m_data;
|
m_data = move.m_data;
|
||||||
move.m_data = nullptr;
|
move.m_data = nullptr;
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -102,5 +107,291 @@ public:
|
||||||
#undef RELATIONAL_OPERATOR
|
#undef RELATIONAL_OPERATOR
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void allocate()
|
||||||
|
{
|
||||||
|
if constexpr (ALIGNMENT > 0)
|
||||||
|
{
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
m_data = static_cast<T*>(_aligned_malloc(SIZE * sizeof(T), ALIGNMENT));
|
||||||
|
if (!m_data)
|
||||||
|
pxFailRel("Memory allocation failed.");
|
||||||
|
#else
|
||||||
|
if (posix_memalign(reinterpret_cast<void**>(&m_data), ALIGNMENT, SIZE * sizeof(T)) != 0)
|
||||||
|
pxFailRel("Memory allocation failed.");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_data = static_cast<T*>(std::malloc(SIZE * sizeof(T)));
|
||||||
|
if (!m_data)
|
||||||
|
pxFailRel("Memory allocation failed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void deallocate()
|
||||||
|
{
|
||||||
|
if constexpr (ALIGNMENT > 0)
|
||||||
|
{
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
_aligned_free(m_data);
|
||||||
|
#else
|
||||||
|
std::free(m_data);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::free(m_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
T* m_data;
|
T* m_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T, size_t alignment = 0>
|
||||||
|
class DynamicHeapArray
|
||||||
|
{
|
||||||
|
static_assert(std::is_trivially_copyable_v<T>, "T is trivially copyable");
|
||||||
|
static_assert(std::is_standard_layout_v<T>, "T is standard layout");
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type = T;
|
||||||
|
using size_type = std::size_t;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using reference = T&;
|
||||||
|
using const_reference = const T&;
|
||||||
|
using pointer = T*;
|
||||||
|
using const_pointer = const T*;
|
||||||
|
using this_type = DynamicHeapArray<T>;
|
||||||
|
|
||||||
|
DynamicHeapArray()
|
||||||
|
: m_data(nullptr)
|
||||||
|
, m_size(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
DynamicHeapArray(size_t size) { internal_resize(size, nullptr, 0); }
|
||||||
|
DynamicHeapArray(const T* begin, const T* end)
|
||||||
|
{
|
||||||
|
const size_t size = reinterpret_cast<const char*>(end) - reinterpret_cast<const char*>(begin);
|
||||||
|
if (size > 0)
|
||||||
|
{
|
||||||
|
internal_resize(size / sizeof(T), nullptr, 0);
|
||||||
|
std::memcpy(m_data, begin, size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_data = nullptr;
|
||||||
|
m_size = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DynamicHeapArray(const T* begin, size_t count)
|
||||||
|
{
|
||||||
|
if (count > 0)
|
||||||
|
{
|
||||||
|
internal_resize(count, nullptr, 0);
|
||||||
|
std::memcpy(m_data, begin, sizeof(T) * count);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_data = nullptr;
|
||||||
|
m_size = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicHeapArray(const this_type& copy)
|
||||||
|
{
|
||||||
|
if (copy.m_size > 0)
|
||||||
|
{
|
||||||
|
internal_resize(copy.m_size, nullptr, 0);
|
||||||
|
std::memcpy(m_data, copy.m_data, sizeof(T) * copy.m_size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_data = nullptr;
|
||||||
|
m_size = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicHeapArray(this_type&& move)
|
||||||
|
{
|
||||||
|
m_data = move.m_data;
|
||||||
|
m_size = move.m_size;
|
||||||
|
move.m_data = nullptr;
|
||||||
|
move.m_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
~DynamicHeapArray() { internal_deallocate(); }
|
||||||
|
|
||||||
|
size_type size() const { return m_size; }
|
||||||
|
size_type capacity() const { return m_size; }
|
||||||
|
bool empty() const { return (m_size == 0); }
|
||||||
|
|
||||||
|
pointer begin() { return m_data; }
|
||||||
|
pointer end() { return m_data + m_size; }
|
||||||
|
|
||||||
|
const_pointer data() const { return m_data; }
|
||||||
|
pointer data() { return m_data; }
|
||||||
|
|
||||||
|
const_pointer cbegin() const { return m_data; }
|
||||||
|
const_pointer cend() const { return m_data + m_size; }
|
||||||
|
|
||||||
|
const_reference operator[](size_type index) const
|
||||||
|
{
|
||||||
|
assert(index < m_size);
|
||||||
|
return m_data[index];
|
||||||
|
}
|
||||||
|
reference operator[](size_type index)
|
||||||
|
{
|
||||||
|
assert(index < m_size);
|
||||||
|
return m_data[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
const_reference front() const { return m_data[0]; }
|
||||||
|
const_reference back() const { return m_data[m_size - 1]; }
|
||||||
|
reference front() { return m_data[0]; }
|
||||||
|
reference back() { return m_data[m_size - 1]; }
|
||||||
|
|
||||||
|
void fill(const_reference value) { std::fill(begin(), end(), value); }
|
||||||
|
|
||||||
|
void swap(this_type& move) { std::swap(m_data, move.m_data); }
|
||||||
|
|
||||||
|
void resize(size_t new_size) { internal_resize(new_size, m_data, m_size); }
|
||||||
|
|
||||||
|
void deallocate()
|
||||||
|
{
|
||||||
|
internal_deallocate();
|
||||||
|
m_data = nullptr;
|
||||||
|
m_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void assign(const T* begin, const T* end)
|
||||||
|
{
|
||||||
|
const size_t size = reinterpret_cast<const char*>(end) - reinterpret_cast<const char*>(begin);
|
||||||
|
const size_t count = size / sizeof(T);
|
||||||
|
if (count > 0)
|
||||||
|
{
|
||||||
|
if (m_size != count)
|
||||||
|
{
|
||||||
|
internal_deallocate();
|
||||||
|
internal_resize(count, nullptr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(m_data, begin, size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
internal_deallocate();
|
||||||
|
|
||||||
|
m_data = nullptr;
|
||||||
|
m_size = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void assign(const T* begin, size_t count)
|
||||||
|
{
|
||||||
|
if (count > 0)
|
||||||
|
{
|
||||||
|
if (m_size != count)
|
||||||
|
{
|
||||||
|
internal_deallocate();
|
||||||
|
internal_resize(count, nullptr, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(m_data, begin, sizeof(T) * count);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
internal_deallocate();
|
||||||
|
|
||||||
|
m_data = nullptr;
|
||||||
|
m_size = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void assign(const this_type& copy) { assign(copy.m_data, copy.m_size); }
|
||||||
|
void assign(this_type&& move)
|
||||||
|
{
|
||||||
|
internal_deallocate();
|
||||||
|
m_data = move.m_data;
|
||||||
|
m_size = move.m_size;
|
||||||
|
move.m_data = nullptr;
|
||||||
|
move.m_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
this_type& operator=(const this_type& rhs)
|
||||||
|
{
|
||||||
|
assign(rhs);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
this_type& operator=(this_type&& move)
|
||||||
|
{
|
||||||
|
assign(std::move(move));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RELATIONAL_OPERATOR(op, size_op) \
|
||||||
|
bool operator op(const this_type& rhs) const \
|
||||||
|
{ \
|
||||||
|
if (m_size != rhs.m_size) \
|
||||||
|
return m_size size_op rhs.m_size; \
|
||||||
|
for (size_type i = 0; i < m_size; i++) \
|
||||||
|
{ \
|
||||||
|
if (!(m_data[i] op rhs.m_data[i])) \
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
RELATIONAL_OPERATOR(==, !=);
|
||||||
|
RELATIONAL_OPERATOR(!=, ==);
|
||||||
|
RELATIONAL_OPERATOR(<, <);
|
||||||
|
RELATIONAL_OPERATOR(<=, <=);
|
||||||
|
RELATIONAL_OPERATOR(>, >);
|
||||||
|
RELATIONAL_OPERATOR(>=, >=);
|
||||||
|
|
||||||
|
#undef RELATIONAL_OPERATOR
|
||||||
|
|
||||||
|
private:
|
||||||
|
void internal_resize(size_t size, T* prev_ptr, size_t prev_size)
|
||||||
|
{
|
||||||
|
if constexpr (alignment > 0)
|
||||||
|
{
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
m_data = static_cast<T*>(_aligned_realloc(prev_ptr, size * sizeof(T), alignment));
|
||||||
|
if (!m_data)
|
||||||
|
pxFailRel("Memory allocation failed.");
|
||||||
|
#else
|
||||||
|
if (posix_memalign(reinterpret_cast<void**>(&m_data), alignment, size * sizeof(T)) != 0)
|
||||||
|
pxFailRel("Memory allocation failed.");
|
||||||
|
|
||||||
|
if (prev_ptr)
|
||||||
|
{
|
||||||
|
std::memcpy(m_data, prev_ptr, prev_size * sizeof(T));
|
||||||
|
std::free(prev_ptr);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_data = static_cast<T*>(std::realloc(prev_ptr, size * sizeof(T)));
|
||||||
|
if (!m_data)
|
||||||
|
pxFailRel("Memory allocation failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_size = size;
|
||||||
|
}
|
||||||
|
void internal_deallocate()
|
||||||
|
{
|
||||||
|
if constexpr (alignment > 0)
|
||||||
|
{
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
_aligned_free(m_data);
|
||||||
|
#else
|
||||||
|
std::free(m_data);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::free(m_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
T* m_data;
|
||||||
|
size_t m_size;
|
||||||
|
};
|
||||||
|
|
|
@ -183,8 +183,14 @@ public:
|
||||||
DoArray(data->data(), data->size());
|
DoArray(data->data(), data->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, size_t N>
|
template <typename T, size_t N, size_t A>
|
||||||
void Do(HeapArray<T, N>* data)
|
void Do(FixedHeapArray<T, N, A>* data)
|
||||||
|
{
|
||||||
|
DoArray(data->data(), data->size());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, size_t A>
|
||||||
|
void Do(DynamicHeapArray<T, A>* data)
|
||||||
{
|
{
|
||||||
DoArray(data->data(), data->size());
|
DoArray(data->data(), data->size());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue