-
Notifications
You must be signed in to change notification settings - Fork 8
/
ring.h
157 lines (131 loc) · 3.88 KB
/
ring.h
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#ifndef _RING_H_
#define _RING_H_
#include <stdbool.h>
struct ring {
size_t size;
char* data;
char* ptr_read, *ptr_write;
};
int ring_alloc(struct ring** ret, size_t size);
void ring_free(struct ring* ring);
int ring_peek(struct ring* ring, char* data, size_t len);
int ring_read(struct ring* ring, char* data, size_t len);
int ring_write(struct ring* ring, char* data, size_t len);
// Optimized inline funnctions
static inline bool ring_any_available(struct ring* ring) {
return ring->ptr_read != ring->ptr_write;
}
// Take a small peek into the buffer
static inline char ring_peek_one(struct ring* ring) {
return *ring->ptr_read;
}
// Peek previous byte
static inline char ring_peek_prev(struct ring* ring) {
if(ring->ptr_read - 1 < ring->data) {
return *(ring->data + ring->size - 1);
}
return *(ring->ptr_read - 1);
}
// Pointer to next byte to read from ringbuffer
static inline char* ring_next(struct ring* ring, char* ptr) {
if(ptr < ring->data + ring->size - 1) {
return ptr + 1;
}
return ring->data;
}
// Read one byte from the buffer
static inline char ring_read_one(struct ring* ring) {
char c = *ring->ptr_read;
ring->ptr_read = ring_next(ring, ring->ptr_read);
return c;
}
static inline void ring_inc_read(struct ring* ring) {
ring->ptr_read = ring_next(ring, ring->ptr_read);
}
// Number of contiguous free bytes after ring->write_ptr
static inline size_t ring_free_space_contig(struct ring* ring) {
if(ring->ptr_read > ring->ptr_write) {
return ring->ptr_read - ring->ptr_write - 1;
}
return ring->size - (ring->ptr_write - ring->data) - (ring->ptr_read == ring->data ? 1 : 0);
}
static inline void ring_advance_read(struct ring* ring, off_t offset) {
assert(offset >= 0);
assert(offset <= ring->size);
if(offset) {
if(ring->ptr_read + offset < ring->data + ring->size) {
ring->ptr_read = ring_next(ring, ring->ptr_read + offset - 1);
} else {
ring->ptr_read = offset - ring->size + ring->ptr_read;
}
}
}
static inline void ring_advance_write(struct ring* ring, off_t offset) {
assert(offset >= 0);
assert(offset <= ring->size);
if(offset) {
if(ring->ptr_write + offset < ring->data + ring->size) {
ring->ptr_write = ring_next(ring, ring->ptr_write + offset - 1);
} else {
ring->ptr_write = offset - ring->size + ring->ptr_write;
}
}
}
// Number of bytes that can be read from ringbuffer
static inline size_t ring_available(struct ring* ring) {
if(ring->ptr_write >= ring->ptr_read) {
return ring->ptr_write - ring->ptr_read;
}
return ring->size - (ring->ptr_read - ring->ptr_write);
}
// Number of virtually contiguous bytes that can be read from ringbuffer
static inline size_t ring_available_contig(struct ring* ring) {
if(ring->ptr_write >= ring->ptr_read) {
return ring->ptr_write - ring->ptr_read;
}
return ring->size - (ring->ptr_read - ring->data);
}
// Number of free bytes
static inline size_t ring_free_space(struct ring* ring) {
if(ring->ptr_read > ring->ptr_write) {
return ring->ptr_read - ring->ptr_write - 1;
}
return ring->size - (ring->ptr_write - ring->ptr_read) - 1;
}
/*
Behaves totally different from memcmp!
Return:
< 0 error (not enough data in buffer)
= 0 match
> 0 no match
*/
static inline int ring_memcmp(struct ring* ring, char* ref, unsigned int len, char** next_pos) {
size_t avail_contig;
if(ring_available(ring) < len) {
return -EINVAL;
}
avail_contig = ring_available_contig(ring);
if(avail_contig >= len) {
// We are lucky
if(memcmp(ring->ptr_read, ref, len)) {
return 1;
}
if(next_pos) {
*next_pos = ring_next(ring, ring->ptr_read + len - 1);
} else {
ring_advance_read(ring, len);
}
return 0;
}
// We (may) need to perform two memcmps
if(memcmp(ring->ptr_read, ref, avail_contig) || memcmp(ring->data, ref + avail_contig, len - avail_contig)) {
return 1;
}
if(next_pos) {
*next_pos = ring->data + len - avail_contig;
} else {
ring_advance_read(ring, len);
}
return 0;
}
#endif