1 /*** skiplist.c -- Pugh's Skiplists
3 * Copyright (C) 2006, 2007, 2008 Sebastian Freundt
5 * Author: Sebastian Freundt <hroptatyr@sxemacs.org>
7 * This file is part of SXEmacs.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the author nor the names of any contributors
21 * may be used to endorse or promote products derived from this
22 * software without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
31 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
33 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
34 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 /* Synched up with: Not in FSF. */
53 #define __SKIPLIST_DEBUG__(args...) fprintf(stderr, "SKIPLIST " args)
54 #ifndef SKIPLIST_DEBUG_FLAG
55 #define SL_DEBUG(args...)
57 #define SL_DEBUG(args...) __SKIPLIST_DEBUG__(args)
59 #define SL_CRITICAL(args...) __SKIPLIST_DEBUG__("CRITICAL: " args)
60 #define SL_DEBUG_LEVEL(args...) SL_DEBUG("[level]: " args)
61 #define SL_DEBUG_NODE(args...) SL_DEBUG("[node]: " args)
62 #define SL_DEBUG_DATA(args...) SL_DEBUG("[data]: " args)
63 #define SL_DEBUG_PATH(args...) SL_DEBUG("[path]: " args)
65 #define ALIGNED(n) __attribute__((aligned(n), packed))
67 Lisp_Object Qskiplistp;
70 struct skiplist_data_s {
76 struct skiplist_level_s {
77 skiplist_level_t nextnode; /* pointer to neighbour node */
78 skiplist_level_t nextlevel; /* pointer to above level */
79 skiplist_node_t node; /* parent */
82 struct skiplist_node_s {
83 skiplist_level_t head; /* pointer to first level */
84 skiplist_level_t foot; /* pointer to lowest level */
85 size_t nlevels; /* number of levels in this node */
87 struct skiplist_data_s data; /* pointer to node's data cell */
90 /* paths stuff, just internal */
91 #define skiplist_path_nil (skiplist_level_t)NULL
95 skiplist_size(const skiplist_t sl)
96 __attribute__((always_inline));
98 skiplist_size(const skiplist_t sl)
100 /* what a fooking name, no? */
101 return (size_t)skiplist_nnodes(sl);
104 /* static bindings */
105 /* low level bindings */
106 static skiplist_level_t make_skiplist_levels(skiplist_node_t, size_t);
109 skiplist_find_key_path(skiplist_t, Lisp_Object, skiplist_level_t[])
110 __attribute__((always_inline));
112 skiplist_find_hash_path(skiplist_t, hcode_t, skiplist_level_t[])
113 __attribute__((always_inline));
114 static inline skiplist_level_t
115 skiplist_find_hash_return_level(skiplist_t, hcode_t)
116 __attribute__((always_inline));
118 /* high level bindings */
120 /* low level bindings */
121 #define node_head_level(node) (node)->head
122 #define node_foot_level(node) (node)->foot
123 #define node_data(node) (node)->data
124 #define node_nlevels(node) (node)->nlevels
125 #define node_data_hash(node) (node)->data.hash
126 #define node_data_key(node) (node)->data.key
127 #define node_data_value(node) (node)->data.value
129 #define next_node(level) (level)->nextnode
130 #define next_level(level) (level)->nextlevel
131 #define parent_node(level) (level)->node
133 #define next_hash(level) node_data_hash(parent_node(next_node(level)))
134 #define next_key(level) node_data_key(parent_node(next_node(level)))
135 #define next_value(level) node_data_value(parent_node(next_node(level)))
137 #define level_hash(l) \
138 (l ? (l->node) ? (l->node->data.hash) : 0 : 0)
139 #define level_key(l) \
140 (l ? (l->node) ? (l->node->data.key) : 0 : 0)
142 /* static hcode_t skiplist_hash(Lisp_Object); */
143 #define skiplist_hash(obj) internal_hash((obj), 0)
144 #define skiplist_keyeq(o1, o2) internal_equal((o1), (o2), 0)
146 /* this is p^n - 1 */
148 #define SL_PROBABILITY_MASK 3
151 static inline skiplist_level_t
152 make_skiplist_levels(skiplist_node_t node, size_t nlevels)
153 __attribute__((always_inline));
154 static inline skiplist_level_t
155 make_skiplist_levels(skiplist_node_t node, size_t nlevels)
157 /* creates an array of NLEVEL levels and returns a pointer */
158 skiplist_level_t levels =
159 xnew_array(struct skiplist_level_s, nlevels+1);
161 /* initialise the parent, it's at least one level we hope */
162 parent_node(levels) = node;
163 next_level(levels) = NULL;
164 next_node(levels) = NULL;
165 while (nlevels > 0) {
166 levels[nlevels].node = node;
167 levels[nlevels].nextnode = NULL;
168 levels[nlevels].nextlevel = &levels[nlevels-1];
175 __fill_skiplist_node(skiplist_node_t n, hcode_t h,
176 Lisp_Object key, Lisp_Object value)
177 __attribute__((always_inline));
179 __fill_skiplist_node(skiplist_node_t n, hcode_t h,
180 Lisp_Object key, Lisp_Object value)
182 /* initialise an empty node */
183 node_data_hash(n) = h;
184 node_data_key(n) = key;
185 node_data_value(n) = value;
189 static inline skiplist_node_t
190 _make_skiplist_node(hcode_t h, Lisp_Object key, Lisp_Object val, size_t nl)
191 __attribute__((always_inline));
192 static inline skiplist_node_t
193 _make_skiplist_node(hcode_t h, Lisp_Object key, Lisp_Object val, size_t nl)
195 skiplist_node_t node = xnew_and_zero(struct skiplist_node_s);
196 skiplist_level_t levs = make_skiplist_levels(node, nl);
198 /* fill in the values */
199 __fill_skiplist_node(node, h, key, val);
203 node->head = &(levs[nl]);
207 static inline skiplist_node_t
208 make_skiplist_node(Lisp_Object key, Lisp_Object value, size_t nlevels)
209 __attribute__((always_inline));
210 static inline skiplist_node_t
211 make_skiplist_node(Lisp_Object key, Lisp_Object value, size_t nlevels)
213 return _make_skiplist_node(skiplist_hash(key), key, value, nlevels);
216 static inline skiplist_level_t
217 raise_head_level(skiplist_t sl)
219 skiplist_nlevels(sl)++;
220 return skiplist_head(sl);
223 static inline skiplist_level_t
224 lower_head_level(skiplist_t sl)
226 if (skiplist_nlevels(sl)-- > 0) {
227 skiplist_nlevels(sl) = 0;
229 return skiplist_head(sl);
233 reconcile_levelling(skiplist_t sl)
235 for (; skiplist_nlevels(sl) > 0; skiplist_nlevels(sl)--) {
236 if (next_node(skiplist_head(sl)) != NULL) {
244 free_skiplist_levels(skiplist_level_t level_array)
245 __attribute__((always_inline));
247 free_skiplist_levels(skiplist_level_t level_array)
254 free_skiplist_node(skiplist_node_t node)
255 __attribute__((always_inline));
257 free_skiplist_node(skiplist_node_t node)
259 /* free the level array */
260 SL_DEBUG_LEVEL("freeing level array 0x%p", node->foot);
261 #if defined LET_GCC_BUGS_BITE_US
262 /* must be the inline code plus write-combining :( */
263 free_skiplist_levels(node->foot);
273 add_level_neighbour(skiplist_level_t level, skiplist_level_t neighbour)
274 __attribute__((always_inline));
276 add_level_neighbour(skiplist_level_t level, skiplist_level_t neighbour)
278 next_node(neighbour) = next_node(level);
279 next_node(level) = neighbour;
283 /* higher level bindings */
285 skiplist_find_key_path(skiplist_t slist, Lisp_Object key, skiplist_level_t p[])
287 return skiplist_find_hash_path(slist, skiplist_hash(key), p);
290 static inline skiplist_level_t
291 skiplist_find_level(skiplist_t slist, Lisp_Object key)
293 return skiplist_find_hash_return_level(slist, skiplist_hash(key));
296 static inline skiplist_level_t
297 pop_node_level(skiplist_node_t node)
299 skiplist_level_t tmp;
305 node->head = tmp->nextlevel;
306 tmp->nextlevel = NULL; /* does not make sense for isolated levels */
309 if (node->head == NULL) {
313 SL_DEBUG_LEVEL("popped level 0x%lx\n", (long unsigned int)tmp);
318 skiplist_find_hash_path(skiplist_t slist, hcode_t hash, skiplist_level_t p[])
320 skiplist_level_t tmp = NULL;
322 /* result is the index of the last element */
325 if (!(tmp = skiplist_head(slist))) {
330 p[result] = tmp; /* just push the skiplist head */
331 for (; tmp; tmp = next_level(tmp)) {
332 for (; next_node(tmp) &&
333 (tmphash = next_hash(tmp)) &&
335 tmp = next_node(tmp)) { }
341 static inline skiplist_level_t
342 skiplist_find_hash_return_level(skiplist_t slist, hcode_t hash)
344 skiplist_level_t result, tmp;
347 if (UNLIKELY((result = tmp = skiplist_head(slist)) == NULL)) {
351 for (; tmp; tmp = next_level(tmp)) {
352 for (; next_node(tmp) &&
353 (tmphash = next_hash(tmp)) &&
355 tmp = next_node(tmp) ) {}
362 /* debugging only ... what's the global #define for it? */
363 #ifdef SKIPLIST_DEBUG_FLAG
365 list_skiplist(skiplist_t sl)
367 skiplist_level_t head, tmp;
369 __SKIPLIST_DEBUG__("*** SXEmacs: internal skiplist structure\n");
370 head = skiplist_head(sl);
374 __SKIPLIST_DEBUG__("%lu->", level_hash(tmp));
375 tmp = next_node(tmp);
377 __SKIPLIST_DEBUG__("0\n");
378 head = next_level(head);
383 DEFUN("list-skiplist", Flist_skiplist, 1, 1, 0, /*
388 list_skiplist(XSKIPLIST(skiplist));
397 mark_skiplist(Lisp_Object obj)
399 /* traverse the skiplist, we simply use the lowest level since
400 * that should be a single-linked list */
401 for (skiplist_level_t tmp = next_node(XSKIPLIST_FOOT(obj));
402 tmp; tmp = next_node(tmp)) {
403 mark_object(node_data_key(parent_node(tmp)));
404 mark_object(node_data_value(parent_node(tmp)));
407 mark_object(XSKIPLIST_PLIST(obj));
408 return XSKIPLIST_PLIST(obj);
412 print_skiplist(Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
414 write_fmt_str(printcharfun, "#<skiplist :size %lu :levels %lu >",
415 (long unsigned int)XSKIPLIST_NNODES(obj),
416 (long unsigned int)XSKIPLIST_NLEVELS(obj));
420 finalise_skiplist(void *header, int SXE_UNUSED(for_disksave))
422 skiplist_t sl = header;
424 SL_DEBUG("*** SXEmacs: skiplist finalisation 0x%lx\n",
425 (long unsigned int)sl);
427 /* traverse the skiplist and free all node and data cells */
428 for (skiplist_level_t tmp = next_node(skiplist_foot(sl)); tmp; ) {
429 volatile skiplist_level_t nex = next_node(tmp);
430 SL_DEBUG_NODE("freeing 0x%lx\n",
431 (long unsigned int)tmp->node);
432 free_skiplist_node(tmp->node);
436 /* free skiplist head levels */
439 /* and finally commit suicide */
444 skiplist_getprop(Lisp_Object obj, Lisp_Object property)
446 return external_plist_get(&XSKIPLIST_PLIST(obj), property, 0, ERROR_ME);
450 skiplist_putprop(Lisp_Object obj, Lisp_Object property, Lisp_Object value)
452 external_plist_put(&XSKIPLIST_PLIST(obj), property, value, 0, ERROR_ME);
457 skiplist_remprop(Lisp_Object obj, Lisp_Object property)
459 return external_remprop(&XSKIPLIST_PLIST(obj), property, 0, ERROR_ME);
462 DEFUN("skiplist-plist", Fskiplist_plist, 1, 1, 0, /*
463 Return the property list of SKIPLIST.
467 CHECK_SKIPLIST(skiplist);
468 return XSKIPLIST_PLIST(skiplist);
471 static const struct lrecord_description skiplist_description[] = {
472 {XD_OPAQUE_PTR, offsetof(struct skiplist_s, headlevs)},
473 {XD_INT, offsetof(struct skiplist_s, nnodes)},
474 {XD_INT, offsetof(struct skiplist_s, nlevels)},
475 {XD_LISP_OBJECT, offsetof(struct skiplist_s, plist)},
479 DEFINE_LRECORD_IMPLEMENTATION_WITH_PROPS("skiplist", skiplist,
480 mark_skiplist, print_skiplist,
483 skiplist_description,
490 static inline skiplist_t
491 allocate_skiplist(void)
492 __attribute__((always_inline));
493 static inline skiplist_t
494 allocate_skiplist(void)
496 skiplist_t skiplist =
497 alloc_lcrecord_type(struct skiplist_s, &lrecord_skiplist);
504 skiplist_t sl = allocate_skiplist();
507 /* the categories are actually seq and dict, but use the per-type
508 implementation for a start */
509 sl->lheader.lheader.morphisms = (1<<cat_mk_lc);
511 sl->headlevs = make_skiplist_levels(NULL, MAX_SKIPLIST_HEIGHT);
512 skiplist_nnodes(sl) = 0;
513 skiplist_nlevels(sl) = 0; /* means 1 actually */
514 skiplist_plist(sl) = Qnil;
516 XSETSKIPLIST(result, sl);
521 DEFUN("make-skiplist", Fmake_skiplist, 0, 0, 0, /*
522 Return a new empty skiplist object.
526 /* gotta seed our oracle; this is a stupid seed value though */
527 return make_skiplist();
532 DEFUN("skiplistp", Fskiplistp, 1, 1, 0, /*
533 Return non-nil if OBJECT is a skiplist.
537 if (SKIPLISTP(object)) {
544 DEFUN("skiplist-empty-p", Fskiplist_empty_p, 1, 1, 0, /*
545 Return non-nil if SKIPLIST is empty.
549 CHECK_SKIPLIST(skiplist);
551 if (XSKIPLIST_NNODES(skiplist) == 0) {
558 /* modifiers and accessors */
560 _put_skiplist(skiplist_t sl, skiplist_level_t *path, size_t psz,
561 hcode_t h, Lisp_Object key, Lisp_Object value)
563 /* entirely new data, build a node for it */
564 /* determine the number of levels to add, this is a log distribution
565 * so we use ffs(3) of a random number */
566 size_t nlevels = __ase_ffsl(random());
568 skiplist_level_t levels, last = path[psz--];
569 skiplist_node_t node;
571 node = _make_skiplist_node(h, key, value, nlevels);
576 add_level_neighbour(last, node->foot /* level[0] */);
578 if (LIKELY(nlevels <= psz)) {
583 for (size_t i = 1; i <= cnt; i++) {
584 skiplist_level_t level = &levels[i];
586 SL_DEBUG_LEVEL("created level 0x%lx\n",
587 (long unsigned int)level);
589 last = /* skiplist_path_pop(path) */ path[psz--];
590 SL_DEBUG("last 0x%lx "
592 (long unsigned int)last,
593 (long unsigned int)level);
594 add_level_neighbour(last, level);
596 for (size_t i = cnt+1; i <= nlevels; i++) {
597 skiplist_level_t newhlevel = raise_head_level(sl);
598 skiplist_level_t level = &levels[i];
600 SL_DEBUG("head level 0x%lx "
602 (long unsigned int)newhlevel,
603 (long unsigned int)level);
604 add_level_neighbour(newhlevel, level);
610 put_skiplist(skiplist_t sl, Lisp_Object key, Lisp_Object value)
612 skiplist_level_t last;
613 /* C99 we need you */
614 skiplist_level_t path[skiplist_nlevels(sl)+2];
615 hcode_t hkey = skiplist_hash(key);
619 last = path[lastidx = skiplist_find_hash_path(sl, hkey, path)];
621 if (UNLIKELY(/* skiplist_path_size(path) == 0 */ lastidx == 0 ||
622 /* skiplist_pop(path) == NULL */ last == NULL)) {
626 /* hash this prick */
627 h = skiplist_hash(key);
629 /* now either we have to insert, or replace */
630 /* for that we check if the element right of left is by chance
631 * the thing we look for */
632 if (UNLIKELY(h == level_hash(next_node(last)))) {
633 skiplist_level_t level = next_node(last);
635 if (UNLIKELY(!skiplist_keyeq(key, level_key(level)))) {
636 SL_CRITICAL("*** SXEmacs CRITICAL: "
637 "non trivial skiplist collision :(\n");
640 /* oh, we have to replace, we just nuke the old
641 * data cell and replace it with the new one
643 SL_DEBUG("*** SXEmacs: skiplist collision, replace\n");
644 node_data_key(parent_node(level)) = key;
645 node_data_value(parent_node(level)) = value;
648 _put_skiplist(sl, path, lastidx, h, key, value);
653 DEFUN("put-skiplist", Fput_skiplist, 3, 3, 0, /*
654 Add KEY to the SKIPLIST and assign VALUE.
656 (skiplist, key, value))
658 CHECK_SKIPLIST(skiplist);
660 put_skiplist(XSKIPLIST(skiplist), key, value);
666 get_skiplist(skiplist_t sl, Lisp_Object key, Lisp_Object default_)
668 skiplist_node_t node;
669 skiplist_level_t level;
671 if (UNLIKELY((level = skiplist_find_level(sl, key)) == NULL)) {
675 /* level points to rightmost and footmost level to the left of key */
676 if (next_node(level)) {
677 level = next_node(level);
680 if (!(node = level->node)) {
684 if (!(skiplist_keyeq(node_data_key(node), key))) {
688 return node_data_value(node);
691 DEFUN("get-skiplist", Fget_skiplist, 2, 3, 0, /*
692 Return the value of KEY in SKIPLIST.
693 If KEY is not an element, return `nil' instead or --
694 if specified -- DEFAULT.
696 (skiplist, key, default_))
698 CHECK_SKIPLIST(skiplist);
700 return get_skiplist(XSKIPLIST(skiplist), key, default_);
704 remove_skiplist(skiplist_t sl, Lisp_Object key)
705 /* remove KEY from SKIPLIST (pathless approach) */
707 skiplist_node_t node;
708 skiplist_level_t level, last;
709 /* C99 we need you! */
710 skiplist_level_t path[skiplist_nlevels(sl)+2];
711 hcode_t hkey = skiplist_hash(key);
714 lastidx = skiplist_find_hash_path(sl, hkey, path);
715 last = path[lastidx];
717 if (/* skiplist_path_size(path) == 0 */ lastidx == 0 ||
718 /* skiplist_last(path) == NULL */ path[0] == NULL) {
722 if (hkey == level_hash(next_node(last)) &&
723 skiplist_keyeq(key, level_key(next_node(last)))) {
724 node = parent_node(next_node(last));
726 /* traverse (bottom-up) the level structure
727 * and free any occurring level pointers */
728 while (lastidx > 0 /* because we `popped' the head */ &&
730 /* skiplist_path_pop(path) */
731 path[lastidx--]) != skiplist_path_nil &&
733 parent_node(next_node(last)) == node) {
734 level = next_node(last);
735 next_node(last) = next_node(level);
738 /* free node (kill data cell and levels with it) */
739 free_skiplist_node(node);
740 /* decrement skiplist size */
741 skiplist_nnodes(sl)--;
743 /* now, the skiplist head might have many nil pointers
744 * we reduce the overall levelling in that case */
745 reconcile_levelling(sl);
750 DEFUN("remove-skiplist", Fremove_skiplist, 2, 2, 0, /*
751 Remove the element specified by KEY from SKIPLIST.
752 If KEY is not an element, this is a no-op.
756 CHECK_SKIPLIST(skiplist);
758 remove_skiplist(XSKIPLIST(skiplist), key);
763 /* C99 where are you? */
765 skiplist_owns_p(skiplist_t skiplist, Lisp_Object key)
766 /* return !0 iff SKIPLIST has a node for KEY */
768 skiplist_node_t node;
769 skiplist_level_t level;
770 hcode_t hkey = skiplist_hash(key);
772 level = skiplist_find_hash_return_level(skiplist, hkey);
774 if (level == skiplist_path_nil) {
778 /* level points to rightmost and footmost level to the left of key */
779 if (next_node(level))
780 level = next_node(level);
782 if ((node = level->node) == NULL) {
786 if (!(skiplist_keyeq(node_data_key(node), key))) {
793 DEFUN("skiplist-owns-p", Fskiplist_owns_p, 2, 2, 0, /*
794 Return non-nil if KEY is associated with a value in SKIPLIST.
798 CHECK_SKIPLIST(skiplist);
800 return (skiplist_owns_p(XSKIPLIST(skiplist), key) ? Qt : Qnil);
804 /* informational cruft */
805 DEFUN("skiplist-size", Fskiplist_size, 1, 1, 0, /*
806 Return the size of SKIPLIST, that is the number of elements.
810 CHECK_SKIPLIST(skiplist);
811 return make_int((int32_t)XSKIPLIST_NNODES(skiplist));
816 copy_skiplist(skiplist_t skiplist)
818 Lisp_Object result = make_skiplist();
819 skiplist_t sl_copy = XSKIPLIST(result);
820 skiplist_level_t tmp;
821 Lisp_Object key, val;
823 /* traverse the skiplist */
824 tmp = next_node(skiplist_foot(skiplist));
826 key = node_data_key(parent_node(tmp));
827 val = node_data_value(parent_node(tmp));
828 put_skiplist(sl_copy, key, val);
829 tmp = next_node(tmp);
834 DEFUN("copy-skiplist", Fcopy_skiplist, 1, 1, 0, /*
835 Return a copy of skiplist SKIPLIST.
836 The elements of SKIPLIST are not copied; they are shared
842 CHECK_SKIPLIST(skiplist);
844 return copy_skiplist(XSKIPLIST(skiplist));
847 void unite_skiplist(skiplist_t target, skiplist_t source)
849 /* unite target and source and store result in target */
850 Lisp_Object key, value;
851 skiplist_level_t lev;
853 lev = next_node(skiplist_foot(source)); /* start at the bottom */
855 key = node_data_key(parent_node(lev));
856 value = node_data_value(parent_node(lev));
857 put_skiplist(target, key, value);
858 lev = next_node(lev);
862 DEFUN("skiplist-union", Fskiplist_union, 0, MANY, 0, /*
863 Return the union skiplist of SKIPLISTS.
864 Args are &rest SKIPLIST.
866 The union is a skiplist containing all key-value-pairs which are
867 in at least one of the SKIPLISTS.
869 Note: Key-value-pairs with equal keys and distinct values are
870 processed from left to right, that is the final union for such pairs
871 contains the value of the rightmost skiplist in @var{skiplists}.
873 (int nargs, Lisp_Object *args))
878 for (i=0; i<nargs; i++)
879 CHECK_SKIPLIST(args[i]);
881 result = make_skiplist();
882 for (i=0; i<nargs; i++) {
883 unite_skiplist(XSKIPLIST(result), XSKIPLIST(args[i]));
888 void intersect_skiplist(skiplist_t target, skiplist_t source)
890 /* intersect target and source and store result in target */
892 skiplist_level_t lev;
894 lev = next_node(skiplist_foot(target)); /* start at the bottom */
896 key = node_data_key(parent_node(lev));
897 lev = next_node(lev);
898 if (!skiplist_owns_p(source, key)) {
899 remove_skiplist(target, key);
901 lev = next_node(lev);
906 DEFUN("skiplist-intersection", Fskiplist_intersection, 0, MANY, 0, /*
907 Return the intersection skiplist of SKIPLISTS.
908 Args are &rest SKIPLIST.
910 The intersection is a skiplist containing all key-value-pairs
911 which are in all skiplists of SKIPLISTS.
913 Note: Key-value-pairs with equal keys and distinct values are
914 processed from right to left, that is the final intersection for such
915 pairs contains the value of the leftmost skiplist in SKIPLISTS.
917 (int nargs, Lisp_Object *args))
923 return make_skiplist();
925 for (i=0; i<nargs; i++)
926 CHECK_SKIPLIST(args[i]);
928 result = copy_skiplist(XSKIPLIST(args[0]));
929 for (i=1; i<nargs; i++) {
930 intersect_skiplist(XSKIPLIST(result), XSKIPLIST(args[i]));
936 map_skiplist(skiplist_t sl, skiplist_map_f mapf)
938 skiplist_level_t lev;
940 lev = next_node(skiplist_foot(sl)); /* start at the bottom */
943 k = node_data_key(parent_node(lev));
944 v = node_data_value(parent_node(lev));
947 lev = next_node(lev);
953 map2_skiplist(skiplist_t sl, skiplist_map2_f mapf, void *ptr)
955 skiplist_level_t lev;
957 lev = next_node(skiplist_foot(sl)); /* start at the bottom */
960 k = node_data_key(parent_node(lev));
961 v = node_data_value(parent_node(lev));
964 lev = next_node(lev);
969 DEFUN("map-skiplist", Fmap_skiplist, 2, 2, 0, /*
970 Map FUNCTION over entries in SKIPLIST, calling it with two args,
971 each key and value in SKIPLIST.
973 FUNCTION may not modify SKIPLIST, with the one exception that FUNCTION
974 may remove or reput the entry currently being processed by FUNCTION.
976 (function, skiplist))
980 skiplist_level_t lev;
981 struct gcpro gcpro1, gcpro2;
983 CHECK_SKIPLIST(skiplist);
985 GCPRO2(function, skiplist);
986 sl = XSKIPLIST(skiplist);
987 lev = next_node(skiplist_foot(sl)); /* start at the bottom */
990 args[1] = node_data_key(parent_node(lev));
991 args[2] = node_data_value(parent_node(lev));
993 Ffuncall(countof(args), args);
994 lev = next_node(lev);
1003 DEFUN("skiplist-to-alist", Fskiplist_to_alist, 1, 1, 0, /*
1004 Return the ordinary association list induced by SKIPLIST.
1008 Lisp_Object result = Qnil;
1009 skiplist_level_t tmp;
1010 Lisp_Object key, val;
1012 CHECK_SKIPLIST(skiplist);
1014 /* traverse the skiplist */
1015 tmp = next_node(XSKIPLIST_FOOT(skiplist));
1017 key = node_data_key(parent_node(tmp));
1018 val = node_data_value(parent_node(tmp));
1019 result = Fcons(Fcons(key, val), result);
1020 tmp = next_node(tmp);
1026 DEFUN("skiplist-to-plist", Fskiplist_to_plist, 1, 1, 0, /*
1027 Return the ordinary association list induced by SKIPLIST.
1031 Lisp_Object result = Qnil;
1032 skiplist_level_t tmp;
1033 Lisp_Object key, val;
1035 CHECK_SKIPLIST(skiplist);
1037 /* traverse the skiplist */
1038 tmp = next_node(XSKIPLIST_FOOT(skiplist));
1040 key = node_data_key(parent_node(tmp));
1041 val = node_data_value(parent_node(tmp));
1042 result = Fcons(val, result);
1043 result = Fcons(key, result);
1044 tmp = next_node(tmp);
1050 DEFUN("alist-to-skiplist", Falist_to_skiplist, 1, 1, 0, /*
1051 Return a skiplist from ALIST with equal key space and image.
1055 Lisp_Object result = make_skiplist();
1056 skiplist_t sl = XSKIPLIST(result);
1057 Lisp_Object tmp, key, val;
1061 /* traverse the alist */
1063 while (!NILP(tmp)) {
1064 key = XCAR(XCAR(tmp));
1065 val = XCDR(XCAR(tmp));
1067 put_skiplist(sl, key, val);
1075 DEFUN("plist-to-skiplist", Fplist_to_skiplist, 1, 1, 0, /*
1076 Return a skiplist from PLIST with equal key space and image.
1080 Lisp_Object result = make_skiplist();
1081 skiplist_t sl = XSKIPLIST(result);
1082 Lisp_Object tmp, key, val;
1086 /* traverse the plist */
1088 while (!NILP(tmp)) {
1090 val = XCAR(XCDR(tmp));
1092 put_skiplist(sl, key, val);
1094 tmp = Fcdr(Fcdr(tmp));
1101 /* iterator crap, only needed for dict so make it static */
1103 skiplist_iter_init(dict_t d, dict_iter_t di)
1106 /* go to the bottommost level */
1107 di->data = next_node(skiplist_foot((skiplist_t)d));
1112 skiplist_iter_fini(dict_iter_t di)
1114 di->dict = di->data = NULL;
1118 /* the next one is for dicts only */
1120 skiplist_diter_next(dict_iter_t di, Lisp_Object *key, Lisp_Object *val)
1122 skiplist_level_t sll = di->data;
1124 if (LIKELY(sll != NULL)) {
1125 *key = node_data_key(parent_node(sll));
1126 *val = node_data_value(parent_node(sll));
1127 di->data = next_node(sll);
1129 *key = *val = Qnull_pointer;
1134 /* and the one for seqs */
1136 skiplist_siter_next(seq_iter_t di, void **elm)
1138 skiplist_level_t sll = di->data;
1140 if (LIKELY(sll != NULL)) {
1141 *elm = (void*)node_data_key(parent_node(sll));
1142 di->data = next_node(sll);
1144 *elm = Qnull_pointer;
1150 skiplist_iter_reset(seq_iter_t si)
1152 /* go to the bottommost level */
1153 si->data = next_node(skiplist_foot((skiplist_t)si->seq));
1158 skiplist_explode(void *restrict tgt[], size_t ntgt, const seq_t s)
1160 volatile size_t i = 0;
1161 volatile skiplist_level_t n = next_node(skiplist_foot((skiplist_t)s));
1163 while (n != NULL && i < ntgt) {
1164 tgt[i++] = (void*)node_data_key(parent_node(n));
1172 * Initialisation stuff
1174 static struct dict_impl_s __dskiplist = {
1175 .size_f = (dict_size_f)skiplist_size,
1176 .put_f = (dict_put_f)put_skiplist,
1177 .get_f = (dict_get_f)get_skiplist,
1178 .remove_f = (dict_remove_f)remove_skiplist,
1179 .iter_init_f = skiplist_iter_init,
1180 .iter_next_f = skiplist_diter_next,
1181 .iter_fini_f = skiplist_iter_fini,
1184 static struct seq_impl_s __sskiplist = {
1185 .length_f = (seq_length_f)skiplist_size,
1186 .iter_init_f = (seq_iter_init_f)skiplist_iter_init,
1187 .iter_next_f = skiplist_siter_next,
1188 .iter_fini_f = (seq_iter_fini_f)skiplist_iter_fini,
1189 .iter_reset_f = skiplist_iter_reset,
1190 .explode_f = skiplist_explode,
1193 /* deal with dict interface */
1194 const dict_impl_t dict_skiplist = &__dskiplist;
1195 /* deal with the seq interface (actually a set interface) */
1196 const seq_impl_t seq_skiplist = &__sskiplist;
1198 void syms_of_skiplist(void)
1200 INIT_LRECORD_IMPLEMENTATION(skiplist);
1202 defsymbol(&Qskiplistp, "skiplistp");
1204 DEFSUBR(Fmake_skiplist);
1205 DEFSUBR(Fskiplist_plist);
1207 DEFSUBR(Fskiplistp);
1208 DEFSUBR(Fskiplist_empty_p);
1210 DEFSUBR(Fput_skiplist);
1211 DEFSUBR(Fget_skiplist);
1212 DEFSUBR(Fremove_skiplist);
1213 DEFSUBR(Fskiplist_owns_p);
1215 DEFSUBR(Fskiplist_size);
1217 DEFSUBR(Fcopy_skiplist);
1218 DEFSUBR(Fskiplist_union);
1219 DEFSUBR(Fskiplist_intersection);
1220 DEFSUBR(Fmap_skiplist);
1222 #ifdef SKIPLIST_DEBUG_FLAG
1223 DEFSUBR(Flist_skiplist);
1226 DEFSUBR(Fskiplist_to_alist);
1227 DEFSUBR(Fskiplist_to_plist);
1228 DEFSUBR(Falist_to_skiplist);
1229 DEFSUBR(Fplist_to_skiplist);
1233 skiplist_reinit(void)
1235 morphisms[lrecord_type_skiplist].seq_impl = seq_skiplist;
1236 morphisms[lrecord_type_skiplist].aset_impl = dict_skiplist;
1240 void vars_of_skiplist(void)
1242 Fprovide(intern("skiplist"));
1245 /* skiplist.c ends here*/