1 /*
2  * Copyright (c) 2002-2014 Balabit
3  * Copyright (c) 2014 Laszlo Budai
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  *
19  * As an additional exemption you are allowed to compile & link against the
20  * OpenSSL libraries as published by the OpenSSL project. See the file
21  * COPYING for details.
22  *
23  */
24 
25 #include "ringbuffer.h"
26 
27 void
ring_buffer_init(RingBuffer * self)28 ring_buffer_init(RingBuffer *self)
29 {
30   self->head = 0;
31   self->tail = 0;
32   self->count = 0;
33   self->capacity = 0;
34   self->element_size = 0;
35   self->buffer = NULL;
36 }
37 
38 void
ring_buffer_alloc(RingBuffer * self,guint32 element_size,guint32 capacity)39 ring_buffer_alloc(RingBuffer *self, guint32 element_size, guint32 capacity)
40 {
41   g_assert(capacity > 0);
42   self->head = 0;
43   self->tail = 0;
44   self->count = 0;
45   self->capacity = capacity;
46   self->element_size = element_size;
47   self->buffer = g_malloc0(element_size * self->capacity);
48 }
49 
50 gboolean
ring_buffer_is_allocated(RingBuffer * self)51 ring_buffer_is_allocated(RingBuffer *self)
52 {
53   return (self->buffer != NULL);
54 }
55 
56 void
ring_buffer_free(RingBuffer * self)57 ring_buffer_free(RingBuffer *self)
58 {
59   g_free(self->buffer);
60   self->head = 0;
61   self->tail = 0;
62   self->count = 0;
63   self->capacity = 0;
64   self->element_size = 0;
65   self->buffer = NULL;
66 }
67 
68 gboolean
ring_buffer_is_full(RingBuffer * self)69 ring_buffer_is_full(RingBuffer *self)
70 {
71   return self->capacity == self->count ? TRUE : FALSE;
72 }
73 
74 gboolean
ring_buffer_is_empty(RingBuffer * self)75 ring_buffer_is_empty(RingBuffer *self)
76 {
77   return (self->count == 0) ? TRUE : FALSE;
78 }
79 
80 gpointer
ring_buffer_push(RingBuffer * self)81 ring_buffer_push(RingBuffer *self)
82 {
83   gpointer r = ring_buffer_tail(self);
84 
85   if (!r)
86     return NULL;
87 
88   ++self->count;
89   self->tail = (self->tail + 1) % self->capacity;
90 
91   return r;
92 }
93 
94 gpointer
ring_buffer_tail(RingBuffer * self)95 ring_buffer_tail (RingBuffer *self)
96 {
97   g_assert(self->buffer != NULL);
98 
99   if (ring_buffer_is_full(self))
100     return NULL;
101 
102   gpointer r = (guint8 *) (self->buffer) + self->tail * self->element_size;
103 
104   return r;
105 }
106 
107 gpointer
ring_buffer_pop(RingBuffer * self)108 ring_buffer_pop(RingBuffer *self)
109 {
110   g_assert(self->buffer != NULL);
111 
112   if (ring_buffer_is_empty(self))
113     return NULL;
114 
115   gpointer r = (guint8 *) (self->buffer) + self->head * self->element_size;
116 
117   --self->count;
118   self->head = (self->head + 1) % self->capacity;
119 
120   return r;
121 }
122 
123 gboolean
ring_buffer_drop(RingBuffer * self,guint32 n)124 ring_buffer_drop(RingBuffer *self, guint32 n)
125 {
126   g_assert(self->buffer != NULL);
127 
128   if (ring_buffer_count(self) < n)
129     return FALSE;
130 
131   self->count -= n;
132   self->head = (self->head + n) % self->capacity;
133 
134   return TRUE;
135 }
136 
137 guint32
ring_buffer_capacity(RingBuffer * self)138 ring_buffer_capacity(RingBuffer *self)
139 {
140   return self->buffer ? self->capacity : 0;
141 }
142 
143 guint32
ring_buffer_count(RingBuffer * self)144 ring_buffer_count(RingBuffer *self)
145 {
146   return self->count;
147 }
148 
149 gpointer
ring_buffer_element_at(RingBuffer * self,guint32 idx)150 ring_buffer_element_at(RingBuffer *self, guint32 idx)
151 {
152   g_assert(self->buffer != NULL);
153 
154   if (idx >= self->count)
155     return NULL;
156 
157   return (guint8 *) (self->buffer) + ((self->head + idx) % self->capacity) * self->element_size;
158 }
159 
160 guint32
ring_buffer_get_continual_range_length(RingBuffer * self,RingBufferIsContinuousPredicate pred)161 ring_buffer_get_continual_range_length(RingBuffer *self, RingBufferIsContinuousPredicate pred)
162 {
163   guint32 r = 0, i;
164 
165   g_assert(self->buffer != NULL);
166 
167   for (i = 0; i < ring_buffer_count(self); i++)
168     {
169       if (!pred(ring_buffer_element_at(self, i)))
170         {
171           break;
172         }
173       ++r;
174     }
175 
176   return r;
177 }
178