Last active
April 8, 2025 11:06
-
-
Save intsuc/dcc55f14bd04f68b994b15c27305e1aa to your computer and use it in GitHub Desktop.
An example implementation of a resizable queue with a growable ring buffer
This file contains hidden or 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
#> 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 |
This file contains hidden or 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
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 |
This file contains hidden or 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
# 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 |
This file contains hidden or 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
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 |
This file contains hidden or 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
$data modify storage _ ring_overflow[$(index)] set from storage _ input |
This file contains hidden or 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
$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