]> git.puffer.fish Git - mirror/frr.git/commitdiff
Revert "lib: remove pqueue_*"
authorDavid Lamparter <equinox@diac24.net>
Mon, 29 Apr 2019 19:18:48 +0000 (21:18 +0200)
committerDavid Lamparter <equinox@diac24.net>
Mon, 29 Apr 2019 19:18:48 +0000 (21:18 +0200)
This reverts commit 798ac49d06b6619adb4c5ac765b092397bc50a6c.

lib/pqueue.c [new file with mode: 0644]
lib/pqueue.h [new file with mode: 0644]
lib/subdir.am
tests/lib/cxxcompat.c
tests/lib/test_timer_correctness.c
tests/lib/test_timer_performance.c

diff --git a/lib/pqueue.c b/lib/pqueue.c
new file mode 100644 (file)
index 0000000..87b54a6
--- /dev/null
@@ -0,0 +1,185 @@
+/* Priority queue functions.
+ * Copyright (C) 2003 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "memory.h"
+#include "pqueue.h"
+
+DEFINE_MTYPE_STATIC(LIB, PQUEUE, "Priority queue")
+DEFINE_MTYPE_STATIC(LIB, PQUEUE_DATA, "Priority queue data")
+
+/* priority queue using heap sort */
+
+/* pqueue->cmp() controls the order of sorting (i.e, ascending or
+   descending). If you want the left node to move upper of the heap
+   binary tree, make cmp() to return less than 0.  for example, if cmp
+   (10, 20) returns -1, the sorting is ascending order. if cmp (10,
+   20) returns 1, the sorting is descending order. if cmp (10, 20)
+   returns 0, this library does not do sorting (which will not be what
+   you want).  To be brief, if the contents of cmp_func (left, right)
+   is left - right, dequeue () returns the smallest node.  Otherwise
+   (if the contents is right - left), dequeue () returns the largest
+   node.  */
+
+#define DATA_SIZE (sizeof (void *))
+#define PARENT_OF(x) ((x - 1) / 2)
+#define LEFT_OF(x)  (2 * x + 1)
+#define RIGHT_OF(x) (2 * x + 2)
+#define HAVE_CHILD(x,q) (x < (q)->size / 2)
+
+void trickle_up(int index, struct pqueue *queue)
+{
+       void *tmp;
+
+       /* Save current node as tmp node.  */
+       tmp = queue->array[index];
+
+       /* Continue until the node reaches top or the place where the parent
+          node should be upper than the tmp node.  */
+       while (index > 0
+              && (*queue->cmp)(tmp, queue->array[PARENT_OF(index)]) < 0) {
+               /* actually trickle up */
+               queue->array[index] = queue->array[PARENT_OF(index)];
+               if (queue->update != NULL)
+                       (*queue->update)(queue->array[index], index);
+               index = PARENT_OF(index);
+       }
+
+       /* Restore the tmp node to appropriate place.  */
+       queue->array[index] = tmp;
+       if (queue->update != NULL)
+               (*queue->update)(tmp, index);
+}
+
+void trickle_down(int index, struct pqueue *queue)
+{
+       void *tmp;
+       int which;
+
+       /* Save current node as tmp node.  */
+       tmp = queue->array[index];
+
+       /* Continue until the node have at least one (left) child.  */
+       while (HAVE_CHILD(index, queue)) {
+               /* If right child exists, and if the right child is more proper
+                  to be moved upper.  */
+               if (RIGHT_OF(index) < queue->size
+                   && (*queue->cmp)(queue->array[LEFT_OF(index)],
+                                    queue->array[RIGHT_OF(index)])
+                              > 0)
+                       which = RIGHT_OF(index);
+               else
+                       which = LEFT_OF(index);
+
+               /* If the tmp node should be upper than the child, break.  */
+               if ((*queue->cmp)(queue->array[which], tmp) > 0)
+                       break;
+
+               /* Actually trickle down the tmp node.  */
+               queue->array[index] = queue->array[which];
+               if (queue->update != NULL)
+                       (*queue->update)(queue->array[index], index);
+               index = which;
+       }
+
+       /* Restore the tmp node to appropriate place.  */
+       queue->array[index] = tmp;
+       if (queue->update != NULL)
+               (*queue->update)(tmp, index);
+}
+
+struct pqueue *pqueue_create(void)
+{
+       struct pqueue *queue;
+
+       queue = XCALLOC(MTYPE_PQUEUE, sizeof(struct pqueue));
+
+       queue->array =
+               XCALLOC(MTYPE_PQUEUE_DATA, DATA_SIZE * PQUEUE_INIT_ARRAYSIZE);
+       queue->array_size = PQUEUE_INIT_ARRAYSIZE;
+
+       /* By default we want nothing to happen when a node changes. */
+       queue->update = NULL;
+       return queue;
+}
+
+void pqueue_delete(struct pqueue *queue)
+{
+       XFREE(MTYPE_PQUEUE_DATA, queue->array);
+       XFREE(MTYPE_PQUEUE, queue);
+}
+
+static int pqueue_expand(struct pqueue *queue)
+{
+       void **newarray;
+
+       newarray =
+               XCALLOC(MTYPE_PQUEUE_DATA, queue->array_size * DATA_SIZE * 2);
+
+       memcpy(newarray, queue->array, queue->array_size * DATA_SIZE);
+
+       XFREE(MTYPE_PQUEUE_DATA, queue->array);
+       queue->array = newarray;
+       queue->array_size *= 2;
+
+       return 1;
+}
+
+void pqueue_enqueue(void *data, struct pqueue *queue)
+{
+       if (queue->size + 2 >= queue->array_size && !pqueue_expand(queue))
+               return;
+
+       queue->array[queue->size] = data;
+       if (queue->update != NULL)
+               (*queue->update)(data, queue->size);
+       trickle_up(queue->size, queue);
+       queue->size++;
+}
+
+void *pqueue_dequeue(struct pqueue *queue)
+{
+       void *data = queue->array[0];
+       queue->array[0] = queue->array[--queue->size];
+       trickle_down(0, queue);
+       return data;
+}
+
+void pqueue_remove_at(int index, struct pqueue *queue)
+{
+       queue->array[index] = queue->array[--queue->size];
+
+       if (index > 0
+           && (*queue->cmp)(queue->array[index],
+                            queue->array[PARENT_OF(index)])
+                      < 0) {
+               trickle_up(index, queue);
+       } else {
+               trickle_down(index, queue);
+       }
+}
+
+void pqueue_remove(void *data, struct pqueue *queue)
+{
+       for (int i = 0; i < queue->size; i++)
+               if (queue->array[i] == data)
+                       pqueue_remove_at(i, queue);
+}
diff --git a/lib/pqueue.h b/lib/pqueue.h
new file mode 100644 (file)
index 0000000..032ee9d
--- /dev/null
@@ -0,0 +1,54 @@
+/* Priority queue functions.
+ * Copyright (C) 2003 Yasuhiro Ohara
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _ZEBRA_PQUEUE_H
+#define _ZEBRA_PQUEUE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct pqueue {
+       void **array;
+       int array_size;
+       int size;
+
+       int (*cmp)(void *, void *);
+       void (*update)(void *node, int actual_position);
+};
+
+#define PQUEUE_INIT_ARRAYSIZE  32
+
+extern struct pqueue *pqueue_create(void);
+extern void pqueue_delete(struct pqueue *queue);
+
+extern void pqueue_enqueue(void *data, struct pqueue *queue);
+extern void *pqueue_dequeue(struct pqueue *queue);
+extern void pqueue_remove_at(int index, struct pqueue *queue);
+extern void pqueue_remove(void *data, struct pqueue *queue);
+
+extern void trickle_down(int index, struct pqueue *queue);
+extern void trickle_up(int index, struct pqueue *queue);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ZEBRA_PQUEUE_H */
index 38688a2470bed7fd9c7af7648d671e082624cc0a..7027f3f0daadd67674aaac0ab877508f018db590 100644 (file)
@@ -58,6 +58,7 @@ lib_libfrr_la_SOURCES = \
        lib/openbsd-tree.c \
        lib/pid_output.c \
        lib/plist.c \
+       lib/pqueue.c \
        lib/prefix.c \
        lib/privs.c \
        lib/ptm_lib.c \
@@ -186,6 +187,7 @@ pkginclude_HEADERS += \
        lib/openbsd-queue.h \
        lib/openbsd-tree.h \
        lib/plist.h \
+       lib/pqueue.h \
        lib/prefix.h \
        lib/privs.h \
        lib/ptm_lib.h \
index d1278cef228d8a6e9717643da9abf92de85a9904..12c333c8b6742990b041aececad906ab4af2ac52 100644 (file)
@@ -71,6 +71,7 @@
 #include "lib/openbsd-tree.h"
 #include "lib/pbr.h"
 #include "lib/plist.h"
+#include "lib/pqueue.h"
 #include "lib/prefix.h"
 #include "lib/privs.h"
 #include "lib/ptm_lib.h"
index cbf9b05546d1d733a438e4630cfdab21ccb0a7e5..43e79ba9d06b57ef5882e583354224d55aabbf3b 100644 (file)
@@ -28,6 +28,7 @@
 #include <unistd.h>
 
 #include "memory.h"
+#include "pqueue.h"
 #include "prng.h"
 #include "thread.h"
 
index 2960e0d81e2382e081bb9578ecae58cd5d590260..d5f4badc85b5cdeff32971f96695e6e3a3733e10 100644 (file)
@@ -28,6 +28,7 @@
 #include <unistd.h>
 
 #include "thread.h"
+#include "pqueue.h"
 #include "prng.h"
 
 #define SCHEDULE_TIMERS 1000000