Skiplist implementation intended for the IDL compound indexes
feature.

Signed-off-by: Esteban Rodriguez Betancourt <esteb...@hpe.com>
---
lib/automake.mk |   2 +
lib/skiplist.c  | 292 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
lib/skiplist.h  |  53 ++++++++++
3 files changed, 347 insertions(+)
create mode 100644 lib/skiplist.c
create mode 100644 lib/skiplist.h

diff --git a/lib/automake.mk b/lib/automake.mk
index 27a1669..1317f85 100644
--- a/lib/automake.mk
+++ b/lib/automake.mk
@@ -224,6 +224,8 @@ lib_libopenvswitch_la_SOURCES = \
               lib/shash.h \
               lib/simap.c \
               lib/simap.h \
+             lib/skiplist.c \
+             lib/skiplist.h \
               lib/smap.c \
               lib/smap.h \
               lib/socket-util.c \
diff --git a/lib/skiplist.c b/lib/skiplist.c
new file mode 100644
index 0000000..01e296c
--- /dev/null
+++ b/lib/skiplist.c
@@ -0,0 +1,292 @@
+/* Copyright (C) 2016 Hewlett Packard Enterprise Development LP
+ * All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+/*
+ * Skiplist implementationn based on:
+ * "Skip List: A Probabilistic Alternative to Balanced Trees",
+ * by William Pugh.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "skiplist.h"
+#include "random.h"
+
+#define SKIPLIST_MAX_LEVELS 64
+
+/*
+ * Skiplist node container
+ */
+struct skiplist_node
+{
+    const void* data;                       /* Pointer to saved data */
+    uint64_t height;                        /* Height of this node */
+    struct skiplist_node *forward[];        /* Links to the next nodes */
+};
+
+/*
+ * Skiplist container
+ */
+
+struct skiplist
+{
+    struct skiplist_node *header;   /* Pointer to head node
+                                       (not first data node)*/
+    skiplist_comparator cmp;        /* Pointer to the skiplist's comparison
+                                       function*/
+    void *cfg;                      /* Pointer to optional comparison
+                                       configuration, used by the comparator */
+    int max_levels;                 /* Max levels of the skiplist. */
+    uint64_t probability;           /* Probability that the node would take an
+                                       additional skiplist level. */
+    int64_t size;                   /* Current size of the skiplist. */
+    int64_t level;                  /* Max number of levels used in this
+                                       skiplist*/
+    void (*free_func)(void *);      /* Function that free the value's memory */
+};
+
+static int skiplist_determine_level(struct skiplist* sl);
+
+static struct skiplist_node* skiplist_create_node(int, const void *);
+
+static struct skiplist_node*
+skiplist_forward_to_(struct skiplist* sl, const void *value,
+                     struct skiplist_node **update);
+
+/*
+ * skiplist_create returns a new skiplist, configured with given max_levels,
+ * data comparer and configuration.
+ * Sets a probability of 0.5 (RAND_MAX / 2).
+ */
+struct skiplist*
+skiplist_create(int max_levels, skiplist_comparator object_comparator,
+                void *configuration)
+{
+    random_init();
+    struct skiplist *sl;
+    sl = malloc(sizeof(struct skiplist));
+    sl->cfg = configuration;
+    sl->max_levels = max_levels < SKIPLIST_MAX_LEVELS ?
+            max_levels : SKIPLIST_MAX_LEVELS;
+    sl->size = 0;
+    sl->level = 0;
+    sl->cmp = object_comparator;
+    sl->probability = UINT32_MAX / 2;
+    sl->header = skiplist_create_node(sl->max_levels, NULL);
+    sl->free_func = NULL;
+
+    return sl;
+}
+
+/*
+ * Set a custom function that free the value's memory when
+ * destroying the skiplist.
+ */
+void
+skiplist_set_free_func(struct skiplist* sl, void (*func)(void *))
+{
+    sl->free_func = func;
+}
+
+/*
+ * Determines the correspondent level for a skiplist node.
+ */
+static int
+skiplist_determine_level(struct skiplist* sl)
+{
+    int lvl = 0;
+    while(random_uint32() <= sl->probability && lvl < sl->max_levels){
+        lvl++;
+    }
+    return lvl;
+}
+
+/*
+ * Creates a new skiplist_node with given levels and data.
+ */
+static struct skiplist_node*
+skiplist_create_node(int levels, const void *object)
+{
+    struct skiplist_node *new_node = malloc(sizeof(struct skiplist_node) +
+                                  (levels+1) * sizeof(struct skiplist_node *));
+    new_node->data = object;
+    new_node->height = levels;
+    memset(new_node->forward, 0, (levels+1) * sizeof(struct skiplist_node *));
+    return new_node;
+}
+
+/*
+ * Find the first exact match of value in the skiplist
+ */
+struct skiplist_node*
+skiplist_find(struct skiplist* sl, const void *value)
+{
+    struct skiplist_node *x = skiplist_forward_to(sl, value);
+    return x && sl->cmp(x->data, value, sl->cfg) == 0 ? x : NULL;
+}
+
+/*
+ * Moves the cursor forward, to the first data equal or greater than value.
+ */
+struct skiplist_node*
+skiplist_forward_to(struct skiplist* sl, const void *value)
+{
+    return skiplist_forward_to_(sl, value, NULL);
+}
+
+static struct skiplist_node*
+skiplist_forward_to_(struct skiplist* sl, const void *value,
+                     struct skiplist_node **update)
+{
+    struct skiplist_node *x = sl->header;
+    int i;
+
+    /* Loop invariant: x < value */
+    for(i = sl->level; i >= 0; i--){
+        while(x->forward[i] &&
+                sl->cmp(x->forward[i]->data, value, sl->cfg) < 0){
+            x = x->forward[i];
+        }
+        /* x < value <= x->forward[1]*/
+        if(update){
+            update[i] = x;
+        }
+    }
+    /* x < value <= x->forward[1]*/
+    x = x->forward[0];
+    return x;
+}
+
+/*
+ * Inserts data into skiplist.
+ */
+void
+skiplist_insert(struct skiplist* list, const void *value)
+{
+    struct skiplist_node *update[SKIPLIST_MAX_LEVELS+1] = {NULL};
+    int i, lvl;
+    struct skiplist_node *x = skiplist_forward_to_(list, value, update);
+
+    if(x && list->cmp(x->data, value, list->cfg) == 0) {
+        x->data = value;
+    } else {
+        lvl = skiplist_determine_level(list);
+        if(lvl > list->level){
+            for(i = list->level + 1; i <= lvl; i++){
+                update[i] = list->header;
+            }
+            list->level = lvl;
+        }
+        x = skiplist_create_node(lvl, value);
+        for(i = 0; i <= lvl; i++){
+            x->forward[i] = update[i]->forward[i];
+            update[i]->forward[i] = x;
+        }
+        list->size++;
+    }
+}
+
+/*
+ * Removes first ocurrence of data from skiplist.
+ */
+void *
+skiplist_delete(struct skiplist* list, const void *value)
+{
+    struct skiplist_node *update[SKIPLIST_MAX_LEVELS+1] = {NULL};
+    void *data = NULL;
+    int i;
+    struct skiplist_node *x = list->header;
+    x = skiplist_forward_to_(list, value, update);
+
+    if(x && list->cmp(x->data, value, list->cfg) == 0) {
+        for(i = 0; i <= list->level; i++){
+            if(!update[i]->forward[i] ||
+                    list->cmp(update[i]->forward[i]->data, value, list->cfg) 
!= 0){
+                break;
+            }
+            update[i]->forward[i] = x->forward[i];
+        }
+        data = (void *) x->data;
+        free(x);
+
+        while(list->level > 0 && !list->header->forward[list->level]){
+            list->level--;
+        }
+        list->size--;
+    }
+    return data;
+}
+
+/*
+ * Returns the value stored in the skiplist node
+ */
+void *
+skiplist_get_data(struct skiplist_node *node)
+{
+    return node ? (void *) node->data : NULL;
+}
+
+/*
+ * Returns the count of items in the skiplist
+ */
+int64_t
+skiplist_get_size(struct skiplist* sl)
+{
+    return sl->size;
+}
+
+/*
+ * Returns the first element in the skiplist
+ */
+struct skiplist_node *
+skiplist_first(struct skiplist* sl)
+{
+    return sl->header->forward[0];
+}
+
+/*
+ * Given a skiplist node, returns a pointer to the next skiplist node.
+ */
+struct skiplist_node *
+skiplist_next(struct skiplist_node* node)
+{
+    return node ? node->forward[0] : NULL;
+}
+
+/*
+ * Destroys the skiplist, and frees all the skiplist nodes, but NOT the data
+ * stored.
+ */
+void
+skiplist_destroy(struct skiplist* sl)
+{
+    struct skiplist_node *node, *next;
+    next = node = sl->header;
+    while(next != NULL){
+        next = node->forward[0];
+        if(sl->free_func) {
+            sl->free_func((void *)node->data);
+        }
+        free(node);
+        node = next;
+    }
+    free(sl);
+}
diff --git a/lib/skiplist.h b/lib/skiplist.h
new file mode 100644
index 0000000..23e7e93
--- /dev/null
+++ b/lib/skiplist.h
@@ -0,0 +1,53 @@
+/* Copyright (C) 2016 Hewlett Packard Enterprise Development LP
+ * All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef LIB_SKIPLIST_H_
+#define LIB_SKIPLIST_H_
+
+#include<stdbool.h>
+#include<stdint.h>
+#include<stdlib.h>
+
+/*
+ * Skiplist comparison function. Allows to store sorted data.
+ */
+typedef int
+(*skiplist_comparator)(const void *a, const void *b, const void* conf);
+
+struct skiplist_node;
+
+struct skiplist;
+
+#define SKIPLIST_FOR_EACH(SKIPLIST_NODE, SKIPLIST) \
+    for(SKIPLIST_NODE = skiplist_first(SKIPLIST); \
+        SKIPLIST_NODE; \
+        SKIPLIST_NODE = skiplist_next(SKIPLIST_NODE))
+
+struct skiplist* skiplist_create(int max_levels,
+                                 skiplist_comparator object_comparator,
+                                 void * configuration);
+void skiplist_set_free_func(struct skiplist* sl, void (*func)(void *));
+void skiplist_insert(struct skiplist* sl, const void *object);
+void *skiplist_delete(struct skiplist* sl, const void *object);
+struct skiplist_node* skiplist_find(struct skiplist* sl, const void *value);
+void * skiplist_get_data(struct skiplist_node *node);
+int64_t skiplist_get_size(struct skiplist* sl);
+struct skiplist_node* skiplist_forward_to(struct skiplist* sl, const void 
*value);
+struct skiplist_node * skiplist_first(struct skiplist* sl);
+struct skiplist_node * skiplist_next(struct skiplist_node* node);
+void skiplist_destroy(struct skiplist* sl);
+
+#endif /* LIB_SKIPLIST_H_ */
--
1.9.1
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to