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 struct skiplist_node
*forward
[]; /* Links to the next nodes. */
46 /* Skiplist container */
48 struct skiplist_node
*header
; /* Pointer to head node (not first
50 skiplist_comparator
*cmp
; /* Pointer to the skiplist's comparison
52 void *cfg
; /* Pointer to optional comparison
53 * configuration, used by the comparator. */
54 int level
; /* Maximum level currently in use. */
55 uint32_t size
; /* Current number of nodes in skiplist. */
58 /* Create a new skiplist_node with given level and data. */
59 static struct skiplist_node
*
60 skiplist_create_node(int level
, const void *object
)
62 struct skiplist_node
*new_node
;
63 size_t alloc_size
= sizeof *new_node
+
64 (level
+ 1) * sizeof new_node
->forward
[0];
66 new_node
= xmalloc(alloc_size
);
67 new_node
->data
= object
;
68 memset(new_node
->forward
, 0,
69 (level
+ 1) * sizeof new_node
->forward
[0]);
75 * Create a new skiplist, configured with given data comparison function
79 skiplist_create(skiplist_comparator object_comparator
, void *configuration
)
84 sl
= xmalloc(sizeof (struct skiplist
));
85 sl
->cfg
= configuration
;
88 sl
->cmp
= object_comparator
;
89 sl
->header
= skiplist_create_node(SKIPLIST_MAX_LEVELS
, NULL
);
95 * Move the cursor forward to the first node with associated data greater than
96 * or equal to "value".
98 static struct skiplist_node
*
99 skiplist_forward_to_(struct skiplist
*sl
, const void *value
,
100 struct skiplist_node
**update
)
102 struct skiplist_node
*x
= sl
->header
;
105 /* Loop invariant: x < value */
106 for (i
= sl
->level
; i
>= 0; i
--) {
107 while (x
->forward
[i
] &&
108 sl
->cmp(x
->forward
[i
]->data
, value
, sl
->cfg
) < 0) {
111 /* x < value <= x->forward[1] */
116 /* x < value <= x->forward[1] */
121 struct skiplist_node
*
122 skiplist_forward_to(struct skiplist
*sl
, const void *value
)
124 return skiplist_forward_to_(sl
, value
, NULL
);
127 /* Find the first exact match of value in the skiplist. */
128 struct skiplist_node
*
129 skiplist_find(struct skiplist
*sl
, const void *value
)
131 struct skiplist_node
*x
= skiplist_forward_to(sl
, value
);
133 return x
&& sl
->cmp(x
->data
, value
, sl
->cfg
) == 0 ? x
: NULL
;
137 * Determine the level for a skiplist node by choosing a level N with
138 * probability P(N) = 1/(2**(N+1)) in the range 0..32, with the returned
139 * level clamped at the current skiplist height plus 1.
142 skiplist_determine_level(struct skiplist
*sl
)
146 lvl
= clz32(random_uint32());
148 return MIN(lvl
, sl
->level
+ 1);
151 /* Insert data into a skiplist. */
153 skiplist_insert(struct skiplist
*list
, const void *value
)
155 struct skiplist_node
*update
[SKIPLIST_MAX_LEVELS
+ 1];
156 struct skiplist_node
*x
= skiplist_forward_to_(list
, value
, update
);
159 if (x
&& list
->cmp(x
->data
, value
, list
->cfg
) == 0) {
162 lvl
= skiplist_determine_level(list
);
163 if (lvl
> list
->level
) {
164 for (i
= list
->level
+ 1; i
<= lvl
; i
++) {
165 update
[i
] = list
->header
;
169 x
= skiplist_create_node(lvl
, value
);
170 for (i
= 0; i
<= lvl
; i
++) {
171 x
->forward
[i
] = update
[i
]->forward
[i
];
172 update
[i
]->forward
[i
] = x
;
178 /* Remove first node with associated data equal to "value" from skiplist. */
180 skiplist_delete(struct skiplist
*list
, const void *value
)
182 struct skiplist_node
*update
[SKIPLIST_MAX_LEVELS
+ 1];
183 struct skiplist_node
*x
;
187 x
= skiplist_forward_to_(list
, value
, update
);
189 if (x
&& list
->cmp(x
->data
, value
, list
->cfg
) == 0) {
190 for (i
= 0; i
<= list
->level
; i
++) {
191 if (update
[i
]->forward
[i
] != x
) {
194 update
[i
]->forward
[i
] = x
->forward
[i
];
196 data
= CONST_CAST(void *, x
->data
);
200 while (list
->level
> 0 && !list
->header
->forward
[list
->level
]) {
208 /* Get the associated data value stored in a skiplist node. */
210 skiplist_get_data(struct skiplist_node
*node
)
212 return node
? CONST_CAST(void *, node
->data
) : NULL
;
215 /* Get the number of items in a skiplist. */
217 skiplist_get_size(struct skiplist
*sl
)
222 /* Get the first node in a skiplist. */
223 struct skiplist_node
*
224 skiplist_first(struct skiplist
*sl
)
226 return sl
->header
->forward
[0];
229 /* Get a node's successor in a skiplist. */
230 struct skiplist_node
*
231 skiplist_next(struct skiplist_node
*node
)
233 return node
? node
->forward
[0] : NULL
;
237 * Destroy a skiplist and free all nodes in the list. If the "data_destroy"
238 * function pointer is non-NULL, it will be called for each node as it is
239 * removed to allow any needed cleanups to be performed on the associated
243 skiplist_destroy(struct skiplist
*sl
, void (*data_destroy
)(void *))
245 struct skiplist_node
*node
, *next
;
247 next
= node
= sl
->header
;
248 while (next
!= NULL
) {
249 next
= node
->forward
[0];
251 data_destroy(CONST_CAST(void *, node
->data
));