Improved consistency with naming of init / create / destroy and when to propagate allocation errors and (#18)
Co-authored-by: Zachary Levy <zachary@sunforge.is> Reviewed-on: #18
This commit was merged in pull request #18.
This commit is contained in:
+269
-99
@@ -1,103 +1,139 @@
|
||||
package ring
|
||||
|
||||
import "base:runtime"
|
||||
import "core:fmt"
|
||||
|
||||
@(private)
|
||||
ODIN_BOUNDS_CHECK :: !ODIN_NO_BOUNDS_CHECK
|
||||
|
||||
Ring :: struct($T: typeid) {
|
||||
data: []T,
|
||||
_end_index, len: int,
|
||||
Ring :: struct($E: typeid) {
|
||||
data: []E,
|
||||
next_write_index, len: int,
|
||||
}
|
||||
|
||||
Ring_Soa :: struct($T: typeid) {
|
||||
data: #soa[]T,
|
||||
_end_index, len: int,
|
||||
Ring_Soa :: struct($E: typeid) {
|
||||
data: #soa[]E,
|
||||
next_write_index, len: int,
|
||||
}
|
||||
|
||||
from_slice_raos :: #force_inline proc(data: $T/[]$E) -> Ring(E) {
|
||||
return {data = data, _end_index = -1}
|
||||
destroy_aos :: #force_inline proc(
|
||||
ring: ^Ring($E),
|
||||
allocator := context.allocator,
|
||||
) -> runtime.Allocator_Error {
|
||||
return delete(ring.data)
|
||||
}
|
||||
|
||||
from_slice_rsoa :: #force_inline proc(data: $T/#soa[]$E) -> Ring_Soa(E) {
|
||||
return {data = data, _end_index = -1}
|
||||
destroy_soa :: #force_inline proc(
|
||||
ring: ^Ring_Soa($E),
|
||||
allocator := context.allocator,
|
||||
) -> runtime.Allocator_Error {
|
||||
return delete(ring.data)
|
||||
}
|
||||
|
||||
from_slice :: proc {
|
||||
from_slice_raos,
|
||||
from_slice_rsoa,
|
||||
destroy :: proc {
|
||||
destroy_aos,
|
||||
destroy_soa,
|
||||
}
|
||||
|
||||
create_aos :: #force_inline proc(
|
||||
$E: typeid,
|
||||
capacity: int,
|
||||
allocator := context.allocator,
|
||||
) -> (
|
||||
ring: Ring(E),
|
||||
err: runtime.Allocator_Error,
|
||||
) #optional_allocator_error {
|
||||
ring.data, err = make([]E, capacity, allocator)
|
||||
return ring, err
|
||||
}
|
||||
|
||||
create_soa :: #force_inline proc(
|
||||
$E: typeid,
|
||||
capacity: int,
|
||||
allocator := context.allocator,
|
||||
) -> (
|
||||
ring: Ring_Soa(E),
|
||||
err: runtime.Allocator_Error,
|
||||
) #optional_allocator_error {
|
||||
ring.data, err = make(#soa[]E, capacity, allocator)
|
||||
return ring, err
|
||||
}
|
||||
|
||||
// All contents of `data` will be completely ignored, `data` is treated as an empty slice.
|
||||
init_from_slice_aos :: #force_inline proc(ring: ^Ring($E), data: $T/[]E) {
|
||||
ring.data = data
|
||||
ring.len = 0
|
||||
ring.next_write_index = 0
|
||||
return
|
||||
}
|
||||
|
||||
// All contents of `data` will be completely ignored, `data` is treated as an empty slice.
|
||||
init_from_slice_soa :: #force_inline proc(ring: ^Ring_Soa($E), data: $T/#soa[]E) {
|
||||
ring.data = data
|
||||
ring.len = 0
|
||||
ring.next_write_index = 0
|
||||
return
|
||||
}
|
||||
|
||||
init_from_slice :: proc {
|
||||
init_from_slice_aos,
|
||||
init_from_slice_soa,
|
||||
}
|
||||
|
||||
// Internal
|
||||
// Index in the backing array where the ring starts
|
||||
_start_index_raos :: proc(ring: Ring($T)) -> int {
|
||||
if ring.len < len(ring.data) {
|
||||
return 0
|
||||
} else {
|
||||
start_index := ring._end_index + 1
|
||||
return 0 if start_index == len(ring.data) else start_index
|
||||
}
|
||||
start_index_aos :: #force_inline proc(ring: Ring($E)) -> int {
|
||||
return ring.len < len(ring.data) ? 0 : ring.next_write_index
|
||||
}
|
||||
|
||||
// Internal
|
||||
// Index in the backing array where the ring starts
|
||||
_start_index_rsoa :: proc(ring: Ring_Soa($T)) -> int {
|
||||
if ring.len < len(ring.data) {
|
||||
return 0
|
||||
} else {
|
||||
start_index := ring._end_index + 1
|
||||
return 0 if start_index == len(ring.data) else start_index
|
||||
}
|
||||
start_index_soa :: #force_inline proc(ring: Ring_Soa($E)) -> int {
|
||||
return ring.len < len(ring.data) ? 0 : ring.next_write_index
|
||||
}
|
||||
|
||||
advance_raos :: proc(ring: ^Ring($T)) {
|
||||
advance_aos :: #force_inline proc(ring: ^Ring($E)) {
|
||||
// Length
|
||||
if ring.len != len(ring.data) do ring.len += 1
|
||||
// End index
|
||||
if ring._end_index == len(ring.data) - 1 { // If we are at the end of the backing array
|
||||
ring._end_index = 0 // Overflow end to 0
|
||||
} else {
|
||||
ring._end_index += 1
|
||||
}
|
||||
// Write index
|
||||
ring.next_write_index += 1
|
||||
if ring.next_write_index == len(ring.data) do ring.next_write_index = 0
|
||||
}
|
||||
|
||||
advance_rsoa :: proc(ring: ^Ring_Soa($T)) {
|
||||
advance_soa :: #force_inline proc(ring: ^Ring_Soa($E)) {
|
||||
// Length
|
||||
if ring.len != len(ring.data) do ring.len += 1
|
||||
// End index
|
||||
if ring._end_index == len(ring.data) - 1 { // If we are at the end of the backing array
|
||||
ring._end_index = 0 // Overflow end to 0
|
||||
} else {
|
||||
ring._end_index += 1
|
||||
}
|
||||
// Write index
|
||||
ring.next_write_index += 1
|
||||
if ring.next_write_index == len(ring.data) do ring.next_write_index = 0
|
||||
}
|
||||
|
||||
advance :: proc {
|
||||
advance_raos,
|
||||
advance_rsoa,
|
||||
advance_aos,
|
||||
advance_soa,
|
||||
}
|
||||
|
||||
append_raos :: proc(ring: ^Ring($T), element: T) {
|
||||
append_aos :: #force_inline proc(ring: ^Ring($E), element: E) {
|
||||
ring.data[ring.next_write_index] = element
|
||||
advance(ring)
|
||||
ring.data[ring._end_index] = element
|
||||
}
|
||||
|
||||
append_rsoa :: proc(ring: ^Ring_Soa($T), element: T) {
|
||||
append_soa :: #force_inline proc(ring: ^Ring_Soa($E), element: E) {
|
||||
ring.data[ring.next_write_index] = element
|
||||
advance(ring)
|
||||
ring.data[ring._end_index] = element
|
||||
}
|
||||
|
||||
append :: proc {
|
||||
append_raos,
|
||||
append_rsoa,
|
||||
append_aos,
|
||||
append_soa,
|
||||
}
|
||||
|
||||
get_raos :: proc(ring: Ring($T), index: int) -> ^T {
|
||||
get_aos :: #force_inline proc(ring: Ring($E), index: int) -> ^E {
|
||||
when ODIN_BOUNDS_CHECK {
|
||||
if index >= ring.len {
|
||||
panic(fmt.tprintf("Ring index %i out of bounds for length %i", index, ring.len))
|
||||
}
|
||||
fmt.assertf(index < ring.len, "Ring index %i out of bounds for length %i", index, ring.len)
|
||||
}
|
||||
|
||||
array_index := _start_index_raos(ring) + index
|
||||
array_index := start_index_aos(ring) + index
|
||||
if array_index < len(ring.data) {
|
||||
return &ring.data[array_index]
|
||||
} else {
|
||||
@@ -107,14 +143,12 @@ get_raos :: proc(ring: Ring($T), index: int) -> ^T {
|
||||
}
|
||||
|
||||
// SOA can't return soa pointer to parapoly T.
|
||||
get_rsoa :: proc(ring: Ring_Soa($T), index: int) -> T {
|
||||
get_soa :: #force_inline proc(ring: Ring_Soa($E), index: int) -> E {
|
||||
when ODIN_BOUNDS_CHECK {
|
||||
if index >= ring.len {
|
||||
panic(fmt.tprintf("Ring index %i out of bounds for length %i", index, ring.len))
|
||||
}
|
||||
fmt.assertf(index < ring.len, "Ring index %i out of bounds for length %i", index, ring.len)
|
||||
}
|
||||
|
||||
array_index := _start_index_rsoa(ring) + index
|
||||
array_index := start_index_soa(ring) + index
|
||||
if array_index < len(ring.data) {
|
||||
return ring.data[array_index]
|
||||
} else {
|
||||
@@ -124,36 +158,36 @@ get_rsoa :: proc(ring: Ring_Soa($T), index: int) -> T {
|
||||
}
|
||||
|
||||
get :: proc {
|
||||
get_raos,
|
||||
get_rsoa,
|
||||
get_aos,
|
||||
get_soa,
|
||||
}
|
||||
|
||||
get_last_raos :: #force_inline proc(ring: Ring($T)) -> ^T {
|
||||
get_last_aos :: #force_inline proc(ring: Ring($E)) -> ^E {
|
||||
return get(ring, ring.len - 1)
|
||||
}
|
||||
|
||||
get_last_rsoa :: #force_inline proc(ring: Ring_Soa($T)) -> T {
|
||||
get_last_soa :: #force_inline proc(ring: Ring_Soa($E)) -> E {
|
||||
return get(ring, ring.len - 1)
|
||||
}
|
||||
|
||||
get_last :: proc {
|
||||
get_last_raos,
|
||||
get_last_rsoa,
|
||||
get_last_aos,
|
||||
get_last_soa,
|
||||
}
|
||||
|
||||
clear_raos :: #force_inline proc "contextless" (ring: ^Ring($T)) {
|
||||
clear_aos :: #force_inline proc "contextless" (ring: ^Ring($E)) {
|
||||
ring.len = 0
|
||||
ring._end_index = -1
|
||||
ring.next_write_index = 0
|
||||
}
|
||||
|
||||
clear_rsoa :: #force_inline proc "contextless" (ring: ^Ring_Soa($T)) {
|
||||
clear_soa :: #force_inline proc "contextless" (ring: ^Ring_Soa($E)) {
|
||||
ring.len = 0
|
||||
ring._end_index = -1
|
||||
ring.next_write_index = 0
|
||||
}
|
||||
|
||||
clear :: proc {
|
||||
clear_raos,
|
||||
clear_rsoa,
|
||||
clear_aos,
|
||||
clear_soa,
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
@@ -164,28 +198,27 @@ import "core:testing"
|
||||
|
||||
@(test)
|
||||
test_ring_aos :: proc(t: ^testing.T) {
|
||||
data := make_slice([]int, 10)
|
||||
ring := from_slice(data)
|
||||
defer delete(ring.data)
|
||||
ring := create_aos(int, 10)
|
||||
defer destroy(&ring)
|
||||
|
||||
for i in 1 ..= 5 {
|
||||
append(&ring, i)
|
||||
log.debug("Length:", ring.len)
|
||||
log.debug("Start index:", _start_index_raos(ring))
|
||||
log.debug("End index:", ring._end_index)
|
||||
log.debug("Start index:", start_index_aos(ring))
|
||||
log.debug("Next write index:", ring.next_write_index)
|
||||
log.debug(ring.data)
|
||||
}
|
||||
testing.expect_value(t, get(ring, 0)^, 1)
|
||||
testing.expect_value(t, get(ring, 4)^, 5)
|
||||
testing.expect_value(t, ring.len, 5)
|
||||
testing.expect_value(t, ring._end_index, 4)
|
||||
testing.expect_value(t, _start_index_raos(ring), 0)
|
||||
testing.expect_value(t, ring.next_write_index, 5)
|
||||
testing.expect_value(t, start_index_aos(ring), 0)
|
||||
|
||||
for i in 6 ..= 15 {
|
||||
append(&ring, i)
|
||||
log.debug("Length:", ring.len)
|
||||
log.debug("Start index:", _start_index_raos(ring))
|
||||
log.debug("End index:", ring._end_index)
|
||||
log.debug("Start index:", start_index_aos(ring))
|
||||
log.debug("Next write index:", ring.next_write_index)
|
||||
log.debug(ring.data)
|
||||
}
|
||||
testing.expect_value(t, get(ring, 0)^, 6)
|
||||
@@ -193,18 +226,18 @@ test_ring_aos :: proc(t: ^testing.T) {
|
||||
testing.expect_value(t, get(ring, 9)^, 15)
|
||||
testing.expect_value(t, get_last(ring)^, 15)
|
||||
testing.expect_value(t, ring.len, 10)
|
||||
testing.expect_value(t, ring._end_index, 4)
|
||||
testing.expect_value(t, _start_index_raos(ring), 5)
|
||||
testing.expect_value(t, ring.next_write_index, 5)
|
||||
testing.expect_value(t, start_index_aos(ring), 5)
|
||||
|
||||
for i in 15 ..= 25 {
|
||||
append(&ring, i)
|
||||
log.debug("Length:", ring.len)
|
||||
log.debug("Start index:", _start_index_raos(ring))
|
||||
log.debug("End index:", ring._end_index)
|
||||
log.debug("Start index:", start_index_aos(ring))
|
||||
log.debug("Next write index:", ring.next_write_index)
|
||||
log.debug(ring.data)
|
||||
}
|
||||
testing.expect_value(t, get(ring, 0)^, 16)
|
||||
testing.expect_value(t, ring._end_index, 5)
|
||||
testing.expect_value(t, ring.next_write_index, 6)
|
||||
testing.expect_value(t, get_last(ring)^, 25)
|
||||
|
||||
clear(&ring)
|
||||
@@ -219,28 +252,27 @@ test_ring_soa :: proc(t: ^testing.T) {
|
||||
x, y: int,
|
||||
}
|
||||
|
||||
data := make_soa_slice(#soa[]Ints, 10)
|
||||
ring := from_slice(data)
|
||||
defer delete(ring.data)
|
||||
ring := create_soa(Ints, 10)
|
||||
defer destroy(&ring)
|
||||
|
||||
for i in 1 ..= 5 {
|
||||
append(&ring, Ints{i, i})
|
||||
log.debug("Length:", ring.len)
|
||||
log.debug("Start index:", _start_index_rsoa(ring))
|
||||
log.debug("End index:", ring._end_index)
|
||||
log.debug("Start index:", start_index_soa(ring))
|
||||
log.debug("Next write index:", ring.next_write_index)
|
||||
log.debug(ring.data)
|
||||
}
|
||||
testing.expect_value(t, get(ring, 0), Ints{1, 1})
|
||||
testing.expect_value(t, get(ring, 4), Ints{5, 5})
|
||||
testing.expect_value(t, ring.len, 5)
|
||||
testing.expect_value(t, ring._end_index, 4)
|
||||
testing.expect_value(t, _start_index_rsoa(ring), 0)
|
||||
testing.expect_value(t, ring.next_write_index, 5)
|
||||
testing.expect_value(t, start_index_soa(ring), 0)
|
||||
|
||||
for i in 6 ..= 15 {
|
||||
append(&ring, Ints{i, i})
|
||||
log.debug("Length:", ring.len)
|
||||
log.debug("Start index:", _start_index_rsoa(ring))
|
||||
log.debug("End index:", ring._end_index)
|
||||
log.debug("Start index:", start_index_soa(ring))
|
||||
log.debug("Next write index:", ring.next_write_index)
|
||||
log.debug(ring.data)
|
||||
}
|
||||
testing.expect_value(t, get(ring, 0), Ints{6, 6})
|
||||
@@ -248,18 +280,18 @@ test_ring_soa :: proc(t: ^testing.T) {
|
||||
testing.expect_value(t, get(ring, 9), Ints{15, 15})
|
||||
testing.expect_value(t, get_last(ring), Ints{15, 15})
|
||||
testing.expect_value(t, ring.len, 10)
|
||||
testing.expect_value(t, ring._end_index, 4)
|
||||
testing.expect_value(t, _start_index_rsoa(ring), 5)
|
||||
testing.expect_value(t, ring.next_write_index, 5)
|
||||
testing.expect_value(t, start_index_soa(ring), 5)
|
||||
|
||||
for i in 15 ..= 25 {
|
||||
append(&ring, Ints{i, i})
|
||||
log.debug("Length:", ring.len)
|
||||
log.debug("Start index:", _start_index_rsoa(ring))
|
||||
log.debug("End index:", ring._end_index)
|
||||
log.debug("Start index:", start_index_soa(ring))
|
||||
log.debug("Next write index:", ring.next_write_index)
|
||||
log.debug(ring.data)
|
||||
}
|
||||
testing.expect_value(t, get(ring, 0), Ints{16, 16})
|
||||
testing.expect_value(t, ring._end_index, 5)
|
||||
testing.expect_value(t, ring.next_write_index, 6)
|
||||
testing.expect_value(t, get_last(ring), Ints{25, 25})
|
||||
|
||||
clear(&ring)
|
||||
@@ -267,3 +299,141 @@ test_ring_soa :: proc(t: ^testing.T) {
|
||||
testing.expect_value(t, ring.len, 1)
|
||||
testing.expect_value(t, get(ring, 0), Ints{1, 1})
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_ring_aos_init_from_slice :: proc(t: ^testing.T) {
|
||||
// Stack-allocated backing with pre-existing garbage and odd capacity.
|
||||
backing: [7]int = {99, 99, 99, 99, 99, 99, 99}
|
||||
|
||||
ring: Ring(int)
|
||||
init_from_slice(&ring, backing[:])
|
||||
|
||||
// Empty ring invariants after init_from_slice.
|
||||
testing.expect_value(t, ring.len, 0)
|
||||
testing.expect_value(t, ring.next_write_index, 0)
|
||||
testing.expect_value(t, start_index_aos(ring), 0)
|
||||
|
||||
// Partial fill (3 / 7).
|
||||
for i in 1 ..= 3 do append(&ring, i)
|
||||
testing.expect_value(t, ring.len, 3)
|
||||
testing.expect_value(t, ring.next_write_index, 3)
|
||||
testing.expect_value(t, start_index_aos(ring), 0)
|
||||
testing.expect_value(t, get(ring, 0)^, 1)
|
||||
testing.expect_value(t, get(ring, 2)^, 3)
|
||||
testing.expect_value(t, get_last(ring)^, 3)
|
||||
|
||||
// Fill exactly to capacity. Pushing element 7 must make len == cap
|
||||
// AND wrap next_write_index from 6 back to 0 in the same step.
|
||||
for i in 4 ..= 7 do append(&ring, i)
|
||||
testing.expect_value(t, ring.len, 7)
|
||||
testing.expect_value(t, ring.next_write_index, 0)
|
||||
testing.expect_value(t, start_index_aos(ring), 0)
|
||||
testing.expect_value(t, get(ring, 0)^, 1)
|
||||
testing.expect_value(t, get(ring, 6)^, 7)
|
||||
testing.expect_value(t, get_last(ring)^, 7)
|
||||
|
||||
// First overwrite — oldest element shifts by one.
|
||||
append(&ring, 8)
|
||||
testing.expect_value(t, ring.len, 7)
|
||||
testing.expect_value(t, ring.next_write_index, 1)
|
||||
testing.expect_value(t, start_index_aos(ring), 1)
|
||||
testing.expect_value(t, get(ring, 0)^, 2)
|
||||
testing.expect_value(t, get(ring, 6)^, 8)
|
||||
testing.expect_value(t, get_last(ring)^, 8)
|
||||
|
||||
// Stress: 3 more complete wrap cycles (21 more pushes).
|
||||
// After 29 total pushes, ring contains the last 7 (23..=29),
|
||||
// and next_write_index = 29 mod 7 = 1.
|
||||
for i in 9 ..= 29 do append(&ring, i)
|
||||
testing.expect_value(t, ring.len, 7)
|
||||
testing.expect_value(t, ring.next_write_index, 1)
|
||||
testing.expect_value(t, start_index_aos(ring), 1)
|
||||
testing.expect_value(t, get(ring, 0)^, 23)
|
||||
testing.expect_value(t, get(ring, 3)^, 26)
|
||||
testing.expect_value(t, get(ring, 6)^, 29)
|
||||
testing.expect_value(t, get_last(ring)^, 29)
|
||||
|
||||
// Clear returns ring to empty-equivalent state.
|
||||
clear(&ring)
|
||||
testing.expect_value(t, ring.len, 0)
|
||||
testing.expect_value(t, ring.next_write_index, 0)
|
||||
testing.expect_value(t, start_index_aos(ring), 0)
|
||||
|
||||
// Single-element edge case: get_last(len==1) routes through get(ring, 0).
|
||||
append(&ring, 42)
|
||||
testing.expect_value(t, ring.len, 1)
|
||||
testing.expect_value(t, ring.next_write_index, 1)
|
||||
testing.expect_value(t, get(ring, 0)^, 42)
|
||||
testing.expect_value(t, get_last(ring)^, 42)
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_ring_soa_init_from_slice :: proc(t: ^testing.T) {
|
||||
Ints :: struct {
|
||||
x, y: int,
|
||||
}
|
||||
|
||||
// Stack-allocated backing with pre-existing garbage and odd capacity.
|
||||
backing: #soa[7]Ints = {{99, 99}, {99, 99}, {99, 99}, {99, 99}, {99, 99}, {99, 99}, {99, 99}}
|
||||
|
||||
ring: Ring_Soa(Ints)
|
||||
init_from_slice(&ring, backing[:])
|
||||
|
||||
// Empty ring invariants after init_from_slice.
|
||||
testing.expect_value(t, ring.len, 0)
|
||||
testing.expect_value(t, ring.next_write_index, 0)
|
||||
testing.expect_value(t, start_index_soa(ring), 0)
|
||||
|
||||
// Partial fill (3 / 7).
|
||||
for i in 1 ..= 3 do append(&ring, Ints{i, i})
|
||||
testing.expect_value(t, ring.len, 3)
|
||||
testing.expect_value(t, ring.next_write_index, 3)
|
||||
testing.expect_value(t, start_index_soa(ring), 0)
|
||||
testing.expect_value(t, get(ring, 0), Ints{1, 1})
|
||||
testing.expect_value(t, get(ring, 2), Ints{3, 3})
|
||||
testing.expect_value(t, get_last(ring), Ints{3, 3})
|
||||
|
||||
// Fill exactly to capacity. Pushing element 7 must make len == cap
|
||||
// AND wrap next_write_index from 6 back to 0 in the same step.
|
||||
for i in 4 ..= 7 do append(&ring, Ints{i, i})
|
||||
testing.expect_value(t, ring.len, 7)
|
||||
testing.expect_value(t, ring.next_write_index, 0)
|
||||
testing.expect_value(t, start_index_soa(ring), 0)
|
||||
testing.expect_value(t, get(ring, 0), Ints{1, 1})
|
||||
testing.expect_value(t, get(ring, 6), Ints{7, 7})
|
||||
testing.expect_value(t, get_last(ring), Ints{7, 7})
|
||||
|
||||
// First overwrite — oldest element shifts by one.
|
||||
append(&ring, Ints{8, 8})
|
||||
testing.expect_value(t, ring.len, 7)
|
||||
testing.expect_value(t, ring.next_write_index, 1)
|
||||
testing.expect_value(t, start_index_soa(ring), 1)
|
||||
testing.expect_value(t, get(ring, 0), Ints{2, 2})
|
||||
testing.expect_value(t, get(ring, 6), Ints{8, 8})
|
||||
testing.expect_value(t, get_last(ring), Ints{8, 8})
|
||||
|
||||
// Stress: 3 more complete wrap cycles (21 more pushes).
|
||||
// After 29 total pushes, ring contains the last 7 (23..=29),
|
||||
// and next_write_index = 29 mod 7 = 1.
|
||||
for i in 9 ..= 29 do append(&ring, Ints{i, i})
|
||||
testing.expect_value(t, ring.len, 7)
|
||||
testing.expect_value(t, ring.next_write_index, 1)
|
||||
testing.expect_value(t, start_index_soa(ring), 1)
|
||||
testing.expect_value(t, get(ring, 0), Ints{23, 23})
|
||||
testing.expect_value(t, get(ring, 3), Ints{26, 26})
|
||||
testing.expect_value(t, get(ring, 6), Ints{29, 29})
|
||||
testing.expect_value(t, get_last(ring), Ints{29, 29})
|
||||
|
||||
// Clear returns ring to empty-equivalent state.
|
||||
clear(&ring)
|
||||
testing.expect_value(t, ring.len, 0)
|
||||
testing.expect_value(t, ring.next_write_index, 0)
|
||||
testing.expect_value(t, start_index_soa(ring), 0)
|
||||
|
||||
// Single-element edge case: get_last(len==1) routes through get(ring, 0).
|
||||
append(&ring, Ints{42, 42})
|
||||
testing.expect_value(t, ring.len, 1)
|
||||
testing.expect_value(t, ring.next_write_index, 1)
|
||||
testing.expect_value(t, get(ring, 0), Ints{42, 42})
|
||||
testing.expect_value(t, get_last(ring), Ints{42, 42})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user