[+] 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 flagReadError : 1 {};
AuUInt8 flagWriteError : 1 {}; AuUInt8 flagWriteError : 1 {};
AuUInt8 flagNoFree : 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 // TODO: flag: allow circular overrun to allow for 100% access of the buffer from either read head
// - implicit padding // - implicit padding
AuUInt8 scaleSize {};// AuUInt8 scaleSize {};//
@ -90,24 +94,25 @@ namespace Aurora::Memory
*/ */
inline ByteBuffer(ByteBuffer &&buffer) inline ByteBuffer(ByteBuffer &&buffer)
{ {
this->base = buffer.base; this->base = buffer.base;
this->length = buffer.length; this->length = buffer.length;
this->allocSize = buffer.length; this->allocSize = buffer.length;
this->writePtr = this->base + (buffer.writePtr - buffer.base); this->writePtr = this->base + (buffer.writePtr - buffer.base);
this->readPtr = this->base + (buffer.readPtr - buffer.base); this->readPtr = this->base + (buffer.readPtr - buffer.base);
this->flagCircular = buffer.flagCircular; this->flagCircular = buffer.flagCircular;
this->flagExpandable = buffer.flagExpandable; this->flagExpandable = buffer.flagExpandable;
this->scaleSize = buffer.scaleSize; this->scaleSize = buffer.scaleSize;
this->flagReadError = buffer.flagReadError; this->flagReadError = buffer.flagReadError;
this->flagWriteError = buffer.flagWriteError; this->flagWriteError = buffer.flagWriteError;
buffer.base = {}; buffer.base = {};
buffer.length = {}; buffer.length = {};
buffer.allocSize = {}; buffer.allocSize = {};
buffer.writePtr = {}; buffer.writePtr = {};
buffer.readPtr = {}; buffer.readPtr = {};
buffer.flagCircular = {}; buffer.flagCircular = {};
buffer.flagExpandable = {}; buffer.flagExpandable = {};
buffer.scaleSize = {}; buffer.flagAlwaysExpandable = {};
buffer.scaleSize = {};
} }
/** /**
@ -124,6 +129,7 @@ namespace Aurora::Memory
this->scaleSize = buffer.scaleSize; this->scaleSize = buffer.scaleSize;
this->flagCircular = buffer.flagCircular; this->flagCircular = buffer.flagCircular;
this->flagExpandable = buffer.flagExpandable; this->flagExpandable = buffer.flagExpandable;
this->flagAlwaysExpandable = buffer.flagAlwaysExpandable;
if (!this->base) if (!this->base)
{ {
Reset(); Reset();
@ -291,27 +297,29 @@ namespace Aurora::Memory
* @brief base of the bytebuffer * @brief base of the bytebuffer
* @return * @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) * @brief size of the byte array as requested by the caller (actual allocation may differ, ::allocSize)
* @return * @return
*/ */
inline auline AuUInt size() const; inline auline AuUInt size() const;
/** /**
* @brief linear read begin * @brief linear read begin
* @warning writers should use ::GetLinearWriteable(uDesiredLength) or ::GetOrAllocateLinearWriteable(...) * @warning writers should use ::GetLinearWriteable(uDesiredLength) or ::GetOrAllocateLinearWriteable(...)
* @return * @return
*/ */
inline auline const AuUInt8 * begin() const; inline auline const AuUInt8 * begin();
inline auline const AuUInt8 * cbegin() const;
/** /**
* @brief linear read end * @brief linear read end
* @warning writers should use ::GetLinearWriteable(uDesiredLength) or ::GetOrAllocateLinearWriteable(...) * @warning writers should use ::GetLinearWriteable(uDesiredLength) or ::GetOrAllocateLinearWriteable(...)
* @return * @return
*/ */
inline auline const AuUInt8 * end() const; inline auline const AuUInt8 * end();
inline auline const AuUInt8 * cend() const;
inline auline bool empty() const; inline auline bool empty() const;
@ -372,14 +380,52 @@ namespace Aurora::Memory
inline auline bool CanWrite(AuUInt length); inline auline bool CanWrite(AuUInt length);
inline auline bool CanRead(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); inline auline MemoryViewRead GetLinearReadable(AuUInt length);
/// legacy: ForExactly variant
inline auline MemoryViewWrite GetLinearWriteable(AuUInt length); inline auline MemoryViewWrite GetLinearWriteable(AuUInt length);
/** /**
* @brief Used to write into existing linear space (writing into a stream or preallocated packet) * @brief Long story short, AuList<AuUInt8> ~= std::vector<AuUInt8>:
* or allocates the linear space if permitted (eg: a default constructor call would allow this). * 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
* This is used to create APIs that accept an input bytebuffer write parameter over write view based apis. * 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 * @param length
* @return * @return
*/ */

View File

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

View File

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

View File

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

View File

@ -19,7 +19,8 @@ namespace Aurora::Memory
{ {
auto readView = buffer.GetNextLinearRead(); 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); this->Resize((this->writePtr - this->base) + readView.length);
} }

View File

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