tigerbeetle-node 0.4.3 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,51 +14,84 @@ pub fn RingBuffer(comptime T: type, comptime size: usize) type {
14
14
  /// The number of items in the buffer.
15
15
  count: usize = 0,
16
16
 
17
- /// Add an element to the RingBuffer. Returns an error if the buffer
18
- /// is already full and the element could not be added.
19
- pub fn push(self: *Self, item: T) error{NoSpaceLeft}!void {
20
- if (self.full()) return error.NoSpaceLeft;
21
- self.buffer[(self.index + self.count) % self.buffer.len] = item;
22
- self.count += 1;
17
+ // TODO add doc comments to these functions:
18
+ pub inline fn head(self: Self) ?T {
19
+ if (self.empty()) return null;
20
+ return self.buffer[self.index];
23
21
  }
24
22
 
25
- /// Return, but do not remove, the next item, if any.
26
- pub fn peek(self: *Self) ?T {
27
- return (self.peek_ptr() orelse return null).*;
23
+ pub inline fn head_ptr(self: *Self) ?*T {
24
+ if (self.empty()) return null;
25
+ return &self.buffer[self.index];
28
26
  }
29
27
 
30
- /// Return a pointer to, but do not remove, the next item, if any.
31
- pub fn peek_ptr(self: *Self) ?*T {
28
+ pub inline fn tail(self: Self) ?T {
32
29
  if (self.empty()) return null;
33
- return &self.buffer[self.index];
30
+ return self.buffer[(self.index + self.count - 1) % self.buffer.len];
34
31
  }
35
32
 
36
- /// Remove and return the next item, if any.
37
- pub fn pop(self: *Self) ?T {
33
+ pub inline fn tail_ptr(self: *Self) ?*T {
38
34
  if (self.empty()) return null;
39
- defer {
40
- self.index = (self.index + 1) % self.buffer.len;
41
- self.count -= 1;
42
- }
43
- return self.buffer[self.index];
35
+ return &self.buffer[(self.index + self.count - 1) % self.buffer.len];
36
+ }
37
+
38
+ pub inline fn next_tail(self: Self) ?T {
39
+ if (self.full()) return null;
40
+ return self.buffer[(self.index + self.count) % self.buffer.len];
41
+ }
42
+
43
+ pub inline fn next_tail_ptr(self: *Self) ?*T {
44
+ if (self.full()) return null;
45
+ return &self.buffer[(self.index + self.count) % self.buffer.len];
46
+ }
47
+
48
+ pub inline fn advance_head(self: *Self) void {
49
+ self.index += 1;
50
+ self.index %= self.buffer.len;
51
+ self.count -= 1;
52
+ }
53
+
54
+ pub inline fn advance_tail(self: *Self) void {
55
+ assert(self.count < self.buffer.len);
56
+ self.count += 1;
44
57
  }
45
58
 
46
59
  /// Returns whether the ring buffer is completely full.
47
- pub fn full(self: *const Self) bool {
60
+ pub inline fn full(self: Self) bool {
48
61
  return self.count == self.buffer.len;
49
62
  }
50
63
 
51
64
  /// Returns whether the ring buffer is completely empty.
52
- pub fn empty(self: *const Self) bool {
65
+ pub inline fn empty(self: Self) bool {
53
66
  return self.count == 0;
54
67
  }
55
68
 
69
+ // Higher level, less error-prone wrappers:
70
+
71
+ /// Add an element to the RingBuffer. Returns an error if the buffer
72
+ /// is already full and the element could not be added.
73
+ pub fn push(self: *Self, item: T) error{NoSpaceLeft}!void {
74
+ const ptr = self.next_tail_ptr() orelse return error.NoSpaceLeft;
75
+ ptr.* = item;
76
+ self.advance_tail();
77
+ }
78
+
79
+ /// Remove and return the next item, if any.
80
+ pub fn pop(self: *Self) ?T {
81
+ const result = self.head() orelse return null;
82
+ self.advance_head();
83
+ return result;
84
+ }
85
+
56
86
  pub const Iterator = struct {
57
87
  ring: *Self,
58
88
  count: usize = 0,
59
89
 
60
90
  pub fn next(it: *Iterator) ?T {
61
- return (it.next_ptr() orelse return null).*;
91
+ assert(it.count <= it.ring.count);
92
+ if (it.count == it.ring.count) return null;
93
+ defer it.count += 1;
94
+ return it.ring.buffer[(it.ring.index + it.count) % it.ring.buffer.len];
62
95
  }
63
96
 
64
97
  pub fn next_ptr(it: *Iterator) ?*T {
@@ -79,43 +112,6 @@ pub fn RingBuffer(comptime T: type, comptime size: usize) type {
79
112
 
80
113
  const testing = std.testing;
81
114
 
82
- test "push/peek/pop/full/empty" {
83
- var fifo = RingBuffer(u32, 3){};
84
-
85
- try testing.expect(!fifo.full());
86
- try testing.expect(fifo.empty());
87
-
88
- try fifo.push(1);
89
- try testing.expectEqual(@as(?u32, 1), fifo.peek());
90
-
91
- try testing.expect(!fifo.full());
92
- try testing.expect(!fifo.empty());
93
-
94
- try fifo.push(2);
95
- try testing.expectEqual(@as(?u32, 1), fifo.peek());
96
-
97
- try fifo.push(3);
98
- try testing.expectError(error.NoSpaceLeft, fifo.push(4));
99
-
100
- try testing.expect(fifo.full());
101
- try testing.expect(!fifo.empty());
102
-
103
- try testing.expectEqual(@as(?u32, 1), fifo.peek());
104
- try testing.expectEqual(@as(?u32, 1), fifo.pop());
105
-
106
- try testing.expect(!fifo.full());
107
- try testing.expect(!fifo.empty());
108
-
109
- fifo.peek_ptr().?.* += 1000;
110
-
111
- try testing.expectEqual(@as(?u32, 1002), fifo.pop());
112
- try testing.expectEqual(@as(?u32, 3), fifo.pop());
113
- try testing.expectEqual(@as(?u32, null), fifo.pop());
114
-
115
- try testing.expect(!fifo.full());
116
- try testing.expect(fifo.empty());
117
- }
118
-
119
115
  fn test_iterator(comptime T: type, ring: *T, values: []const u32) !void {
120
116
  const ring_index = ring.index;
121
117
 
@@ -133,22 +129,41 @@ fn test_iterator(comptime T: type, ring: *T, values: []const u32) !void {
133
129
  try testing.expectEqual(ring_index, ring.index);
134
130
  }
135
131
 
136
- test "iterator" {
132
+ test "RingBuffer: low level interface" {
137
133
  const Ring = RingBuffer(u32, 2);
138
134
 
139
135
  var ring = Ring{};
140
136
  try test_iterator(Ring, &ring, &[_]u32{});
141
137
 
142
- try ring.push(0);
138
+ try testing.expectEqual(@as(?u32, null), ring.head());
139
+ try testing.expectEqual(@as(?*u32, null), ring.head_ptr());
140
+ try testing.expectEqual(@as(?u32, null), ring.tail());
141
+ try testing.expectEqual(@as(?*u32, null), ring.tail_ptr());
142
+
143
+ ring.next_tail_ptr().?.* = 0;
144
+ ring.advance_tail();
145
+ try testing.expectEqual(@as(?u32, 0), ring.tail());
146
+ try testing.expectEqual(@as(u32, 0), ring.tail_ptr().?.*);
143
147
  try test_iterator(Ring, &ring, &[_]u32{0});
144
148
 
145
- try ring.push(1);
149
+ ring.next_tail_ptr().?.* = 1;
150
+ ring.advance_tail();
151
+ try testing.expectEqual(@as(?u32, 1), ring.tail());
152
+ try testing.expectEqual(@as(u32, 1), ring.tail_ptr().?.*);
146
153
  try test_iterator(Ring, &ring, &[_]u32{ 0, 1 });
147
154
 
148
- try testing.expectEqual(@as(?u32, 0), ring.pop());
155
+ try testing.expectEqual(@as(?u32, null), ring.next_tail());
156
+ try testing.expectEqual(@as(?*u32, null), ring.next_tail_ptr());
157
+
158
+ try testing.expectEqual(@as(?u32, 0), ring.head());
159
+ try testing.expectEqual(@as(u32, 0), ring.head_ptr().?.*);
160
+ ring.advance_head();
149
161
  try test_iterator(Ring, &ring, &[_]u32{1});
150
162
 
151
- try ring.push(2);
163
+ ring.next_tail_ptr().?.* = 2;
164
+ ring.advance_tail();
165
+ try testing.expectEqual(@as(?u32, 2), ring.tail());
166
+ try testing.expectEqual(@as(u32, 2), ring.tail_ptr().?.*);
152
167
  try test_iterator(Ring, &ring, &[_]u32{ 1, 2 });
153
168
 
154
169
  var iterator = ring.iterator();
@@ -156,15 +171,67 @@ test "iterator" {
156
171
  item_ptr.* += 1000;
157
172
  }
158
173
 
159
- try testing.expectEqual(@as(?u32, 1001), ring.pop());
174
+ try testing.expectEqual(@as(?u32, 1001), ring.head());
175
+ try testing.expectEqual(@as(u32, 1001), ring.head_ptr().?.*);
176
+ ring.advance_head();
160
177
  try test_iterator(Ring, &ring, &[_]u32{1002});
161
178
 
162
- try ring.push(3);
179
+ ring.next_tail_ptr().?.* = 3;
180
+ ring.advance_tail();
181
+ try testing.expectEqual(@as(?u32, 3), ring.tail());
182
+ try testing.expectEqual(@as(u32, 3), ring.tail_ptr().?.*);
163
183
  try test_iterator(Ring, &ring, &[_]u32{ 1002, 3 });
164
184
 
165
- try testing.expectEqual(@as(?u32, 1002), ring.pop());
185
+ try testing.expectEqual(@as(?u32, 1002), ring.head());
186
+ try testing.expectEqual(@as(u32, 1002), ring.head_ptr().?.*);
187
+ ring.advance_head();
166
188
  try test_iterator(Ring, &ring, &[_]u32{3});
167
189
 
168
- try testing.expectEqual(@as(?u32, 3), ring.pop());
190
+ try testing.expectEqual(@as(?u32, 3), ring.head());
191
+ try testing.expectEqual(@as(u32, 3), ring.head_ptr().?.*);
192
+ ring.advance_head();
169
193
  try test_iterator(Ring, &ring, &[_]u32{});
194
+
195
+ try testing.expectEqual(@as(?u32, null), ring.head());
196
+ try testing.expectEqual(@as(?*u32, null), ring.head_ptr());
197
+ try testing.expectEqual(@as(?u32, null), ring.tail());
198
+ try testing.expectEqual(@as(?*u32, null), ring.tail_ptr());
199
+ }
200
+
201
+ test "RingBuffer: push/pop high level interface" {
202
+ var fifo = RingBuffer(u32, 3){};
203
+
204
+ try testing.expect(!fifo.full());
205
+ try testing.expect(fifo.empty());
206
+
207
+ try fifo.push(1);
208
+ try testing.expectEqual(@as(?u32, 1), fifo.head());
209
+
210
+ try testing.expect(!fifo.full());
211
+ try testing.expect(!fifo.empty());
212
+
213
+ try fifo.push(2);
214
+ try testing.expectEqual(@as(?u32, 1), fifo.head());
215
+
216
+ try fifo.push(3);
217
+ try testing.expectError(error.NoSpaceLeft, fifo.push(4));
218
+
219
+ try testing.expect(fifo.full());
220
+ try testing.expect(!fifo.empty());
221
+
222
+ try testing.expectEqual(@as(?u32, 1), fifo.head());
223
+ try testing.expectEqual(@as(?u32, 1), fifo.pop());
224
+
225
+ try testing.expect(!fifo.full());
226
+ try testing.expect(!fifo.empty());
227
+
228
+ try fifo.push(4);
229
+
230
+ try testing.expectEqual(@as(?u32, 2), fifo.pop());
231
+ try testing.expectEqual(@as(?u32, 3), fifo.pop());
232
+ try testing.expectEqual(@as(?u32, 4), fifo.pop());
233
+ try testing.expectEqual(@as(?u32, null), fifo.pop());
234
+
235
+ try testing.expect(!fifo.full());
236
+ try testing.expect(fifo.empty());
170
237
  }