1 /******************************************************************************
2 *
3 * Copyright (C) 2015 Google Inc.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at:
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 ******************************************************************************/
18
19 #include <assert.h>
20 #include <stdlib.h>
21
22 #include "osi/include/allocator.h"
23 #include "osi/include/ringbuffer.h"
24
25 struct ringbuffer_t {
26 size_t total;
27 size_t available;
28 uint8_t *base;
29 uint8_t *head;
30 uint8_t *tail;
31 };
32
ringbuffer_init(const size_t size)33 ringbuffer_t* ringbuffer_init(const size_t size) {
34 ringbuffer_t* p = osi_calloc(sizeof(ringbuffer_t));
35 if (p == 0)
36 return NULL;
37
38 p->base = osi_calloc(size);
39 if (p->base == 0) {
40 osi_free(p);
41 return NULL;
42 }
43
44 p->head = p->tail = p->base;
45 p->total = p->available = size;
46
47 return p;
48 }
49
ringbuffer_free(ringbuffer_t * rb)50 void ringbuffer_free(ringbuffer_t *rb) {
51 if (rb != NULL)
52 osi_free(rb->base);
53 osi_free(rb);
54 }
55
ringbuffer_available(const ringbuffer_t * rb)56 size_t ringbuffer_available(const ringbuffer_t *rb) {
57 assert(rb);
58 return rb->available;
59 }
60
ringbuffer_size(const ringbuffer_t * rb)61 size_t ringbuffer_size(const ringbuffer_t *rb) {
62 assert(rb);
63 return rb->total - rb->available;
64 }
65
ringbuffer_insert(ringbuffer_t * rb,const uint8_t * p,size_t length)66 size_t ringbuffer_insert(ringbuffer_t *rb, const uint8_t *p, size_t length) {
67 assert(rb);
68 assert(p);
69
70 if (length > ringbuffer_available(rb))
71 length = ringbuffer_available(rb);
72
73 for (size_t i = 0; i != length; ++i) {
74 *rb->tail++ = *p++;
75 if (rb->tail >= (rb->base + rb->total))
76 rb->tail = rb->base;
77 }
78
79 rb->available -= length;
80 return length;
81 }
82
ringbuffer_delete(ringbuffer_t * rb,size_t length)83 size_t ringbuffer_delete(ringbuffer_t *rb, size_t length) {
84 assert(rb);
85
86 if (length > ringbuffer_size(rb))
87 length = ringbuffer_size(rb);
88
89 rb->head += length;
90 if (rb->head >= (rb->base + rb->total))
91 rb->head -= rb->total;
92
93 rb->available += length;
94 return length;
95 }
96
ringbuffer_peek(const ringbuffer_t * rb,uint8_t * p,size_t length)97 size_t ringbuffer_peek(const ringbuffer_t *rb, uint8_t *p, size_t length) {
98 assert(rb);
99 assert(p);
100
101 uint8_t *b = rb->head;
102 size_t copied = 0;
103
104 while (copied < length && copied < ringbuffer_size(rb)) {
105 *p++ = *b++;
106 if (b >= (rb->base + rb->total))
107 b = rb->base;
108 ++copied;
109 }
110
111 return copied;
112 }
113
ringbuffer_pop(ringbuffer_t * rb,uint8_t * p,size_t length)114 size_t ringbuffer_pop(ringbuffer_t *rb, uint8_t *p, size_t length) {
115 assert(rb);
116 assert(p);
117
118 const size_t copied = ringbuffer_peek(rb, p, length);
119 rb->head += copied;
120 if (rb->head >= (rb->base + rb->total))
121 rb->head -= rb->total;
122
123 rb->available += copied;
124 return copied;
125 }
126