|
@@ -0,0 +1,157 @@
|
|
|
|
+package test_core_container
|
|
|
|
+
|
|
|
|
+import "base:runtime"
|
|
|
|
+import "core:container/queue"
|
|
|
|
+import "core:testing"
|
|
|
|
+
|
|
|
|
+@test
|
|
|
|
+test_queue :: proc(t: ^testing.T) {
|
|
|
|
+ buf := [?]int{99, 99, 99, 99, 99}
|
|
|
|
+ q: queue.Queue(int)
|
|
|
|
+
|
|
|
|
+ testing.expect(t, queue.init_from_slice(&q, buf[:]))
|
|
|
|
+ testing.expect_value(t, queue.reserve(&q, len(buf)), nil)
|
|
|
|
+
|
|
|
|
+ queue.push_back(&q, 1)
|
|
|
|
+ queue.push_back_elems(&q, 2, 3)
|
|
|
|
+ queue.push_front(&q, 0)
|
|
|
|
+
|
|
|
|
+ // {
|
|
|
|
+ // data = [1, 2, 3, 99, 0],
|
|
|
|
+ // len = 4,
|
|
|
|
+ // offset = 4,
|
|
|
|
+ // }
|
|
|
|
+
|
|
|
|
+ testing.expect_value(t, queue.back(&q), 3)
|
|
|
|
+ testing.expect_value(t, queue.back_ptr(&q), &buf[2])
|
|
|
|
+ testing.expect_value(t, queue.front(&q), 0)
|
|
|
|
+ testing.expect_value(t, queue.front_ptr(&q), &buf[4])
|
|
|
|
+
|
|
|
|
+ queue.get(&q, 3)
|
|
|
|
+
|
|
|
|
+ for i in 0..<4 {
|
|
|
|
+ testing.expect_value(t, queue.get(&q, i), i)
|
|
|
|
+ queue.set(&q, i, i)
|
|
|
|
+ }
|
|
|
|
+ testing.expect_value(t, queue.get_ptr(&q, 3), &buf[2])
|
|
|
|
+
|
|
|
|
+ queue.consume_back(&q, 1)
|
|
|
|
+ queue.consume_front(&q, 1)
|
|
|
|
+ testing.expect_value(t, queue.pop_back(&q), 2)
|
|
|
|
+ v, ok := queue.pop_back_safe(&q)
|
|
|
|
+ testing.expect_value(t, v, 1)
|
|
|
|
+ testing.expect_value(t, ok, true)
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ // Test `init_with_contents`.
|
|
|
|
+ buf2 := [?]int{99, 3, 5}
|
|
|
|
+
|
|
|
|
+ queue.init_with_contents(&q, buf2[:])
|
|
|
|
+ push_ok, push_err := queue.push_back(&q, 1)
|
|
|
|
+ testing.expect(t, !push_ok)
|
|
|
|
+ testing.expect_value(t, push_err, runtime.Allocator_Error.Out_Of_Memory)
|
|
|
|
+ push_ok, push_err = queue.push_front(&q, 2)
|
|
|
|
+ testing.expect(t, !push_ok)
|
|
|
|
+ testing.expect_value(t, push_err, runtime.Allocator_Error.Out_Of_Memory)
|
|
|
|
+
|
|
|
|
+ pop_front_v, pop_front_ok := queue.pop_front_safe(&q)
|
|
|
|
+ testing.expect(t, pop_front_ok)
|
|
|
|
+ testing.expect_value(t, pop_front_v, 99)
|
|
|
|
+
|
|
|
|
+ // Re-initialization.
|
|
|
|
+ queue.init(&q, 0)
|
|
|
|
+ defer queue.destroy(&q)
|
|
|
|
+
|
|
|
|
+ queue.push_back_elems(&q, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18)
|
|
|
|
+ testing.expect_value(t, queue.len(q), 18)
|
|
|
|
+ queue.push_back_elems(&q, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18)
|
|
|
|
+ testing.expect_value(t, queue.len(q), 36)
|
|
|
|
+
|
|
|
|
+ for i in 1..=18 {
|
|
|
|
+ testing.expect_value(t, queue.pop_front(&q), i)
|
|
|
|
+ }
|
|
|
|
+ for i in 1..=18 {
|
|
|
|
+ testing.expect_value(t, queue.pop_front(&q), i)
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+@test
|
|
|
|
+test_queue_grow_edge_case :: proc(t: ^testing.T) {
|
|
|
|
+ // Create a situation in which we trigger `q.offset + q.len > n` inside
|
|
|
|
+ // `_grow` to evaluate the `copy` behavior.
|
|
|
|
+ qq: queue.Queue(int)
|
|
|
|
+ queue.init(&qq, 0)
|
|
|
|
+ defer queue.destroy(&qq)
|
|
|
|
+
|
|
|
|
+ queue.push_back_elems(&qq, 1, 2, 3, 4, 5, 6, 7)
|
|
|
|
+ testing.expect_value(t, queue.pop_front(&qq), 1)
|
|
|
|
+ testing.expect_value(t, queue.pop_front(&qq), 2)
|
|
|
|
+ testing.expect_value(t, queue.pop_front(&qq), 3)
|
|
|
|
+ queue.push_back(&qq, 8)
|
|
|
|
+ queue.push_back(&qq, 9)
|
|
|
|
+
|
|
|
|
+ testing.expect_value(t, qq.len, 6)
|
|
|
|
+ testing.expect_value(t, qq.offset, 3)
|
|
|
|
+ testing.expect_value(t, len(qq.data), 8) // value contingent on smallest dynamic array capacity on first allocation
|
|
|
|
+
|
|
|
|
+ queue.reserve(&qq, 16)
|
|
|
|
+
|
|
|
|
+ testing.expect_value(t, queue.len(qq), 6)
|
|
|
|
+ for i in 4..=9 {
|
|
|
|
+ testing.expect_value(t, queue.pop_front(&qq), i)
|
|
|
|
+ }
|
|
|
|
+ testing.expect_value(t, queue.len(qq), 0)
|
|
|
|
+
|
|
|
|
+ // If we made it to this point without failure, the queue should have
|
|
|
|
+ // copied the data into the right place after resizing the backing array.
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+@test
|
|
|
|
+test_queue_grow_edge_case_2 :: proc(t: ^testing.T) {
|
|
|
|
+ // Create a situation in which we trigger `insert_from + insert_to > sz` inside `push_back_elems`
|
|
|
|
+ // to evaluate the modified `insert_to` behavior.
|
|
|
|
+ qq: queue.Queue(int)
|
|
|
|
+ queue.init(&qq, 8)
|
|
|
|
+ defer queue.destroy(&qq)
|
|
|
|
+
|
|
|
|
+ queue.push_back_elems(&qq, -1, -2, -3, -4, -5, -6, -7)
|
|
|
|
+ queue.consume_front(&qq, 3)
|
|
|
|
+ queue.push_back_elems(&qq, -8, -9, -10)
|
|
|
|
+
|
|
|
|
+ queue.push_back_elems(&qq, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
|
|
|
|
+
|
|
|
|
+ testing.expect_value(t, queue.len(qq), 17)
|
|
|
|
+ for i in 4..=10 {
|
|
|
|
+ testing.expect_value(t, queue.pop_front(&qq), -i)
|
|
|
|
+ }
|
|
|
|
+ for i in 1..=10 {
|
|
|
|
+ testing.expect_value(t, queue.pop_front(&qq), i)
|
|
|
|
+ }
|
|
|
|
+ testing.expect_value(t, queue.len(qq), 0)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+@test
|
|
|
|
+test_queue_shrink :: proc(t: ^testing.T) {
|
|
|
|
+ qq: queue.Queue(int)
|
|
|
|
+ queue.init(&qq, 8)
|
|
|
|
+ defer queue.destroy(&qq)
|
|
|
|
+
|
|
|
|
+ queue.push_back_elems(&qq, -1, -2, -3, -4, -5, -6, -7)
|
|
|
|
+ queue.consume_front(&qq, 3)
|
|
|
|
+ queue.push_back_elems(&qq, -8, -9, -10)
|
|
|
|
+
|
|
|
|
+ queue.push_back_elems(&qq, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
|
|
|
|
+
|
|
|
|
+ queue.shrink(&qq)
|
|
|
|
+ queue.consume_front(&qq, 7)
|
|
|
|
+ queue.shrink(&qq)
|
|
|
|
+
|
|
|
|
+ for i in 1..=10 {
|
|
|
|
+ testing.expect_value(t, queue.pop_front(&qq), i)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ buf: [1]int
|
|
|
|
+ qq_backed: queue.Queue(int)
|
|
|
|
+ queue.init_from_slice(&qq_backed, buf[:])
|
|
|
|
+ queue.shrink(&qq_backed)
|
|
|
|
+}
|