-
Notifications
You must be signed in to change notification settings - Fork 25
/
bipbuffer.c
138 lines (115 loc) · 2.87 KB
/
bipbuffer.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/**
* Copyright (c) 2011, Willem-Hendrik Thiart
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* @file
* @author Willem Thiart himself@willemthiart.com
*/
#include "stdio.h"
#include <stdlib.h>
/* for memcpy */
#include <string.h>
#include "bipbuffer.h"
size_t bipbuf_sizeof(const unsigned int size)
{
return sizeof(bipbuf_t) + size;
}
int bipbuf_unused(const bipbuf_t* me)
{
if (1 == me->b_inuse)
/* distance between region B and region A */
return me->a_start - me->b_end;
else
return me->size - me->a_end;
}
int bipbuf_size(const bipbuf_t* me)
{
return me->size;
}
int bipbuf_used(const bipbuf_t* me)
{
return (me->a_end - me->a_start) + me->b_end;
}
void bipbuf_init(bipbuf_t* me, const unsigned int size)
{
me->a_start = me->a_end = me->b_end = 0;
me->size = size;
me->b_inuse = 0;
}
bipbuf_t *bipbuf_new(const unsigned int size)
{
bipbuf_t *me = malloc(bipbuf_sizeof(size));
if (!me)
return NULL;
bipbuf_init(me, size);
return me;
}
void bipbuf_free(bipbuf_t* me)
{
free(me);
}
int bipbuf_is_empty(const bipbuf_t* me)
{
return me->a_start == me->a_end;
}
/* find out if we should turn on region B
* ie. is the distance from A to buffer's end less than B to A? */
static void __check_for_switch_to_b(bipbuf_t* me)
{
if (me->size - me->a_end < me->a_start - me->b_end)
me->b_inuse = 1;
}
int bipbuf_offer(bipbuf_t* me, const unsigned char *data, const int size)
{
/* not enough space */
if (bipbuf_unused(me) < size)
return 0;
if (1 == me->b_inuse)
{
memcpy(me->data + me->b_end, data, size);
me->b_end += size;
}
else
{
memcpy(me->data + me->a_end, data, size);
me->a_end += size;
}
__check_for_switch_to_b(me);
return size;
}
unsigned char *bipbuf_peek(const bipbuf_t* me, const unsigned int size)
{
/* make sure we can actually peek at this data */
if (me->size < me->a_start + size)
return NULL;
if (bipbuf_is_empty(me))
return NULL;
return (unsigned char*)me->data + me->a_start;
}
unsigned char *bipbuf_poll(bipbuf_t* me, const unsigned int size)
{
if (bipbuf_is_empty(me))
return NULL;
/* make sure we can actually poll this data */
if (me->size < me->a_start + size)
return NULL;
void *end = me->data + me->a_start;
me->a_start += size;
/* we seem to be empty.. */
if (me->a_start == me->a_end)
{
/* replace a with region b */
if (1 == me->b_inuse)
{
me->a_start = 0;
me->a_end = me->b_end;
me->b_end = me->b_inuse = 0;
}
else
/* safely move cursor back to the start because we are empty */
me->a_start = me->a_end = 0;
}
__check_for_switch_to_b(me);
return end;
}