Created
December 13, 2023 03:57
-
-
Save belzecue/a502fb242d1e622ec4b196e840ed7060 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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