diff --git a/Source/Engine/Core/Collections/RingBuffer.h b/Source/Engine/Core/Collections/RingBuffer.h new file mode 100644 index 000000000..bffc70e40 --- /dev/null +++ b/Source/Engine/Core/Collections/RingBuffer.h @@ -0,0 +1,95 @@ +// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. + +#pragma once + +#include "Engine/Platform/Platform.h" +#include "Engine/Core/Memory/Memory.h" +#include "Engine/Core/Memory/Allocation.h" + +/// +/// Template for ring buffer with variable capacity. +/// +template +class RingBuffer +{ +public: + + typedef T ItemType; + typedef typename AllocationType::template Data AllocationData; + +private: + + int32 _front = 0, _back = 0, _count = 0, _capacity = 0; + AllocationData _allocation; + +public: + + ~RingBuffer() + { + Memory::DestructItems(Get() + Math::Min(_front, _back), _count); + } + + FORCE_INLINE T* Get() + { + return _allocation.Get(); + } + + FORCE_INLINE int32 Count() const + { + return _count; + } + + FORCE_INLINE int32 Capacity() const + { + return _capacity; + } + + void PushBack(const T& data) + { + if (_capacity == 0 || _capacity == _count) + { + const int32 capacity = _allocation.CalculateCapacityGrow(_capacity, 0); + AllocationData alloc; + alloc.Allocate(capacity); + const int32 frontCount = Math::Min(_capacity - _front, _count); + Memory::MoveItems(alloc.Get(), _allocation.Get() + _front, frontCount); + Memory::DestructItems(_allocation.Get() + _front, frontCount); + const int32 backCount = _count - frontCount; + Memory::MoveItems(alloc.Get() + frontCount, _allocation.Get(), backCount); + Memory::DestructItems(_allocation.Get(), backCount); + _allocation.Swap(alloc); + _front = 0; + _back = _count; + _capacity = capacity; + } + Memory::ConstructItems(_allocation.Get() + _back, &data, 1); + _back = (_back + 1) % _capacity; + _count++; + } + + FORCE_INLINE T& PeekFront() + { + ASSERT(_front != _back); + return _allocation.Get()[_front]; + } + + FORCE_INLINE const T& PeekFront() const + { + ASSERT(_front != _back); + return _allocation.Get()[_front]; + } + + void PopFront() + { + ASSERT(_front != _back); + Memory::DestructItems(_allocation.Get() + _front, 1); + _front = (_front + 1) % _capacity; + _count--; + } + + void Clear() + { + Memory::DestructItems(Get() + Math::Min(_front, _back), _count); + _front = _back = _count = 0; + } +};