master
c 195 lines 4.71 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "../libnetdata.h"
4 #include "ringbuffer_internal.h"
5
6 rbuf_t rbuf_create(size_t size)
7 {
8 rbuf_t buffer = mallocz(sizeof(struct rbuf) + size);
9 memset(buffer, 0, sizeof(struct rbuf));
10
11 buffer->data = ((char*)buffer) + sizeof(struct rbuf);
12
13 buffer->head = buffer->data;
14 buffer->tail = buffer->data;
15 buffer->size = size;
16 buffer->end = buffer->data + size;
17
18 return buffer;
19 }
20
21 void rbuf_free(rbuf_t buffer)
22 {
23 freez(buffer);
24 }
25
26 void rbuf_flush(rbuf_t buffer)
27 {
28 buffer->head = buffer->data;
29 buffer->tail = buffer->data;
30 buffer->size_data = 0;
31 }
32
33 char *rbuf_get_linear_insert_range(rbuf_t buffer, size_t *bytes)
34 {
35 *bytes = 0;
36 if (buffer->head == buffer->tail && buffer->size_data)
37 return NULL;
38
39 *bytes = ((buffer->head >= buffer->tail) ? buffer->end : buffer->tail) - buffer->head;
40 return buffer->head;
41 }
42
43 char *rbuf_get_linear_read_range(rbuf_t buffer, size_t *bytes)
44 {
45 *bytes = 0;
46 if(buffer->head == buffer->tail && !buffer->size_data)
47 return NULL;
48
49 *bytes = ((buffer->tail >= buffer->head) ? buffer->end : buffer->head) - buffer->tail;
50
51 return buffer->tail;
52 }
53
54 int rbuf_bump_head(rbuf_t buffer, size_t bytes)
55 {
56 size_t free_bytes = rbuf_bytes_free(buffer);
57 if (bytes > free_bytes)
58 return 0;
59 int i = buffer->head - buffer->data;
60 buffer->head = &buffer->data[(i + bytes) % buffer->size];
61 buffer->size_data += bytes;
62 return 1;
63 }
64
65 int rbuf_bump_tail_noopt(rbuf_t buffer, size_t bytes)
66 {
67 if (bytes > buffer->size_data)
68 return 0;
69 int i = buffer->tail - buffer->data;
70 buffer->tail = &buffer->data[(i + bytes) % buffer->size];
71 buffer->size_data -= bytes;
72
73 return 1;
74 }
75
76 int rbuf_bump_tail(rbuf_t buffer, size_t bytes)
77 {
78 if(!rbuf_bump_tail_noopt(buffer, bytes))
79 return 0;
80
81 // if tail catched up with head
82 // start writing buffer from beggining
83 // this is not necessary (rbuf must work well without it)
84 // but helps to optimize big writes as rbuf_get_linear_insert_range
85 // will return bigger continuous region
86 if(buffer->tail == buffer->head) {
87 assert(buffer->size_data == 0);
88 rbuf_flush(buffer);
89 }
90
91 return 1;
92 }
93
94 size_t rbuf_get_capacity(rbuf_t buffer)
95 {
96 return buffer->size;
97 }
98
99 size_t rbuf_bytes_available(rbuf_t buffer)
100 {
101 return buffer->size_data;
102 }
103
104 size_t rbuf_bytes_free(rbuf_t buffer)
105 {
106 return buffer->size - buffer->size_data;
107 }
108
109 size_t rbuf_push(rbuf_t buffer, const char *data, size_t len)
110 {
111 size_t to_cpy;
112 char *w_ptr = rbuf_get_linear_insert_range(buffer, &to_cpy);
113 if(!to_cpy)
114 return to_cpy;
115
116 to_cpy = MIN(to_cpy, len);
117 memcpy(w_ptr, data, to_cpy);
118 rbuf_bump_head(buffer, to_cpy);
119 if(to_cpy < len)
120 to_cpy += rbuf_push(buffer, &data[to_cpy], len - to_cpy);
121 return to_cpy;
122 }
123
124 size_t rbuf_pop(rbuf_t buffer, char *data, size_t len)
125 {
126 size_t to_cpy;
127 const char *r_ptr = rbuf_get_linear_read_range(buffer, &to_cpy);
128 if(!to_cpy)
129 return to_cpy;
130
131 to_cpy = MIN(to_cpy, len);
132 memcpy(data, r_ptr, to_cpy);
133 rbuf_bump_tail(buffer, to_cpy);
134 if(to_cpy < len)
135 to_cpy += rbuf_pop(buffer, &data[to_cpy], len - to_cpy);
136 return to_cpy;
137 }
138
139 static inline void rbuf_ptr_inc(rbuf_t buffer, const char **ptr)
140 {
141 (*ptr)++;
142 if(*ptr >= buffer->end)
143 *ptr = buffer->data;
144 }
145
146 int rbuf_memcmp(rbuf_t buffer, const char *haystack, const char *needle, size_t needle_bytes)
147 {
148 const char *end = needle + needle_bytes;
149
150 // as head==tail can mean 2 things here
151 if (haystack == buffer->head && buffer->size_data) {
152 if (*haystack != *needle)
153 return (*haystack - *needle);
154 rbuf_ptr_inc(buffer, &haystack);
155 needle++;
156 }
157
158 while (haystack != buffer->head && needle != end) {
159 if (*haystack != *needle)
160 return (*haystack - *needle);
161 rbuf_ptr_inc(buffer, &haystack);
162 needle++;
163 }
164 return 0;
165 }
166
167 int rbuf_memcmp_n(rbuf_t buffer, const char *to_cmp, size_t to_cmp_bytes)
168 {
169 return rbuf_memcmp(buffer, buffer->tail, to_cmp, to_cmp_bytes);
170 }
171
172 char *rbuf_find_bytes(rbuf_t buffer, const char *needle, size_t needle_bytes, int *found_idx)
173 {
174 const char *ptr = buffer->tail;
175 *found_idx = 0;
176
177 if (!rbuf_bytes_available(buffer))
178 return NULL;
179
180 if (buffer->head == buffer->tail && buffer->size_data) {
181 if(!rbuf_memcmp(buffer, ptr, needle, needle_bytes))
182 return (char *)ptr;
183 rbuf_ptr_inc(buffer, &ptr);
184 (*found_idx)++;
185 }
186
187 while (ptr != buffer->head)
188 {
189 if(!rbuf_memcmp(buffer, ptr, needle, needle_bytes))
190 return (char *)ptr;
191 rbuf_ptr_inc(buffer, &ptr);
192 (*found_idx)++;
193 }
194 return NULL;
195 }