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