xref: /memcached-1.4.29/bipbuffer.c (revision 1ecdbdb0)
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