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 | |
8 | static 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 | |
13 | ring_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 | |
31 | ring_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 | |
44 | void 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 | |
52 | void ring_buffer_destroy(ring_buffer_t *buffer) |
53 | { |
54 | kfree(ptr: buffer->data); |
55 | kfree(ptr: buffer); |
56 | } |
57 | |
58 | bool 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 | |
80 | size_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 | |
95 | size_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 | |
115 | size_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 | |
134 | size_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 | |