libpurple/circbuffer.c

branch
soc.2013.gobjectification
changeset 34529
68cf25486001
parent 27361
62f1aa8045bb
equal deleted inserted replaced
34528:d43e45869467 34529:68cf25486001
25 25
26 #include "circbuffer.h" 26 #include "circbuffer.h"
27 27
28 #define DEFAULT_BUF_SIZE 256 28 #define DEFAULT_BUF_SIZE 256
29 29
30 PurpleCircBuffer * 30 #define PURPLE_CIRCULAR_BUFFER_GET_PRIVATE(obj) \
31 purple_circ_buffer_new(gsize growsize) { 31 (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_CIRCULAR_BUFFER, PurpleCircularBufferPrivate))
32 PurpleCircBuffer *buf = g_new0(PurpleCircBuffer, 1); 32
33 buf->growsize = growsize ? growsize : DEFAULT_BUF_SIZE; 33 /******************************************************************************
34 return buf; 34 * Structs
35 } 35 *****************************************************************************/
36 36 typedef struct {
37 void purple_circ_buffer_destroy(PurpleCircBuffer *buf) { 37 gchar *buffer;
38 g_return_if_fail(buf != NULL); 38 gsize growsize;
39 39 gsize buflen;
40 g_free(buf->buffer); 40 gsize bufused;
41 g_free(buf); 41 gchar *input;
42 } 42 gchar *output;
43 43 } PurpleCircularBufferPrivate;
44 static void grow_circ_buffer(PurpleCircBuffer *buf, gsize len) { 44
45 int in_offset = 0, out_offset = 0; 45 /******************************************************************************
46 int start_buflen; 46 * Enums
47 47 *****************************************************************************/
48 g_return_if_fail(buf != NULL); 48 enum {
49 49 PROP_ZERO,
50 start_buflen = buf->buflen; 50 PROP_GROW_SIZE,
51 51 PROP_BUFFER_USED,
52 while ((buf->buflen - buf->bufused) < len) 52 PROP_INPUT,
53 buf->buflen += buf->growsize; 53 PROP_OUTPUT,
54 54 PROP_LAST,
55 if (buf->inptr != NULL) { 55 };
56 in_offset = buf->inptr - buf->buffer; 56
57 out_offset = buf->outptr - buf->buffer; 57 /******************************************************************************
58 } 58 * Globals
59 buf->buffer = g_realloc(buf->buffer, buf->buflen); 59 *****************************************************************************/
60 static GObjectClass *parent_class = NULL;
61
62 /******************************************************************************
63 * Circular Buffer Implementation
64 *****************************************************************************/
65 static void
66 purple_circular_buffer_real_grow(PurpleCircularBuffer *buffer, gsize len) {
67 PurpleCircularBufferPrivate *priv = NULL;
68 gint in_offset = 0, out_offset = 0;
69 gint start_buflen;
70
71 priv = PURPLE_CIRCULAR_BUFFER_GET_PRIVATE(buffer);
72
73 start_buflen = priv->buflen;
74
75 while((priv->buflen - priv->bufused) < len)
76 priv->buflen += priv->growsize;
77
78 if(priv->input != NULL) {
79 in_offset = priv->input - priv->buffer;
80 out_offset = priv->output - priv->buffer;
81 }
82
83 priv->buffer = g_realloc(priv->buffer, priv->buflen);
60 84
61 /* adjust the fill and remove pointer locations */ 85 /* adjust the fill and remove pointer locations */
62 if (buf->inptr == NULL) { 86 if(priv->input == NULL) {
63 buf->inptr = buf->outptr = buf->buffer; 87 priv->input = priv->output = priv->buffer;
64 } else { 88 } else {
65 buf->inptr = buf->buffer + in_offset; 89 priv->input = priv->buffer + in_offset;
66 buf->outptr = buf->buffer + out_offset; 90 priv->output = priv->buffer + out_offset;
67 } 91 }
68 92
69 /* If the fill pointer is wrapped to before the remove 93 /* If the fill pointer is wrapped to before the remove
70 * pointer, we need to shift the data */ 94 * pointer, we need to shift the data */
71 if (in_offset < out_offset 95 if(in_offset < out_offset
72 || (in_offset == out_offset && buf->bufused > 0)) { 96 || (in_offset == out_offset && priv->bufused > 0))
73 int shift_n = MIN(buf->buflen - start_buflen, 97 {
74 in_offset); 98 gint shift_n = MIN(priv->buflen - start_buflen, in_offset);
75 memcpy(buf->buffer + start_buflen, buf->buffer, 99 memcpy(priv->buffer + start_buflen, priv->buffer, shift_n);
76 shift_n); 100
77 101 /* If we couldn't fit the wrapped read buffer at the end */
78 /* If we couldn't fit the wrapped read buffer
79 * at the end */
80 if (shift_n < in_offset) { 102 if (shift_n < in_offset) {
81 memmove(buf->buffer, 103 memmove(priv->buffer, priv->buffer + shift_n, in_offset - shift_n);
82 buf->buffer + shift_n, 104 priv->input = priv->buffer + (in_offset - shift_n);
83 in_offset - shift_n);
84 buf->inptr = buf->buffer +
85 (in_offset - shift_n);
86 } else { 105 } else {
87 buf->inptr = buf->buffer + 106 priv->input = priv->buffer + start_buflen + in_offset;
88 start_buflen + in_offset;
89 } 107 }
90 } 108 }
91 } 109 }
92 110
93 void purple_circ_buffer_append(PurpleCircBuffer *buf, gconstpointer src, gsize len) { 111 static void
94 112 purple_circular_buffer_real_append(PurpleCircularBuffer *buffer,
95 int len_stored; 113 gconstpointer src, gsize len)
96 114 {
97 g_return_if_fail(buf != NULL); 115 PurpleCircularBufferPrivate *priv = NULL;
116 gint len_stored;
117
118 priv = PURPLE_CIRCULAR_BUFFER_GET_PRIVATE(buffer);
98 119
99 /* Grow the buffer, if necessary */ 120 /* Grow the buffer, if necessary */
100 if ((buf->buflen - buf->bufused) < len) 121 if((priv->buflen - priv->bufused) < len)
101 grow_circ_buffer(buf, len); 122 purple_circular_buffer_grow(buffer, len);
102 123
103 /* If there is not enough room to copy all of src before hitting 124 /* If there is not enough room to copy all of src before hitting
104 * the end of the buffer then we will need to do two copies. 125 * the end of the buffer then we will need to do two copies.
105 * One copy from inptr to the end of the buffer, and the 126 * One copy from input to the end of the buffer, and the
106 * second copy from the start of the buffer to the end of src. */ 127 * second copy from the start of the buffer to the end of src. */
107 if (buf->inptr >= buf->outptr) 128 if(priv->input >= priv->output)
108 len_stored = MIN(len, buf->buflen 129 len_stored = MIN(len, priv->buflen - (priv->input - priv->buffer));
109 - (buf->inptr - buf->buffer));
110 else 130 else
111 len_stored = len; 131 len_stored = len;
112 132
113 if (len_stored > 0) 133 if(len_stored > 0)
114 memcpy(buf->inptr, src, len_stored); 134 memcpy(priv->input, src, len_stored);
115 135
116 if (len_stored < len) { 136 if(len_stored < len) {
117 memcpy(buf->buffer, (char*)src + len_stored, len - len_stored); 137 memcpy(priv->buffer, (char*)src + len_stored, len - len_stored);
118 buf->inptr = buf->buffer + (len - len_stored); 138 priv->input = priv->buffer + (len - len_stored);
119 } else { 139 } else {
120 buf->inptr += len_stored; 140 priv->input += len_stored;
121 } 141 }
122 142
123 buf->bufused += len; 143 priv->bufused += len;
124 } 144 }
125 145
126 gsize purple_circ_buffer_get_max_read(const PurpleCircBuffer *buf) { 146 static gsize
147 purple_circular_buffer_real_max_read_size(const PurpleCircularBuffer *buffer) {
148 PurpleCircularBufferPrivate *priv = NULL;
127 gsize max_read; 149 gsize max_read;
128 150
129 g_return_val_if_fail(buf != NULL, 0); 151 priv = PURPLE_CIRCULAR_BUFFER_GET_PRIVATE(buffer);
130 152
131 if (buf->bufused == 0) 153 if(priv->bufused == 0)
132 max_read = 0; 154 max_read = 0;
133 else if ((buf->outptr - buf->inptr) >= 0) 155 else if((priv->output - priv->input) >= 0)
134 max_read = buf->buflen - (buf->outptr - buf->buffer); 156 max_read = priv->buflen - (priv->output - priv->buffer);
135 else 157 else
136 max_read = buf->inptr - buf->outptr; 158 max_read = priv->input - priv->output;
137 159
138 return max_read; 160 return max_read;
139 } 161 }
140 162
141 gboolean purple_circ_buffer_mark_read(PurpleCircBuffer *buf, gsize len) { 163 static gboolean
142 g_return_val_if_fail(buf != NULL, FALSE); 164 purple_circular_buffer_real_mark_read(PurpleCircularBuffer *buffer,
143 g_return_val_if_fail(purple_circ_buffer_get_max_read(buf) >= len, FALSE); 165 gsize len)
144 166 {
145 buf->outptr += len; 167 PurpleCircularBufferPrivate *priv = NULL;
146 buf->bufused -= len; 168
169 g_return_val_if_fail(purple_circular_buffer_get_max_read(buffer) >= len, FALSE);
170
171 priv = PURPLE_CIRCULAR_BUFFER_GET_PRIVATE(buffer);
172
173 priv->output += len;
174 priv->bufused -= len;
175
147 /* wrap to the start if we're at the end */ 176 /* wrap to the start if we're at the end */
148 if ((buf->outptr - buf->buffer) == buf->buflen) 177 if((priv->output - priv->buffer) == priv->buflen)
149 buf->outptr = buf->buffer; 178 priv->output = priv->buffer;
150 179
151 return TRUE; 180 return TRUE;
152 } 181 }
153 182
183 /******************************************************************************
184 * Private API
185 *****************************************************************************/
186 static void
187 purple_circular_buffer_set_grow_size(PurpleCircularBuffer *buffer,
188 gsize grow_size)
189 {
190 PurpleCircularBufferPrivate *priv =
191 PURPLE_CIRCULAR_BUFFER_GET_PRIVATE(buffer);
192
193 priv->growsize = (grow_size != 0) ? grow_size : DEFAULT_BUF_SIZE;
194
195 g_object_notify(G_OBJECT(buffer), "grow-size");
196 }
197
198 /******************************************************************************
199 * Object Stuff
200 *****************************************************************************/
201 static void
202 purple_circular_buffer_finalize(GObject *obj) {
203 PurpleCircularBufferPrivate *priv =
204 PURPLE_CIRCULAR_BUFFER_GET_PRIVATE(obj);
205
206 g_free(priv->buffer);
207
208 G_OBJECT_CLASS(parent_class)->finalize(obj);
209 }
210
211 static void
212 purple_circular_buffer_get_property(GObject *obj, guint param_id,
213 GValue *value, GParamSpec *pspec)
214 {
215 PurpleCircularBuffer *buffer = PURPLE_CIRCULAR_BUFFER(obj);
216
217 switch(param_id) {
218 case PROP_GROW_SIZE:
219 g_value_set_ulong(value,
220 purple_circular_buffer_get_grow_size(buffer));
221 break;
222 case PROP_BUFFER_USED:
223 g_value_set_ulong(value,
224 purple_circular_buffer_get_used(buffer));
225 break;
226 case PROP_INPUT:
227 g_value_set_pointer(value,
228 (void*) purple_circular_buffer_get_input(buffer));
229 break;
230 case PROP_OUTPUT:
231 g_value_set_pointer(value,
232 (void*) purple_circular_buffer_get_output(buffer));
233 break;
234 default:
235 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
236 break;
237 }
238 }
239
240 static void
241 purple_circular_buffer_set_property(GObject *obj, guint param_id,
242 const GValue *value, GParamSpec *pspec)
243 {
244 PurpleCircularBuffer *buffer = PURPLE_CIRCULAR_BUFFER(obj);
245
246 switch(param_id) {
247 case PROP_GROW_SIZE:
248 purple_circular_buffer_set_grow_size(buffer,
249 g_value_get_uint(value));
250 break;
251 default:
252 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
253 break;
254 }
255 }
256
257 static void
258 purple_circular_buffer_class_init(PurpleCircularBufferClass *klass) {
259 GObjectClass *obj_class = G_OBJECT_CLASS(klass);
260 PurpleCircularBufferClass *buffer_class = PURPLE_CIRCULAR_BUFFER_CLASS(klass);
261
262 parent_class = g_type_class_peek_parent(klass);
263
264 g_type_class_add_private(klass, sizeof(PurpleCircularBufferPrivate));
265
266 obj_class->finalize = purple_circular_buffer_finalize;
267 obj_class->get_property = purple_circular_buffer_get_property;
268 obj_class->set_property = purple_circular_buffer_set_property;
269
270 buffer_class->grow = purple_circular_buffer_real_grow;
271 buffer_class->append = purple_circular_buffer_real_append;
272 buffer_class->max_read_size = purple_circular_buffer_real_max_read_size;
273 buffer_class->mark_read = purple_circular_buffer_real_mark_read;
274
275 /* using a ulong for the gsize properties since there is no
276 * g_param_spec_size, and the ulong should always work. --gk 3/21/11
277 */
278 g_object_class_install_property(obj_class, PROP_GROW_SIZE,
279 g_param_spec_ulong("grow-size", "grow-size",
280 "The grow size of the buffer",
281 0, G_MAXSIZE, 0,
282 G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
283
284 g_object_class_install_property(obj_class, PROP_BUFFER_USED,
285 g_param_spec_ulong("buffer-used", "buffer-used",
286 "The amount of the buffer used",
287 0, G_MAXSIZE, 0,
288 G_PARAM_READABLE));
289
290 g_object_class_install_property(obj_class, PROP_INPUT,
291 g_param_spec_pointer("input", "input",
292 "The input pointer of the buffer",
293 G_PARAM_READABLE));
294
295 g_object_class_install_property(obj_class, PROP_OUTPUT,
296 g_param_spec_pointer("output", "output",
297 "The output pointer of the buffer",
298 G_PARAM_READABLE));
299 }
300
301 /******************************************************************************
302 * API
303 *****************************************************************************/
304 GType
305 purple_circular_buffer_get_type(void) {
306 static GType type = 0;
307
308 if(G_UNLIKELY(type == 0)) {
309 static const GTypeInfo info = {
310 .class_size = sizeof(PurpleCircularBufferClass),
311 .class_init = (GClassInitFunc)purple_circular_buffer_class_init,
312 .instance_size = sizeof(PurpleCircularBuffer),
313 };
314
315 type = g_type_register_static(G_TYPE_OBJECT,
316 "PurpleCircularBuffer",
317 &info, 0);
318 }
319
320 return type;
321 }
322
323 PurpleCircularBuffer *
324 purple_circular_buffer_new(gsize growsize) {
325 return g_object_new(PURPLE_TYPE_CIRCULAR_BUFFER,
326 "grow-size", growsize ? growsize : DEFAULT_BUF_SIZE,
327 NULL);
328 }
329
330 void
331 purple_circular_buffer_grow(PurpleCircularBuffer *buffer, gsize len) {
332 PurpleCircularBufferClass *klass = NULL;
333
334 g_return_if_fail(PURPLE_IS_CIRCULAR_BUFFER(buffer));
335
336 klass = PURPLE_CIRCULAR_BUFFER_GET_CLASS(buffer);
337 if(klass && klass->grow)
338 klass->grow(buffer, len);
339 }
340
341 void
342 purple_circular_buffer_append(PurpleCircularBuffer *buffer, gconstpointer src,
343 gsize len)
344 {
345 PurpleCircularBufferClass *klass = NULL;
346
347 g_return_if_fail(PURPLE_IS_CIRCULAR_BUFFER(buffer));
348 g_return_if_fail(src != NULL);
349
350 klass = PURPLE_CIRCULAR_BUFFER_GET_CLASS(buffer);
351 if(klass && klass->append)
352 klass->append(buffer, src, len);
353 }
354
355 gsize
356 purple_circular_buffer_get_max_read(const PurpleCircularBuffer *buffer) {
357 PurpleCircularBufferClass *klass = NULL;
358
359 g_return_val_if_fail(PURPLE_IS_CIRCULAR_BUFFER(buffer), 0);
360
361 klass = PURPLE_CIRCULAR_BUFFER_GET_CLASS(buffer);
362 if(klass && klass->max_read_size)
363 return klass->max_read_size(buffer);
364
365 return 0;
366 }
367
368 gboolean
369 purple_circular_buffer_mark_read(PurpleCircularBuffer *buffer, gsize len) {
370 PurpleCircularBufferClass *klass = NULL;
371
372 g_return_val_if_fail(PURPLE_IS_CIRCULAR_BUFFER(buffer), FALSE);
373
374 klass = PURPLE_CIRCULAR_BUFFER_CLASS(buffer);
375 if(klass && klass->mark_read)
376 return klass->mark_read(buffer, len);
377
378 return FALSE;
379 }
380
381 gsize
382 purple_circular_buffer_get_grow_size(const PurpleCircularBuffer *buffer) {
383
384 PurpleCircularBufferPrivate *priv = NULL;
385
386 g_return_val_if_fail(PURPLE_IS_CIRCULAR_BUFFER(buffer), 0);
387
388 priv = PURPLE_CIRCULAR_BUFFER_GET_PRIVATE(buffer);
389
390 return priv->growsize;
391 }
392
393 gsize
394 purple_circular_buffer_get_used(const PurpleCircularBuffer *buffer) {
395 PurpleCircularBufferPrivate *priv = NULL;
396
397 g_return_val_if_fail(PURPLE_IS_CIRCULAR_BUFFER(buffer), 0);
398
399 priv = PURPLE_CIRCULAR_BUFFER_GET_PRIVATE(buffer);
400
401 return priv->bufused;
402 }
403
404 const gchar *
405 purple_circular_buffer_get_input(const PurpleCircularBuffer *buffer) {
406 PurpleCircularBufferPrivate *priv = NULL;
407
408 g_return_val_if_fail(PURPLE_IS_CIRCULAR_BUFFER(buffer), NULL);
409
410 priv = PURPLE_CIRCULAR_BUFFER_GET_PRIVATE(buffer);
411
412 return priv->input;
413 }
414
415 const gchar *
416 purple_circular_buffer_get_output(const PurpleCircularBuffer *buffer) {
417 PurpleCircularBufferPrivate *priv = NULL;
418
419 g_return_val_if_fail(PURPLE_IS_CIRCULAR_BUFFER(buffer), NULL);
420
421 priv = PURPLE_CIRCULAR_BUFFER_GET_PRIVATE(buffer);
422
423 return priv->output;
424 }
425
426 void
427 purple_circular_buffer_reset(PurpleCircularBuffer *buffer) {
428 PurpleCircularBufferPrivate *priv = NULL;
429 GObject *obj = NULL;
430
431 g_return_if_fail(PURPLE_IS_CIRCULAR_BUFFER(buffer));
432
433 priv = PURPLE_CIRCULAR_BUFFER_GET_PRIVATE(buffer);
434
435 priv->input = priv->buffer;
436 priv->output = priv->buffer;
437
438 obj = G_OBJECT(buffer);
439 g_object_freeze_notify(obj);
440 g_object_notify(obj, "input");
441 g_object_notify(obj, "output");
442 g_object_thaw_notify(obj);
443 }
444

mercurial