[+] AuMemory::SharedByteBuffer

[+] AuMemory::ByteBuffer.flagNoFree
[*] SetBuffer(MemoryViewRead readView, bool bMoveWriteHeadForReaders = true);
...added bMoveWriteHeadForReaders
[-] AuMemory::SetBuffer(const void *in, AuUInt length)
[-] AuMemory::SetBuffer(const AuList<AuUInt8> &buffer)
[*] Harden AuMemory::ByteBuffer::RemainingBytes bc it is a high level api that is not called excessively. Invalid head states should not mess with ::CanRead/::CanWrite
[*] Harden AuMemory::ByteBuffer::RemainingWrite bc it is a high level api that is not called excessively. Invalid head states should not mess with ::CanRead/::CanWrite
This commit is contained in:
Reece Wilson 2023-04-30 02:23:54 +01:00
parent e0d672ae9b
commit 37472e508e
3 changed files with 130 additions and 29 deletions

View File

@ -78,6 +78,7 @@ namespace Aurora::Memory
AuUInt8 flagReadError : 1 {};
AuUInt8 flagWriteError : 1 {};
AuUInt8 flagNoFree : 1 {};
// TODO: flag: allow circular overrun to allow for 100% access of the buffer from either read head
// - implicit padding
AuUInt8 scaleSize {};//
@ -388,9 +389,7 @@ namespace Aurora::Memory
inline auline bool Allocate(AuUInt length, bool fast = true);
inline auline bool Allocate(AuUInt length, AuUInt alignment, bool fast = true);
inline auline bool SetBuffer(MemoryViewRead readView);
inline auline bool SetBuffer(const void *in, AuUInt length);
inline auline bool SetBuffer(const AuList<AuUInt8> &buffer);
inline auline bool SetBuffer(MemoryViewRead readView, bool bMoveWriteHeadForReaders = true);
/**
* @brief Releases excess memory (like, shrink to fit in c++)
@ -481,4 +480,31 @@ namespace Aurora::Memory
{
return ByteBuffer(length, true, false);
}
struct SharedByteBuffer : ByteBuffer
{
AuSPtr<void> memory;
inline SharedByteBuffer(AuSPtr<MemoryViewWrite> pReadView) : ByteBuffer()
{
this->allocSize = 0;
this->base = (AuUInt8 *)pReadView->ptr;
this->length = pReadView->length;
this->readPtr = this->base;
this->writePtr = this->base + this->length;
this->flagNoFree = true;
this->memory = pReadView;
}
inline SharedByteBuffer(AuSPtr<void> pRAIIParentOwner, MemoryViewWrite view) : ByteBuffer()
{
this->allocSize = 0;
this->base = (AuUInt8 *)view.ptr;
this->length = view.length;
this->readPtr = this->base;
this->writePtr = this->base + this->length;
this->flagNoFree = true;
this->memory = pRAIIParentOwner;
}
};
}

View File

@ -11,6 +11,11 @@ namespace Aurora::Memory
{
bool ByteBuffer::Allocate(AuUInt length, bool fast)
{
if (this->flagNoFree)
{
return false;
}
if (this->base)
{
Free(this->base);
@ -40,6 +45,11 @@ namespace Aurora::Memory
bool ByteBuffer::Allocate(AuUInt length, AuUInt alignment, bool fast)
{
if (this->flagNoFree)
{
return false;
}
if (this->base)
{
Free(this->base);
@ -68,8 +78,13 @@ namespace Aurora::Memory
return true;
}
bool ByteBuffer::SetBuffer(MemoryViewRead readView)
bool ByteBuffer::SetBuffer(MemoryViewRead readView, bool bMoveWriteHeadForReaders)
{
if (this->flagNoFree)
{
return false;
}
if (!Allocate(readView.length))
{
return false;
@ -81,28 +96,19 @@ namespace Aurora::Memory
}
AuMemcpy(this->base, readView.ptr, this->length);
return true;
}
bool ByteBuffer::SetBuffer(const void *in, AuUInt length)
{
if (!Allocate(length))
if (bMoveWriteHeadForReaders)
{
return false;
this->readPtr = this->base;
this->writePtr = this->base + this->length;
}
AuMemcpy(this->base, in, this->length);
return true;
}
bool ByteBuffer::SetBuffer(const AuList<AuUInt8> &buffer)
{
return SetBuffer(buffer.data(), buffer.size());
}
void ByteBuffer::Reset()
{
if (this->base)
if (this->base && !this->flagNoFree)
{
Free(this->base);
this->base = {};
@ -128,6 +134,11 @@ namespace Aurora::Memory
void ByteBuffer::GC()
{
if (this->flagNoFree)
{
return;
}
if (!this->base)
{
return;
@ -151,6 +162,11 @@ namespace Aurora::Memory
bool ByteBuffer::Resize(AuUInt length)
{
if (this->flagNoFree)
{
return false;
}
AuUInt oldWriteIdx, oldReadIdx, oldLength, newLength;
AuUInt8 *nextRead, *nextWrite, *nextPtr;

View File

@ -97,20 +97,45 @@ namespace Aurora::Memory
AuUInt ByteBuffer::RemainingBytes(bool endAtWrite) const
{
if (flagCircular)
// sanity:
if (this->writePtr > this->base + this->length)
{
if (readPtr == writePtr)
return 0;
}
if (this->writePtr < this->base)
{
return 0;
}
if (this->readPtr > this->base + this->length)
{
return 0;
}
if (this->readPtr < this->base)
{
return 0;
}
/////////////
if (this->flagCircular)
{
if (this->readPtr == this->writePtr)
{
return 0;
}
else if ((readPtr < writePtr) && (endAtWrite))
else if ((this->readPtr < this->writePtr) && (endAtWrite))
{
return writePtr - readPtr;
return this->writePtr - this->readPtr;
}
else
{
auto linearOverhead = length - (readPtr - base);
auto toWriteOverhead = writePtr - base;
// you should be able to read the entirety of the buffer - writers cannot to prevent overflows
auto linearOverhead = this->length - (this->readPtr - this->base);
auto toWriteOverhead = this->writePtr - this->base;
return linearOverhead + toWriteOverhead;
}
}
@ -118,24 +143,48 @@ namespace Aurora::Memory
{
if (endAtWrite)
{
if (writePtr < readPtr)
if (this->writePtr < this->readPtr)
{
return 0;
}
else
{
return writePtr - readPtr;
return this->writePtr - this->readPtr;
}
}
else
{
return (length - (readPtr - base));
return (this->length - (this->readPtr - this->base));
}
}
}
AuUInt ByteBuffer::RemainingWrite(bool endAtRead) const
{
// sanity:
if (this->writePtr > this->base + this->length)
{
return 0;
}
if (this->writePtr < this->base)
{
return 0;
}
if (this->readPtr > this->base + this->length)
{
return 0;
}
if (this->readPtr < this->base)
{
return 0;
}
/////////////
if (this->flagCircular)
{
if (this->readPtr == this->writePtr)
@ -144,12 +193,14 @@ namespace Aurora::Memory
}
else if ((this->writePtr < this->readPtr) && (endAtRead))
{
// writers must not fall into a state of head parity, meaning that the entire buffer is readable
return (this->readPtr - this->writePtr) - 1;
}
else
{
auto linearOverhead = length - (writePtr - base);
auto toWriteOverhead = readPtr - base;
auto linearOverhead = this->length - (this->writePtr - this->base);
auto toWriteOverhead = this->readPtr - this->base;
// writers must not fall into a state of head parity, meaning that the entire buffer is readable
return (linearOverhead + toWriteOverhead) - 1;
}
}
@ -203,13 +254,17 @@ namespace Aurora::Memory
pBase = this->readPtr;
}
// sanity:
if (pBase + uCount > this->base + this->length)
{
this->flagReadError = true;
return {};
}
if (pBase < this->base)
{
this->flagReadError = true;
return {};
}
@ -251,13 +306,17 @@ namespace Aurora::Memory
pBase = this->writePtr;
}
// sanity:
if (pBase + uCount > this->base + this->length)
{
this->flagWriteError = true;
return {};
}
if (pBase < this->base)
{
this->flagWriteError = true;
return {};
}