#pragma once #include "ring_buffer.h" #include #include template class TRingBufferWithSpinLock { private: TRingBuffer RingBuffer; TSpinLock SpinLock; TAtomic CachedSize; public: TRingBufferWithSpinLock() : CachedSize(0) { } void Push(const T& t) { PushAll(t); } void PushAll(TArrayRef collection) { if (collection.empty()) { return; } TGuard Guard(SpinLock); RingBuffer.PushAll(collection); AtomicSet(CachedSize, RingBuffer.Size()); } bool TryPop(T* r, size_t* sizePtr = nullptr) { if (AtomicGet(CachedSize) == 0) { return false; } bool ok; size_t size; { TGuard Guard(SpinLock); ok = RingBuffer.TryPop(r); size = RingBuffer.Size(); AtomicSet(CachedSize, size); } if (!!sizePtr) { *sizePtr = size; } return ok; } TMaybe TryPop() { T tmp; if (TryPop(&tmp)) { return tmp; } else { return TMaybe(); } } bool PushAllAndTryPop(TArrayRef collection, T* r) { if (collection.size() == 0) { return TryPop(r); } else { if (AtomicGet(CachedSize) == 0) { *r = collection[0]; if (collection.size() > 1) { TGuard guard(SpinLock); RingBuffer.PushAll(MakeArrayRef(collection.data() + 1, collection.size() - 1)); AtomicSet(CachedSize, RingBuffer.Size()); } } else { TGuard guard(SpinLock); RingBuffer.PushAll(collection); *r = RingBuffer.Pop(); AtomicSet(CachedSize, RingBuffer.Size()); } return true; } } bool Empty() const { return AtomicGet(CachedSize) == 0; } size_t Size() const { TGuard Guard(SpinLock); return RingBuffer.Size(); } };