using System; using System.Diagnostics; using System.Collections; namespace BeefPerf { class CircularBuffer { public class View { public uint8* mPtr; public int32 mSrcIdx; public int32 mSrcSize; public uint8* mTempBuf ~ delete _; public int32 mTempBufSize; public CircularBuffer mCircularBuffer; //void Commit(int size = -1); }; uint8* mBuffer; int32 mTail; int32 mDataSize; int32 mBufSize; public this() { mTail = 0; mBufSize = 0; mDataSize = 0; mBuffer = null; } public ~this() { delete mBuffer; } public void Resize(int32 newSize) { uint8* newBuffer = new uint8[newSize]*; Read(newBuffer, 0, mDataSize); delete mBuffer; mBuffer = newBuffer; mBufSize = newSize; mTail = 0; } public void GrowReserve(int32 addSize) { if (mDataSize + addSize <= mBufSize) return; Resize(Math.Max(mDataSize + addSize, mDataSize + mDataSize/2)); } public void Grow(int32 addSize) { GrowReserve(addSize); mDataSize += addSize; } /// This ensures that we have a span that does not wrap around. This ensures we can decode /// an entire block without wrap checks. public void EnsureSpan(int32 spanSize) { //Debug.WriteLine("Span Size:{0} Tail:{1} DataSize:{2} BufSize:{3}", spanSize, mTail, mDataSize, mBufSize); if (mDataSize + spanSize > mBufSize) { int32 newSize = (int32)Math.Max(mDataSize + spanSize, (int32)mBufSize * 1.5); //Debug.WriteLine("Resizing {0}", newSize); Resize(newSize); return; } int head = mTail + mDataSize; if (head + spanSize > mBufSize) { // If we are sufficiently full then keep the buffer at the same size if (mDataSize + spanSize < mBufSize / 2) { // If our buffer doesn't wrap around then we can just pull back inplace if (mTail + mDataSize <= mBufSize) { if (mTail != 0) { //Debug.WriteLine("MemMove"); Internal.MemMove(mBuffer, mBuffer + mTail, mDataSize); mTail = 0; } return; } //Debug.WriteLine("MakeLinear"); MakeLinear(); return; } int32 newSize = (int32)Math.Max(mDataSize + spanSize, (int32)mBufSize * 1.5); //Debug.WriteLine("Resizing2 {0}", newSize); Resize(newSize); return; } /*if (mTail + spanSize > mBufSize) { /*Debug.WriteLine("EnsureSpan {0} {1} {2} {3}", mTail, spanSize, mBufSize, mDataSize); // If we are sufficiently full then keep the buffer at the same size if (mDataSize + spanSize < mBufSize / 2) { // If our buffer doesn't wrap around then we can just pull back inplace if (mTail + mDataSize <= mBufSize) { if (mTail != 0) { Internal.MemMove(mBuffer, mBuffer + mTail, mDataSize); mTail = 0; } return; } MakeLinear(); return; }*/ int32 newBufSize = (int32)((mTail + spanSize) * 1.5); Resize(newBufSize); }*/ } public void MakeLinear() { if (mDataSize == 0) { mTail = 0; return; } Resize(mBufSize); } public void GrowFront(int32 addSize) { if (mDataSize + addSize > mBufSize) { Resize(mDataSize + addSize); } mDataSize += addSize; mTail = (mTail + mBufSize - addSize) % mBufSize; } public int32 GetSize() { return mDataSize; } public int32 GetBufSize() { return mBufSize; } public uint8* GetPtr() { return mBuffer + mTail; } public void SetPtr(uint8* ptr) { int32 newTail = (int32)(ptr - mBuffer); mDataSize -= newTail - mTail; Debug.Assert(mDataSize >= 0); if (newTail == mBufSize) newTail = 0; mTail = newTail; Debug.Assert(mTail < mBufSize); } public void MapView(int32 idx, int32 len, View view) { view.mCircularBuffer = this; view.mSrcIdx = idx; view.mSrcSize = len; if (mTail + idx + len <= mBufSize) { view.mPtr = mBuffer + mTail + idx; } else { if (view.mTempBufSize < len) { delete view.mTempBuf; view.mTempBuf = new uint8[len]*; view.mTempBufSize = len; } view.mPtr = view.mTempBuf; Read(view.mTempBuf, idx, len); } } public void Read(void* ptr, int32 idx, int32 len) { Debug.Assert(len <= mBufSize); if (len == 0) return; int absIdx = (mTail + idx) % mBufSize; if (absIdx + len > mBufSize) { int lowSize = mBufSize - absIdx; Internal.MemCpy(ptr, mBuffer + absIdx, lowSize); Internal.MemCpy((uint8*)ptr + lowSize, mBuffer, len - lowSize); } else { Internal.MemCpy(ptr, mBuffer + absIdx, len); } } public uint8 Read() { uint8 val = mBuffer[mTail]; mTail = (mTail + 1) % mBufSize; mDataSize--; return val; } public int64 ReadSLEB128() { int64 value = 0; int32 shift = 0; int64 curByte; repeat { curByte = Read(); value |= ((curByte & 0x7f) << shift); shift += 7; } while (curByte >= 128); // Sign extend negative numbers. if (((curByte & 0x40) != 0) && (shift < 64)) value |= ~0L << shift; return value; } public void Write(void* ptr, int32 idx, int32 len) { Debug.Assert(len <= mBufSize); if (len == 0) return; int absIdx = (mTail + idx) % mBufSize; if (absIdx + len > mBufSize) { int lowSize = mBufSize - absIdx; Internal.MemCpy(mBuffer + absIdx, ptr, lowSize); Internal.MemCpy(mBuffer, (uint8*)ptr + lowSize, len - lowSize); } else { Internal.MemCpy(mBuffer + absIdx, ptr, len); } } public void RemoveFront(int32 len) { mTail = (mTail + len) % mBufSize; mDataSize -= len; } public void RemoveBack(int32 len) { mDataSize -= len; } } }