Skip to content

Instantly share code, notes, and snippets.

@intsuc
Last active April 8, 2025 11:06
Show Gist options
  • Save intsuc/dcc55f14bd04f68b994b15c27305e1aa to your computer and use it in GitHub Desktop.
Save intsuc/dcc55f14bd04f68b994b15c27305e1aa to your computer and use it in GitHub Desktop.
An example implementation of a resizable queue with a growable ring buffer
#> example
function init
tellraw @s {storage: "_", nbt: "{}"}
# ┌ #read
# ring_overflow: [ _ | ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
data modify storage _ input set value 0
function push
tellraw @s {storage: "_", nbt: "{}"}
# ┌ #read
# ring_overflow: [ 0 | ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
data modify storage _ input set value 1
function push
tellraw @s {storage: "_", nbt: "{}"}
# ┌ #read
# ring_overflow: [ 0 | 1 ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
data modify storage _ input set value 2
function push
tellraw @s {storage: "_", nbt: "{}"}
# ┌ #read
# ring_overflow: [ 0 | 1, 2 ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
function pop
tellraw @s {storage: "_", nbt: "{}"}
# ┌ #read
# ring_overflow: [ _, 1, 2 | ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
function pop
tellraw @s {storage: "_", nbt: "{}"}
# ┌ #read
# ring_overflow: [ _, _, 2 | ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
function pop
tellraw @s {storage: "_", nbt: "{}"}
# ┌ #read
# ring_overflow: [ _ | ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
data modify storage _ input set value 3
function push
tellraw @s {storage: "_", nbt: "{}"}
# ┌ #read
# ring_overflow: [ 3 | ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
data modify storage _ input set value 4
function push
tellraw @s {storage: "_", nbt: "{}"}
# ┌ #read
# ring_overflow: [ 3 | 4 ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
data modify storage _ input set value 5
function push
tellraw @s {storage: "_", nbt: "{}"}
# ┌ #read
# ring_overflow: [ 3 | 4, 5 ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
function pop
tellraw @s {storage: "_", nbt: "{}"}
# ┌ #read
# ring_overflow: [ _ 4, 5 | ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
data modify storage _ input set value 6
function push
tellraw @s {storage: "_", nbt: "{}"}
# ┌ #read
# ring_overflow: [ 6, 4, 5 | ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
data modify storage _ input set value 7
function push
tellraw @s {storage: "_", nbt: "{}"}
# ┌ #read
# ring_overflow: [ 6, 4, 5 | 7 ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
function pop
tellraw @s {storage: "_", nbt: "{}"}
# ┌ #read
# ring_overflow: [ 6, _, 5 | 7 ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
data modify storage _ input set value 8
function push
tellraw @s {storage: "_", nbt: "{}"}
# ┌ #read
# ring_overflow: [ 6, _, 5 | 7, 8 ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
function pop
tellraw @s {storage: "_", nbt: "{}"}
# ┌ #read
# ring_overflow: [ 6, _, _ | 7, 8 ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
function pop
tellraw @s {storage: "_", nbt: "{}"}
# ┌ #read
# ring_overflow: [ _, _, _, 7, 8 | ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
data modify storage _ input set value 9
function push
tellraw @s {storage: "_", nbt: "{}"}
# ┌ #read
# ring_overflow: [ 9, _, _ 7, 8 | ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
data modify storage _ input set value 10
function push
tellraw @s {storage: "_", nbt: "{}"}
# ┌ #read
# ring_overflow: [ 9, 10, _, 7, 8 | ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
data modify storage _ input set value 11
function push
tellraw @s {storage: "_", nbt: "{}"}
# ┌ #read
# ring_overflow: [ 9, 10, 11, 7, 8 | ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
function pop
tellraw @s {storage: "_", nbt: "{}"}
# ┌ #read
# ring_overflow: [ 9, 10, 11, _, 8 | ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
function pop
tellraw @s {storage: "_", nbt: "{}"}
# ┌ #read
# ring_overflow: [ 9, 10, 11, _, _ | ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
function pop
tellraw @s {storage: "_", nbt: "{}"}
# ┌ #read
# ring_overflow: [ _, 10, 11, _, _ | ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
function pop
tellraw @s {storage: "_", nbt: "{}"}
# ┌ #read
# ring_overflow: [ _, _, 11, _, _ | ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
function pop
tellraw @s {storage: "_", nbt: "{}"}
# ┌ #read
# ring_overflow: [ _ | ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
data modify storage _ input set value 12
function push
tellraw @s {storage: "_", nbt: "{}"}
# ┌ #read
# ring_overflow: [ 12 | ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
function pop
tellraw @s {storage: "_", nbt: "{}"}
# ┌ #read
# ring_overflow: [ _ | ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
scoreboard objectives add _ dummy
# The queue is represented by a buffer called ring_overflow.
# The ring_overflow has a fixed-length ring buffer at the front
# and a variable-length overflow buffer following it.
#
# We can eliminate extra conditionals by keeping the number of elements in the ring_overflow greater than 0.
data modify storage _ ring_overflow set value [false]
# The size of the ring buffer in the ring_overflow.
scoreboard players set #ring_size _ 1
# The next index to read in the ring buffer.
scoreboard players set #read _ 0
# The next index to write in the ring buffer.
scoreboard players set #write _ 0
# ┌ #read
# ring_overflow: [ _ | ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
# We can always pop an element from the ring buffer,
# assuming that we do not pop more elements than we have pushed.
# If you maintain the size of the queue, you can perform a runtime check here.
#
# ┌ #read
# ring_overflow: [ ..., ?, ... | ]
# │
# └ #ring_size
scoreboard players operation #temp _ = #read _
execute store result storage _ index int 1 run \
scoreboard players operation #temp _ %= #ring_size _
function take with storage _
scoreboard players add #read _ 1
# If the ring buffer is not empty, we have nothing to do.
#
# ┌ #read
# ring_overflow: [ ..., ?, ..., ?, ... | ]
# #write ┘
execute unless score #read _ = #write _ run \
return 0
# If the ring buffer is empty, we need to extend the ring buffer
# by merging the overflow buffer into the ring buffer.
#
# ┌ #read
# ring_overflow: [ ..., _, ... | ... ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
execute store result score #ring_overflow_size _ run data get storage _ ring_overflow
# If the overflow buffer is empty too, we can safely garbage collect the old ring_overflow buffer
# and allocate a new one with less capacity.
# If you do not want to pay the cost of internal growths of the ring_buffer again,
# you can reuse the existing ring_overflow buffer instance.
#
# This is the special case where all the elements in the ring buffer are popped out
# without overflowing the ring buffer.
#
# ┌ #read
# ring_overflow: [ ..., _, ... | ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
execute if score #ring_size _ = #ring_overflow_size _ \
store result score #read _ run \
scoreboard players set #write _ 0
execute if score #ring_size _ = #ring_overflow_size _ \
store result score #ring_size _ run \
return run \
data modify storage _ ring_overflow set value [false]
# If the overflow buffer is not empty,
# we move the #read pointer to the start of the overflow buffer and the #write pointer to the start of the ring buffer.
# We also extend the ring buffer by setting the #ring_size to the entire size of the ring_overflow buffer.
#
# ┌ #read
# ring_overflow: [ _, ..., _, ... | ?, ... ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
scoreboard players operation #read _ = #ring_size _
scoreboard players operation #read _ %= #ring_overflow_size _
scoreboard players operation #write _ = #ring_overflow_size _
scoreboard players operation #ring_size _ = #ring_overflow_size _
# ┌ #read
# ring_overflow: [ _, ..., _, ..., ?, ... | ]
# #write ┘ │ └ #ring_overflow_size
# └ #ring_size
execute store result score #ring_overflow_size _ run data get storage _ ring_overflow
# If the overflow buffer is not empty,
# we need to push the input to the overflow buffer until the ring buffer becomes empty.
#
# ring_overflow: [ ... | ?, ... ]
# │ └ #ring_overflow_size
# └ #ring_size
execute if score #ring_overflow_size _ > #ring_size _ run \
return run \
data modify storage _ ring_overflow append from storage _ input
# If the ring buffer is full (#write goes around the ring buffer from #read),
# we need to push the input to the overflow buffer
#
# ┌ #read
# ring_overflow: [ ..., ?, ... | ]
# #write ┘ │
# └ #ring_size
scoreboard players operation #temp _ = #read _
scoreboard players operation #temp _ += #ring_size _
execute if score #temp _ = #write _ run \
return run \
data modify storage _ ring_overflow append from storage _ input
# Otherwise, we can just push the input to the ring buffer.
#
# ┌ #read
# ring_overflow: [ ..., ?, ..., ?, ... | ]
# #write ┘ │
# └ #ring_size
scoreboard players operation #temp _ = #write _
execute store result storage _ index int 1 run \
scoreboard players operation #temp _ %= #ring_size _
function store with storage _
scoreboard players add #write _ 1
$data modify storage _ ring_overflow[$(index)] set from storage _ input
$data modify storage _ output set from storage _ ring_overflow[$(index)]
$data modify storage _ ring_overflow[$(index)] set value false
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment