-
Notifications
You must be signed in to change notification settings - Fork 1
/
ringbuf.c
131 lines (121 loc) · 3.65 KB
/
ringbuf.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
/* Project page: https://github.com/ezag/ringbuf
License: MIT (see LICENSE file or http://opensource.org/licenses/mit)
Copyright (c) 2012 Eugen Zagorodniy <https://github.com/ezag>
*/
#include <stdlib.h>
#include <string.h>
#include "ringbuf.h"
RingBuf *rbuf_new(size_t size) {
RingBuf *rbuf = malloc(sizeof(RingBuf));
if (rbuf == NULL) return NULL;
rbuf->rbuf_start = malloc(size);
if (rbuf->rbuf_start == NULL) return NULL;
rbuf->rbuf_size = size;
rbuf->rbuf_head = NULL;
rbuf->rbuf_tail = rbuf->rbuf_start;
return rbuf;
}
void rbuf_free(RingBuf *rbuf) {
free(rbuf->rbuf_start);
free(rbuf);
}
size_t rbuf_size(const RingBuf *rbuf) {
return rbuf->rbuf_size;
}
size_t rbuf_can_get(const RingBuf *rbuf) {
if (rbuf->rbuf_head == NULL) {
return 0;
}
if (rbuf->rbuf_tail == NULL) {
return rbuf->rbuf_size;
}
if (rbuf->rbuf_head < rbuf->rbuf_tail) {
return (char*)rbuf->rbuf_tail - (char*)rbuf->rbuf_head;
}
else {
return rbuf->rbuf_size - (size_t)(
(char*)rbuf->rbuf_head - (char*)rbuf->rbuf_tail);
}
}
size_t rbuf_can_put(const RingBuf *rbuf) {
return rbuf->rbuf_size - rbuf_can_get(rbuf);
}
typedef struct {
size_t before_split_size;
size_t after_split_size;
size_t total_size;
const void *split;
void *fixed;
void *shifting;
} MemMap;
MemMap map_mem(const void *linear, size_t linear_size,
const void *circular, size_t circular_size,
void *fixed, void *shifting) {
MemMap mm;
mm.fixed = fixed;
mm.after_split_size = 0;
if (shifting == NULL) {
mm.before_split_size = 0;
mm.shifting = shifting;
}
else {
if (fixed == NULL || fixed <= shifting) {
mm.before_split_size = circular_size - (size_t)(
(char*)shifting - (char*)circular);
if (fixed == NULL && linear_size > 0) {
mm.fixed = shifting;
}
if (mm.before_split_size < linear_size) {
const size_t remaining_bytes = linear_size - mm.before_split_size;
mm.after_split_size = (char*)mm.fixed - (char*)circular;
if (mm.after_split_size > remaining_bytes) {
mm.after_split_size = remaining_bytes;
}
mm.shifting = (char*)circular + mm.after_split_size;
}
else {
mm.before_split_size = linear_size;
mm.shifting = (char*)shifting + mm.before_split_size;
}
}
else {
mm.before_split_size = (char*)mm.fixed - (char*)shifting;
if (mm.before_split_size > linear_size) {
mm.before_split_size = linear_size;
}
mm.shifting = (char*)shifting + mm.before_split_size;
}
}
mm.split = (char*)linear + mm.before_split_size;
mm.total_size = mm.before_split_size + mm.after_split_size;
if (mm.shifting == mm.fixed) {
mm.shifting = NULL;
}
return mm;
}
size_t rbuf_put(RingBuf *rbuf, const void *data, size_t count) {
MemMap mm = map_mem(data, count, rbuf->rbuf_start, rbuf->rbuf_size,
rbuf->rbuf_head, rbuf->rbuf_tail);
if (mm.before_split_size) {
memcpy(rbuf->rbuf_tail, data, mm.before_split_size);
}
if (mm.after_split_size) {
memcpy(rbuf->rbuf_start, mm.split, mm.after_split_size);
}
rbuf->rbuf_tail = mm.shifting;
rbuf->rbuf_head = mm.fixed;
return mm.total_size;
}
size_t rbuf_get(RingBuf *rbuf, void *data, size_t count) {
MemMap mm = map_mem(data, count, rbuf->rbuf_start, rbuf->rbuf_size,
rbuf->rbuf_tail, rbuf->rbuf_head);
if (mm.before_split_size) {
memcpy(data, rbuf->rbuf_head, mm.before_split_size);
}
if (mm.after_split_size) {
memcpy(mm.split, rbuf->rbuf_start, mm.after_split_size);
}
rbuf->rbuf_head = mm.shifting;
rbuf->rbuf_tail = mm.fixed;
return mm.total_size;
}