1/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2/* If you are missing that file, acquire a complete release at teeworlds.com. */
3#ifndef ENGINE_SHARED_RINGBUFFER_H
4#define ENGINE_SHARED_RINGBUFFER_H
5
6#include <base/system.h>
7
8#include <functional>
9
10class CRingBufferBase
11{
12 class CItem
13 {
14 public:
15 CItem *m_pPrev;
16 CItem *m_pNext;
17 int m_Free;
18 int m_Size;
19 };
20
21 CItem *m_pBuffer;
22
23 CItem *m_pProduce;
24 CItem *m_pConsume;
25
26 CItem *m_pFirst;
27 CItem *m_pLast;
28
29 int m_Size;
30 int m_Flags;
31
32 std::function<void(void *pCurrent)> m_PopCallback = nullptr;
33
34 CItem *NextBlock(CItem *pItem);
35 CItem *PrevBlock(CItem *pItem);
36 CItem *MergeBack(CItem *pItem);
37
38protected:
39 void *Allocate(int Size);
40
41 void *Prev(void *pCurrent);
42 void *Next(void *pCurrent);
43 void *First();
44 void *Last();
45
46 void Init(void *pMemory, int Size, int Flags);
47 int PopFirst();
48 void SetPopCallback(std::function<void(void *pCurrent)> PopCallback);
49
50public:
51 enum
52 {
53 // Will start to destroy items to try to fit the next one
54 FLAG_RECYCLE = 1
55 };
56 static constexpr int ITEM_SIZE = sizeof(CItem);
57
58 void Clear();
59};
60
61template<typename T>
62class CTypedRingBuffer : public CRingBufferBase
63{
64public:
65 T *Allocate(int Size) { return (T *)CRingBufferBase::Allocate(Size); }
66 int PopFirst() { return CRingBufferBase::PopFirst(); }
67 void SetPopCallback(const std::function<void(T *pCurrent)> &PopCallback)
68 {
69 CRingBufferBase::SetPopCallback([PopCallback](void *pCurrent) {
70 PopCallback((T *)pCurrent);
71 });
72 }
73
74 T *Prev(T *pCurrent) { return (T *)CRingBufferBase::Prev(pCurrent); }
75 T *Next(T *pCurrent) { return (T *)CRingBufferBase::Next(pCurrent); }
76 T *First() { return (T *)CRingBufferBase::First(); }
77 T *Last() { return (T *)CRingBufferBase::Last(); }
78};
79
80template<typename T, int TSIZE, int TFLAGS = 0>
81class CStaticRingBuffer : public CTypedRingBuffer<T>
82{
83 unsigned char m_aBuffer[TSIZE];
84
85public:
86 CStaticRingBuffer() { Init(); }
87
88 void Init() { CRingBufferBase::Init(pMemory: m_aBuffer, Size: TSIZE, Flags: TFLAGS); }
89};
90
91template<typename T>
92class CDynamicRingBuffer : public CTypedRingBuffer<T>
93{
94 unsigned char *m_pBuffer = nullptr;
95
96public:
97 CDynamicRingBuffer(int Size, int Flags = 0) { Init(Size, Flags); }
98
99 ~CDynamicRingBuffer()
100 {
101 free(ptr: m_pBuffer);
102 }
103
104 void Init(int Size, int Flags)
105 {
106 free(ptr: m_pBuffer);
107 m_pBuffer = static_cast<unsigned char *>(malloc(size: Size));
108 CRingBufferBase::Init(pMemory: m_pBuffer, Size, Flags);
109 }
110};
111
112#endif
113