├── .github └── FUNDING.yml ├── LICENSE ├── README.md └── src ├── pqueue.c ├── pqueue.h ├── sample-multiattr.c └── sample.c /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2014-2022 Volkan Yazıcı 2 | # All rights reserved. 3 | # 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions are met: 6 | # 7 | # 1. Redistributions of source code must retain the above copyright notice, this 8 | # list of conditions and the following disclaimer. 9 | # 2. Redistributions in binary form must reproduce the above copyright notice, 10 | # this list of conditions and the following disclaimer in the documentation 11 | # and/or other materials provided with the distribution. 12 | # 13 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | github: vy 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Volkan Yazıcı 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | L oo.ooooo. .ooooo oo oooo oooo .ooooo. oooo oooo .ooooo. 3 | 888' `88b d88' `888 `888 `888 d88' `88b `888 `888 d88' `88b 4 | 888 888 888 888 888 888 888ooo888 888 888 888ooo888 5 | I 888 888 888 888 888 888 888 .o 888 888 888 .o 6 | 888bod8P' `V8bod888 `V88V"V8P' `Y8bod8P' `V88V"V8P' `Y8bod8P' 7 | 888 888. 8 | B o888o 8P' 9 | " 10 | 11 | `libpqueue` is a generic priority queue (heap) implementation used by the Apache HTTP Server project. (Particularly, 2.2.14 release.) I just tidied up the source and API a little bit, introduced some minor functionality, etc. 12 | -------------------------------------------------------------------------------- /src/pqueue.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Volkan Yazıcı 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include "pqueue.h" 32 | 33 | 34 | #define left(i) ((i) << 1) 35 | #define right(i) (((i) << 1) + 1) 36 | #define parent(i) ((i) >> 1) 37 | 38 | 39 | pqueue_t * 40 | pqueue_init(size_t n, 41 | pqueue_cmp_pri_f cmppri, 42 | pqueue_get_pri_f getpri, 43 | pqueue_set_pri_f setpri, 44 | pqueue_get_pos_f getpos, 45 | pqueue_set_pos_f setpos) 46 | { 47 | pqueue_t *q; 48 | 49 | if (!(q = malloc(sizeof(pqueue_t)))) 50 | return NULL; 51 | 52 | /* Need to allocate n+1 elements since element 0 isn't used. */ 53 | if (!(q->d = malloc((n + 1) * sizeof(void *)))) { 54 | free(q); 55 | return NULL; 56 | } 57 | 58 | q->size = 1; 59 | q->avail = q->step = (n+1); /* see comment above about n+1 */ 60 | q->cmppri = cmppri; 61 | q->setpri = setpri; 62 | q->getpri = getpri; 63 | q->getpos = getpos; 64 | q->setpos = setpos; 65 | 66 | return q; 67 | } 68 | 69 | 70 | void 71 | pqueue_free(pqueue_t *q) 72 | { 73 | free(q->d); 74 | free(q); 75 | } 76 | 77 | 78 | size_t 79 | pqueue_size(pqueue_t *q) 80 | { 81 | /* queue element 0 exists but doesn't count since it isn't used. */ 82 | return (q->size - 1); 83 | } 84 | 85 | 86 | static void 87 | bubble_up(pqueue_t *q, size_t i) 88 | { 89 | size_t parent_node; 90 | void *moving_node = q->d[i]; 91 | pqueue_pri_t moving_pri = q->getpri(moving_node); 92 | 93 | for (parent_node = parent(i); 94 | ((i > 1) && q->cmppri(q->getpri(q->d[parent_node]), moving_pri)); 95 | i = parent_node, parent_node = parent(i)) 96 | { 97 | q->d[i] = q->d[parent_node]; 98 | q->setpos(q->d[i], i); 99 | } 100 | 101 | q->d[i] = moving_node; 102 | q->setpos(moving_node, i); 103 | } 104 | 105 | 106 | static size_t 107 | maxchild(pqueue_t *q, size_t i) 108 | { 109 | size_t child_node = left(i); 110 | 111 | if (child_node >= q->size) 112 | return 0; 113 | 114 | if ((child_node+1) < q->size && 115 | q->cmppri(q->getpri(q->d[child_node]), q->getpri(q->d[child_node+1]))) 116 | child_node++; /* use right child instead of left */ 117 | 118 | return child_node; 119 | } 120 | 121 | 122 | static void 123 | percolate_down(pqueue_t *q, size_t i) 124 | { 125 | size_t child_node; 126 | void *moving_node = q->d[i]; 127 | pqueue_pri_t moving_pri = q->getpri(moving_node); 128 | 129 | while ((child_node = maxchild(q, i)) && 130 | q->cmppri(moving_pri, q->getpri(q->d[child_node]))) 131 | { 132 | q->d[i] = q->d[child_node]; 133 | q->setpos(q->d[i], i); 134 | i = child_node; 135 | } 136 | 137 | q->d[i] = moving_node; 138 | q->setpos(moving_node, i); 139 | } 140 | 141 | 142 | int 143 | pqueue_insert(pqueue_t *q, void *d) 144 | { 145 | void *tmp; 146 | size_t i; 147 | size_t newsize; 148 | 149 | if (!q) return 1; 150 | 151 | /* allocate more memory if necessary */ 152 | if (q->size >= q->avail) { 153 | newsize = q->size + q->step; 154 | if (!(tmp = realloc(q->d, sizeof(void *) * newsize))) 155 | return 1; 156 | q->d = tmp; 157 | q->avail = newsize; 158 | } 159 | 160 | /* insert item */ 161 | i = q->size++; 162 | q->d[i] = d; 163 | bubble_up(q, i); 164 | 165 | return 0; 166 | } 167 | 168 | 169 | void 170 | pqueue_change_priority(pqueue_t *q, 171 | pqueue_pri_t new_pri, 172 | void *d) 173 | { 174 | size_t posn; 175 | pqueue_pri_t old_pri = q->getpri(d); 176 | 177 | q->setpri(d, new_pri); 178 | posn = q->getpos(d); 179 | if (q->cmppri(old_pri, new_pri)) 180 | bubble_up(q, posn); 181 | else 182 | percolate_down(q, posn); 183 | } 184 | 185 | 186 | int 187 | pqueue_remove(pqueue_t *q, void *d) 188 | { 189 | size_t posn = q->getpos(d); 190 | q->d[posn] = q->d[--q->size]; 191 | if (q->cmppri(q->getpri(d), q->getpri(q->d[posn]))) 192 | bubble_up(q, posn); 193 | else 194 | percolate_down(q, posn); 195 | 196 | return 0; 197 | } 198 | 199 | 200 | void * 201 | pqueue_pop(pqueue_t *q) 202 | { 203 | void *head; 204 | 205 | if (!q || q->size == 1) 206 | return NULL; 207 | 208 | head = q->d[1]; 209 | q->d[1] = q->d[--q->size]; 210 | percolate_down(q, 1); 211 | 212 | return head; 213 | } 214 | 215 | 216 | void * 217 | pqueue_peek(pqueue_t *q) 218 | { 219 | void *d; 220 | if (!q || q->size == 1) 221 | return NULL; 222 | d = q->d[1]; 223 | return d; 224 | } 225 | 226 | 227 | void 228 | pqueue_dump(pqueue_t *q, 229 | FILE *out, 230 | pqueue_print_entry_f print) 231 | { 232 | int i; 233 | 234 | fprintf(stdout,"posn\tleft\tright\tparent\tmaxchild\t...\n"); 235 | for (i = 1; i < q->size ;i++) { 236 | fprintf(stdout, 237 | "%d\t%d\t%d\t%d\t%ul\t", 238 | i, 239 | left(i), right(i), parent(i), 240 | (unsigned int)maxchild(q, i)); 241 | print(out, q->d[i]); 242 | } 243 | } 244 | 245 | 246 | static void 247 | set_pos(void *d, size_t val) 248 | { 249 | /* do nothing */ 250 | } 251 | 252 | 253 | static void 254 | set_pri(void *d, pqueue_pri_t pri) 255 | { 256 | /* do nothing */ 257 | } 258 | 259 | 260 | void 261 | pqueue_print(pqueue_t *q, 262 | FILE *out, 263 | pqueue_print_entry_f print) 264 | { 265 | pqueue_t *dup; 266 | void *e; 267 | 268 | dup = pqueue_init(q->size, 269 | q->cmppri, q->getpri, set_pri, 270 | q->getpos, set_pos); 271 | dup->size = q->size; 272 | dup->avail = q->avail; 273 | dup->step = q->step; 274 | 275 | memcpy(dup->d, q->d, (q->size * sizeof(void *))); 276 | 277 | while ((e = pqueue_pop(dup))) 278 | print(out, e); 279 | 280 | pqueue_free(dup); 281 | } 282 | 283 | 284 | static int 285 | subtree_is_valid(pqueue_t *q, int pos) 286 | { 287 | if (left(pos) < q->size) { 288 | /* has a left child */ 289 | if (q->cmppri(q->getpri(q->d[pos]), q->getpri(q->d[left(pos)]))) 290 | return 0; 291 | if (!subtree_is_valid(q, left(pos))) 292 | return 0; 293 | } 294 | if (right(pos) < q->size) { 295 | /* has a right child */ 296 | if (q->cmppri(q->getpri(q->d[pos]), q->getpri(q->d[right(pos)]))) 297 | return 0; 298 | if (!subtree_is_valid(q, right(pos))) 299 | return 0; 300 | } 301 | return 1; 302 | } 303 | 304 | 305 | int 306 | pqueue_is_valid(pqueue_t *q) 307 | { 308 | return subtree_is_valid(q, 1); 309 | } 310 | -------------------------------------------------------------------------------- /src/pqueue.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Volkan Yazıcı 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | 27 | /** 28 | * @file pqueue.h 29 | * @brief Priority Queue function declarations 30 | * 31 | * @{ 32 | */ 33 | 34 | 35 | #ifndef PQUEUE_H 36 | #define PQUEUE_H 37 | 38 | /** priority data type */ 39 | typedef unsigned long long pqueue_pri_t; 40 | 41 | /** callback functions to get/set/compare the priority of an element */ 42 | typedef pqueue_pri_t (*pqueue_get_pri_f)(void *a); 43 | typedef void (*pqueue_set_pri_f)(void *a, pqueue_pri_t pri); 44 | typedef int (*pqueue_cmp_pri_f)(pqueue_pri_t next, pqueue_pri_t curr); 45 | 46 | 47 | /** callback functions to get/set the position of an element */ 48 | typedef size_t (*pqueue_get_pos_f)(void *a); 49 | typedef void (*pqueue_set_pos_f)(void *a, size_t pos); 50 | 51 | 52 | /** debug callback function to print a entry */ 53 | typedef void (*pqueue_print_entry_f)(FILE *out, void *a); 54 | 55 | 56 | /** the priority queue handle */ 57 | typedef struct pqueue_t 58 | { 59 | size_t size; /**< number of elements in this queue */ 60 | size_t avail; /**< slots available in this queue */ 61 | size_t step; /**< growth stepping setting */ 62 | pqueue_cmp_pri_f cmppri; /**< callback to compare nodes */ 63 | pqueue_get_pri_f getpri; /**< callback to get priority of a node */ 64 | pqueue_set_pri_f setpri; /**< callback to set priority of a node */ 65 | pqueue_get_pos_f getpos; /**< callback to get position of a node */ 66 | pqueue_set_pos_f setpos; /**< callback to set position of a node */ 67 | void **d; /**< The actualy queue in binary heap form */ 68 | } pqueue_t; 69 | 70 | 71 | /** 72 | * initialize the queue 73 | * 74 | * @param n the initial estimate of the number of queue items for which memory 75 | * should be preallocated 76 | * @param cmppri The callback function to run to compare two elements 77 | * This callback should return 0 for 'lower' and non-zero 78 | * for 'higher', or vice versa if reverse priority is desired 79 | * @param setpri the callback function to run to assign a score to an element 80 | * @param getpri the callback function to run to set a score to an element 81 | * @param getpos the callback function to get the current element's position 82 | * @param setpos the callback function to set the current element's position 83 | * 84 | * @return the handle or NULL for insufficent memory 85 | */ 86 | pqueue_t * 87 | pqueue_init(size_t n, 88 | pqueue_cmp_pri_f cmppri, 89 | pqueue_get_pri_f getpri, 90 | pqueue_set_pri_f setpri, 91 | pqueue_get_pos_f getpos, 92 | pqueue_set_pos_f setpos); 93 | 94 | 95 | /** 96 | * free all memory used by the queue 97 | * @param q the queue 98 | */ 99 | void pqueue_free(pqueue_t *q); 100 | 101 | 102 | /** 103 | * return the size of the queue. 104 | * @param q the queue 105 | */ 106 | size_t pqueue_size(pqueue_t *q); 107 | 108 | 109 | /** 110 | * insert an item into the queue. 111 | * @param q the queue 112 | * @param d the item 113 | * @return 0 on success 114 | */ 115 | int pqueue_insert(pqueue_t *q, void *d); 116 | 117 | 118 | /** 119 | * move an existing entry to a different priority 120 | * @param q the queue 121 | * @param new_pri the new priority 122 | * @param d the entry 123 | */ 124 | void 125 | pqueue_change_priority(pqueue_t *q, 126 | pqueue_pri_t new_pri, 127 | void *d); 128 | 129 | 130 | /** 131 | * pop the highest-ranking item from the queue. 132 | * @param q the queue 133 | * @return NULL on error, otherwise the entry 134 | */ 135 | void *pqueue_pop(pqueue_t *q); 136 | 137 | 138 | /** 139 | * remove an item from the queue. 140 | * @param q the queue 141 | * @param d the entry 142 | * @return 0 on success 143 | */ 144 | int pqueue_remove(pqueue_t *q, void *d); 145 | 146 | 147 | /** 148 | * access highest-ranking item without removing it. 149 | * @param q the queue 150 | * @return NULL on error, otherwise the entry 151 | */ 152 | void *pqueue_peek(pqueue_t *q); 153 | 154 | 155 | /** 156 | * print the queue 157 | * @internal 158 | * DEBUG function only 159 | * @param q the queue 160 | * @param out the output handle 161 | * @param the callback function to print the entry 162 | */ 163 | void 164 | pqueue_print(pqueue_t *q, 165 | FILE *out, 166 | pqueue_print_entry_f print); 167 | 168 | 169 | /** 170 | * dump the queue and it's internal structure 171 | * @internal 172 | * debug function only 173 | * @param q the queue 174 | * @param out the output handle 175 | * @param the callback function to print the entry 176 | */ 177 | void 178 | pqueue_dump(pqueue_t *q, 179 | FILE *out, 180 | pqueue_print_entry_f print); 181 | 182 | 183 | /** 184 | * checks that the pq is in the right order, etc 185 | * @internal 186 | * debug function only 187 | * @param q the queue 188 | */ 189 | int pqueue_is_valid(pqueue_t *q); 190 | 191 | 192 | #endif /* PQUEUE_H */ 193 | /** @} */ 194 | -------------------------------------------------------------------------------- /src/sample-multiattr.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Volkan Yazıcı 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | 27 | /** 28 | * There are two ways to store multi-attribute priorities in the heap. 29 | * 30 | * 1) Modify pqueue.h and replace "pqueue_pri_t" with a "void *", instead of 31 | * "double". Now in your "node_t" struct, you can represent your node 32 | * priority in any way you like: Using an "int" array, "struct", etc. 33 | * 34 | * In this scheme, you will also need to pass fresh memory blocks to 35 | * "pqueue_change_priority" function calls and free previous priority data 36 | * structure manually. (A wrapper over "pqueue_change_priority" can handle 37 | * this easily. Also using a GC (e.g. Boehm GC) would ease the work and 38 | * improve performance -- consider thousands of tiny allocations.) 39 | * 40 | * Pros: 41 | * - Clean, flexible design. (Open to further improvements.) 42 | * - Ability to use any operator to compare any desired priority data type. 43 | * 44 | * Cons: 45 | * - Requires modification in "pqueue.h" and a from scratch compilation of 46 | * "pqueue.c". 47 | * 48 | * 2) Use a seperate vector to store the priorities and make "priority" slot of 49 | * "node_t" structures to point to the cells of this vector. 50 | * 51 | * Pros: 52 | * - No outside modification is required. (Vanilla libpqueue is ok.) 53 | * - It works. 54 | * 55 | * Cons: 56 | * - A nasty, error-prone design. 57 | * 58 | * This file represents a sample implementation for the second scheme. 59 | */ 60 | 61 | 62 | #include 63 | #include 64 | 65 | #include "pqueue.h" 66 | 67 | 68 | static int **pris; 69 | 70 | 71 | typedef struct node_t 72 | { 73 | int pri; 74 | int val; 75 | size_t pos; 76 | } node_t; 77 | 78 | 79 | static int 80 | cmp_pri(pqueue_pri_t next, pqueue_pri_t curr) 81 | { 82 | int *_next = pris[(int) next]; 83 | int *_curr = pris[(int) curr]; 84 | 85 | return 86 | (_next[0] > _curr[0]) || 87 | (_next[0] == _curr[0] && _next[1] > _curr[1]); 88 | } 89 | 90 | 91 | static pqueue_pri_t 92 | get_pri(void *a) 93 | { 94 | return ((node_t *) a)->pri; 95 | } 96 | 97 | 98 | static void 99 | set_pri(void *a, pqueue_pri_t pri) 100 | { 101 | ((node_t *) a)->pri = (int) pri; 102 | } 103 | 104 | 105 | static size_t 106 | get_pos(void *a) 107 | { 108 | return ((node_t *) a)->pos; 109 | } 110 | 111 | 112 | static void 113 | set_pos(void *a, size_t pos) 114 | { 115 | ((node_t *) a)->pos = pos; 116 | } 117 | 118 | 119 | static void 120 | pr_node(FILE *out, void *a) 121 | { 122 | node_t *n = a; 123 | 124 | fprintf(out, "pri: %d, val: %d, real-val: [%d %d]\n", 125 | n->pri, n->val, pris[n->pri][0], pris[n->pri][1]); 126 | } 127 | 128 | 129 | int 130 | main(void) 131 | { 132 | int i; 133 | int p; 134 | 135 | pqueue_t *pq; 136 | node_t *ns; 137 | node_t *n; 138 | 139 | /* We will need (N + 1) slots in "pris" vector. Extra one slot for spare 140 | * usages. */ 141 | pris = malloc(5 * sizeof(int *)); 142 | for (i = 0; i < 5; i++) 143 | pris[i] = malloc(2 * sizeof(int)); 144 | 145 | pris[0][0] = 4; pris[0][1] = 2; 146 | pris[1][0] = 3; pris[1][1] = 7; 147 | pris[2][0] = 3; pris[2][1] = 1; 148 | pris[3][0] = 5; pris[3][1] = 6; 149 | p = 4; /* Initialize spare slot. */ 150 | 151 | pq = pqueue_init(10, cmp_pri, get_pri, set_pri, get_pos, set_pos); 152 | ns = malloc(4 * sizeof(node_t)); 153 | 154 | ns[0].pri = 0; ns[0].val = 0; pqueue_insert(pq, &ns[0]); 155 | ns[1].pri = 1; ns[0].val = 1; pqueue_insert(pq, &ns[1]); 156 | ns[2].pri = 2; ns[0].val = 2; pqueue_insert(pq, &ns[2]); 157 | ns[3].pri = 3; ns[0].val = 3; pqueue_insert(pq, &ns[3]); 158 | 159 | printf("initial:\n"); pqueue_print(pq, stdout, pr_node); 160 | 161 | n = pqueue_pop(pq); 162 | printf("[pop] pri: %d, val: %d, real-pri: [%d %d]\n", 163 | n->pri, n->val, pris[n->pri][0], pris[n->pri][1]); 164 | printf("after first pop:\n"); pqueue_print(pq, stdout, pr_node); 165 | 166 | pris[p][0] = 3; pris[p][1] = 0; 167 | pqueue_change_priority(pq, p, &ns[3]); /* 3: (5,6) -> (3,0) */ 168 | p = 3; /* Move spare slot to 3. */ 169 | printf("after 3: (5,6) -> (3,0):\n"); pqueue_print(pq, stdout, pr_node); 170 | 171 | pris[p][0] = 3; pris[p][1] = -1; 172 | pqueue_change_priority(pq, p, &ns[0]); /* 0: (4,2) -> (3,-1) */ 173 | p = 0; /* Move spare slot to 0. */ 174 | printf("after 0: (4,2) -> (3,-1):\n"); pqueue_print(pq, stdout, pr_node); 175 | 176 | while ((n = pqueue_pop(pq))) 177 | printf("[pop] pri: %d, val: %d, real-pri: [%d %d]\n", 178 | n->pri, n->val, pris[n->pri][0], pris[n->pri][1]); 179 | 180 | pqueue_free(pq); 181 | free(ns); 182 | free(pris); 183 | 184 | return 0; 185 | } 186 | 187 | /* 188 | * $ cc -Wall -g pqueue.c sample-multiattr.c -o sample-multiattr 189 | * $ ./sample-multiattr 190 | * initial: 191 | * pri: 2, val: 0, real-val: [3 1] 192 | * pri: 1, val: 0, real-val: [3 7] 193 | * pri: 0, val: 3, real-val: [4 2] 194 | * pri: 3, val: 0, real-val: [5 6] 195 | * [pop] pri: 2, val: 0, real-pri: [3 1] 196 | * after first pop: 197 | * pri: 1, val: 0, real-val: [3 7] 198 | * pri: 0, val: 3, real-val: [4 2] 199 | * pri: 3, val: 0, real-val: [5 6] 200 | * after 3: (5,6) -> (3,0): 201 | * pri: 4, val: 0, real-val: [3 0] 202 | * pri: 1, val: 0, real-val: [3 7] 203 | * pri: 0, val: 3, real-val: [4 2] 204 | * after 0: (4,2) -> (3,-1): 205 | * pri: 3, val: 3, real-val: [3 -1] 206 | * pri: 4, val: 0, real-val: [3 0] 207 | * pri: 1, val: 0, real-val: [3 7] 208 | * [pop] pri: 3, val: 3, real-pri: [3 -1] 209 | * [pop] pri: 4, val: 0, real-pri: [3 0] 210 | * [pop] pri: 1, val: 0, real-pri: [3 7] 211 | */ 212 | -------------------------------------------------------------------------------- /src/sample.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Volkan Yazıcı 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * 1. Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | */ 25 | 26 | 27 | /** 28 | * A simple usage of libpqueue. (Priorities are represented as "double" values.) 29 | */ 30 | 31 | 32 | #include 33 | #include 34 | 35 | #include "pqueue.h" 36 | 37 | 38 | typedef struct node_t 39 | { 40 | pqueue_pri_t pri; 41 | int val; 42 | size_t pos; 43 | } node_t; 44 | 45 | 46 | static int 47 | cmp_pri(pqueue_pri_t next, pqueue_pri_t curr) 48 | { 49 | return (next < curr); 50 | } 51 | 52 | 53 | static pqueue_pri_t 54 | get_pri(void *a) 55 | { 56 | return ((node_t *) a)->pri; 57 | } 58 | 59 | 60 | static void 61 | set_pri(void *a, pqueue_pri_t pri) 62 | { 63 | ((node_t *) a)->pri = pri; 64 | } 65 | 66 | 67 | static size_t 68 | get_pos(void *a) 69 | { 70 | return ((node_t *) a)->pos; 71 | } 72 | 73 | 74 | static void 75 | set_pos(void *a, size_t pos) 76 | { 77 | ((node_t *) a)->pos = pos; 78 | } 79 | 80 | 81 | int 82 | main(void) 83 | { 84 | pqueue_t *pq; 85 | node_t *ns; 86 | node_t *n; 87 | 88 | ns = malloc(10 * sizeof(node_t)); 89 | pq = pqueue_init(10, cmp_pri, get_pri, set_pri, get_pos, set_pos); 90 | if (!(ns && pq)) return 1; 91 | 92 | ns[0].pri = 5; ns[0].val = -5; pqueue_insert(pq, &ns[0]); 93 | ns[1].pri = 4; ns[1].val = -4; pqueue_insert(pq, &ns[1]); 94 | ns[2].pri = 2; ns[2].val = -2; pqueue_insert(pq, &ns[2]); 95 | ns[3].pri = 6; ns[3].val = -6; pqueue_insert(pq, &ns[3]); 96 | ns[4].pri = 1; ns[4].val = -1; pqueue_insert(pq, &ns[4]); 97 | 98 | n = pqueue_peek(pq); 99 | printf("peek: %lld [%d]\n", n->pri, n->val); 100 | 101 | pqueue_change_priority(pq, 8, &ns[4]); 102 | pqueue_change_priority(pq, 7, &ns[2]); 103 | 104 | while ((n = pqueue_pop(pq))) 105 | printf("pop: %lld [%d]\n", n->pri, n->val); 106 | 107 | pqueue_free(pq); 108 | free(ns); 109 | 110 | return 0; 111 | } 112 | 113 | /* 114 | * $ cc -Wall -g pqueue.c sample.c -o sample 115 | * $ ./sample 116 | * peek: 6 [-6] 117 | * pop: 8 [-1] 118 | * pop: 7 [-2] 119 | * pop: 6 [-6] 120 | * pop: 5 [-5] 121 | * pop: 4 [-4] 122 | */ 123 | --------------------------------------------------------------------------------