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 | |
10 | class 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_pProduce; |
22 | CItem *m_pConsume; |
23 | |
24 | CItem *m_pFirst; |
25 | CItem *m_pLast; |
26 | |
27 | int m_Size; |
28 | int m_Flags; |
29 | |
30 | std::function<void(void *pCurrent)> m_PopCallback = nullptr; |
31 | |
32 | CItem *NextBlock(CItem *pItem); |
33 | CItem *PrevBlock(CItem *pItem); |
34 | CItem *MergeBack(CItem *pItem); |
35 | |
36 | protected: |
37 | void *Allocate(int Size); |
38 | |
39 | void *Prev(void *pCurrent); |
40 | void *Next(void *pCurrent); |
41 | void *First(); |
42 | void *Last(); |
43 | |
44 | void Init(void *pMemory, int Size, int Flags); |
45 | int PopFirst(); |
46 | void SetPopCallback(const std::function<void(void *pCurrent)> PopCallback); |
47 | |
48 | public: |
49 | enum |
50 | { |
51 | // Will start to destroy items to try to fit the next one |
52 | FLAG_RECYCLE = 1 |
53 | }; |
54 | static constexpr int ITEM_SIZE = sizeof(CItem); |
55 | }; |
56 | |
57 | template<typename T> |
58 | class CTypedRingBuffer : public CRingBufferBase |
59 | { |
60 | public: |
61 | T *Allocate(int Size) { return (T *)CRingBufferBase::Allocate(Size); } |
62 | int PopFirst() { return CRingBufferBase::PopFirst(); } |
63 | void SetPopCallback(std::function<void(T *pCurrent)> PopCallback) |
64 | { |
65 | CRingBufferBase::SetPopCallback([PopCallback](void *pCurrent) { |
66 | PopCallback((T *)pCurrent); |
67 | }); |
68 | } |
69 | |
70 | T *Prev(T *pCurrent) { return (T *)CRingBufferBase::Prev(pCurrent); } |
71 | T *Next(T *pCurrent) { return (T *)CRingBufferBase::Next(pCurrent); } |
72 | T *First() { return (T *)CRingBufferBase::First(); } |
73 | T *Last() { return (T *)CRingBufferBase::Last(); } |
74 | }; |
75 | |
76 | template<typename T, int TSIZE, int TFLAGS = 0> |
77 | class CStaticRingBuffer : public CTypedRingBuffer<T> |
78 | { |
79 | unsigned char m_aBuffer[TSIZE]; |
80 | |
81 | public: |
82 | CStaticRingBuffer() { Init(); } |
83 | |
84 | void Init() { CRingBufferBase::Init(pMemory: m_aBuffer, Size: TSIZE, Flags: TFLAGS); } |
85 | }; |
86 | |
87 | template<typename T> |
88 | class CDynamicRingBuffer : public CTypedRingBuffer<T> |
89 | { |
90 | unsigned char *m_pBuffer = nullptr; |
91 | |
92 | public: |
93 | CDynamicRingBuffer(int Size, int Flags = 0) { Init(Size, Flags); } |
94 | |
95 | virtual ~CDynamicRingBuffer() |
96 | { |
97 | free(ptr: m_pBuffer); |
98 | } |
99 | |
100 | void Init(int Size, int Flags) |
101 | { |
102 | free(ptr: m_pBuffer); |
103 | m_pBuffer = static_cast<unsigned char *>(malloc(size: Size)); |
104 | CRingBufferBase::Init(pMemory: m_pBuffer, Size, Flags); |
105 | } |
106 | }; |
107 | |
108 | #endif |
109 | |