AuroraRuntime/Include/Aurora/Memory/ByteBuffer_Position.inl

435 lines
11 KiB
C++

/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: ByteBuffer_Position.inl
Date: 2022-1-18
Author: Reece
***/
#pragma once
namespace Aurora::Memory
{
bool ByteBuffer::WriterTryGoForward(AuUInt32 offset)
{
if (!offset)
{
return true;
}
auto old = writePtr - base;
auto n = Write(nullptr, offset);
if (n != offset)
{
this->writePtr = this->base + old;
return false;
}
return true;
}
bool ByteBuffer::ReaderTryGoForward(AuUInt32 offset)
{
if (!offset)
{
return true;
}
auto old = readPtr - base;
auto n = Read(nullptr, offset, false);
if (n != offset)
{
this->readPtr = this->base + old;
return false;
}
return true;
}
bool ByteBuffer::ReaderTryGoBack(AuUInt32 offset)
{
if (flagCircular)
{
AuUInt32 readOffset = readPtr - base;
if (readOffset < offset)
{
auto absPosition = (AuUInt)offset - readOffset;
auto goAround = absPosition;
auto backIdx = length - goAround;
auto writeOffset = writePtr - base;
if ((AuUInt)writeOffset > (AuUInt)backIdx)
{
return false;
}
readPtr = base + backIdx;
}
else
{
AuUInt writeOffset = writePtr - base;
AuUInt backIdx = readOffset - offset;
if (writeOffset > backIdx)
{
return false;
}
readPtr = base + backIdx;
}
return true;
}
else
{
AuUInt readOffset = readPtr - base;
if (readOffset < offset)
{
return false;
}
readPtr -= offset;
return true;
}
}
AuUInt ByteBuffer::RemainingBytes(bool endAtWrite) 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)
{
return 0;
}
else if ((this->readPtr < this->writePtr) && (endAtWrite))
{
return this->writePtr - this->readPtr;
}
else
{
// 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;
}
}
else
{
if (endAtWrite)
{
if (this->writePtr < this->readPtr)
{
return 0;
}
else
{
return this->writePtr - this->readPtr;
}
}
else
{
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)
{
return this->length - 1;
}
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 = 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;
}
}
else
{
return this->length - (this->writePtr - this->base);
}
}
bool ByteBuffer::Skip(AuUInt count)
{
auto oldptr = readPtr;
auto skipped = Read(nullptr, count);
if (skipped != count)
{
readPtr = oldptr;
return false;
}
return true;
}
void ByteBuffer::ResetReadPointer()
{
this->readPtr = this->base;
}
MemoryViewRead ByteBuffer::GetNextLinearRead()
{
AuUInt8 *pBase {};
AuUInt uCount {};
if (this->flagCircular && this->base + this->length == this->readPtr)
{
this->readPtr = this->base;
// avoid taking equal pairs out of parity
if (this->writePtr == this->base + this->length)
{
this->writePtr = this->base;
}
}
if (this->writePtr >= this->readPtr)
{
uCount = this->writePtr - this->readPtr;
pBase = this->readPtr;
}
else if (this->flagCircular)
{
uCount = (this->base + this->length) - this->readPtr;
pBase = this->readPtr;
}
// sanity:
if (pBase + uCount > this->base + this->length)
{
this->flagReadError = true;
return {};
}
if (pBase < this->base)
{
this->flagReadError = true;
return {};
}
return MemoryViewRead(pBase, uCount);
}
MemoryViewWrite ByteBuffer::GetNextLinearWrite()
{
AuUInt8 *pBase {};
AuUInt uCount {};
if (this->flagCircular)
{
if (this->writePtr == this->base + this->length)
{
this->writePtr = this->base;
// avoid taking equal pairs out of parity
if (this->readPtr == this->base + this->length)
{
this->readPtr = this->base;
}
}
if (this->readPtr > this->writePtr)
{
uCount = (this->writePtr - this->readPtr) - 1;
pBase = this->writePtr;
}
else
{
uCount = (this->base + this->length) - this->writePtr;
pBase = this->writePtr;
}
}
else
{
uCount = (this->base + this->length) - this->writePtr;
pBase = this->writePtr;
}
// sanity:
if (pBase + uCount > this->base + this->length)
{
this->flagWriteError = true;
return {};
}
if (pBase < this->base)
{
this->flagWriteError = true;
return {};
}
return MemoryViewWrite(pBase, uCount);
}
bool ByteBuffer::CanWrite(AuUInt length)
{
return this->RemainingWrite(true) >= length;
}
bool ByteBuffer::CanRead(AuUInt 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)
{
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);
}
MemoryViewWrite ByteBuffer::GetOrAllocateLinearWriteable(AuUInt length)
{
if (this->CanWrite(length))
{
return this->GetLinearWriteable(length);
}
else if ((this->length == 0 && this->flagExpandable) ||
this->flagAlwaysExpandable)
{
if (!this->Resize(length))
{
SysPushErrorMemory("Couldn't resize bytebuffer for bytes: {}", length);
return {};
}
return this->GetLinearWriteable(length);
}
else
{
return {};
}
}
AuUInt ByteBuffer::GetReadOffset() const
{
if (this->flagCircular)
{
return 0;
}
else
{
return this->readPtr - this->base;
}
}
AuUInt ByteBuffer::GetWriteOffset() const
{
if (this->flagCircular)
{
return 0;
}
else
{
return this->writePtr - this->base;
}
}
}