1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#include <mos/lib/structures/ring_buffer.h>
4#include <mos/moslib_global.h>
5#include <mos_stdlib.h>
6#include <mos_string.h>
7
8static u8 ring_buffer_get(u8 *data, ring_buffer_pos_t *pos, size_t index)
9{
10 return data[(pos->head + index) % pos->count];
11}
12
13ring_buffer_t *ring_buffer_create(size_t capacity)
14{
15 if (capacity == 0)
16 return NULL; // forget about it
17
18 ring_buffer_t *rb = kmalloc(sizeof(ring_buffer_t));
19 if (!rb)
20 return NULL;
21 rb->data = kmalloc(capacity);
22 if (!rb->data)
23 {
24 kfree(ptr: rb);
25 return NULL;
26 }
27 ring_buffer_pos_init(pos: &rb->pos, capacity);
28 return rb;
29}
30
31ring_buffer_t *ring_buffer_create_at(void *data, size_t capacity)
32{
33 if (capacity == 0)
34 return NULL; // forget about it
35
36 ring_buffer_t *rb = kmalloc(sizeof(ring_buffer_t));
37 if (!rb)
38 return NULL;
39 rb->data = data;
40 ring_buffer_pos_init(pos: &rb->pos, capacity);
41 return rb;
42}
43
44void ring_buffer_pos_init(ring_buffer_pos_t *pos, size_t capacity)
45{
46 pos->capacity = capacity;
47 pos->count = 0;
48 pos->head = 0;
49 pos->next_pos = 0;
50}
51
52void ring_buffer_destroy(ring_buffer_t *buffer)
53{
54 kfree(ptr: buffer->data);
55 kfree(ptr: buffer);
56}
57
58bool ring_buffer_resize(ring_buffer_t *buffer, size_t new_capacity)
59{
60 if (new_capacity < buffer->pos.count)
61 return false;
62 void *new_data = kmalloc(new_capacity);
63 if (!new_data)
64 return false;
65 size_t i = 0;
66 while (i < buffer->pos.count)
67 {
68 ((char *) new_data)[i] = ring_buffer_get(data: buffer->data, pos: &buffer->pos, index: i);
69 i++;
70 }
71
72 kfree(ptr: buffer->data);
73 buffer->data = new_data;
74 buffer->pos.capacity = new_capacity;
75 buffer->pos.head = 0;
76 buffer->pos.next_pos = buffer->pos.count;
77 return true;
78}
79
80size_t ring_buffer_pos_push_back(u8 *data, ring_buffer_pos_t *pos, const u8 *target, size_t size)
81{
82 if (pos->count + size > pos->capacity)
83 size = pos->capacity - pos->count;
84
85 size_t first_part_i = pos->next_pos;
86 size_t first_part_size = MIN(size, pos->capacity - pos->next_pos);
87 size_t second_part = size - first_part_size;
88 memcpy(dest: data + first_part_i, src: target, n: first_part_size);
89 memcpy(dest: data, src: target + first_part_size, n: second_part);
90 pos->next_pos = (pos->next_pos + size) % pos->capacity;
91 pos->count += size;
92 return size;
93}
94
95size_t ring_buffer_pos_pop_back(u8 *data, ring_buffer_pos_t *pos, u8 *target, size_t size)
96{
97 if (size > pos->count)
98 size = pos->count;
99
100 size_t first_part_i = (pos->capacity + pos->next_pos - size) % pos->capacity;
101 size_t first_part_size = MIN(size, pos->capacity - first_part_i);
102
103 size_t second_part_i = 0;
104 size_t second_part_size = size - first_part_size;
105
106 memcpy(dest: target, src: data + first_part_i, n: first_part_size);
107 memcpy(dest: target + first_part_size, src: data + second_part_i, n: second_part_size);
108
109 pos->next_pos = (pos->capacity + pos->next_pos - size) % pos->capacity;
110 pos->count -= size;
111
112 return size;
113}
114
115size_t ring_buffer_pos_push_front(u8 *data, ring_buffer_pos_t *pos, const u8 *target, size_t size)
116{
117 if (pos->count + size > pos->capacity)
118 return 0;
119
120 size_t first_part_i = (pos->capacity + pos->head - size) % pos->capacity;
121 size_t first_part_size = MIN(size, pos->capacity - first_part_i);
122
123 size_t second_part_i = 0;
124 size_t second_part_size = size - first_part_size;
125
126 memcpy(dest: data + first_part_i, src: target, n: first_part_size);
127 memcpy(dest: data + second_part_i, src: target + first_part_size, n: second_part_size);
128
129 pos->head = (pos->capacity + pos->head - size) % pos->capacity;
130 pos->count += size;
131 return size;
132}
133
134size_t ring_buffer_pos_pop_front(u8 *data, ring_buffer_pos_t *pos, u8 *target, size_t size)
135{
136 if (size > pos->count)
137 size = pos->count;
138
139 size_t first_part_i = pos->head;
140 size_t first_part_size = MIN(size, pos->capacity - first_part_i);
141
142 size_t second_part_i = 0;
143 size_t second_part_size = size - first_part_size;
144
145 memcpy(dest: target, src: data + first_part_i, n: first_part_size);
146 memcpy(dest: target + first_part_size, src: data + second_part_i, n: second_part_size);
147
148 pos->head = (pos->head + size) % pos->capacity;
149 pos->count -= size;
150 return size;
151}
152