-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathpqueue.c
More file actions
145 lines (128 loc) · 3.54 KB
/
Copy pathpqueue.c
File metadata and controls
145 lines (128 loc) · 3.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// Copyright 2023 Joshua J Baker. All rights reserved.
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
#include <stdlib.h>
#include <string.h>
#ifndef PQUEUE_STATIC
#include "pqueue.h"
#else
#define PQUEUE_EXTERN static
#endif
#ifndef PQUEUE_EXTERN
#define PQUEUE_EXTERN
#endif
struct pqueue {
size_t elsize;
int (*compare)(const void* a, const void* b, void* udata);
void* udata;
char* items;
size_t len;
size_t cap;
};
PQUEUE_EXTERN
struct pqueue* pqueue_new(size_t elsize,
int (*compare)(const void* a, const void* b,
void* udata),
void* udata) {
struct pqueue* queue = m_alloc(sizeof(struct pqueue));
if (!queue)
return NULL;
queue->elsize = elsize;
queue->compare = compare;
queue->udata = udata;
queue->cap = 8;
queue->len = 0;
queue->items = m_alloc(elsize * (queue->cap + 1));
if (!queue->items) {
free(queue);
return NULL;
}
return queue;
}
PQUEUE_EXTERN
void pqueue_free(struct pqueue* queue) {
if (queue->items)
m_free(queue->items);
m_free(queue);
}
PQUEUE_EXTERN
void pqueue_clear(struct pqueue* queue) {
queue->len = 0;
}
static void* get(struct pqueue* queue, size_t index) {
return queue->items + (queue->elsize * index);
}
static void set(struct pqueue* queue, const void* item, size_t index) {
memcpy(get(queue, index), item, queue->elsize);
}
static bool push(struct pqueue* queue, const void* item) {
if (queue->len == queue->cap) {
size_t cap = queue->cap * 2;
char* items = m_realloc(queue->items, queue->elsize * (cap + 1));
if (!items)
return false;
queue->items = items;
queue->cap = cap;
}
set(queue, item, queue->len++);
return true;
}
static void swap(struct pqueue* queue, size_t i, size_t j) {
set(queue, get(queue, i), queue->len);
set(queue, get(queue, j), i);
set(queue, get(queue, queue->len), j);
}
static void* swap_remove(struct pqueue* queue, size_t i) {
set(queue, get(queue, i), queue->len);
set(queue, get(queue, queue->len - 1), i);
return get(queue, queue->len--);
}
static int compare(struct pqueue* queue, size_t i, size_t j) {
return queue->compare(get(queue, i), get(queue, j), queue->udata);
}
PQUEUE_EXTERN
bool pqueue_push(struct pqueue* queue, const void* item) {
if (!push(queue, item))
return false;
size_t i = queue->len - 1;
while (i != 0) {
size_t parent = (i - 1) / 2;
if (!(compare(queue, parent, i) > 0))
break;
swap(queue, parent, i);
i = parent;
}
return true;
}
PQUEUE_EXTERN
size_t pqueue_count(const struct pqueue* queue) {
return queue->len;
}
PQUEUE_EXTERN
const void* pqueue_peek(const struct pqueue* queue) {
return queue->len == 0 ? NULL : queue->items;
}
PQUEUE_EXTERN
const void* pqueue_pop(struct pqueue* queue) {
if (queue->len == 0)
return NULL;
void* item = swap_remove(queue, 0);
size_t i = 0;
while (1) {
size_t smallest = i;
size_t left = i * 2 + 1;
size_t right = i * 2 + 2;
if (left < queue->len && compare(queue, left, smallest) <= 0) {
smallest = left;
}
if (right < queue->len && compare(queue, right, smallest) <= 0) {
smallest = right;
}
if (smallest == i) {
break;
}
swap(queue, smallest, i);
i = smallest;
}
return item;
}