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 | |
10 | static 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 | |
15 | ring_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 | |
33 | ring_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 | |
46 | void 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 | |
54 | void ring_buffer_destroy(ring_buffer_t *buffer) |
55 | { |
56 | kfree(ptr: buffer->data); |
57 | delete buffer; |
58 | } |
59 | |
60 | bool 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 | |
82 | size_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 | |
97 | size_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 | |
117 | size_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 | |
136 | size_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 | |