diff options
author | Marvin Borner | 2023-05-26 23:10:37 +0200 |
---|---|---|
committer | Marvin Borner | 2023-05-26 23:17:47 +0200 |
commit | 90a0366ba0556314b8624a3f46c667eaf5824e4c (patch) | |
tree | 2a420ad4ef9c285313cf2ff20fd801838c8f526d | |
parent | d977a98fec7fcea74e7ab51762a6d93084a8c70c (diff) |
Added libpqueue
will be part of the scheduler
-rw-r--r-- | inc/lib/pqueue.h | 107 | ||||
-rw-r--r-- | readme.md | 13 | ||||
-rw-r--r-- | src/lib/pqueue.c | 159 | ||||
-rw-r--r-- | src/schedule.c | 0 |
4 files changed, 275 insertions, 4 deletions
diff --git a/inc/lib/pqueue.h b/inc/lib/pqueue.h new file mode 100644 index 0000000..860a366 --- /dev/null +++ b/inc/lib/pqueue.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2014, Volkan Yazıcı <volkan.yazici@gmail.com> + * Copyright (c) 2014, Marvin Borner <dev@marvinborner.de> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file pqueue.h + * @brief Priority Queue function declarations + * + * @{ + */ + +#ifndef CALM_PQUEUE_H +#define CALM_PQUEUE_H + +#include <stddef.h> +#include <stdio.h> + +/** priority data type */ +typedef unsigned long long pqueue_pri_t; + +/** callback functions to get/set/compare the priority of an element */ +typedef pqueue_pri_t (*pqueue_get_pri_f)(void *a); +typedef int (*pqueue_cmp_pri_f)(pqueue_pri_t next, pqueue_pri_t curr); + +/** callback functions to get/set the position of an element */ +typedef size_t (*pqueue_get_pos_f)(void *a); +typedef void (*pqueue_set_pos_f)(void *a, size_t pos); + +/** debug callback function to print a entry */ +typedef void (*pqueue_print_entry_f)(FILE *out, void *a); + +/** the priority queue handle */ +struct pqueue { + size_t size; /**< number of elements in this queue */ + size_t avail; /**< slots available in this queue */ + size_t step; /**< growth stepping setting */ + pqueue_cmp_pri_f cmppri; /**< callback to compare nodes */ + pqueue_get_pri_f getpri; /**< callback to get priority of a node */ + pqueue_set_pos_f setpos; /**< callback to set position of a node */ + void **d; /**< The actualy queue in binary heap form */ +}; + +/** + * initialize the queue + * + * @param n the initial estimate of the number of queue items for which memory + * should be preallocated + * @param cmppri The callback function to run to compare two elements + * This callback should return 0 for 'lower' and non-zero + * for 'higher', or vice versa if reverse priority is desired + * @param getpri the callback function to run to set a score to an element + * + * @return the handle or NULL for insufficent memory + */ +struct pqueue *pqueue_init(size_t n, pqueue_cmp_pri_f cmppri, + pqueue_get_pri_f getpri, pqueue_set_pos_f set_pos); + +/** + * free all memory used by the queue + * @param q the queue + */ +void pqueue_free(struct pqueue *q); + +/** + * return the size of the queue. + * @param q the queue + */ +size_t pqueue_size(struct pqueue *q); + +/** + * insert an item into the queue. + * @param q the queue + * @param d the item + * @return 0 on success + */ +int pqueue_insert(struct pqueue *q, void *d); + +/** + * pop the highest-ranking item from the queue. + * @param q the queue + * @return NULL on error, otherwise the entry + */ +void *pqueue_pop(struct pqueue *q); + +#endif @@ -2,9 +2,14 @@ > **c**alm **a**bstract **l**ambda **m**achine +- aggressive multi-threaded reduction of lambda calculus expressions +- small memory footprint + ## Libraries -- [hashmap.c](https://github.com/tidwall/hashmap.c) \[MIT\]: Simple - but efficient hashmap -- [xxHash](https://github.com/Cyan4973/xxHash/) \[BSD 2-Clause\]: - Extremely fast hash algorithm +- [hashmap.c](https://github.com/tidwall/hashmap.c) \[MIT\]: Simple but + efficient hashmap +- [pqueue](https://github.com/vy/libpqueue/) \[BSD 2-Clause\]: Simple + priority queue implementation +- [xxHash](https://github.com/Cyan4973/xxHash/) \[BSD 2-Clause\]: + Extremely fast hash algorithm diff --git a/src/lib/pqueue.c b/src/lib/pqueue.c new file mode 100644 index 0000000..6f21e5f --- /dev/null +++ b/src/lib/pqueue.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2014, Volkan Yazıcı <volkan.yazici@gmail.com> + * Copyright (c) 2023, Marvin Borner <dev@marvinborner.de> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <lib/pqueue.h> + +#define left(i) ((i) << 1) +#define right(i) (((i) << 1) + 1) +#define parent(i) ((i) >> 1) + +struct pqueue *pqueue_init(size_t n, pqueue_cmp_pri_f cmppri, + pqueue_get_pri_f getpri, pqueue_set_pos_f setpos) +{ + struct pqueue *q; + + if (!(q = malloc(sizeof(struct pqueue)))) + return NULL; + + /* Need to allocate n+1 elements since element 0 isn't used. */ + if (!(q->d = malloc((n + 1) * sizeof(void *)))) { + free(q); + return NULL; + } + + q->size = 1; + q->avail = q->step = (n + 1); /* see comment above about n+1 */ + q->cmppri = cmppri; + q->getpri = getpri; + q->setpos = setpos; + + return q; +} + +void pqueue_free(struct pqueue *q) +{ + free(q->d); + free(q); +} + +size_t pqueue_size(struct pqueue *q) +{ + /* queue element 0 exists but doesn't count since it isn't used. */ + return (q->size - 1); +} + +static void bubble_up(struct pqueue *q, size_t i) +{ + size_t parent_node; + void *moving_node = q->d[i]; + pqueue_pri_t moving_pri = q->getpri(moving_node); + + for (parent_node = parent(i); + ((i > 1) && q->cmppri(q->getpri(q->d[parent_node]), moving_pri)); + i = parent_node, parent_node = parent(i)) { + q->d[i] = q->d[parent_node]; + q->setpos(q->d[i], i); + } + + q->d[i] = moving_node; + q->setpos(moving_node, i); +} + +static size_t maxchild(struct pqueue *q, size_t i) +{ + size_t child_node = left(i); + + if (child_node >= q->size) + return 0; + + if ((child_node + 1) < q->size && + q->cmppri(q->getpri(q->d[child_node]), + q->getpri(q->d[child_node + 1]))) + child_node++; /* use right child instead of left */ + + return child_node; +} + +static void percolate_down(struct pqueue *q, size_t i) +{ + size_t child_node; + void *moving_node = q->d[i]; + pqueue_pri_t moving_pri = q->getpri(moving_node); + + while ((child_node = maxchild(q, i)) && + q->cmppri(moving_pri, q->getpri(q->d[child_node]))) { + q->d[i] = q->d[child_node]; + q->setpos(q->d[i], i); + i = child_node; + } + + q->d[i] = moving_node; + q->setpos(moving_node, i); +} + +int pqueue_insert(struct pqueue *q, void *d) +{ + void *tmp; + size_t i; + size_t newsize; + + if (!q) + return 1; + + /* allocate more memory if necessary */ + if (q->size >= q->avail) { + newsize = q->size + q->step; + if (!(tmp = realloc(q->d, sizeof(void *) * newsize))) + return 1; + q->d = tmp; + q->avail = newsize; + } + + /* insert item */ + i = q->size++; + q->d[i] = d; + bubble_up(q, i); + + return 0; +} + +void *pqueue_pop(struct pqueue *q) +{ + void *head; + + if (!q || q->size == 1) + return NULL; + + head = q->d[1]; + q->d[1] = q->d[--q->size]; + percolate_down(q, 1); + + return head; +} diff --git a/src/schedule.c b/src/schedule.c new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/schedule.c |