1 /*************************************************************************/
2 /*  ring_buffer.h                                                        */
3 /*************************************************************************/
4 /*                       This file is part of:                           */
5 /*                           GODOT ENGINE                                */
6 /*                      https://godotengine.org                          */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur.                 */
9 /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md)    */
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 #ifndef RINGBUFFER_H
31 #define RINGBUFFER_H
32 
33 #include "vector.h"
34 
35 template <typename T>
36 class RingBuffer {
37 
38 	Vector<T> data;
39 	int read_pos;
40 	int write_pos;
41 	int size_mask;
42 
inc(int & p_var,int p_size)43 	inline int inc(int &p_var, int p_size) {
44 		int ret = p_var;
45 		p_var += p_size;
46 		p_var = p_var & size_mask;
47 		return ret;
48 	};
49 
50 public:
read()51 	T read() {
52 		ERR_FAIL_COND_V(space_left() < 1, T());
53 		return data[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 			for (int i = 0; i < total; i++) {
67 				p_buf[dst++] = data[pos + i];
68 			};
69 			to_read -= total;
70 			pos = 0;
71 		};
72 		if (p_advance) {
73 			inc(read_pos, p_size);
74 		};
75 		return p_size;
76 	};
77 
copy(T * p_buf,int p_offset,int p_size)78 	int copy(T *p_buf, int p_offset, int p_size) {
79 
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 		p_size = MIN(left, p_size);
87 		int pos = read_pos;
88 		inc(pos, p_offset);
89 		int to_read = p_size;
90 		int dst = 0;
91 		while (to_read) {
92 			int end = pos + to_read;
93 			end = MIN(end, size());
94 			int total = end - pos;
95 			for (int i = 0; i < total; i++) {
96 				p_buf[dst++] = data[pos + i];
97 			};
98 			to_read -= total;
99 			pos = 0;
100 		};
101 		return p_size;
102 	};
103 
advance_read(int p_n)104 	inline int advance_read(int p_n) {
105 		p_n = MIN(p_n, data_left());
106 		inc(read_pos, p_n);
107 		return p_n;
108 	};
109 
write(const T & p_v)110 	Error write(const T &p_v) {
111 		ERR_FAIL_COND_V(space_left() < 1, FAILED);
112 		data[inc(write_pos, 1)] = p_v;
113 		return OK;
114 	};
115 
write(const T * p_buf,int p_size)116 	int write(const T *p_buf, int p_size) {
117 
118 		int left = space_left();
119 		p_size = MIN(left, p_size);
120 
121 		int pos = write_pos;
122 		int to_write = p_size;
123 		int src = 0;
124 		while (to_write) {
125 
126 			int end = pos + to_write;
127 			end = MIN(end, size());
128 			int total = end - pos;
129 
130 			for (int i = 0; i < total; i++) {
131 				data[pos + i] = p_buf[src++];
132 			};
133 			to_write -= total;
134 			pos = 0;
135 		};
136 
137 		inc(write_pos, p_size);
138 		return p_size;
139 	};
140 
space_left()141 	inline int space_left() {
142 		int left = read_pos - write_pos;
143 		if (left < 0) {
144 			return size() + left - 1;
145 		};
146 		if (left == 0) {
147 			return size() - 1;
148 		};
149 		return left - 1;
150 	};
data_left()151 	inline int data_left() {
152 		return size() - space_left() - 1;
153 	};
154 
size()155 	inline int size() {
156 		return data.size();
157 	};
158 
clear()159 	inline void clear() {
160 		read_pos = 0;
161 		write_pos = 0;
162 	}
163 
resize(int p_power)164 	void resize(int p_power) {
165 		int old_size = size();
166 		int new_size = 1 << p_power;
167 		int mask = new_size - 1;
168 		data.resize(1 << p_power);
169 		if (old_size < new_size && read_pos > write_pos) {
170 			for (int i = 0; i < write_pos; i++) {
171 				data[(old_size + i) & mask] = data[i];
172 			};
173 			write_pos = (old_size + write_pos) & mask;
174 		} else {
175 			read_pos = read_pos & mask;
176 			write_pos = write_pos & mask;
177 		};
178 
179 		size_mask = mask;
180 	};
181 
182 	RingBuffer<T>(int p_power = 0) {
183 		read_pos = 0;
184 		write_pos = 0;
185 		resize(p_power);
186 	};
187 	~RingBuffer<T>(){};
188 };
189 
190 #endif
191