Serene Runtime 1.0.0-dev
C runtime for the Serene programming language
Loading...
Searching...
No Matches
pqmh.c
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 library is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser 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 library 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 Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this library. If not, see <https://www.gnu.org/licenses/>.
17 */
18
19#include "serene/rt/impl/pqmh.h"
20
21#include "serene/rt/context.h"
22#include "serene/rt/engine.h"
24#include "serene/utils.h"
25
26/// Capacity a queue created with `initial_cap == 0` starts at.
27#define PQMH_MIN_CAP 8U
28
29// Array-backed binary heap, the children of index `i` live at `2i+1` and
30// `2i+2`, its parent at `(i-1)/2`.
31
32/**
33 * Move the element at `i` up toward the root until the heap order holds (its
34 * parent is no longer ordered after it).
35 */
36static void sift_up(srn_context_t *ctx, pqmh_t *pq, size_t i) {
37 while (i > 0) {
38 size_t parent = (i - 1) / 2;
39
40 if (!pq->ctl->less(ctx, pq->data[i], pq->data[parent])) {
41 // Now the order is correct
42 break;
43 }
44
45 void *tmp = pq->data[i];
46 pq->data[i] = pq->data[parent];
47 pq->data[parent] = tmp;
48 i = parent;
49 }
50}
51
52/**
53 * Move the element at `i` down toward the leaves until the heap order holds
54 * (neither child is ordered before it).
55 */
56static void sift_down(srn_context_t *ctx, pqmh_t *pq, size_t i) {
57 for (;;) {
58 size_t left = (2 * i) + 1;
59 size_t right = (2 * i) + 2;
60 size_t smallest = i;
61
62 if (left < pq->len && (int)pq->ctl->less(ctx, pq->data[left], pq->data[smallest])) {
63 smallest = left;
64 }
65
66 if (right < pq->len && (int)pq->ctl->less(ctx, pq->data[right], pq->data[smallest])) {
67 smallest = right;
68 }
69
70 if (smallest == i) {
71 break;
72 }
73
74 void *tmp = pq->data[i];
75 pq->data[i] = pq->data[smallest];
76 pq->data[smallest] = tmp;
77 i = smallest;
78 }
79}
80
81pqmh_t pqmh_make(srn_context_t *ctx, const pqmh_control_t *ctl, size_t initial_cap) {
82 PANIC_IF_NULL(ctx);
83 PANIC_IF_NULL(ctl);
84
85 size_t cap = (initial_cap == 0) ? PQMH_MIN_CAP : initial_cap;
86 void **data = (void **)srn_mm_malloc(ctx->engine->mm, cap * sizeof(void *));
87 PANIC_IF_NULL(data);
88
89 return (pqmh_t){.ctl = ctl, .data = data, .len = 0, .cap = cap};
90}
91
92void pqmh_push(srn_context_t *ctx, pqmh_t *pq, void *elem) {
93 PANIC_IF_NULL(ctx);
94 PANIC_IF_NULL(pq);
95
96 if (pq->len == pq->cap) {
97 PANIC_IF(pq->cap > SIZE_MAX / 2 / sizeof(void *), "priority queue capacity overflows");
98 size_t new_cap = pq->cap * 2;
99 void **new_data =
100 (void **)srn_mm_reallocate(ctx->engine->mm, (void *)pq->data, new_cap * sizeof(void *));
101 PANIC_IF_NULL(new_data);
102 pq->data = new_data;
103 pq->cap = new_cap;
104 }
105
106 pq->data[pq->len] = elem;
107 pq->len++;
108 sift_up(ctx, pq, pq->len - 1);
109}
110
111bool pqmh_pop(srn_context_t *ctx, pqmh_t *pq, void **out) {
112 PANIC_IF_NULL(ctx);
113 PANIC_IF_NULL(pq);
114 PANIC_IF_NULL(out);
115
116 if (pq->len == 0) {
117 return false;
118 }
119
120 *out = pq->data[0];
121 pq->len--;
122
123 if (pq->len > 0) {
124 // Promote the last element to the root and sink it into place.
125 pq->data[0] = pq->data[pq->len];
126 sift_down(ctx, pq, 0);
127 }
128
129 return true;
130}
131
132void *pqmh_peek(const pqmh_t *pq) {
133 PANIC_IF_NULL(pq);
134 return (pq->len == 0) ? nullptr : pq->data[0];
135}
136
137size_t pqmh_len(const pqmh_t *pq) {
138 PANIC_IF_NULL(pq);
139 return pq->len;
140}
141
143 PANIC_IF_NULL(ctx);
144 PANIC_IF_NULL(pq);
145
146 srn_mm_free(ctx->engine->mm, (void *)pq->data);
147 pq->data = nullptr;
148 pq->len = 0;
149 pq->cap = 0;
150}
void * srn_mm_reallocate(srn_mm_t *mm, void *ptr, size_t new_size)
Definition default.c:160
void srn_mm_free(srn_mm_t *mm, void *ptr)
Release a pointer previously returned by srn_mm_malloc or srn_mm_reallocate.
Definition default.c:165
void * srn_mm_malloc(srn_mm_t *mm, size_t size)
Generic allocations that do not participate in the block based pools.
Definition default.c:155
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
#define PQMH_MIN_CAP
Capacity a queue created with initial_cap == 0 starts at.
Definition pqmh.c:27
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
static void sift_down(srn_context_t *ctx, pqmh_t *pq, size_t i)
Move the element at i down toward the leaves until the heap order holds (neither child is ordered bef...
Definition pqmh.c:56
static void sift_up(srn_context_t *ctx, pqmh_t *pq, size_t i)
Move the element at i up toward the root until the heap order holds (its parent is no longer ordered ...
Definition pqmh.c:36
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.
Per type configuration.
Definition pqmh.h:57
pqmh_less_fn less
Definition pqmh.h:58
A priority queue.
Definition pqmh.h:66
size_t cap
Definition pqmh.h:70
size_t len
Definition pqmh.h:69
void ** data
Definition pqmh.h:68
const pqmh_control_t * ctl
Definition pqmh.h:67
srn_engine_t * engine
Long term state of the compiler.
Definition context.h:49
srn_mm_t * mm
Memory manager.
Definition engine.h:65
#define PANIC_IF_NULL(ptr)
Definition utils.h:66
#define PANIC_IF(cond, msg)
Definition utils.h:59