189f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach/******************************************************************************
289f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach *
35b790feeeb211c42bf78ca3ae9c26aa30e516765Jakub Pawlowski *  Copyright 2015 Google Inc.
489f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach *
589f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach *  Licensed under the Apache License, Version 2.0 (the "License");
689f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach *  you may not use this file except in compliance with the License.
789f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach *  You may obtain a copy of the License at:
889f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach *
989f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach *  http://www.apache.org/licenses/LICENSE-2.0
1089f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach *
1189f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach *  Unless required by applicable law or agreed to in writing, software
1289f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach *  distributed under the License is distributed on an "AS IS" BASIS,
1389f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1489f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach *  See the License for the specific language governing permissions and
1589f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach *  limitations under the License.
1689f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach *
1789f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach ******************************************************************************/
1889f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach
19f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He#include <base/logging.h>
2089f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach#include <stdlib.h>
2189f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach
2289f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach#include "osi/include/allocator.h"
2389f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach#include "osi/include/ringbuffer.h"
2489f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach
2589f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbachstruct ringbuffer_t {
2689f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach  size_t total;
2789f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach  size_t available;
28b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  uint8_t* base;
29b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  uint8_t* head;
30b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  uint8_t* tail;
3189f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach};
3289f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach
3389f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbachringbuffer_t* ringbuffer_init(const size_t size) {
34b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  ringbuffer_t* p =
35b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson      static_cast<ringbuffer_t*>(osi_calloc(sizeof(ringbuffer_t)));
3689f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach
37b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  p->base = static_cast<uint8_t*>(osi_calloc(size));
3889f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach  p->head = p->tail = p->base;
3989f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach  p->total = p->available = size;
4089f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach
4189f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach  return p;
4289f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach}
4389f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach
44b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonvoid ringbuffer_free(ringbuffer_t* rb) {
45b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  if (rb != NULL) osi_free(rb->base);
4689f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach  osi_free(rb);
4789f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach}
4889f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach
49b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonsize_t ringbuffer_available(const ringbuffer_t* rb) {
50f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(rb);
5189f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach  return rb->available;
5289f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach}
5389f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach
54b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonsize_t ringbuffer_size(const ringbuffer_t* rb) {
55f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(rb);
5689f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach  return rb->total - rb->available;
5789f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach}
5889f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach
59b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonsize_t ringbuffer_insert(ringbuffer_t* rb, const uint8_t* p, size_t length) {
60f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(rb);
61f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p);
6289f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach
63b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  if (length > ringbuffer_available(rb)) length = ringbuffer_available(rb);
6489f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach
6589f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach  for (size_t i = 0; i != length; ++i) {
6689f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach    *rb->tail++ = *p++;
67b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson    if (rb->tail >= (rb->base + rb->total)) rb->tail = rb->base;
6889f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach  }
6989f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach
7089f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach  rb->available -= length;
7189f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach  return length;
7289f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach}
7389f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach
74b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonsize_t ringbuffer_delete(ringbuffer_t* rb, size_t length) {
75f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(rb);
7689f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach
77b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  if (length > ringbuffer_size(rb)) length = ringbuffer_size(rb);
7889f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach
7989f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach  rb->head += length;
80b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  if (rb->head >= (rb->base + rb->total)) rb->head -= rb->total;
8189f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach
8289f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach  rb->available += length;
8389f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach  return length;
8489f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach}
8589f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach
86b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonsize_t ringbuffer_peek(const ringbuffer_t* rb, off_t offset, uint8_t* p,
87b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson                       size_t length) {
88f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(rb);
89f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p);
90f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(offset >= 0);
91f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK((size_t)offset <= ringbuffer_size(rb));
9289f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach
93b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  uint8_t* b = ((rb->head - rb->base + offset) % rb->total) + rb->base;
94b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  const size_t bytes_to_copy = (offset + length > ringbuffer_size(rb))
95b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson                                   ? ringbuffer_size(rb) - offset
96b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson                                   : length;
9789f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach
98b35c23483633826617d2312be805df93aeb9d8caSharvil Nanavati  for (size_t copied = 0; copied < bytes_to_copy; ++copied) {
9989f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach    *p++ = *b++;
100b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson    if (b >= (rb->base + rb->total)) b = rb->base;
10189f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach  }
10289f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach
103b35c23483633826617d2312be805df93aeb9d8caSharvil Nanavati  return bytes_to_copy;
10489f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach}
10589f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach
106b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonsize_t ringbuffer_pop(ringbuffer_t* rb, uint8_t* p, size_t length) {
107f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(rb);
108f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He  CHECK(p);
10989f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach
110b35c23483633826617d2312be805df93aeb9d8caSharvil Nanavati  const size_t copied = ringbuffer_peek(rb, 0, p, length);
11189f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach  rb->head += copied;
112b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson  if (rb->head >= (rb->base + rb->total)) rb->head -= rb->total;
11389f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach
11489f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach  rb->available += copied;
11589f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach  return copied;
11689f5e411d9ef31436741288a2267e46dd744e273Andre Eisenbach}
117