Serene Runtime 1.0.0-dev
C runtime for the Serene programming language
Loading...
Searching...
No Matches
pqmh_tests.h
Go to the documentation of this file.
1/* -*- C -*-
2 * Serene programming language
3 * Copyright (C) 2019-2026 Sameer Rahmani <[email protected]>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <https://www.gnu.org/licenses/>.
17 */
18
19#pragma once
20
21#include <stdint.h>
22
23#include "acutest.h"
24#include "base.h"
25#include "serene/rt/impl/pqmh.h"
26
27#define PQMH_TESTS(X) \
28 X("pqmh::empty", test_pqmh_empty), X("pqmh::ordering", test_pqmh_ordering), \
29 X("pqmh::peek", test_pqmh_peek), X("pqmh::grow", test_pqmh_grow)
30
31// Elements are stored by pointer; the tests stuff small ints into the pointer
32// so no per-element allocation is needed.
33static bool pqmh_int_less(srn_context_t *ctx, const void *a, const void *b) {
34 UNUSED(ctx);
35 return (intptr_t)a < (intptr_t)b;
36}
37
38static const pqmh_control_t pqmh_int_ctl = {.less = pqmh_int_less};
39
40#define PQ_INT(v) ((void *)(intptr_t)(v))
41
42// An empty queue, length 0, peek is NULL, pop fails and leaves `out` untouched.
43static void test_pqmh_empty() {
44 MAKE_ENGINE(mm, engine);
45 MAKE_CONTEXT(engine, ctx);
46
47 pqmh_t pq = pqmh_make(ctx, &pqmh_int_ctl, 0);
48 TEST_CHECK(pqmh_len(&pq) == 0);
49 TEST_CHECK(pqmh_peek(&pq) == nullptr);
50
51 void *out = PQ_INT(123);
52 TEST_CHECK(!pqmh_pop(ctx, &pq, &out));
53 TEST_CHECK(out == PQ_INT(123)); // untouched on empty
54
55 pqmh_free(ctx, &pq);
56 RELEASE_CONTEXT(ctx);
57 SHUTDOWN_ENGINE(mm, engine);
58}
59
60// Push out of order, pop in ascending order (min-heap).
61static void test_pqmh_ordering() {
62 MAKE_ENGINE(mm, engine);
63 MAKE_CONTEXT(engine, ctx);
64
65 pqmh_t pq = pqmh_make(ctx, &pqmh_int_ctl, 4);
66 int in[] = {5, 1, 4, 2, 8, 3, 7, 6, 0, 9};
67 enum { N = (int)(sizeof(in) / sizeof(in[0])) };
68 for (int i = 0; i < N; i++) {
69 pqmh_push(ctx, &pq, PQ_INT(in[i]));
70 }
71 TEST_CHECK(pqmh_len(&pq) == (size_t)N);
72
73 for (int i = 0; i < N; i++) {
74 void *out = nullptr;
75 TEST_CHECK(pqmh_pop(ctx, &pq, &out));
76 TEST_CHECK((intptr_t)out == i);
77 }
78 TEST_CHECK(pqmh_len(&pq) == 0);
79
80 pqmh_free(ctx, &pq);
81 RELEASE_CONTEXT(ctx);
82 SHUTDOWN_ENGINE(mm, engine);
83}
84
85// peek returns the min without removing it.
86static void test_pqmh_peek() {
87 MAKE_ENGINE(mm, engine);
88 MAKE_CONTEXT(engine, ctx);
89
90 pqmh_t pq = pqmh_make(ctx, &pqmh_int_ctl, 0);
91 pqmh_push(ctx, &pq, PQ_INT(42));
92 pqmh_push(ctx, &pq, PQ_INT(7));
93 pqmh_push(ctx, &pq, PQ_INT(99));
94
95 TEST_CHECK((intptr_t)pqmh_peek(&pq) == 7);
96 TEST_CHECK(pqmh_len(&pq) == 3); // peek does not remove
97
98 void *out = nullptr;
99 TEST_CHECK(pqmh_pop(ctx, &pq, &out));
100 TEST_CHECK((intptr_t)out == 7);
101 TEST_CHECK((intptr_t)pqmh_peek(&pq) == 42);
102
103 pqmh_free(ctx, &pq);
104 RELEASE_CONTEXT(ctx);
105 SHUTDOWN_ENGINE(mm, engine);
106}
107
108// Start tiny and push far past the initial capacity to exercise growth, then
109// confirm everything still comes out sorted.
110static void test_pqmh_grow() {
111 MAKE_ENGINE(mm, engine);
112 MAKE_CONTEXT(engine, ctx);
113
114 pqmh_t pq = pqmh_make(ctx, &pqmh_int_ctl, 2); // forces several doublings
115 enum { N = 1000 };
116 for (int i = N - 1; i >= 0; i--) { // descending in, each push sifts to root
117 pqmh_push(ctx, &pq, PQ_INT(i));
118 }
119 TEST_CHECK(pqmh_len(&pq) == (size_t)N);
120
121 for (int i = 0; i < N; i++) {
122 void *out = nullptr;
123 TEST_CHECK(pqmh_pop(ctx, &pq, &out));
124 TEST_CHECK((intptr_t)out == i);
125 }
126 TEST_CHECK(pqmh_len(&pq) == 0);
127
128 pqmh_free(ctx, &pq);
129 RELEASE_CONTEXT(ctx);
130 SHUTDOWN_ENGINE(mm, engine);
131}
#define TEST_CHECK(cond)
Definition acutest.h:95
#define RELEASE_CONTEXT(x)
Definition base.h:46
#define SHUTDOWN_ENGINE(mm, engine)
Definition base.h:38
#define MAKE_ENGINE(mm, engine)
Definition base.h:32
#define MAKE_CONTEXT(engine, x)
Definition base.h:42
void pqmh_free(srn_context_t *ctx, pqmh_t *pq)
Release the backing array and reset the queue to empty.
Definition pqmh.c:142
void pqmh_push(srn_context_t *ctx, pqmh_t *pq, void *elem)
Insert elem, growing the backing array (doubling) if it is full.
Definition pqmh.c:92
pqmh_t pqmh_make(srn_context_t *ctx, const pqmh_control_t *ctl, size_t initial_cap)
Create an empty queue ordered by ctl, with room for initial_cap elements (a small default is used whe...
Definition pqmh.c:81
void * pqmh_peek(const pqmh_t *pq)
The highest priority element without removing it, or NULL when the queue is empty.
Definition pqmh.c:132
bool pqmh_pop(srn_context_t *ctx, pqmh_t *pq, void **out)
Remove the highest priority element into *out and return true, or return false (leaving *out untouche...
Definition pqmh.c:111
size_t pqmh_len(const pqmh_t *pq)
The number of elements currently in the queue.
Definition pqmh.c:137
A generic priority queue backed by a binary min-heap.
static void test_pqmh_empty()
Definition pqmh_tests.h:43
static const pqmh_control_t pqmh_int_ctl
Definition pqmh_tests.h:38
static void test_pqmh_peek()
Definition pqmh_tests.h:86
#define PQ_INT(v)
Definition pqmh_tests.h:40
static void test_pqmh_grow()
Definition pqmh_tests.h:110
static bool pqmh_int_less(srn_context_t *ctx, const void *a, const void *b)
Definition pqmh_tests.h:33
static void test_pqmh_ordering()
Definition pqmh_tests.h:61
Per type configuration.
Definition pqmh.h:57
A priority queue.
Definition pqmh.h:66
#define UNUSED(x)
Definition utils.h:45