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