mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-25 15:54:31 +01:00
Cleanup MemoryStream code (#22593)
* Deduplicate code, use std::bit_ceil to compute new capacity * Remove unused constructor overload * Remove more unused functions * Fix memory leak using assignment operator with move * Make access explicit via constness, do not allow arbitrary access * Move the template specialized Write/Read to private section * Simplify a lot of code by using the right types * Fix copy constructor * Directly copy the member in copy constructor * Fix little mistake * Pluck a memory leak on Android, fix the build * Update changelog.txt
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "Memory.hpp"
|
||||
|
||||
#include <bit>
|
||||
#include <cstring>
|
||||
|
||||
namespace OpenRCT2
|
||||
@@ -20,44 +21,53 @@ namespace OpenRCT2
|
||||
_access = copy._access;
|
||||
_dataCapacity = copy._dataCapacity;
|
||||
_dataSize = copy._dataSize;
|
||||
_position = copy._position;
|
||||
|
||||
if (_access & MEMORY_ACCESS::OWNER)
|
||||
{
|
||||
_data = Memory::Allocate<void>(_dataCapacity);
|
||||
// Create a copy when the memory stream owns the memory.
|
||||
_data = Memory::Allocate<std::byte>(_dataCapacity);
|
||||
std::memcpy(_data, copy._data, _dataCapacity);
|
||||
_position = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(_data) + copy.GetPosition());
|
||||
}
|
||||
else
|
||||
{
|
||||
// External pointer.
|
||||
_data = copy._data;
|
||||
}
|
||||
}
|
||||
|
||||
MemoryStream::MemoryStream(size_t capacity)
|
||||
{
|
||||
_dataCapacity = capacity;
|
||||
_data = Memory::Allocate<void>(capacity);
|
||||
_position = _data;
|
||||
_data = Memory::Allocate<std::byte>(capacity);
|
||||
_position = 0;
|
||||
}
|
||||
|
||||
MemoryStream::MemoryStream(void* data, size_t dataSize, uint8_t access)
|
||||
MemoryStream::MemoryStream(void* data, size_t dataSize)
|
||||
: _access{ MEMORY_ACCESS::READ | MEMORY_ACCESS::WRITE }
|
||||
, _dataCapacity{ dataSize }
|
||||
, _dataSize{ dataSize }
|
||||
, _data{ static_cast<std::byte*>(data) }
|
||||
, _position{ 0 }
|
||||
{
|
||||
_access = access;
|
||||
_dataCapacity = dataSize;
|
||||
_dataSize = dataSize;
|
||||
_data = data;
|
||||
_position = _data;
|
||||
}
|
||||
|
||||
MemoryStream::MemoryStream(const void* data, size_t dataSize)
|
||||
: MemoryStream(const_cast<void*>(data), dataSize, MEMORY_ACCESS::READ)
|
||||
: _access{ MEMORY_ACCESS::READ }
|
||||
, _dataCapacity{ dataSize }
|
||||
, _dataSize{ dataSize }
|
||||
, _data{ static_cast<std::byte*>(const_cast<void*>(data)) }
|
||||
, _position{ 0 }
|
||||
{
|
||||
}
|
||||
|
||||
MemoryStream::MemoryStream(std::vector<uint8_t>&& v)
|
||||
MemoryStream::MemoryStream(const void* data, size_t dataSize, bool)
|
||||
: _access{ MEMORY_ACCESS::READ | MEMORY_ACCESS::OWNER }
|
||||
, _dataCapacity{ dataSize }
|
||||
, _dataSize{ dataSize }
|
||||
, _data{ static_cast<std::byte*>(const_cast<void*>(data)) }
|
||||
, _position{ 0 }
|
||||
{
|
||||
_access = MEMORY_ACCESS::OWNER;
|
||||
_dataCapacity = v.size();
|
||||
_dataSize = v.size();
|
||||
_data = Memory::Allocate<void>(v.size());
|
||||
_position = _data;
|
||||
std::memcpy(_data, v.data(), v.size());
|
||||
}
|
||||
|
||||
MemoryStream::MemoryStream(MemoryStream&& mv) noexcept
|
||||
@@ -68,7 +78,7 @@ namespace OpenRCT2
|
||||
, _position(mv._position)
|
||||
{
|
||||
mv._data = nullptr;
|
||||
mv._position = nullptr;
|
||||
mv._position = 0;
|
||||
mv._dataCapacity = 0;
|
||||
mv._dataSize = 0;
|
||||
}
|
||||
@@ -88,6 +98,11 @@ namespace OpenRCT2
|
||||
{
|
||||
if (this != &mv)
|
||||
{
|
||||
if (_access & MEMORY_ACCESS::OWNER)
|
||||
{
|
||||
Memory::Free(_data);
|
||||
}
|
||||
|
||||
_access = mv._access;
|
||||
_dataCapacity = mv._dataCapacity;
|
||||
_data = mv._data;
|
||||
@@ -95,7 +110,7 @@ namespace OpenRCT2
|
||||
_position = mv._position;
|
||||
|
||||
mv._data = nullptr;
|
||||
mv._position = nullptr;
|
||||
mv._position = 0;
|
||||
mv._dataCapacity = 0;
|
||||
mv._dataSize = 0;
|
||||
}
|
||||
@@ -105,20 +120,7 @@ namespace OpenRCT2
|
||||
|
||||
const void* MemoryStream::GetData() const
|
||||
{
|
||||
return _data;
|
||||
}
|
||||
|
||||
void* MemoryStream::GetDataCopy() const
|
||||
{
|
||||
auto result = Memory::Allocate<void>(_dataSize);
|
||||
std::memcpy(result, _data, _dataSize);
|
||||
return result;
|
||||
}
|
||||
|
||||
void* MemoryStream::TakeData()
|
||||
{
|
||||
_access &= ~MEMORY_ACCESS::OWNER;
|
||||
return _data;
|
||||
return static_cast<const void*>(_data);
|
||||
}
|
||||
|
||||
bool MemoryStream::CanRead() const
|
||||
@@ -138,7 +140,7 @@ namespace OpenRCT2
|
||||
|
||||
uint64_t MemoryStream::GetPosition() const
|
||||
{
|
||||
return static_cast<uint64_t>(reinterpret_cast<uintptr_t>(_position) - reinterpret_cast<uintptr_t>(_data));
|
||||
return _position;
|
||||
}
|
||||
|
||||
void MemoryStream::SetPosition(uint64_t position)
|
||||
@@ -167,19 +169,18 @@ namespace OpenRCT2
|
||||
{
|
||||
throw IOException("New position out of bounds.");
|
||||
}
|
||||
_position = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(_data) + static_cast<uintptr_t>(newPosition));
|
||||
_position = newPosition;
|
||||
}
|
||||
|
||||
void MemoryStream::Read(void* buffer, uint64_t length)
|
||||
{
|
||||
uint64_t position = GetPosition();
|
||||
if (position + length > _dataSize)
|
||||
if (_position + length > _dataSize)
|
||||
{
|
||||
throw IOException("Attempted to read past end of stream.");
|
||||
}
|
||||
|
||||
std::memcpy(buffer, _position, length);
|
||||
_position = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(_position) + length);
|
||||
std::memcpy(buffer, _data + _position, length);
|
||||
_position += length;
|
||||
}
|
||||
|
||||
void MemoryStream::Read1(void* buffer)
|
||||
@@ -217,23 +218,12 @@ namespace OpenRCT2
|
||||
|
||||
void MemoryStream::Write(const void* buffer, uint64_t length)
|
||||
{
|
||||
uint64_t position = GetPosition();
|
||||
uint64_t nextPosition = position + length;
|
||||
if (nextPosition > _dataCapacity)
|
||||
{
|
||||
if (_access & MEMORY_ACCESS::OWNER)
|
||||
{
|
||||
EnsureCapacity(static_cast<size_t>(nextPosition));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw IOException("Attempted to write past end of stream.");
|
||||
}
|
||||
}
|
||||
const auto nextPosition = _position + length;
|
||||
EnsureCapacity(nextPosition);
|
||||
|
||||
std::memcpy(_position, buffer, length);
|
||||
_position = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(_position) + length);
|
||||
_dataSize = std::max<size_t>(_dataSize, static_cast<size_t>(nextPosition));
|
||||
std::memcpy(_data + _position, buffer, length);
|
||||
_position += length;
|
||||
_dataSize = std::max<size_t>(_dataSize, nextPosition);
|
||||
}
|
||||
|
||||
void MemoryStream::Write1(const void* buffer)
|
||||
@@ -264,24 +254,25 @@ namespace OpenRCT2
|
||||
void MemoryStream::Clear()
|
||||
{
|
||||
_dataSize = 0;
|
||||
SetPosition(0);
|
||||
_position = 0;
|
||||
}
|
||||
|
||||
void MemoryStream::EnsureCapacity(size_t capacity)
|
||||
{
|
||||
if (_dataCapacity < capacity)
|
||||
if (capacity <= _dataCapacity)
|
||||
{
|
||||
size_t newCapacity = std::max<size_t>(8, _dataCapacity);
|
||||
while (newCapacity < capacity)
|
||||
{
|
||||
newCapacity *= 2;
|
||||
}
|
||||
|
||||
uint64_t position = GetPosition();
|
||||
_dataCapacity = newCapacity;
|
||||
_data = Memory::Reallocate(_data, _dataCapacity);
|
||||
_position = reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(_data) + static_cast<uintptr_t>(position));
|
||||
return;
|
||||
}
|
||||
|
||||
if ((_access & MEMORY_ACCESS::OWNER) == 0)
|
||||
{
|
||||
throw IOException("Can not grow external memory");
|
||||
}
|
||||
|
||||
size_t newCapacity = std::max<size_t>(32, std::bit_ceil(capacity));
|
||||
|
||||
_dataCapacity = newCapacity;
|
||||
_data = Memory::Reallocate(_data, _dataCapacity);
|
||||
}
|
||||
|
||||
} // namespace OpenRCT2
|
||||
|
||||
Reference in New Issue
Block a user