Home | History | Annotate | Download | only in src
      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 
     33 ringbuffer_t* ringbuffer_init(const size_t size) {
     34   ringbuffer_t* p = osi_calloc(sizeof(ringbuffer_t));
     35 
     36   p->base = osi_calloc(size);
     37   p->head = p->tail = p->base;
     38   p->total = p->available = size;
     39 
     40   return p;
     41 }
     42 
     43 void ringbuffer_free(ringbuffer_t *rb) {
     44   if (rb != NULL)
     45     osi_free(rb->base);
     46   osi_free(rb);
     47 }
     48 
     49 size_t ringbuffer_available(const ringbuffer_t *rb) {
     50   assert(rb);
     51   return rb->available;
     52 }
     53 
     54 size_t ringbuffer_size(const ringbuffer_t *rb) {
     55   assert(rb);
     56   return rb->total - rb->available;
     57 }
     58 
     59 size_t ringbuffer_insert(ringbuffer_t *rb, const uint8_t *p, size_t length) {
     60   assert(rb);
     61   assert(p);
     62 
     63   if (length > ringbuffer_available(rb))
     64     length = ringbuffer_available(rb);
     65 
     66   for (size_t i = 0; i != length; ++i) {
     67     *rb->tail++ = *p++;
     68     if (rb->tail >= (rb->base + rb->total))
     69       rb->tail = rb->base;
     70   }
     71 
     72   rb->available -= length;
     73   return length;
     74 }
     75 
     76 size_t ringbuffer_delete(ringbuffer_t *rb, size_t length) {
     77   assert(rb);
     78 
     79   if (length > ringbuffer_size(rb))
     80     length = ringbuffer_size(rb);
     81 
     82   rb->head += length;
     83   if (rb->head >= (rb->base + rb->total))
     84     rb->head -= rb->total;
     85 
     86   rb->available += length;
     87   return length;
     88 }
     89 
     90 size_t ringbuffer_peek(const ringbuffer_t *rb, off_t offset, uint8_t *p, size_t length) {
     91   assert(rb);
     92   assert(p);
     93   assert(offset >= 0);
     94   assert((size_t)offset <= ringbuffer_size(rb));
     95 
     96   uint8_t *b = ((rb->head - rb->base + offset) % rb->total) + rb->base;
     97   const size_t bytes_to_copy = (offset + length > ringbuffer_size(rb)) ? ringbuffer_size(rb) - offset : length;
     98 
     99   for (size_t copied = 0; copied < bytes_to_copy; ++copied) {
    100     *p++ = *b++;
    101     if (b >= (rb->base + rb->total))
    102       b = rb->base;
    103   }
    104 
    105   return bytes_to_copy;
    106 }
    107 
    108 size_t ringbuffer_pop(ringbuffer_t *rb, uint8_t *p, size_t length) {
    109   assert(rb);
    110   assert(p);
    111 
    112   const size_t copied = ringbuffer_peek(rb, 0, p, length);
    113   rb->head += copied;
    114   if (rb->head >= (rb->base + rb->total))
    115     rb->head -= rb->total;
    116 
    117   rb->available += copied;
    118   return copied;
    119 }
    120