aboutsummaryrefslogtreecommitdiff
path: root/src/build/skiplist.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/build/skiplist.h')
-rw-r--r--src/build/skiplist.h206
1 files changed, 0 insertions, 206 deletions
diff --git a/src/build/skiplist.h b/src/build/skiplist.h
deleted file mode 100644
index ab6a920..0000000
--- a/src/build/skiplist.h
+++ /dev/null
@@ -1,206 +0,0 @@
-/*
- * Copyright © 2024 Michael Smith <mikesmiffy128@gmail.com>
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
- * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
- * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef INC_SKIPLIST_H
-#define INC_SKIPLIST_H
-
-#include <stdlib.h>
-
-#include "../intdefs.h"
-#include "../os.h"
-
-#ifdef _WIN32
-static inline int _skiplist_ffs(uint x) {
- uchar _BitScanForward(ulong *idx, ulong mask);
- uint ret;
- // on Windows, sizeof(ulong) == sizeof(uint)
- if (_BitScanForward((ulong *)&ret, x)) return ret + 1; else return 0;
-}
-#else
-#include <strings.h>
-#define _skiplist_ffs ffs
-#endif
-
-// WARNING: this is a really hacked-up version of the skiplist.h from cbits in
-// order to support windows. It probably isn't a good idea to plop straight into
-// your own use case.
-
-#if defined(__GNUC__) || defined(__clang__)
-#define _skiplist_unused __attribute__((unused)) // heck off gcc
-#else
-#define _skiplist_unused
-#endif
-
-// NOTE: using xoroshiro128++, a comparatively bad (i.e. non-cryptographic) prng
-// for the sake of simplicity; original cbits skiplist.h relies on libcpoly to
-// get arc4random() everywhere but since we're only using this at build time
-// that seemed like a silly dependency to bother with.
-//#define _skiplist_rng arc4random
-
-// ALSO NOTE: the PRNG code here is *decidedly not* thread safe. again, this
-// isn't a problem for our use case. just keep it in mind if reusing this header
-// for something else. or ideally, don't reuse this header for something else...
-static inline uvlong _skiplist_rotl(const uvlong x, int k) {
- return (x << k) | (x >> (64 - k));
-}
-_skiplist_unused static uvlong _skiplist_rng(void) {
- static uvlong s[2];
- static bool init = false;
- if (!init) { os_randombytes(s, sizeof(s)); init = true; }
- uvlong s0 = s[0], s1 = s[1];
- uvlong ret = _skiplist_rotl(s0 * 5, 7) * 9;
- s1 ^= s0;
- s[0] = _skiplist_rotl(s0, 24) ^ s1 ^ (s1 << 16);
- s[1] = _skiplist_rotl(s1, 37);
- return ret;
-}
-
-/*
- * Declares the skiplist header struct skiplist_hdr##name, but none of the
- * associated functions. Use when the structure needs to be passed around in
- * some way but actual operations on the list are a private implementation
- * detail. Otherwise, see DECL_SKIPLIST below.
- */
-#define DECL_SKIPLIST_TYPE(name, dtype, ktype, levels) \
-typedef dtype _skiplist_dt_##name; \
-typedef ktype _skiplist_kt_##name; \
-enum { skiplist_lvls_##name = (levels) }; \
-struct skiplist_hdr_##name { dtype *x[levels]; };
-
-/*
- * Declares the skiplist header struct skiplist_hdr_##name, with functions
- * skiplist_{get,del,pop,insert}_##name for operating on the list. A single
- * occurrence of DEF_SKIPLIST is required to actually implement the
- * functions.
- *
- * This macro implies DECL_SKIPLIST_TYPE (both should not be used).
- *
- * mod should be either static or extern.
- *
- * dtype should be the struct type that the skiplist header will be embedded in,
- * forming the linked structure.
- *
- * ktype should be the type of the struct member used for comparisons, for
- * example int or char *.
- *
- * levels should be the number of levels in each node. 4 is probably a
- * reasonable number, depending on the size of the structure and how many
- * entries need to be stored and looked up.
- *
- * The resulting get, del, pop and insert functions are hopefully self-
- * explanatory - get and del return the relevant node or a null pointer if
- * no such node is found.
- */
-#define DECL_SKIPLIST(mod, name, dtype, ktype, levels) \
-DECL_SKIPLIST_TYPE(name, dtype, ktype, levels) \
-\
-_skiplist_unused mod dtype *skiplist_get_##name(struct skiplist_hdr_##name *l, \
- ktype k); \
-_skiplist_unused mod dtype *skiplist_del_##name(struct skiplist_hdr_##name *l, \
- ktype k); \
-_skiplist_unused mod dtype *skiplist_pop_##name(struct skiplist_hdr_##name *l); \
-_skiplist_unused mod void skiplist_insert_##name(struct skiplist_hdr_##name *l, \
- ktype k, dtype *node);
-
-/*
- * Implements the functions corresponding to a skiplist - must come after
- * DECL_SKIPLIST with the same modifier and name.
- *
- * compfunc should be a function declared as follows (or an equivalent macro):
- * int cf(dtype *x, ktype y);
- *
- * hdrfunc should be a function declared as follows (or an equivalent macro):
- * struct skiplist_hdr_##name *hf(dtype *l);
- */
-#define DEF_SKIPLIST(mod, name, compfunc, hdrfunc) \
-static inline int _skiplist_lvl_##name(void) { \
- int i; \
- /* for 2 levels we get 1 50% of the time, 2 25% of the time, 0 25% of the
- time. loop if 0 to distribute this evenly (this gets less likely the more
- levels there are: at 4 levels, only loops 6% of the time) */ \
- while (!(i = _skiplist_ffs(_skiplist_rng() & \
- ((1 << skiplist_lvls_##name) - 1)))); \
- /* ffs gives bit positions as 1-N but we actually want an array index */ \
- return i - 1; \
-} \
-\
-_skiplist_unused \
-mod _skiplist_dt_##name *skiplist_get_##name(struct skiplist_hdr_##name *l, \
- _skiplist_kt_##name k) { \
- for (int cmp, lvl = skiplist_lvls_##name - 1; lvl > -1; --lvl) { \
- while (l->x[lvl] && (cmp = compfunc(l->x[lvl], k)) < 0) { \
- l = hdrfunc(l->x[lvl]); \
- } \
- /* NOTE: cmp can be uninitialised here, but only if the list is
- completely empty, in which case we'd return 0 anyway - so it doesn't
- actually matter! */ \
- if (cmp == 0) return l->x[lvl]; \
- } \
- /* reached the end, no match */ \
- return 0; \
-} \
-\
-_skiplist_unused \
-_skiplist_dt_##name *skiplist_del_##name(struct skiplist_hdr_##name *l, \
- _skiplist_kt_##name k) { \
- _skiplist_dt_##name *ret = 0; \
- /* ALSO NOTE: in *this* case, cmp DOES need to be initialised to prevent a
- possible null-deref via hdrfunc(l->x[lvl])->x */ \
- for (int cmp = 1, lvl = skiplist_lvls_##name - 1; lvl > -1; --lvl) { \
- while (l->x[lvl] && (cmp = compfunc(l->x[lvl], k)) < 0) { \
- l = hdrfunc(l->x[lvl]); \
- } \
- if (cmp == 0) { \
- ret = l->x[lvl]; \
- /* just shift each link by 1 */ \
- l->x[lvl] = hdrfunc(l->x[lvl])->x[0]; \
- /* ... and update every level of links via loop */ \
- } \
- } \
- /* reached the end, return whatever was found */ \
- return ret; \
-} \
-\
-_skiplist_unused \
-mod _skiplist_dt_##name *skiplist_pop_##name(struct skiplist_hdr_##name *l) { \
- _skiplist_dt_##name *cur = l->x[0]; \
- if (!cur) return 0; \
- l->x[0] = hdrfunc(cur)->x[0]; \
- for (int lvl = 1; lvl < skiplist_lvls_##name; ++lvl) { \
- if (l->x[lvl]) l->x[lvl] = hdrfunc(l->x[lvl])->x[lvl]; \
- } \
- return cur; \
-} \
-\
-_skiplist_unused \
-mod void skiplist_insert_##name(struct skiplist_hdr_##name *l, \
- _skiplist_kt_##name k, _skiplist_dt_##name *node) { \
- /* note: higher levels are unset but also skipped in other searches */ \
- int inslvl = _skiplist_lvl_##name(); \
- for (int lvl = skiplist_lvls_##name - 1; lvl > -1; --lvl) { \
- while (l->x[lvl] && compfunc(l->x[lvl], k) < 0) { \
- l = hdrfunc(l->x[lvl]); \
- } \
- if (lvl <= inslvl) { \
- hdrfunc(node)->x[lvl] = l->x[lvl]; \
- l->x[lvl] = node; \
- } \
- } \
-} \
-
-#endif
-
-// vi: sw=4 ts=4 noet tw=80 cc=80