1 | /**************************************************************************/ |
2 | /* ring_buffer.h */ |
3 | /**************************************************************************/ |
4 | /* This file is part of: */ |
5 | /* GODOT ENGINE */ |
6 | /* https://godotengine.org */ |
7 | /**************************************************************************/ |
8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
10 | /* */ |
11 | /* Permission is hereby granted, free of charge, to any person obtaining */ |
12 | /* a copy of this software and associated documentation files (the */ |
13 | /* "Software"), to deal in the Software without restriction, including */ |
14 | /* without limitation the rights to use, copy, modify, merge, publish, */ |
15 | /* distribute, sublicense, and/or sell copies of the Software, and to */ |
16 | /* permit persons to whom the Software is furnished to do so, subject to */ |
17 | /* the following conditions: */ |
18 | /* */ |
19 | /* The above copyright notice and this permission notice shall be */ |
20 | /* included in all copies or substantial portions of the Software. */ |
21 | /* */ |
22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ |
23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ |
24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ |
25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ |
26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ |
27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ |
28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
29 | /**************************************************************************/ |
30 | |
31 | #ifndef RING_BUFFER_H |
32 | #define RING_BUFFER_H |
33 | |
34 | #include "core/templates/vector.h" |
35 | |
36 | template <typename T> |
37 | class RingBuffer { |
38 | Vector<T> data; |
39 | int read_pos = 0; |
40 | int write_pos = 0; |
41 | int size_mask; |
42 | |
43 | inline int inc(int &p_var, int p_size) const { |
44 | int ret = p_var; |
45 | p_var += p_size; |
46 | p_var = p_var & size_mask; |
47 | return ret; |
48 | } |
49 | |
50 | public: |
51 | T read() { |
52 | ERR_FAIL_COND_V(space_left() < 1, T()); |
53 | return data.ptr()[inc(read_pos, 1)]; |
54 | } |
55 | |
56 | int read(T *p_buf, int p_size, bool p_advance = true) { |
57 | int left = data_left(); |
58 | p_size = MIN(left, p_size); |
59 | int pos = read_pos; |
60 | int to_read = p_size; |
61 | int dst = 0; |
62 | while (to_read) { |
63 | int end = pos + to_read; |
64 | end = MIN(end, size()); |
65 | int total = end - pos; |
66 | const T *read = data.ptr(); |
67 | for (int i = 0; i < total; i++) { |
68 | p_buf[dst++] = read[pos + i]; |
69 | } |
70 | to_read -= total; |
71 | pos = 0; |
72 | } |
73 | if (p_advance) { |
74 | inc(read_pos, p_size); |
75 | } |
76 | return p_size; |
77 | } |
78 | |
79 | int copy(T *p_buf, int p_offset, int p_size) const { |
80 | int left = data_left(); |
81 | if ((p_offset + p_size) > left) { |
82 | p_size -= left - p_offset; |
83 | if (p_size <= 0) { |
84 | return 0; |
85 | } |
86 | } |
87 | p_size = MIN(left, p_size); |
88 | int pos = read_pos; |
89 | inc(pos, p_offset); |
90 | int to_read = p_size; |
91 | int dst = 0; |
92 | while (to_read) { |
93 | int end = pos + to_read; |
94 | end = MIN(end, size()); |
95 | int total = end - pos; |
96 | for (int i = 0; i < total; i++) { |
97 | p_buf[dst++] = data[pos + i]; |
98 | } |
99 | to_read -= total; |
100 | pos = 0; |
101 | } |
102 | return p_size; |
103 | } |
104 | |
105 | int find(const T &t, int p_offset, int p_max_size) const { |
106 | int left = data_left(); |
107 | if ((p_offset + p_max_size) > left) { |
108 | p_max_size -= left - p_offset; |
109 | if (p_max_size <= 0) { |
110 | return 0; |
111 | } |
112 | } |
113 | p_max_size = MIN(left, p_max_size); |
114 | int pos = read_pos; |
115 | inc(pos, p_offset); |
116 | int to_read = p_max_size; |
117 | while (to_read) { |
118 | int end = pos + to_read; |
119 | end = MIN(end, size()); |
120 | int total = end - pos; |
121 | for (int i = 0; i < total; i++) { |
122 | if (data[pos + i] == t) { |
123 | return i + (p_max_size - to_read); |
124 | } |
125 | } |
126 | to_read -= total; |
127 | pos = 0; |
128 | } |
129 | return -1; |
130 | } |
131 | |
132 | inline int advance_read(int p_n) { |
133 | p_n = MIN(p_n, data_left()); |
134 | inc(read_pos, p_n); |
135 | return p_n; |
136 | } |
137 | |
138 | inline int decrease_write(int p_n) { |
139 | p_n = MIN(p_n, data_left()); |
140 | inc(write_pos, size_mask + 1 - p_n); |
141 | return p_n; |
142 | } |
143 | |
144 | Error write(const T &p_v) { |
145 | ERR_FAIL_COND_V(space_left() < 1, FAILED); |
146 | data.write[inc(write_pos, 1)] = p_v; |
147 | return OK; |
148 | } |
149 | |
150 | int write(const T *p_buf, int p_size) { |
151 | int left = space_left(); |
152 | p_size = MIN(left, p_size); |
153 | |
154 | int pos = write_pos; |
155 | int to_write = p_size; |
156 | int src = 0; |
157 | while (to_write) { |
158 | int end = pos + to_write; |
159 | end = MIN(end, size()); |
160 | int total = end - pos; |
161 | |
162 | for (int i = 0; i < total; i++) { |
163 | data.write[pos + i] = p_buf[src++]; |
164 | } |
165 | to_write -= total; |
166 | pos = 0; |
167 | } |
168 | |
169 | inc(write_pos, p_size); |
170 | return p_size; |
171 | } |
172 | |
173 | inline int space_left() const { |
174 | int left = read_pos - write_pos; |
175 | if (left < 0) { |
176 | return size() + left - 1; |
177 | } |
178 | if (left == 0) { |
179 | return size() - 1; |
180 | } |
181 | return left - 1; |
182 | } |
183 | inline int data_left() const { |
184 | return size() - space_left() - 1; |
185 | } |
186 | |
187 | inline int size() const { |
188 | return data.size(); |
189 | } |
190 | |
191 | inline void clear() { |
192 | read_pos = 0; |
193 | write_pos = 0; |
194 | } |
195 | |
196 | void resize(int p_power) { |
197 | int old_size = size(); |
198 | int new_size = 1 << p_power; |
199 | int mask = new_size - 1; |
200 | data.resize(1 << p_power); |
201 | if (old_size < new_size && read_pos > write_pos) { |
202 | for (int i = 0; i < write_pos; i++) { |
203 | data.write[(old_size + i) & mask] = data[i]; |
204 | } |
205 | write_pos = (old_size + write_pos) & mask; |
206 | } else { |
207 | read_pos = read_pos & mask; |
208 | write_pos = write_pos & mask; |
209 | } |
210 | |
211 | size_mask = mask; |
212 | } |
213 | |
214 | RingBuffer<T>(int p_power = 0) { |
215 | resize(p_power); |
216 | } |
217 | ~RingBuffer<T>() {} |
218 | }; |
219 | |
220 | #endif // RING_BUFFER_H |
221 | |