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