libamxc  1.10.3
C Generic Data Containers
Ring Buffer

Data Structures

struct  _amxc_rbuffer
 The ring buffer structure. More...
 

Typedefs

typedef struct _amxc_rbuffer amxc_rbuffer_t
 The ring buffer structure. More...
 

Functions

int amxc_rbuffer_new (amxc_rbuffer_t **rb, const size_t size)
 Allocates a ring buffer. More...
 
void amxc_rbuffer_delete (amxc_rbuffer_t **rb)
 Frees the previously allocated ring buffer. More...
 
int amxc_rbuffer_init (amxc_rbuffer_t *const rb, const size_t size)
 Initializes a ring buffer. More...
 
void amxc_rbuffer_clean (amxc_rbuffer_t *const rb)
 Frees the buffer and sets all pointers of the ring buffer structure to NULL. More...
 
int amxc_rbuffer_grow (amxc_rbuffer_t *const rb, const size_t size)
 Grows the ring buffer. More...
 
int amxc_rbuffer_shrink (amxc_rbuffer_t *const rb, const size_t size)
 Shrinks the ring buffer. More...
 
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. More...
 
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. More...
 
size_t amxc_rbuffer_size (const amxc_rbuffer_t *const rb)
 Get the size of the data stored in the ring buffer. More...
 
AMXC_INLINE size_t amxc_rbuffer_capacity (const amxc_rbuffer_t *const rb)
 Get the capacity of the ring buffer. More...
 
AMXC_INLINE bool amxc_rbuffer_is_empty (const amxc_rbuffer_t *const rb)
 Checks that the ring buffer is empty. More...
 

Detailed Description

Typedef Documentation

◆ amxc_rbuffer_t

typedef struct _amxc_rbuffer amxc_rbuffer_t

The ring buffer structure.

Function Documentation

◆ amxc_rbuffer_capacity()

AMXC_INLINE size_t amxc_rbuffer_capacity ( const amxc_rbuffer_t *const  rb)

Get the capacity of the ring buffer.

The capacity is the maximum bytes that can be stored in the ring buffer. The capacity - the size is the number of bytes that is currently not used.

Parameters
rba pointer to the ring buffer structure
Returns
The number of bytes that can be stored in the ring buffer

Definition at line 286 of file amxc_rbuffer.h.

286  {
287  return rb != NULL ? rb->buffer_end - rb->buffer_start : 0;
288 }
char * buffer_end
Definition: amxc_rbuffer.h:86
char * buffer_start
Definition: amxc_rbuffer.h:85

◆ amxc_rbuffer_clean()

void amxc_rbuffer_clean ( amxc_rbuffer_t *const  rb)

Frees the buffer and sets all pointers of the ring buffer structure to NULL.

Parameters
rba pointer to the ring buffer structure

Definition at line 134 of file amxc_rbuffer.c.

134  {
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 }
#define when_null(x, l)
Definition: amxc_macros.h:126
char * write_pos
Definition: amxc_rbuffer.h:88
char * read_pos
Definition: amxc_rbuffer.h:87

◆ amxc_rbuffer_delete()

void amxc_rbuffer_delete ( amxc_rbuffer_t **  rb)

Frees the previously allocated ring buffer.

Frees the ring buffer, all data that is still in the buffer will be lost. Also frees the allocated memory to store the ring buffer structure and sets the pointer in the structure to NULL.

Note
Only call this function for ring buffers that are allocated on the heap using amxc_rbuffer_new
Parameters
rba pointer to the location where the pointer to the ring buffer is stored

Definition at line 96 of file amxc_rbuffer.c.

96  {
97  when_null(rb, exit);
98 
99  amxc_rbuffer_clean(*rb);
100  free(*rb);
101  *rb = NULL;
102 
103 exit:
104  return;
105 }
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

◆ amxc_rbuffer_grow()

int amxc_rbuffer_grow ( amxc_rbuffer_t *const  rb,
const size_t  size 
)

Grows the ring buffer.

Increases the capacity of the ring buffer with a number of bytes. The extra memory is always allocated behind the current position of the write pointer. Growing the ring buffer has no effect on the data that is already in the ring buffer.

Parameters
rba pointer to the ring buffer structure
sizethe number of bytes the ring buffer has to grow
Returns
0 on success. -1 if an error has occurred.

Definition at line 147 of file amxc_rbuffer.c.

147  {
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 }
static char * amxc_rbuffer_alloc(amxc_rbuffer_t *const rb, const size_t size)
Definition: amxc_rbuffer.c:62

◆ amxc_rbuffer_init()

int amxc_rbuffer_init ( amxc_rbuffer_t *const  rb,
const size_t  size 
)

Initializes a ring buffer.

Initializes the ring buffer structure. Memory is allocated from the heap to be able to store the number of bytes requested.

This function is typically called for ring buffers that are on the stack. Allocating and initializing a ring buffer on the heap can be done using amxc_rbuffer_new

Note
When calling this function on an already allocated and initialized ring buffer a memory leak occurs, the previously allocated buffer is not reachable anymore. Use amxc_rbuffer_clean to free the buffer and reset all the pointers in the ring buffer structure to NULL.
Parameters
rba pointer to the ring buffer structure.
sizethe size of the ring buffer in number of bytes
Returns
0 on success or -1 when an error occured.

Definition at line 107 of file amxc_rbuffer.c.

107  {
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 }

◆ amxc_rbuffer_is_empty()

AMXC_INLINE bool amxc_rbuffer_is_empty ( const amxc_rbuffer_t *const  rb)

Checks that the ring buffer is empty.

Parameters
rba pointer to the ring buffer structure
Returns
true when there is no data in the ring buffer, or false when there is at least 1 byte of data stored in the ring buffer.

Definition at line 302 of file amxc_rbuffer.h.

302  {
303  return rb != NULL ? (rb->read_pos == rb->write_pos) : true;
304 }

◆ amxc_rbuffer_new()

int amxc_rbuffer_new ( amxc_rbuffer_t **  rb,
const size_t  size 
)

Allocates a ring buffer.

Allocates and initializes memory to store a ring buffer. This functions allocates memory for the ring buffer structure as well as memory for the ring buffer itself. This function allocates memory from the heap, if a ring buffer structure is on the stack, it can be initialized using function amxc_rbuffer_init

The size of the ring buffer is not fixed and can be changed with the functions amxc_rbuffer_grow or amxc_rbuffer_shrink

The size of the ring buffer is expressed in number of bytes that can be stored in the ring buffer.

Note
The allocated memory must be freed when not used anymore, use amxc_rbuffer_delete to free the memory of the ring buffer and the ring buffer structure and amxc_rbuffer_clean to free the buffer itself, but keep the ring buffer structure.
Parameters
rba pointer to the location where the pointer to the new ring buffer structure can be stored
sizethe size of the ring buffer in number of bytes
Returns
-1 if an error occurred. 0 on success

Definition at line 79 of file amxc_rbuffer.c.

79  {
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 }
int amxc_rbuffer_init(amxc_rbuffer_t *const rb, const size_t size)
Initializes a ring buffer.
Definition: amxc_rbuffer.c:107
The ring buffer structure.
Definition: amxc_rbuffer.h:84

◆ amxc_rbuffer_read()

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.

Copies bytes from the ring buffer, starting from the current read position, into the provided buffer to a maximum number of bytes specified. When less bytes then the specified count are copied in the provided buffer, no more data is available in the ring buffer.

Parameters
rba pointer to the ring buffer structure
bufa pointer to a buffer where the data can be copied in.
countthe maximum number of bytes that can be copied
Returns
The number of bytes copied, when less then the specified maximum, the ring buffer is empty.

Definition at line 250 of file amxc_rbuffer.c.

252  {
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 }

◆ amxc_rbuffer_shrink()

int amxc_rbuffer_shrink ( amxc_rbuffer_t *const  rb,
const size_t  size 
)

Shrinks the ring buffer.

Shrinks the ring buffer by the given number of bytes. The memory is freed.

Note
Shrinking the ring buffer could lead to data loss. The buffer shrinks from the current read pointer to the write pointer. The data loss will always be the last part written in the ring buffer.
Parameters
rba pointer to the ring buffer structure
sizethe number of bytes the ring buffer has to shrink
Returns
0 on success. -1 if an error has occurred.

Definition at line 190 of file amxc_rbuffer.c.

190  {
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 }
#define when_true(x, l)
Definition: amxc_macros.h:134

◆ amxc_rbuffer_size()

size_t amxc_rbuffer_size ( const amxc_rbuffer_t *const  rb)

Get the size of the data stored in the ring buffer.

Parameters
rba pointer to the ring buffer structure
Returns
The number of bytes stored in the ring buffer

Definition at line 327 of file amxc_rbuffer.c.

327  {
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 }

◆ amxc_rbuffer_write()

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.

Copies the specified number of bytes to the ring buffer, starting from the current write position, from the provided buffer. The ring buffer grows when there is not enough space left in the ring buffer.

Parameters
rba pointer to the ring buffer structure
bufa pointer to a buffer that contains the data that must be put in the ring buffer.
countthe number of bytes that need to be copied in the ring buffer
Returns
The number of bytes copied or -1 when failed to copy the bytes in the ring buffer.

Definition at line 292 of file amxc_rbuffer.c.

294  {
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 }
#define when_failed(x, l)
Definition: amxc_macros.h:142
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_grow(amxc_rbuffer_t *const rb, const size_t size)
Grows the ring buffer.
Definition: amxc_rbuffer.c:147