1 /* Copyright (C) 2016 Hewlett Packard Enterprise Development LP
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may
5 * not use this file except in compliance with the License. You may obtain
6 * a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations
17 /* Skiplist implementation based on:
18 * "Skip List: A Probabilistic Alternative to Balanced Trees",
33 * A maximum height level of 32 should be more than sufficient for
34 * anticipated use cases, delivering good expected performance with
35 * up to 2**32 list nodes. Changes to this limit will also require
36 * changes in skiplist_determine_level().
38 #define SKIPLIST_MAX_LEVELS 32
40 /* Skiplist node container */
41 struct skiplist_node
{
42 const void *data
; /* Pointer to saved data. */
43 int height
; /* Height of this node. */
44 struct skiplist_node
*forward
[]; /* Links to the next nodes. */
47 /* Skiplist container */
49 struct skiplist_node
*header
; /* Pointer to head node (not first
51 skiplist_comparator
*cmp
; /* Pointer to the skiplist's comparison
53 void *cfg
; /* Pointer to optional comparison
54 * configuration, used by the comparator. */
55 int level
; /* Maximum level currently in use. */
56 uint32_t size
; /* Current number of nodes in skiplist. */
59 /* Create a new skiplist_node with given level and data. */
60 static struct skiplist_node
*
61 skiplist_create_node(int level
, const void *object
)
63 struct skiplist_node
*new_node
;
64 size_t alloc_size
= sizeof *new_node
+
65 (level
+ 1) * sizeof new_node
->forward
[0];
67 new_node
= xmalloc(alloc_size
);
68 new_node
->data
= object
;
69 new_node
->height
= level
;
70 memset(new_node
->forward
, 0,
71 (level
+ 1) * sizeof new_node
->forward
[0]);
77 * Create a new skiplist, configured with given data comparison function
81 skiplist_create(skiplist_comparator object_comparator
, void *configuration
)
86 sl
= xmalloc(sizeof (struct skiplist
));
87 sl
->cfg
= configuration
;
90 sl
->cmp
= object_comparator
;
91 sl
->header
= skiplist_create_node(SKIPLIST_MAX_LEVELS
, NULL
);
97 * Move the cursor forward to the first node with associated data greater than
98 * or equal to "value".
100 static struct skiplist_node
*
101 skiplist_forward_to_(struct skiplist
*sl
, const void *value
,
102 struct skiplist_node
**update
)
104 struct skiplist_node
*x
= sl
->header
;
107 /* Loop invariant: x < value */
108 for (i
= sl
->level
; i
>= 0; i
--) {
109 while (x
->forward
[i
] &&
110 sl
->cmp(x
->forward
[i
]->data
, value
, sl
->cfg
) < 0) {
113 /* x < value <= x->forward[1] */
118 /* x < value <= x->forward[1] */
123 struct skiplist_node
*
124 skiplist_forward_to(struct skiplist
*sl
, const void *value
)
126 return skiplist_forward_to_(sl
, value
, NULL
);
129 /* Find the first exact match of value in the skiplist. */
130 struct skiplist_node
*
131 skiplist_find(struct skiplist
*sl
, const void *value
)
133 struct skiplist_node
*x
= skiplist_forward_to(sl
, value
);
135 return x
&& sl
->cmp(x
->data
, value
, sl
->cfg
) == 0 ? x
: NULL
;
139 * Determine the level for a skiplist node by choosing a level N with
140 * probability P(N) = 1/(2**(N+1)) in the range 0..32, with the returned
141 * level clamped at the current skiplist height plus 1.
144 skiplist_determine_level(struct skiplist
*sl
)
148 lvl
= clz32(random_uint32());
150 return MIN(lvl
, sl
->level
+ 1);
153 /* Insert data into a skiplist. */
155 skiplist_insert(struct skiplist
*list
, const void *value
)
157 struct skiplist_node
*update
[SKIPLIST_MAX_LEVELS
+ 1];
158 struct skiplist_node
*x
= skiplist_forward_to_(list
, value
, update
);
161 if (x
&& list
->cmp(x
->data
, value
, list
->cfg
) == 0) {
164 lvl
= skiplist_determine_level(list
);
165 if (lvl
> list
->level
) {
166 for (i
= list
->level
+ 1; i
<= lvl
; i
++) {
167 update
[i
] = list
->header
;
171 x
= skiplist_create_node(lvl
, value
);
172 for (i
= 0; i
<= lvl
; i
++) {
173 x
->forward
[i
] = update
[i
]->forward
[i
];
174 update
[i
]->forward
[i
] = x
;
180 /* Remove first node with associated data equal to "value" from skiplist. */
182 skiplist_delete(struct skiplist
*list
, const void *value
)
184 struct skiplist_node
*update
[SKIPLIST_MAX_LEVELS
+ 1];
185 struct skiplist_node
*x
;
189 x
= skiplist_forward_to_(list
, value
, update
);
191 if (x
&& list
->cmp(x
->data
, value
, list
->cfg
) == 0) {
192 for (i
= 0; i
<= list
->level
; i
++) {
193 if (!update
[i
]->forward
[i
] ||
194 list
->cmp(update
[i
]->forward
[i
]->data
, value
,
198 update
[i
]->forward
[i
] = x
->forward
[i
];
200 data
= CONST_CAST(void *, x
->data
);
204 while (list
->level
> 0 && !list
->header
->forward
[list
->level
]) {
212 /* Get the associated data value stored in a skiplist node. */
214 skiplist_get_data(struct skiplist_node
*node
)
216 return node
? CONST_CAST(void *, node
->data
) : NULL
;
219 /* Get the number of items in a skiplist. */
221 skiplist_get_size(struct skiplist
*sl
)
226 /* Get the first node in a skiplist. */
227 struct skiplist_node
*
228 skiplist_first(struct skiplist
*sl
)
230 return sl
->header
->forward
[0];
233 /* Get a node's successor in a skiplist. */
234 struct skiplist_node
*
235 skiplist_next(struct skiplist_node
*node
)
237 return node
? node
->forward
[0] : NULL
;
241 * Destroy a skiplist and free all nodes in the list. If the "data_destroy"
242 * function pointer is non-NULL, it will be called for each node as it is
243 * removed to allow any needed cleanups to be performed on the associated
247 skiplist_destroy(struct skiplist
*sl
, void (*data_destroy
)(void *))
249 struct skiplist_node
*node
, *next
;
251 next
= node
= sl
->header
;
252 while (next
!= NULL
) {
253 next
= node
->forward
[0];
255 data_destroy(CONST_CAST(void *, node
->data
));