[+] Futureproofing: AuByteBuffer flag

This commit is contained in:
Reece Wilson 2023-06-10 21:47:37 +01:00
parent 4a584ce73a
commit 98c1235554
6 changed files with 137 additions and 36 deletions

View File

@ -79,6 +79,10 @@ namespace Aurora::Memory
AuUInt8 flagReadError : 1 {};
AuUInt8 flagWriteError : 1 {};
AuUInt8 flagNoFree : 1 {};
AuUInt8 flagAlwaysExpandable : 1 {}; // it's a long story from how we got from string views to std::vector<std::uint8_t>s to current day AuByteBuffer.
// anyway long story short, if you want a buffered api to write into us linearly and grow, enable me.
// if you just want ::Write and similar functions to work keem me false and enable flagExpandable.
// flagExpandable is for when the default constructor is called. i'm for apis that use us as an interface to grow.
// TODO: flag: allow circular overrun to allow for 100% access of the buffer from either read head
// - implicit padding
AuUInt8 scaleSize {};//
@ -90,24 +94,25 @@ namespace Aurora::Memory
*/
inline ByteBuffer(ByteBuffer &&buffer)
{
this->base = buffer.base;
this->length = buffer.length;
this->allocSize = buffer.length;
this->writePtr = this->base + (buffer.writePtr - buffer.base);
this->readPtr = this->base + (buffer.readPtr - buffer.base);
this->flagCircular = buffer.flagCircular;
this->flagExpandable = buffer.flagExpandable;
this->scaleSize = buffer.scaleSize;
this->flagReadError = buffer.flagReadError;
this->flagWriteError = buffer.flagWriteError;
buffer.base = {};
buffer.length = {};
buffer.allocSize = {};
buffer.writePtr = {};
buffer.readPtr = {};
buffer.flagCircular = {};
buffer.flagExpandable = {};
buffer.scaleSize = {};
this->base = buffer.base;
this->length = buffer.length;
this->allocSize = buffer.length;
this->writePtr = this->base + (buffer.writePtr - buffer.base);
this->readPtr = this->base + (buffer.readPtr - buffer.base);
this->flagCircular = buffer.flagCircular;
this->flagExpandable = buffer.flagExpandable;
this->scaleSize = buffer.scaleSize;
this->flagReadError = buffer.flagReadError;
this->flagWriteError = buffer.flagWriteError;
buffer.base = {};
buffer.length = {};
buffer.allocSize = {};
buffer.writePtr = {};
buffer.readPtr = {};
buffer.flagCircular = {};
buffer.flagExpandable = {};
buffer.flagAlwaysExpandable = {};
buffer.scaleSize = {};
}
/**
@ -124,6 +129,7 @@ namespace Aurora::Memory
this->scaleSize = buffer.scaleSize;
this->flagCircular = buffer.flagCircular;
this->flagExpandable = buffer.flagExpandable;
this->flagAlwaysExpandable = buffer.flagAlwaysExpandable;
if (!this->base)
{
Reset();
@ -291,27 +297,29 @@ namespace Aurora::Memory
* @brief base of the bytebuffer
* @return
*/
inline auline AuUInt8 * data() const;
inline auline AuUInt8 * data() const;
/**
* @brief size of the byte array as requested by the caller (actual allocation may differ, ::allocSize)
* @return
*/
inline auline AuUInt size() const;
inline auline AuUInt size() const;
/**
* @brief linear read begin
* @warning writers should use ::GetLinearWriteable(uDesiredLength) or ::GetOrAllocateLinearWriteable(...)
* @return
*/
inline auline const AuUInt8 * begin() const;
inline auline const AuUInt8 * begin();
inline auline const AuUInt8 * cbegin() const;
/**
* @brief linear read end
* @warning writers should use ::GetLinearWriteable(uDesiredLength) or ::GetOrAllocateLinearWriteable(...)
* @return
*/
inline auline const AuUInt8 * end() const;
inline auline const AuUInt8 * end();
inline auline const AuUInt8 * cend() const;
inline auline bool empty() const;
@ -372,14 +380,52 @@ namespace Aurora::Memory
inline auline bool CanWrite(AuUInt length);
inline auline bool CanRead(AuUInt length);
/**
* @brief Returns a linear amount of memory for exactly length of linear bytes
* @param length
* @return
*/
inline auline MemoryViewRead GetLinearReadableForExactly(AuUInt length)
{
return GetLinearReadable(length);
}
inline auline MemoryViewWrite GetLinearWriteableForExactly(AuUInt length)
{
return GetLinearWriteable(length);
}
/**
* @brief Returns a linear amount of memory of at least length
* @param length
* @return
*/
inline auline MemoryViewRead GetLinearReadableForAtleast(AuUInt length);
inline auline MemoryViewWrite GetLinearWriteableForAtleast(AuUInt length);
/**
* @brief Returns a linear amount of memory capped to length
* @param length
* @return
*/
inline auline MemoryViewRead GetLinearReadableForNoMore(AuUInt length);
inline auline MemoryViewWrite GetLinearWriteableForNoMore(AuUInt length);
/// legacy: ForExactly variant
inline auline MemoryViewRead GetLinearReadable(AuUInt length);
/// legacy: ForExactly variant
inline auline MemoryViewWrite GetLinearWriteable(AuUInt length);
/**
* @brief Used to write into existing linear space (writing into a stream or preallocated packet)
* or allocates the linear space if permitted (eg: a default constructor call would allow this).
*
* This is used to create APIs that accept an input bytebuffer write parameter over write view based apis.
* @brief Long story short, AuList<AuUInt8> ~= std::vector<AuUInt8>:
* AuByteBuffer should be (was) a drag and drop replacement for trash code that uses lists as bytebuffers. This is opposed to ye old std::string contains anything buffers.
* Either way, to the point, AuByteBuffer's default constructor is to allow for expandability on Write. GetOrAllocateLinearWriteable is used by certain parse APIs to
* expand ONCE into a buffer that is uninitialized. Should the caller setup the AuByteBuffer, preallocate a runway, etc, etc, GetOrAllocateLinearWriteable will run on
* the memory - the read/write heads of the already setup buffer.
* Otherwise, the default constructor shall allow this to ALLOCATE ONCE given a buffer in an uninitialized/!IsValid()/!refByteBuffer state.
* @param length
* @return
*/

View File

@ -333,15 +333,56 @@ namespace Aurora::Memory
return this->RemainingBytes(true) >= length;
}
MemoryViewRead ByteBuffer::GetLinearReadableForAtleast(AuUInt length)
{
auto view = this->GetNextLinearRead();
return view.length < length ? MemoryViewRead {} : MemoryViewRead(view.ptr, view.length);
}
MemoryViewWrite ByteBuffer::GetLinearWriteableForAtleast(AuUInt length)
{
auto view = this->GetNextLinearWrite();
if (this->flagAlwaysExpandable &&
(view.length < length))
{
return this->GetOrAllocateLinearWriteable(length);
}
return view.length < length ? MemoryViewWrite {} : MemoryViewWrite(view.ptr, view.length);
}
MemoryViewRead ByteBuffer::GetLinearReadableForNoMore(AuUInt length)
{
auto view = this->GetNextLinearRead();
return MemoryViewRead(view.ptr, AuMin(view.length, length));
}
MemoryViewWrite ByteBuffer::GetLinearWriteableForNoMore(AuUInt length)
{
auto view = this->GetNextLinearWrite();
if (this->flagAlwaysExpandable &&
(view.length < length))
{
return this->GetOrAllocateLinearWriteable(length);
}
return MemoryViewWrite(view.ptr, AuMin(view.length, length));
}
/* exactly */
MemoryViewRead ByteBuffer::GetLinearReadable(AuUInt length)
{
auto view = this->GetNextLinearRead();
return view.length < length ? MemoryViewRead {} : MemoryViewRead(view.ptr, length);
}
/* exactly */
MemoryViewWrite ByteBuffer::GetLinearWriteable(AuUInt length)
{
auto view = this->GetNextLinearWrite();
if (this->flagAlwaysExpandable &&
(view.length < length))
{
return this->GetOrAllocateLinearWriteable(length);
}
return view.length < length ? MemoryViewWrite {} : MemoryViewWrite(view.ptr, length);
}
@ -351,7 +392,7 @@ namespace Aurora::Memory
{
return this->GetLinearWriteable(length);
}
else if (!this->flagCircular && this->length == 0 && this->flagExpandable)
else if (!this->flagCircular && ((this->length == 0 && this->flagExpandable) || this->flagAlwaysExpandable))
{
if (!this->Resize(length))
{

View File

@ -92,7 +92,7 @@ namespace Aurora::Memory
if ((len != requestLength))
{
if ((flagExpandable))
if ((this->flagExpandable || this->flagAlwaysExpandable))
{
if (!Resize(offset + requestLength))
{

View File

@ -41,8 +41,8 @@ namespace Aurora::Memory
AuUInt8 &ByteBuffer::operator [](AuUInt idx) const
{
auto pBegin = (AuUInt8 *)this->begin(); // intentionally returning a volatile reference
auto pEnd = this->end();
auto pBegin = (AuUInt8 *)this->cbegin(); // intentionally returning a volatile reference
auto pEnd = this->cend();
SysAssert(idx < (AuUInt)(pEnd - pBegin));
return *(pBegin + idx);
}
@ -62,7 +62,7 @@ namespace Aurora::Memory
return IsEmpty();
}
const AuUInt8 *ByteBuffer::begin() const
const AuUInt8 *ByteBuffer::cbegin() const
{
if (this->flagCircular)
{
@ -75,7 +75,12 @@ namespace Aurora::Memory
return this->readPtr;
}
const AuUInt8 *ByteBuffer::end() const
const AuUInt8 *ByteBuffer::begin()
{
return cbegin();
}
const AuUInt8 *ByteBuffer::cend() const
{
AuUInt8 *pBase {};
AuUInt uCount {};
@ -132,6 +137,11 @@ namespace Aurora::Memory
return uCount + pBase;
}
const AuUInt8 *ByteBuffer::end()
{
return cend();
}
AuUInt32 ByteBuffer::GetAllocationPower() const
{
return AuUInt32(1) << (AuUInt32(this->scaleSize));
@ -139,7 +149,7 @@ namespace Aurora::Memory
ByteBuffer::operator MemoryViewRead() const
{
return MemoryViewRead(begin(), end());
return MemoryViewRead(cbegin(), cend());
}
ByteBuffer::operator MemoryViewWrite()
@ -177,7 +187,7 @@ namespace Aurora::Memory
bool ByteBuffer::IsValid() const
{
return (!IsEmpty() || this->flagExpandable) && !HasStreamError();
return (!IsEmpty() || (this->flagExpandable || this->flagAlwaysExpandable)) && !HasStreamError();
}
bool ByteBuffer::IsEmpty() const
@ -195,6 +205,7 @@ namespace Aurora::Memory
this->readPtr = this->base + (other.readPtr - other.base);
this->flagCircular = other.flagCircular;
this->flagExpandable = other.flagExpandable;
this->flagAlwaysExpandable = other.flagAlwaysExpandable;
this->scaleSize = other.scaleSize;
other.base = {};
other.length = {};
@ -203,6 +214,7 @@ namespace Aurora::Memory
other.readPtr = {};
other.flagCircular = {};
other.flagExpandable = {};
other.flagAlwaysExpandable = {};
other.scaleSize = {};
return *this;
}
@ -230,6 +242,7 @@ namespace Aurora::Memory
AuMemcpy(this->base, buffer.base, this->length);
this->flagCircular = buffer.flagCircular;
this->flagExpandable = buffer.flagExpandable;
this->flagAlwaysExpandable = buffer.flagAlwaysExpandable;
this->scaleSize = buffer.scaleSize;
return *this;
}

View File

@ -19,7 +19,8 @@ namespace Aurora::Memory
{
auto readView = buffer.GetNextLinearRead();
if (this->flagExpandable && !this->CanWrite(readView.length))
if ((this->flagExpandable || this->flagAlwaysExpandable) &&
!this->CanWrite(readView.length))
{
this->Resize((this->writePtr - this->base) + readView.length);
}

View File

@ -45,7 +45,7 @@ namespace Aurora::Compression
{
if (auto pBuffer = pThat->GetWeakBuffer())
{
auto view = pBuffer->GetLinearReadable(dwAmount);
auto view = pBuffer->GetLinearReadableForNoMore(dwAmount);
in = (T *)view.ptr;
inAlreadyAvailable = view.length;
pBuffer->readPtr += view.length;