Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0-or-later
2 : /*
3 : * Circular buffer implementation.
4 : * Copyright (C) 2017 Cumulus Networks
5 : * Quentin Young
6 : */
7 : #include <zebra.h>
8 :
9 : #include "ringbuf.h"
10 : #include "memory.h"
11 :
12 12 : DEFINE_MTYPE_STATIC(LIB, RINGBUFFER, "Ring buffer");
13 :
14 8 : struct ringbuf *ringbuf_new(size_t size)
15 : {
16 8 : struct ringbuf *buf = XCALLOC(MTYPE_RINGBUFFER, sizeof(struct ringbuf));
17 8 : buf->data = XCALLOC(MTYPE_RINGBUFFER, size);
18 8 : buf->size = size;
19 8 : buf->empty = true;
20 8 : return buf;
21 : }
22 :
23 4 : void ringbuf_del(struct ringbuf *buf)
24 : {
25 4 : XFREE(MTYPE_RINGBUFFER, buf->data);
26 4 : XFREE(MTYPE_RINGBUFFER, buf);
27 4 : }
28 :
29 198 : size_t ringbuf_remain(struct ringbuf *buf)
30 : {
31 198 : ssize_t diff = buf->end - buf->start;
32 198 : diff += ((diff == 0) && !buf->empty) ? buf->size : 0;
33 198 : diff += (diff < 0) ? buf->size : 0;
34 198 : return (size_t)diff;
35 : }
36 :
37 30 : size_t ringbuf_space(struct ringbuf *buf)
38 : {
39 30 : return buf->size - ringbuf_remain(buf);
40 : }
41 :
42 14 : size_t ringbuf_put(struct ringbuf *buf, const void *data, size_t size)
43 : {
44 14 : const uint8_t *dp = data;
45 14 : size_t space = ringbuf_space(buf);
46 14 : size_t copysize = MIN(size, space);
47 14 : size_t tocopy = copysize;
48 14 : if (tocopy >= buf->size - buf->end) {
49 0 : size_t ts = buf->size - buf->end;
50 0 : memcpy(buf->data + buf->end, dp, ts);
51 0 : buf->end = 0;
52 0 : tocopy -= ts;
53 0 : dp += ts;
54 : }
55 14 : memcpy(buf->data + buf->end, dp, tocopy);
56 14 : buf->end += tocopy;
57 14 : buf->empty = (buf->start == buf->end) && (buf->empty && !copysize);
58 14 : return copysize;
59 : }
60 :
61 22 : size_t ringbuf_get(struct ringbuf *buf, void *data, size_t size)
62 : {
63 22 : uint8_t *dp = data;
64 22 : size_t remain = ringbuf_remain(buf);
65 22 : size_t copysize = MIN(remain, size);
66 22 : size_t tocopy = copysize;
67 22 : if (tocopy >= buf->size - buf->start) {
68 0 : size_t ts = buf->size - buf->start;
69 0 : memcpy(dp, buf->data + buf->start, ts);
70 0 : buf->start = 0;
71 0 : tocopy -= ts;
72 0 : dp += ts;
73 : }
74 22 : memcpy(dp, buf->data + buf->start, tocopy);
75 22 : buf->start = buf->start + tocopy;
76 22 : buf->empty = (buf->start == buf->end) && (buf->empty || copysize);
77 22 : return copysize;
78 : }
79 :
80 88 : size_t ringbuf_peek(struct ringbuf *buf, size_t offset, void *data, size_t size)
81 : {
82 88 : uint8_t *dp = data;
83 88 : size_t remain = ringbuf_remain(buf);
84 88 : if (offset >= remain)
85 : return 0;
86 88 : size_t copysize = MAX(MIN(remain - offset, size), (size_t)0);
87 88 : size_t tocopy = copysize;
88 88 : size_t cstart = (buf->start + offset) % buf->size;
89 88 : if (tocopy >= buf->size - cstart) {
90 0 : size_t ts = buf->size - cstart;
91 0 : memcpy(dp, buf->data + cstart, ts);
92 0 : cstart = 0;
93 0 : tocopy -= ts;
94 0 : dp += ts;
95 : }
96 88 : memcpy(dp, buf->data + cstart, tocopy);
97 88 : return copysize;
98 : }
99 :
100 0 : size_t ringbuf_copy(struct ringbuf *to, struct ringbuf *from, size_t size)
101 : {
102 0 : size_t tocopy = MIN(ringbuf_space(to), size);
103 0 : uint8_t *cbuf = XCALLOC(MTYPE_TMP, tocopy);
104 0 : tocopy = ringbuf_peek(from, 0, cbuf, tocopy);
105 0 : size_t put = ringbuf_put(to, cbuf, tocopy);
106 0 : XFREE(MTYPE_TMP, cbuf);
107 0 : return put;
108 : }
109 :
110 20 : void ringbuf_reset(struct ringbuf *buf)
111 : {
112 20 : buf->start = buf->end = 0;
113 20 : buf->empty = true;
114 20 : }
115 :
116 20 : void ringbuf_wipe(struct ringbuf *buf)
117 : {
118 20 : memset(buf->data, 0x00, buf->size);
119 20 : ringbuf_reset(buf);
120 20 : }
|