Ring Buffers and the Rotating Surface
A pottery wheel gives you a circular workspace. The clay spins, your hands stay mostly still, and every point on the rim eventually returns to where you can shape it. You don’t need an infinite surface—just enough room for one revolution, used over and over.
A ring buffer works the same way: a fixed-size array where writes wrap back to the beginning once you reach the end. Producer writes at the head, consumer reads from the tail, and as long as the producer doesn’t lap the consumer, you never run out of space. Used everywhere in the ’70s for terminal I/O, audio streams, and anywhere data flows faster than you can process it.
class RingBuffer:
def __init__(self, size):
self.buf = [None] * size
self.head = self.tail = 0
self.size = size
def write(self, val):
self.buf[self.head] = val
self.head = (self.head + 1) % self.size
def read(self):
val = self.buf[self.tail]
self.tail = (self.tail + 1) % self.size
return val
const RingBuffer = struct {
buf: [256]u8,
head: usize = 0,
tail: usize = 0,
fn write(self: *RingBuffer, val: u8) void {
self.buf[self.head] = val;
self.head = (self.head + 1) % self.buf.len;
}
fn read(self: *RingBuffer) u8 {
const val = self.buf[self.tail];
self.tail = (self.tail + 1) % self.buf.len;
return val;
}
};
The modulo operator % size does the wrapping. Once head or tail reaches the end, it cycles back to zero. Python’s version is dynamically sized; Zig’s uses a fixed compile-time array. Both avoid allocation churn—you allocate once, reuse forever.
Pottery uses the same efficiency: the wheel’s surface is fixed, but the amount of work you can do on it is unlimited. You don’t throw away the wheel after each bowl. You center new clay on the same surface, and it spins through your hands again.