Bläddra i källkod

Deps: Add ziptree.h

Julius Pfrommer 5 år sedan
förälder
incheckning
835b83b2f9
1 ändrade filer med 239 tillägg och 0 borttagningar
  1. 239 0
      deps/ziptree.h

+ 239 - 0
deps/ziptree.h

@@ -0,0 +1,239 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
+ *
+ *    Copyright 2018 (c) Julius Pfrommer
+ */
+
+#ifndef	ZIPTREE_H_
+#define	ZIPTREE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Reusable zip tree implementation. The style is inspired by the BSD
+ * sys/queue.h linked list definition.
+ *
+ * Zip trees were developed in: Tarjan, R. E., Levy, C. C., and Timmel, S. "Zip
+ * Trees." arXiv preprint arXiv:1806.06726 (2018).
+ *
+ * The ZIP_ENTRY definitions are to be contained in the tree entries themselves.
+ * Use ZIP_PROTTYPE to define the signature of the zip tree and ZIP_IMPL (in a
+ * .c compilation unit) for the method implementations.
+ *
+ * Zip trees are a probabilistic data structure. Entries are assigned a
+ * (nonzero) rank k with probability 1/2^{k+1}. This header file does not assume
+ * a specific random number generator. So the rank must be given when an entry
+ * is inserted. A fast way (with a single call to a pseudo random generator) to
+ * compute the rank is with ZIP_FFS32(random()). The ZIP_FFS32 returns the least
+ * significant nonzero bit of a 32bit number. */
+
+#define ZIP_HEAD(name, type)                    \
+struct name {                                   \
+    struct type *zip_root;                      \
+}
+
+#define ZIP_INIT(head) do { (head)->zip_root = NULL; } while (0)
+#define ZIP_ROOT(head) (head)->zip_root
+#define ZIP_EMPTY(head) (ZIP_ROOT(head) == NULL)
+
+#define ZIP_ENTRY(type)                         \
+struct {                                        \
+    struct type *zip_left;                      \
+    struct type *zip_right;                     \
+    unsigned char rank;                         \
+}
+
+#define ZIP_LEFT(elm, field) (elm)->field.zip_left
+#define ZIP_RIGHT(elm, field) (elm)->field.zip_right
+#define ZIP_RANK(elm, field) (elm)->field.rank
+
+/* Shortcuts */
+#define ZIP_INSERT(name, head, elm, rank) name##_ZIP_INSERT(head, elm, rank)
+#define ZIP_REMOVE(name, head, elm) name##_ZIP_REMOVE(head, elm)
+#define ZIP_FIND(name, head, key) name##_ZIP_FIND(head, key)
+#define ZIP_MIN(name, head) name##_ZIP_MIN(head)
+#define ZIP_MAX(name, head) name##_ZIP_MAX(head)
+#define ZIP_ITER(name, head, cb, d) name##_ZIP_ITER(head, cb, d)
+
+/* Zip tree method prototypes */
+#define ZIP_PROTTYPE(name, type, keytype)                               \
+void name##_ZIP_INSERT(struct name *head, struct type *elm, unsigned char rank); \
+void name##_ZIP_REMOVE(struct name *head, struct type *elm);            \
+struct type *name##_ZIP_FIND(struct name *head, const keytype *key);    \
+struct type *name##_ZIP_MIN(struct name *head);                         \
+struct type *name##_ZIP_MAX(struct name *head);                         \
+typedef void (*name##_cb)(struct type *elm, void *data);                \
+void name##_ZIP_ITER(struct name *head, name##_cb cb, void *data);      \
+
+/* The comparison method "cmp" defined for every zip tree has the signature
+ *
+ *   enum ZIP_CMP cmpDateTime(const keytype *a, const keytype *b);
+ *
+ * The entries need an absolute ordering. So ZIP_CMP_EQ must only be returned if
+ * a and b point to the same memory. (E.g. assured by unique identifiers.) */
+enum ZIP_CMP {
+    ZIP_CMP_LESS = -1,
+    ZIP_CMP_EQ = 0,
+    ZIP_CMP_MORE = 1
+};
+
+/* Find the position of the first bit in an unsigned 32bit integer */
+#ifdef _MSC_VER
+static __inline
+#else
+static inline
+#endif
+unsigned char
+ZIP_FFS32(unsigned int v) {
+    unsigned int t = 1;
+    unsigned char r = 1;
+    if(v == 0) return 0;
+    while((v & t) == 0) {
+        t = t << 1; r++;
+    }
+    return r;
+}
+
+/* Zip tree method implementations */
+#define ZIP_IMPL(name, type, field, keytype, keyfield, cmp)             \
+static struct type *                                                    \
+__##name##_ZIP_INSERT(struct type *root, struct type *elm) {            \
+    if(!root) {                                                         \
+        ZIP_LEFT(elm, field) = NULL;                                    \
+        ZIP_RIGHT(elm, field) = NULL;                                   \
+        return elm;                                                     \
+    }                                                                   \
+    if((cmp)(&(elm)->keyfield, &(root)->keyfield) == ZIP_CMP_LESS) {    \
+        if(__##name##_ZIP_INSERT(ZIP_LEFT(root, field), elm) == elm) {  \
+            if(ZIP_RANK(elm, field) < ZIP_RANK(root, field)) {          \
+                ZIP_LEFT(root, field) = elm;                            \
+            } else {                                                    \
+                ZIP_LEFT(root, field) = ZIP_RIGHT(elm, field);          \
+                ZIP_RIGHT(elm, field) = root;                           \
+                return elm;                                             \
+            }                                                           \
+        }                                                               \
+    } else {                                                            \
+        if(__##name##_ZIP_INSERT(ZIP_RIGHT(root, field), elm) == elm) { \
+            if(ZIP_RANK(elm, field) <= ZIP_RANK(root, field)) {         \
+                ZIP_RIGHT(root, field) = elm;                           \
+            } else {                                                    \
+                ZIP_RIGHT(root, field) = ZIP_LEFT(elm, field);          \
+                ZIP_LEFT(elm, field) = root;                            \
+                return elm;                                             \
+            }                                                           \
+        }                                                               \
+    }                                                                   \
+    return root;                                                        \
+}                                                                       \
+                                                                        \
+void                                                                    \
+name##_ZIP_INSERT(struct name *head, struct type *elm,                  \
+                  unsigned char rank) {                                 \
+    ZIP_RANK(elm, field) = rank;                                        \
+    ZIP_ROOT(head) = __##name##_ZIP_INSERT(ZIP_ROOT(head), elm);        \
+}                                                                       \
+                                                                        \
+static struct type *                                                    \
+__##name##ZIP(struct type *x, struct type *y) {                         \
+    if(!x) return y;                                                    \
+    if(!y) return x;                                                    \
+    if(ZIP_RANK(x, field) < ZIP_RANK(y, field)) {                       \
+        ZIP_LEFT(y, field) = __##name##ZIP(x, ZIP_LEFT(y, field));      \
+        return y;                                                       \
+    }                                                                   \
+    ZIP_RIGHT(x, field) = __##name##ZIP(ZIP_RIGHT(x, field), y);        \
+    return x;                                                           \
+}                                                                       \
+                                                                        \
+static struct type *                                                    \
+__##name##_ZIP_REMOVE(struct type *root, struct type *elm) {            \
+    if(root == elm)                                                     \
+        return __##name##ZIP(ZIP_LEFT(root, field),                     \
+                             ZIP_RIGHT(root, field));                   \
+    enum ZIP_CMP eq = (cmp)(&(elm)->keyfield, &(root)->keyfield);       \
+    if(eq == ZIP_CMP_LESS) {                                            \
+        struct type *left = ZIP_LEFT(root, field);                      \
+        if(elm == left)                                                 \
+            ZIP_LEFT(root, field) =                                     \
+                __##name##ZIP(ZIP_LEFT(left, field),                    \
+                              ZIP_RIGHT(left, field));                  \
+        else                                                            \
+            __##name##_ZIP_REMOVE(left, elm);                           \
+    } else {                                                            \
+        struct type *right = ZIP_RIGHT(root, field);                    \
+        if(elm == right)                                                \
+            ZIP_RIGHT(root, field) =                                    \
+                __##name##ZIP(ZIP_LEFT(right, field),                   \
+                              ZIP_RIGHT(right, field));                 \
+        else                                                            \
+            __##name##_ZIP_REMOVE(right, elm);                          \
+    }                                                                   \
+    return root;                                                        \
+}                                                                       \
+                                                                        \
+void                                                                    \
+name##_ZIP_REMOVE(struct name *head, struct type *elm) {                \
+    ZIP_ROOT(head) = __##name##_ZIP_REMOVE(ZIP_ROOT(head), elm);        \
+}                                                                       \
+                                                                        \
+static struct type *                                                    \
+__##name##_ZIP_FIND(struct type *root, const keytype *key) {            \
+    if(!root)                                                           \
+        return NULL;                                                    \
+    enum ZIP_CMP eq = (cmp)(key, &(root)->keyfield);                    \
+    if(eq == ZIP_CMP_EQ) {                                              \
+        return root;                                                    \
+    } else if(eq == ZIP_CMP_LESS) {                                     \
+        return __##name##_ZIP_FIND(ZIP_LEFT(root, field), key);         \
+    } else {                                                            \
+        return __##name##_ZIP_FIND(ZIP_RIGHT(root, field), key);        \
+    }                                                                   \
+}                                                                       \
+                                                                        \
+struct type *                                                           \
+name##_ZIP_FIND(struct name *head, const keytype *key) {                \
+    return __##name##_ZIP_FIND(ZIP_ROOT(head), key);                    \
+}                                                                       \
+                                                                        \
+struct type *                                                           \
+name##_ZIP_MIN(struct name *head) {                                     \
+    struct type *cur = ZIP_ROOT(head);                                  \
+    if(!cur) return NULL;                                               \
+    while(ZIP_LEFT(cur, field)) {                                       \
+        cur = ZIP_LEFT(cur, field);                                     \
+    }                                                                   \
+    return cur;                                                         \
+}                                                                       \
+                                                                        \
+struct type *                                                           \
+name##_ZIP_MAX(struct name *head) {                                     \
+    struct type *cur = ZIP_ROOT(head);                                  \
+    if(!cur) return NULL;                                               \
+    while(ZIP_RIGHT(cur, field)) {                                      \
+        cur = ZIP_RIGHT(cur, field);                                    \
+    }                                                                   \
+    return cur;                                                         \
+}                                                                       \
+                                                                        \
+static void                                                             \
+__##name##_ZIP_ITER(struct type *elm, name##_cb cb, void *data) {       \
+    if(!elm)                                                            \
+        return;                                                         \
+    __##name##_ZIP_ITER(ZIP_LEFT(elm, field), cb, data);                \
+    __##name##_ZIP_ITER(ZIP_RIGHT(elm, field), cb, data);               \
+    cb(elm, data);                                                      \
+}                                                                       \
+                                                                        \
+void                                                                    \
+name##_ZIP_ITER(struct name *head, name##_cb cb, void *data) {          \
+    __##name##_ZIP_ITER(ZIP_ROOT(head), cb, data);                      \
+}
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* ZIPTREE_H_ */