435 lines
11 KiB
C++
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;
|
|
}
|
|
}
|
|
} |