]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Add some comments describing the various kinds of magic going on in the
authorJeremy Fitzhardinge <jeremy@valgrind.org>
Wed, 30 Jun 2004 01:27:06 +0000 (01:27 +0000)
committerJeremy Fitzhardinge <jeremy@valgrind.org>
Wed, 30 Jun 2004 01:27:06 +0000 (01:27 +0000)
skiplist implementation.  Also, fix a bug which allocated way too much memory
for the list head (found by Nick).

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@2451

coregrind/vg_skiplist.c

index 922ce762b38327e364f0a2d3288603d50abf8191..350f53c1756133c5a920a617cce75335aaec8ff5 100644 (file)
    The GNU General Public License is contained in the file COPYING.
 */
 
+/* 
+   This file implements a generic skip-list type.
+
+   Skip-lists are described in William Pugh, Skip Lists: A
+   Probabilistic Alternative to Balanced Trees, CACM, 33(6):668-676,
+   June 1990. 
+   http://www.cs.unc.edu/~baruah/Teaching/2002f/HandOuts/skiplist-CACM.pdf
+
+   Skip-lists are a randomized linked-list, where a node in the list
+   has at least one "next" pointer, but may have more.  When
+   traversing the list, the "higher" next pointers allow you to skip
+   multiple list entries, allowing you to find the right place
+   quickly.  
+
+   On average, 1/2 the entries have one next pointer, 1/4 have 2, 1/8
+   have 3, etc.  This means that the skiplist has the same search
+   complexity as a balanced binary tree, but there is no need to
+   rebalance or do any other structural changes.  The randomness also
+   means that it is invulnerable to pathalogical workloads.
+
+   Because the each node can be a different size, this implementation
+   puts the SkipNode structure at the end of the allocation, with the
+   node data starting at the beginning.
+
+   low address ->+---------------+  ^
+                | list data     |  |
+     key offset->:       key     : structure size
+                |               |  |
+                +---------------+  V
+                | struct        |
+                |   SkipNode    |
+                +- - - - - - - -+
+                | next pointers |
+                :               :
+
+
+   When you declare the list with SKIPLIST_INIT, you specify the
+   structure for each list node, structure member you want to use as a
+   key, and the function for comparing keys.
+
+   Each node must be allocated with SkipNode_Alloc, which allocates
+   enough space for the client data, the SkipNode structure, and the
+   next pointers for this node.
+
+   The helper functions data_of_node and node_of_data do the correct
+   pointer arithmetic to sort all this out.  The SkipNode also has a
+   magic number which is checked after each operation to make sure
+   that we're really operating on a SkipNode.
+
+   The first node of the list, the head node, is special.  It contains
+   the maximum number of next pointers (SK_MAXHEIGHT).  It has no data
+   associated with it, and it always compares less-than to all other
+   nodes.  Because it has no data attached to it, it is always an
+   error to try and use data_of_node on it.  To detect this problem,
+   it has a different magic number from all other SkipNodes so that it
+   won't be accidentally used.
+ */
+
 #include "vg_include.h"
 
 #include <stdlib.h>
@@ -46,7 +104,10 @@ struct _SkipNode {
 };
 
 
-
+/* 
+   Compute the height of a new node.  1/2 will be 1, 1/4 2, 1/8 3,
+   etc.
+ */
 static inline Int get_height(void)
 {
    UInt ret = 0;
@@ -57,11 +118,19 @@ static inline Int get_height(void)
    return ret;
 }
 
+/* 
+   Given a pointer to the node's data, return a pointer to the key.
+ */
 static inline void *key_of_data(const SkipList *l, void *d)
 {
    return (void *)((Char *)d + l->keyoff);
 }
 
+/* 
+   Given a pointer to the node's data, return the pointer to the SkipNode
+   structure.  If the node has a bad magic number, it will die with an
+   assertion failure.
+ */
 static inline SkipNode *node_of_data(const SkipList *l, const void *d)
 {
    SkipNode *n = (SkipNode *)((Char *)d + l->size);
@@ -75,6 +144,9 @@ static inline SkipNode *node_of_data(const SkipList *l, const void *d)
    return n; 
 }
 
+/* 
+   Given a SkipNode structure, return the pointer to the node's data.
+ */
 static inline void *data_of_node(const SkipList *l, const SkipNode *n)
 {
    if (SKIPLIST_DEBUG && n->magic != SKIPLIST_MAGIC)
@@ -85,6 +157,9 @@ static inline void *data_of_node(const SkipList *l, const SkipNode *n)
    return (void *)((Char *)n - l->size);
 }
 
+/* 
+   Given a SkipNode structure, return the pointer to the node's key.
+ */
 static inline void *key_of_node(const SkipList *l, const SkipNode *n)
 {
    return key_of_data(l, data_of_node(l, n));
@@ -285,7 +360,7 @@ void VG_(SkipList_Insert)(SkipList *l, void *data)
    validate_skiplist(l, "SkipList_Insert before");
 
    if (l->head == NULL) {
-      Int size = sizeof(SkipNode) * sizeof(SkipNode *) * SK_MAXHEIGHT;
+      Int size = sizeof(SkipNode) + sizeof(SkipNode *) * SK_MAXHEIGHT;
 
       if (l->arena == -1)
         *(Short *)&l->arena = VG_AR_TOOL;