1 /**
2 * Copyright (c) 2011, Willem-Hendrik Thiart
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE.bipbuffer file.
5 *
6 * @file
7 * @author Willem Thiart [email protected]
8 */
9
10 #include "stdio.h"
11 #include <stdlib.h>
12
13 /* for memcpy */
14 #include <string.h>
15
16 #include "bipbuffer.h"
17
bipbuf_sizeof(const unsigned int size)18 static size_t bipbuf_sizeof(const unsigned int size)
19 {
20 return sizeof(bipbuf_t) + size;
21 }
22
bipbuf_unused(const bipbuf_t * me)23 int bipbuf_unused(const bipbuf_t* me)
24 {
25 if (1 == me->b_inuse)
26 /* distance between region B and region A */
27 return me->a_start - me->b_end;
28 else
29 return me->size - me->a_end;
30 }
31
bipbuf_size(const bipbuf_t * me)32 int bipbuf_size(const bipbuf_t* me)
33 {
34 return me->size;
35 }
36
bipbuf_used(const bipbuf_t * me)37 int bipbuf_used(const bipbuf_t* me)
38 {
39 return (me->a_end - me->a_start) + me->b_end;
40 }
41
bipbuf_init(bipbuf_t * me,const unsigned int size)42 void bipbuf_init(bipbuf_t* me, const unsigned int size)
43 {
44 me->a_start = me->a_end = me->b_end = 0;
45 me->size = size;
46 me->b_inuse = 0;
47 }
48
bipbuf_new(const unsigned int size)49 bipbuf_t *bipbuf_new(const unsigned int size)
50 {
51 bipbuf_t *me = malloc(bipbuf_sizeof(size));
52 if (!me)
53 return NULL;
54 bipbuf_init(me, size);
55 return me;
56 }
57
bipbuf_free(bipbuf_t * me)58 void bipbuf_free(bipbuf_t* me)
59 {
60 free(me);
61 }
62
bipbuf_is_empty(const bipbuf_t * me)63 int bipbuf_is_empty(const bipbuf_t* me)
64 {
65 return me->a_start == me->a_end;
66 }
67
68 /* find out if we should turn on region B
69 * ie. is the distance from A to buffer's end less than B to A? */
__check_for_switch_to_b(bipbuf_t * me)70 static void __check_for_switch_to_b(bipbuf_t* me)
71 {
72 if (me->size - me->a_end < me->a_start - me->b_end)
73 me->b_inuse = 1;
74 }
75
76 /* TODO: DOCUMENT THESE TWO FUNCTIONS */
bipbuf_request(bipbuf_t * me,const int size)77 unsigned char *bipbuf_request(bipbuf_t* me, const int size)
78 {
79 if (bipbuf_unused(me) < size)
80 return 0;
81 if (1 == me->b_inuse)
82 {
83 return (unsigned char *)me->data + me->b_end;
84 }
85 else
86 {
87 return (unsigned char *)me->data + me->a_end;
88 }
89 }
90
bipbuf_push(bipbuf_t * me,const int size)91 int bipbuf_push(bipbuf_t* me, const int size)
92 {
93 if (bipbuf_unused(me) < size)
94 return 0;
95
96 if (1 == me->b_inuse)
97 {
98 me->b_end += size;
99 }
100 else
101 {
102 me->a_end += size;
103 }
104
105 __check_for_switch_to_b(me);
106 return size;
107 }
108
bipbuf_offer(bipbuf_t * me,const unsigned char * data,const int size)109 int bipbuf_offer(bipbuf_t* me, const unsigned char *data, const int size)
110 {
111 /* not enough space */
112 if (bipbuf_unused(me) < size)
113 return 0;
114
115 if (1 == me->b_inuse)
116 {
117 memcpy(me->data + me->b_end, data, size);
118 me->b_end += size;
119 }
120 else
121 {
122 memcpy(me->data + me->a_end, data, size);
123 me->a_end += size;
124 }
125
126 __check_for_switch_to_b(me);
127 return size;
128 }
129
bipbuf_peek(const bipbuf_t * me,const unsigned int size)130 unsigned char *bipbuf_peek(const bipbuf_t* me, const unsigned int size)
131 {
132 /* make sure we can actually peek at this data */
133 if (me->size < me->a_start + size)
134 return NULL;
135
136 if (bipbuf_is_empty(me))
137 return NULL;
138
139 return (unsigned char *)me->data + me->a_start;
140 }
141
bipbuf_peek_all(const bipbuf_t * me,unsigned int * size)142 unsigned char *bipbuf_peek_all(const bipbuf_t* me, unsigned int *size)
143 {
144 if (bipbuf_is_empty(me))
145 return NULL;
146
147 *size = me->a_end - me->a_start;
148 return (unsigned char*)me->data + me->a_start;
149 }
150
bipbuf_poll(bipbuf_t * me,const unsigned int size)151 unsigned char *bipbuf_poll(bipbuf_t* me, const unsigned int size)
152 {
153 if (bipbuf_is_empty(me))
154 return NULL;
155
156 /* make sure we can actually poll this data */
157 if (me->size < me->a_start + size)
158 return NULL;
159
160 void *end = me->data + me->a_start;
161 me->a_start += size;
162
163 /* we seem to be empty.. */
164 if (me->a_start == me->a_end)
165 {
166 /* replace a with region b */
167 if (1 == me->b_inuse)
168 {
169 me->a_start = 0;
170 me->a_end = me->b_end;
171 me->b_end = me->b_inuse = 0;
172 }
173 else
174 /* safely move cursor back to the start because we are empty */
175 me->a_start = me->a_end = 0;
176 }
177
178 __check_for_switch_to_b(me);
179 return end;
180 }
181