libamxc  1.10.3
C Generic Data Containers
amxc_rbuffer.c
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** SPDX-License-Identifier: BSD-2-Clause-Patent
4 **
5 ** SPDX-FileCopyrightText: Copyright (c) 2023 SoftAtHome
6 **
7 ** Redistribution and use in source and binary forms, with or without modification,
8 ** are permitted provided that the following conditions are met:
9 **
10 ** 1. Redistributions of source code must retain the above copyright notice,
11 ** this list of conditions and the following disclaimer.
12 **
13 ** 2. Redistributions in binary form must reproduce the above copyright notice,
14 ** this list of conditions and the following disclaimer in the documentation
15 ** and/or other materials provided with the distribution.
16 **
17 ** Subject to the terms and conditions of this license, each copyright holder
18 ** and contributor hereby grants to those receiving rights under this license
19 ** a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
20 ** (except for failure to satisfy the conditions of this license) patent license
21 ** to make, have made, use, offer to sell, sell, import, and otherwise transfer
22 ** this software, where such license applies only to those patent claims, already
23 ** acquired or hereafter acquired, licensable by such copyright holder or contributor
24 ** that are necessarily infringed by:
25 **
26 ** (a) their Contribution(s) (the licensed copyrights of copyright holders and
27 ** non-copyrightable additions of contributors, in source or binary form) alone;
28 ** or
29 **
30 ** (b) combination of their Contribution(s) with the work of authorship to which
31 ** such Contribution(s) was added by such copyright holder or contributor, if,
32 ** at the time the Contribution is added, such addition causes such combination
33 ** to be necessarily infringed. The patent license shall not apply to any other
34 ** combinations which include the Contribution.
35 **
36 ** Except as expressly stated above, no rights or licenses from any copyright
37 ** holder or contributor is granted under this license, whether expressly, by
38 ** implication, estoppel or otherwise.
39 **
40 ** DISCLAIMER
41 **
42 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
43 ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 ** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
46 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
48 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
49 ** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50 ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
51 ** USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 **
53 ****************************************************************************/
54 
55 #include <stdlib.h>
56 #include <string.h>
57 #include <unistd.h>
58 
59 #include <amxc/amxc_rbuffer.h>
60 #include <amxc/amxc_macros.h>
61 
62 static char* amxc_rbuffer_alloc(amxc_rbuffer_t* const rb, const size_t size) {
63  char* buffer = NULL;
64  if(rb->buffer_start == NULL) {
65  buffer = (char*) calloc(1, size);
66  } else {
67  buffer = (char*) realloc(rb->buffer_start, size);
68  }
69 
70  return buffer;
71 }
72 
79 int amxc_rbuffer_new(amxc_rbuffer_t** rb, const size_t size) {
80  int retval = -1;
81  when_null(rb, exit);
82 
83  *rb = (amxc_rbuffer_t*) calloc(1, sizeof(amxc_rbuffer_t));
84  when_null(*rb, exit);
85 
86  retval = amxc_rbuffer_init(*rb, size);
87  if(retval == -1) {
88  free(*rb);
89  *rb = NULL;
90  }
91 
92 exit:
93  return retval;
94 }
95 
97  when_null(rb, exit);
98 
99  amxc_rbuffer_clean(*rb);
100  free(*rb);
101  *rb = NULL;
102 
103 exit:
104  return;
105 }
106 
107 int amxc_rbuffer_init(amxc_rbuffer_t* const rb, const size_t size) {
108  int retval = -1;
109  when_null(rb, exit);
110 
111  rb->buffer_start = NULL;
112  rb->buffer_end = NULL;
113  rb->read_pos = NULL;
114  rb->write_pos = NULL;
115 
116  if(size == 0) {
117  retval = 0;
118  goto exit;
119  }
120 
121  rb->buffer_start = amxc_rbuffer_alloc(rb, size);
122  when_null(rb->buffer_start, exit);
123 
124  rb->buffer_end = rb->buffer_start + size;
125  rb->read_pos = rb->buffer_start;
126  rb->write_pos = rb->buffer_start;
127 
128  retval = 0;
129 
130 exit:
131  return retval;
132 }
133 
135  when_null(rb, exit);
136 
137  free(rb->buffer_start);
138  rb->buffer_start = NULL;
139  rb->buffer_end = NULL;
140  rb->read_pos = NULL;
141  rb->write_pos = NULL;
142 
143 exit:
144  return;
145 }
146 
147 int amxc_rbuffer_grow(amxc_rbuffer_t* const rb, const size_t size) {
148  int retval = -1;
149  size_t read_pos = 0;
150  size_t write_pos = 0;
151  size_t new_size = 0;
152  char* new_buffer = NULL;
153 
154  when_null(rb, exit);
155 
156  read_pos = rb->read_pos - rb->buffer_start;
157  write_pos = rb->write_pos - rb->buffer_start;
158 
159  new_size = (rb->buffer_end - rb->buffer_start) + size;
160  new_buffer = amxc_rbuffer_alloc(rb, new_size);
161  if(!new_buffer) {
162  goto exit;
163  }
164 
165  rb->buffer_start = new_buffer;
166  rb->buffer_end = rb->buffer_start + new_size;
167  rb->read_pos = rb->buffer_start + read_pos;
168  rb->write_pos = rb->buffer_start + write_pos;
169 
170  // if the read pointer is after the write pointer,
171  // the read pointer must be move the number of bytes
172  // the buffer has grown, and the data has to be moved
173  if(rb->read_pos > rb->write_pos) {
174  memmove(rb->buffer_start + read_pos + size,
175  rb->buffer_start + read_pos,
176  size);
177  memset(rb->buffer_start + read_pos, 0, size);
178  rb->read_pos += size;
179  } else {
180  memset(rb->buffer_start + write_pos, 0, size);
181  }
182 
183  retval = 0;
184 
185 exit:
186  return retval;
187 }
188 
189 // TODO: this function needs refactorying/splitting up - too long
190 int amxc_rbuffer_shrink(amxc_rbuffer_t* const rb, const size_t size) {
191  int retval = -1;
192  size_t buffer_size = 0;
193  size_t new_size = 0;
194  size_t read_pos = 0;
195  size_t write_pos = 0;
196  char* new_buffer = NULL;
197  when_null(rb, exit);
198 
199  buffer_size = rb->buffer_end - rb->buffer_start;
200  when_true(size > buffer_size, exit);
201 
202  if(size == buffer_size) {
203  amxc_rbuffer_clean(rb);
204  retval = 0;
205  goto exit;
206  }
207 
208  new_size = (rb->buffer_end - rb->buffer_start) - size;
209  if(rb->read_pos > rb->write_pos) {
210  size_t bytes = rb->read_pos - rb->buffer_start;
211  size_t move = (size > bytes) ? bytes : size;
212  memmove(rb->buffer_start + move,
213  rb->read_pos,
214  rb->buffer_end - rb->read_pos);
215  rb->read_pos -= move;
216  if(rb->read_pos > rb->buffer_start) {
217  if(rb->write_pos > rb->read_pos) {
218  rb->write_pos = rb->read_pos - 1;
219  }
220  } else {
221  rb->write_pos = rb->buffer_start + new_size;
222  }
223  } else {
224  size_t move = rb->write_pos - rb->read_pos;
225  memmove(rb->buffer_start, rb->read_pos, move);
226  rb->read_pos = rb->buffer_start;
227  if(move > new_size) {
228  rb->write_pos = rb->buffer_start + new_size;
229  } else {
230  rb->write_pos = rb->buffer_start + move;
231  }
232  }
233 
234  read_pos = rb->read_pos - rb->buffer_start;
235  write_pos = rb->write_pos - rb->buffer_start;
236 
237  new_buffer = (char*) realloc(rb->buffer_start, new_size);
238 
239  rb->buffer_start = new_buffer;
240  rb->buffer_end = rb->buffer_start + new_size;
241  rb->read_pos = rb->buffer_start + read_pos;
242  rb->write_pos = rb->buffer_start + write_pos;
243 
244  retval = 0;
245 
246 exit:
247  return retval;
248 }
249 
251  char* const buf,
252  size_t count) {
253  ssize_t retval = -1;
254  when_null(rb, exit);
255  when_null(buf, exit);
256 
257  if((count == 0) || (rb->read_pos == rb->write_pos)) {
258  retval = 0;
259  goto exit;
260  }
261 
262  if(rb->read_pos > rb->write_pos) {
263  size_t data_size = rb->buffer_end - rb->read_pos;
264  if(count > data_size) {
265  size_t max_size = 0;
266  memcpy(buf, rb->read_pos, data_size);
267  count -= data_size;
268  max_size = rb->write_pos - rb->buffer_start;
269  memcpy(buf + data_size,
270  rb->buffer_start,
271  count > max_size ? max_size : count);
272  retval = data_size + (count > max_size ? max_size : count);
273  rb->read_pos = rb->buffer_start +
274  (count > max_size ? max_size : count);
275  } else {
276  data_size = rb->write_pos - rb->read_pos;
277  memcpy(buf, rb->read_pos, data_size > count ? count : data_size);
278  rb->read_pos += data_size > count ? count : data_size;
279  retval = data_size > count ? count : data_size;
280  }
281  } else {
282  size_t data_size = rb->write_pos - rb->read_pos;
283  memcpy(buf, rb->read_pos, data_size > count ? count : data_size);
284  rb->read_pos += data_size > count ? count : data_size;
285  retval = data_size > count ? count : data_size;
286  }
287 
288 exit:
289  return retval;
290 }
291 
293  const char* const buf,
294  const size_t count) {
295  ssize_t retval = -1;
296  size_t free_space = 0;
297  when_null(rb, exit);
298 
299  // check space, grow if needed
300  free_space = (rb->buffer_end - rb->buffer_start) - amxc_rbuffer_size(rb);
301  if(free_space < count) {
302  when_failed(amxc_rbuffer_grow(rb, count * 2), exit);
303  }
304 
305  // check border
306  if(rb->write_pos >= rb->read_pos) {
307  free_space = rb->buffer_end - rb->write_pos;
308  if(count > free_space) {
309  memcpy(rb->write_pos, buf, free_space);
310  memcpy(rb->buffer_start, buf + free_space, count - free_space);
311  rb->write_pos = rb->buffer_start + (count - free_space);
312  } else {
313  memcpy(rb->write_pos, buf, count);
314  rb->write_pos += count;
315  }
316  } else {
317  memcpy(rb->write_pos, buf, count);
318  rb->write_pos += count;
319  }
320 
321  retval = count;
322 
323 exit:
324  return retval;
325 }
326 
327 size_t amxc_rbuffer_size(const amxc_rbuffer_t* const rb) {
328  size_t retval = 0;
329  when_null(rb, exit);
330  when_true(rb->read_pos == rb->write_pos, exit);
331 
332  if(rb->read_pos > rb->write_pos) {
333  retval = (rb->buffer_end - rb->read_pos) +
334  (rb->write_pos - rb->buffer_start);
335  } else {
336  retval = (rb->write_pos - rb->read_pos);
337  }
338 
339 exit:
340  return retval;
341 }
#define when_failed(x, l)
Definition: amxc_macros.h:142
#define when_true(x, l)
Definition: amxc_macros.h:134
#define when_null(x, l)
Definition: amxc_macros.h:126
static char * amxc_rbuffer_alloc(amxc_rbuffer_t *const rb, const size_t size)
Definition: amxc_rbuffer.c:62
Ambiorix ring buffer API header file.
size_t amxc_rbuffer_size(const amxc_rbuffer_t *const rb)
Get the size of the data stored in the ring buffer.
Definition: amxc_rbuffer.c:327
int amxc_rbuffer_shrink(amxc_rbuffer_t *const rb, const size_t size)
Shrinks the ring buffer.
Definition: amxc_rbuffer.c:190
void amxc_rbuffer_clean(amxc_rbuffer_t *const rb)
Frees the buffer and sets all pointers of the ring buffer structure to NULL.
Definition: amxc_rbuffer.c:134
ssize_t amxc_rbuffer_write(amxc_rbuffer_t *const rb, const char *const buf, const size_t count)
Writes a number of bytes to the ring buffer.
Definition: amxc_rbuffer.c:292
int amxc_rbuffer_new(amxc_rbuffer_t **rb, const size_t size)
Allocates a ring buffer.
Definition: amxc_rbuffer.c:79
int amxc_rbuffer_grow(amxc_rbuffer_t *const rb, const size_t size)
Grows the ring buffer.
Definition: amxc_rbuffer.c:147
void amxc_rbuffer_delete(amxc_rbuffer_t **rb)
Frees the previously allocated ring buffer.
Definition: amxc_rbuffer.c:96
int amxc_rbuffer_init(amxc_rbuffer_t *const rb, const size_t size)
Initializes a ring buffer.
Definition: amxc_rbuffer.c:107
ssize_t amxc_rbuffer_read(amxc_rbuffer_t *const rb, char *const buf, size_t count)
Reads a number of bytes from the ring buffer.
Definition: amxc_rbuffer.c:250
The ring buffer structure.
Definition: amxc_rbuffer.h:84
char * buffer_end
Definition: amxc_rbuffer.h:86
char * buffer_start
Definition: amxc_rbuffer.h:85
char * write_pos
Definition: amxc_rbuffer.h:88
char * read_pos
Definition: amxc_rbuffer.h:87