-
Notifications
You must be signed in to change notification settings - Fork 0
/
ring_buffer.zig
99 lines (82 loc) · 2.92 KB
/
ring_buffer.zig
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// Fifo RingBuffer usable as some sort of input-queue.
//
// Fixed stack-allocation is specified at compile-time. A suitable purpose for a structure like this
// could for something like a uart input communication line.
//
// An efficient deque is implemented in a similar way, instead of being cyclic it would perform
// some smart resizing and shuffling of data/indices.
pub fn RingBuffer(comptime T: type, comptime size: usize) -> type {
struct {
// We must bind the explicit struct to a separate variable since we cannot instantiate a
// struct directly using the this value.
const Self = this;
// Can define constant and vars statically for all instances of a struct.
// The only difference here is these are namespaced for the struct type itself.
const capacity = size;
// Member variables of the struct are not preceeded by a binding type.
items: [size]T,
head: usize,
len: usize,
pub fn init() -> Self {
Self {
.items = undefined,
.head = 0,
.len = 0,
}
}
pub fn offset(self: &const Self, index: usize) -> usize {
(self.head + index) % capacity
}
pub fn append(self: &Self, value: T) {
self.items[self.offset(self.len)] = value;
self.len += 1;
}
pub fn peek(self: &Self) -> ?T {
if (self.len > 0) self.items[self.offset(self.len - 1)] else null
}
pub fn next(self: &Self) -> ?T {
if (self.len == 0) {
return null;
}
const value = self.items[self.offset(0)];
self.head = self.offset(1);
value
}
}
}
var rb = RingBuffer(u8, 128).init();
pub fn main() -> %void {
const printf = @import("std").io.stdout.printf;
rb.append(5);
%%printf("{}\n", rb.peek()); // 5
{
var i: u8 = 0;
while (i < 10) : (i += 1) {
rb.append(2 * i);
}
}
{
// Can perform a read-only pass using the offset function.
var i: usize = 0;
while (i < 10) : (i += 1) {
%%printf("{} ", rb.items[rb.offset(i)]);
}
%%printf("\n");
}
%%printf("{}\n", rb.next()); // 5
%%printf("{}\n", rb.next()); // 0
%%printf("{}\n", rb.next()); // 2
{
// Can add an 'infinite' number of items.
var i: usize = 0;
while (i < 1000) : (i += 1) {
// Use overflowing multiplication operator since this will otherwise exceed the u8 range.
// Also use the @truncate builtin to take just the bits that will fit in a u8, discarding
// the rest.
const in = 3 *% @truncate(u8, i);
rb.append(in);
}
// The output here will be completely different. Our original head is overwriten (4).
%%printf("{}\n", rb.next());
}
}