mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-07-03 21:41:26 +12:00
rsx: Improve simple array performance for small objects
- Also adds map/collect transformation
This commit is contained in:
parent
e17c2f2397
commit
12dc03a903
1 changed files with 101 additions and 15 deletions
|
@ -6,7 +6,8 @@
|
||||||
|
|
||||||
namespace rsx
|
namespace rsx
|
||||||
{
|
{
|
||||||
template <typename Ty> requires std::is_trivially_destructible_v<Ty>
|
template <typename Ty>
|
||||||
|
requires std::is_trivially_destructible_v<Ty>
|
||||||
struct simple_array
|
struct simple_array
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -15,15 +16,23 @@ namespace rsx
|
||||||
using value_type = Ty;
|
using value_type = Ty;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
u32 _capacity = 0;
|
static constexpr u32 _local_capacity = std::max<u32>(64u / sizeof(Ty), 1u);
|
||||||
|
Ty _local_storage[_local_capacity];
|
||||||
|
|
||||||
|
u32 _capacity = _local_capacity;
|
||||||
|
Ty* _data = _local_capacity ? _local_storage : nullptr;
|
||||||
u32 _size = 0;
|
u32 _size = 0;
|
||||||
Ty* _data = nullptr;
|
|
||||||
|
|
||||||
inline u64 offset(const_iterator pos)
|
inline u64 offset(const_iterator pos)
|
||||||
{
|
{
|
||||||
return (_data) ? u64(pos - _data) : 0ull;
|
return (_data) ? u64(pos - _data) : 0ull;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_local_storage() const
|
||||||
|
{
|
||||||
|
return _data == _local_storage;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
simple_array() = default;
|
simple_array() = default;
|
||||||
|
|
||||||
|
@ -56,12 +65,12 @@ namespace rsx
|
||||||
|
|
||||||
simple_array(const simple_array& other)
|
simple_array(const simple_array& other)
|
||||||
{
|
{
|
||||||
_capacity = other._capacity;
|
resize(other._size);
|
||||||
_size = other._size;
|
|
||||||
|
|
||||||
const auto size_bytes = sizeof(Ty) * _capacity;
|
if (_size)
|
||||||
_data = static_cast<Ty*>(malloc(size_bytes));
|
{
|
||||||
std::memcpy(_data, other._data, size_bytes);
|
std::memcpy(_data, other._data, size_bytes());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
simple_array(simple_array&& other) noexcept
|
simple_array(simple_array&& other) noexcept
|
||||||
|
@ -73,7 +82,12 @@ namespace rsx
|
||||||
{
|
{
|
||||||
if (&other != this)
|
if (&other != this)
|
||||||
{
|
{
|
||||||
simple_array{ other }.swap(*this);
|
resize(other._size);
|
||||||
|
|
||||||
|
if (_size)
|
||||||
|
{
|
||||||
|
std::memcpy(_data, other._data, size_bytes());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
|
@ -88,26 +102,86 @@ namespace rsx
|
||||||
~simple_array()
|
~simple_array()
|
||||||
{
|
{
|
||||||
if (_data)
|
if (_data)
|
||||||
|
{
|
||||||
|
if (!is_local_storage())
|
||||||
{
|
{
|
||||||
free(_data);
|
free(_data);
|
||||||
|
}
|
||||||
|
|
||||||
_data = nullptr;
|
_data = nullptr;
|
||||||
_size = _capacity = 0;
|
_size = _capacity = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void swap(simple_array<Ty>& other) noexcept
|
void swap(simple_array<Ty>& that) noexcept
|
||||||
{
|
{
|
||||||
std::swap(_capacity, other._capacity);
|
if (!_size && !that._size)
|
||||||
std::swap(_size, other._size);
|
{
|
||||||
std::swap(_data, other._data);
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use memcpy to allow compiler optimizations
|
||||||
|
Ty _stack_alloc[_local_capacity];
|
||||||
|
std::memcpy(_stack_alloc, that._local_storage, that.size_bytes());
|
||||||
|
std::memcpy(that._local_storage, _local_storage, size_bytes());
|
||||||
|
std::memcpy(_local_storage, _stack_alloc, that.size_bytes());
|
||||||
|
std::swap(_size, that._size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void reserve(u32 size)
|
void reserve(u32 size)
|
||||||
{
|
{
|
||||||
if (_capacity >= size)
|
if (_capacity >= size)
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_local_storage())
|
||||||
|
{
|
||||||
|
// Switch to heap storage
|
||||||
|
_data = static_cast<Ty*>(std::malloc(sizeof(Ty) * size));
|
||||||
|
std::memcpy(_data, _local_storage, size_bytes());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Extend heap storage
|
||||||
ensure(_data = static_cast<Ty*>(std::realloc(_data, sizeof(Ty) * size))); // "realloc() failed!"
|
ensure(_data = static_cast<Ty*>(std::realloc(_data, sizeof(Ty) * size))); // "realloc() failed!"
|
||||||
|
}
|
||||||
|
|
||||||
_capacity = size;
|
_capacity = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,5 +409,17 @@ namespace rsx
|
||||||
|
|
||||||
std::sort(begin(), end(), predicate);
|
std::sort(begin(), end(), predicate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename F, typename U = std::invoke_result<F, const Ty&>::type>
|
||||||
|
requires std::is_invocable_v<F, const Ty&>
|
||||||
|
simple_array<U> map(F&& xform) const
|
||||||
|
{
|
||||||
|
simple_array<U> result(size());
|
||||||
|
for (auto it = begin(); it != end(); ++it)
|
||||||
|
{
|
||||||
|
result.push_back(xform(*it));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue