Skip to content

Instantly share code, notes, and snippets.

@adam12
Forked from havenwood/ring_buffer.rb
Created July 7, 2023 16:59
Show Gist options
  • Save adam12/e39a992a48f8a7cfd1a0c5e3486b3f53 to your computer and use it in GitHub Desktop.
Save adam12/e39a992a48f8a7cfd1a0c5e3486b3f53 to your computer and use it in GitHub Desktop.
A ring buffer implementation example for Ruby Discord.
# frozen_string_literal: true
class RingBuffer
Nothing = Data.define
EMPTY = Nothing.new
attr_reader :size
def initialize(capacity:)
@capacity = capacity
@buffer = Array.new(capacity, EMPTY)
reset_counters
end
def reset_counters
@head = nil
@tail = nil
@looping = false
@size = 0
end
def clear
@buffer.fill(EMPTY)
reset_counters
end
def <<(value)
@head ||= 0
if @tail
@tail = @tail.succ.modulo(@capacity)
@looping = true if @tail.zero?
@head = @head.succ.modulo(@capacity) if @looping
else
@tail = 0
end
@size = @size.succ.clamp(..@capacity)
@buffer[@tail] = value
end
alias put <<
def get
return EMPTY unless @tail
tail = @buffer.fetch(@tail)
@buffer[@tail] = EMPTY
if @tail == @head
clear
return tail
end
if @tail.zero?
@tail = @capacity - 1
else
@tail -= 1
end
@size -= 1
tail
end
alias detail get
def behead
return EMPTY unless @head
head = @buffer.fetch(@head)
@buffer[@head] = EMPTY
if @head == @tail
clear
return head
end
@head = @head.succ.modulo(@capacity)
@size -= 1
head
end
def head
return EMPTY unless @head
@buffer.fetch(@head)
end
def tail
return EMPTY unless @tail
@buffer.fetch(@tail)
end
def [](index)
return EMPTY unless @head
@buffer.fetch((@head + index) % @capacity)
end
def clear
@head = nil
@tail = nil
@looping = false
@buffer.fill(EMPTY)
@size = 0
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment