]>
Commit | Line | Data |
---|---|---|
5318d896 QY |
1 | /* |
2 | * Circular buffer implementation. | |
3 | * Copyright (C) 2017 Cumulus Networks | |
4 | * Quentin Young | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify it | |
7 | * under the terms of the GNU General Public License as published by the Free | |
8 | * Software Foundation; either version 2 of the License, or (at your option) | |
9 | * any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, but WITHOUT | |
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
14 | * more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License along | |
17 | * with this program; see the file COPYING; if not, write to the Free Software | |
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
19 | */ | |
20 | #include <zebra.h> | |
21 | ||
22 | #include "ringbuf.h" | |
23 | #include "memory.h" | |
24 | ||
25 | DEFINE_MTYPE_STATIC(LIB, RINGBUFFER, "Ring buffer") | |
26 | ||
27 | struct ringbuf *ringbuf_new(size_t size) | |
28 | { | |
29 | struct ringbuf *buf = XCALLOC(MTYPE_RINGBUFFER, sizeof(struct ringbuf)); | |
30 | buf->data = XCALLOC(MTYPE_RINGBUFFER, size); | |
31 | buf->size = size; | |
32 | buf->empty = true; | |
33 | return buf; | |
34 | } | |
35 | ||
36 | void ringbuf_del(struct ringbuf *buf) | |
37 | { | |
38 | XFREE(MTYPE_RINGBUFFER, buf->data); | |
39 | XFREE(MTYPE_RINGBUFFER, buf); | |
40 | } | |
41 | ||
42 | size_t ringbuf_remain(struct ringbuf *buf) | |
43 | { | |
44 | ssize_t diff = buf->end - buf->start; | |
45 | diff += ((diff == 0) && !buf->empty) ? buf->size : 0; | |
46 | diff += (diff < 0) ? buf->size : 0; | |
47 | return (size_t)diff; | |
48 | } | |
49 | ||
50 | size_t ringbuf_space(struct ringbuf *buf) | |
51 | { | |
52 | return buf->size - ringbuf_remain(buf); | |
53 | } | |
54 | ||
55 | size_t ringbuf_put(struct ringbuf *buf, const void *data, size_t size) | |
56 | { | |
57 | const uint8_t *dp = data; | |
58 | size_t space = ringbuf_space(buf); | |
59 | size_t copysize = MIN(size, space); | |
60 | size_t tocopy = copysize; | |
74e4a329 | 61 | if (tocopy >= buf->size - buf->end) { |
5318d896 QY |
62 | size_t ts = buf->size - buf->end; |
63 | memcpy(buf->data + buf->end, dp, ts); | |
64 | buf->end = 0; | |
65 | tocopy -= ts; | |
66 | dp += ts; | |
67 | } | |
68 | memcpy(buf->data + buf->end, dp, tocopy); | |
69 | buf->end += tocopy; | |
70 | buf->empty = (buf->start == buf->end) && (buf->empty && !copysize); | |
71 | return copysize; | |
72 | } | |
73 | ||
74 | size_t ringbuf_get(struct ringbuf *buf, void *data, size_t size) | |
75 | { | |
76 | uint8_t *dp = data; | |
77 | size_t remain = ringbuf_remain(buf); | |
78 | size_t copysize = MIN(remain, size); | |
79 | size_t tocopy = copysize; | |
a5080622 | 80 | if (tocopy >= buf->size - buf->start) { |
5318d896 QY |
81 | size_t ts = buf->size - buf->start; |
82 | memcpy(dp, buf->data + buf->start, ts); | |
83 | buf->start = 0; | |
84 | tocopy -= ts; | |
85 | dp += ts; | |
86 | } | |
87 | memcpy(dp, buf->data + buf->start, tocopy); | |
88 | buf->start = buf->start + tocopy; | |
89 | buf->empty = (buf->start == buf->end) && (buf->empty || copysize); | |
90 | return copysize; | |
91 | } | |
92 | ||
a5080622 QY |
93 | size_t ringbuf_peek(struct ringbuf *buf, size_t offset, void *data, size_t size) |
94 | { | |
95 | uint8_t *dp = data; | |
96 | size_t remain = ringbuf_remain(buf); | |
97 | if (offset >= remain) | |
98 | return 0; | |
996c9314 | 99 | size_t copysize = MAX(MIN(remain - offset, size), (size_t)0); |
a5080622 QY |
100 | size_t tocopy = copysize; |
101 | size_t cstart = (buf->start + offset) % buf->size; | |
102 | if (tocopy >= buf->size - cstart) { | |
103 | size_t ts = buf->size - cstart; | |
104 | memcpy(dp, buf->data + cstart, ts); | |
74e4a329 | 105 | cstart = 0; |
a5080622 QY |
106 | tocopy -= ts; |
107 | dp += ts; | |
108 | } | |
109 | memcpy(dp, buf->data + cstart, tocopy); | |
110 | return copysize; | |
111 | } | |
112 | ||
cb94eaeb QY |
113 | size_t ringbuf_copy(struct ringbuf *to, struct ringbuf *from, size_t size) |
114 | { | |
115 | size_t tocopy = MIN(ringbuf_space(to), size); | |
116 | uint8_t *cbuf = XCALLOC(MTYPE_TMP, tocopy); | |
117 | tocopy = ringbuf_peek(from, 0, cbuf, tocopy); | |
74e4a329 | 118 | size_t put = ringbuf_put(to, cbuf, tocopy); |
cb94eaeb | 119 | XFREE(MTYPE_TMP, cbuf); |
74e4a329 | 120 | return put; |
cb94eaeb QY |
121 | } |
122 | ||
5318d896 QY |
123 | void ringbuf_reset(struct ringbuf *buf) |
124 | { | |
125 | buf->start = buf->end = 0; | |
126 | buf->empty = true; | |
127 | } | |
128 | ||
129 | void ringbuf_wipe(struct ringbuf *buf) | |
130 | { | |
131 | memset(buf->data, 0x00, buf->size); | |
132 | ringbuf_reset(buf); | |
5318d896 | 133 | } |