Line data Source code
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 670 : DEFINE_MTYPE_STATIC(LIB, RINGBUFFER, "Ring buffer");
26 :
27 132 : struct ringbuf *ringbuf_new(size_t size)
28 : {
29 132 : struct ringbuf *buf = XCALLOC(MTYPE_RINGBUFFER, sizeof(struct ringbuf));
30 132 : buf->data = XCALLOC(MTYPE_RINGBUFFER, size);
31 132 : buf->size = size;
32 132 : buf->empty = true;
33 132 : return buf;
34 : }
35 :
36 132 : void ringbuf_del(struct ringbuf *buf)
37 : {
38 132 : XFREE(MTYPE_RINGBUFFER, buf->data);
39 132 : XFREE(MTYPE_RINGBUFFER, buf);
40 132 : }
41 :
42 3151 : size_t ringbuf_remain(struct ringbuf *buf)
43 : {
44 3151 : ssize_t diff = buf->end - buf->start;
45 3151 : diff += ((diff == 0) && !buf->empty) ? buf->size : 0;
46 3151 : diff += (diff < 0) ? buf->size : 0;
47 3151 : return (size_t)diff;
48 : }
49 :
50 769 : size_t ringbuf_space(struct ringbuf *buf)
51 : {
52 769 : return buf->size - ringbuf_remain(buf);
53 : }
54 :
55 257 : size_t ringbuf_put(struct ringbuf *buf, const void *data, size_t size)
56 : {
57 257 : const uint8_t *dp = data;
58 257 : size_t space = ringbuf_space(buf);
59 257 : size_t copysize = MIN(size, space);
60 257 : size_t tocopy = copysize;
61 257 : if (tocopy >= buf->size - buf->end) {
62 0 : size_t ts = buf->size - buf->end;
63 0 : memcpy(buf->data + buf->end, dp, ts);
64 0 : buf->end = 0;
65 0 : tocopy -= ts;
66 0 : dp += ts;
67 : }
68 257 : memcpy(buf->data + buf->end, dp, tocopy);
69 257 : buf->end += tocopy;
70 257 : buf->empty = (buf->start == buf->end) && (buf->empty && !copysize);
71 257 : return copysize;
72 : }
73 :
74 300 : size_t ringbuf_get(struct ringbuf *buf, void *data, size_t size)
75 : {
76 300 : uint8_t *dp = data;
77 300 : size_t remain = ringbuf_remain(buf);
78 300 : size_t copysize = MIN(remain, size);
79 300 : size_t tocopy = copysize;
80 300 : if (tocopy >= buf->size - buf->start) {
81 0 : size_t ts = buf->size - buf->start;
82 0 : memcpy(dp, buf->data + buf->start, ts);
83 0 : buf->start = 0;
84 0 : tocopy -= ts;
85 0 : dp += ts;
86 : }
87 300 : memcpy(dp, buf->data + buf->start, tocopy);
88 300 : buf->start = buf->start + tocopy;
89 300 : buf->empty = (buf->start == buf->end) && (buf->empty || copysize);
90 300 : return copysize;
91 : }
92 :
93 1225 : size_t ringbuf_peek(struct ringbuf *buf, size_t offset, void *data, size_t size)
94 : {
95 1225 : uint8_t *dp = data;
96 1225 : size_t remain = ringbuf_remain(buf);
97 1225 : if (offset >= remain)
98 : return 0;
99 1200 : size_t copysize = MAX(MIN(remain - offset, size), (size_t)0);
100 1200 : size_t tocopy = copysize;
101 1200 : size_t cstart = (buf->start + offset) % buf->size;
102 1200 : if (tocopy >= buf->size - cstart) {
103 0 : size_t ts = buf->size - cstart;
104 0 : memcpy(dp, buf->data + cstart, ts);
105 0 : cstart = 0;
106 0 : tocopy -= ts;
107 0 : dp += ts;
108 : }
109 1200 : memcpy(dp, buf->data + cstart, tocopy);
110 1200 : return copysize;
111 : }
112 :
113 25 : size_t ringbuf_copy(struct ringbuf *to, struct ringbuf *from, size_t size)
114 : {
115 25 : size_t tocopy = MIN(ringbuf_space(to), size);
116 25 : uint8_t *cbuf = XCALLOC(MTYPE_TMP, tocopy);
117 25 : tocopy = ringbuf_peek(from, 0, cbuf, tocopy);
118 25 : size_t put = ringbuf_put(to, cbuf, tocopy);
119 25 : XFREE(MTYPE_TMP, cbuf);
120 25 : return put;
121 : }
122 :
123 295 : void ringbuf_reset(struct ringbuf *buf)
124 : {
125 295 : buf->start = buf->end = 0;
126 295 : buf->empty = true;
127 295 : }
128 :
129 295 : void ringbuf_wipe(struct ringbuf *buf)
130 : {
131 295 : memset(buf->data, 0x00, buf->size);
132 295 : ringbuf_reset(buf);
133 295 : }
|