Skip to content

Instantly share code, notes, and snippets.

@belzecue
Created December 13, 2023 03:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save belzecue/a502fb242d1e622ec4b196e840ed7060 to your computer and use it in GitHub Desktop.
Save belzecue/a502fb242d1e622ec4b196e840ed7060 to your computer and use it in GitHub Desktop.
class_name RingBuffer extends Reference
"""
Uses simple arrays as ring buffers, passed to these static methods.
Allocates the first two slots for metadata (pointer, queue length).
USAGE:
var rb: Array = RingBuffer.create(5)
RingBuffer.push(rb, "i1")
RingBuffer.push(rb, "i2")
RingBuffer.push_all(rb, [
"i3",
"i4",
"i5",
])
var returned = RingBuffer.pop(rb) # FIFO by default
var returned = RingBuffer.pop(rb, RingBuffer.MODE_LIFO) # LIFO
"""
# Struct: POPMODE
enum {
MODE_LIFO,
MODE_FIFO
}
# Struct: Q
enum {
Q_CURSOR,
Q_LENGTH
}
const Q_ENUM_SIZE: int = 2
# Do not permit instantiating this static class.
func _init() -> void:
assert(false, "Must not instantiate static class: RingBuffer")
static func create(_size: int = 8) -> Array:
var result: Array = []
result.resize(_size + Q_ENUM_SIZE)
result[Q_CURSOR] = Q_ENUM_SIZE - 1 # cursor
result[Q_LENGTH] = 0 # Q length
return result
static func push(_rbarray: Array, item) -> void:
var array_size: int = _rbarray.size()
assert(array_size > Q_ENUM_SIZE, "Error! Ringbuffer class - array must be at least %s in length" % (Q_ENUM_SIZE + 1))
# Get the cursor, increment, and wrap
var cursor: int = wrapi(_rbarray[Q_CURSOR] + 1, Q_ENUM_SIZE, array_size)
# Update queue length, capped at array size
_rbarray[Q_LENGTH] = clamp(_rbarray[Q_LENGTH] + 1, 0, array_size - Q_ENUM_SIZE)
# Update cursor
_rbarray[Q_CURSOR] = cursor
# Assign the item to the new cursor slot
_rbarray[cursor] = item
static func push_all(_rbarray: Array, items: Array) -> void:
for i in items: push(_rbarray, i)
static func pop(_rbarray: Array, _popmode: int = MODE_FIFO):
var array_size: int = _rbarray.size()
assert(array_size > Q_ENUM_SIZE, "Error! Ringbuffer class - array must be at least %s in length" % (Q_ENUM_SIZE + 1))
# Get queue length
var qlength: int = _rbarray[Q_LENGTH]
# Check for empty queue
if qlength == 0: return null
# Get the cursor
var cursor: int = _rbarray[Q_CURSOR] if _popmode == MODE_LIFO \
else wrapi(_rbarray[Q_CURSOR] - qlength + 1, Q_ENUM_SIZE, array_size)
var result = _rbarray[cursor]
# Null the current slot to de-reference value
_rbarray[cursor] = null
# decrement the cursor (only in LIFO mode)
if _popmode == MODE_LIFO: _rbarray[Q_CURSOR] = wrapi(cursor - 1, Q_ENUM_SIZE, array_size)
# decrement the queue length
_rbarray[Q_LENGTH] = qlength - 1
# Return the popped value
return result
static func is_empty(_rbarray: Array) -> bool:
var array_size: int = _rbarray.size()
assert(array_size > Q_ENUM_SIZE, "Error! Ringbuffer class - array must be at least %s in length" % (Q_ENUM_SIZE + 1))
return _rbarray[Q_LENGTH] == 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment