Commit 0f55d808bac6e555da289248fe06150064920c0b

Thomas de Grivel 2024-03-03T18:10:14

fix skiplist random height

diff --git a/libc3/skiplist.c.in b/libc3/skiplist.c.in
index 4559713..9c3b9e7 100644
--- a/libc3/skiplist.c.in
+++ b/libc3/skiplist.c.in
@@ -94,32 +94,35 @@ skiplist_find___NAME$ (s_skiplist___NAME$ *skiplist, _TYPE$ _NAME$)
   return NULL;
 }
 
-static void skiplist_height_table_init___NAME$ (s_skiplist___NAME$ *skiplist, f64 spacing)
+static s_skiplist___NAME$ *
+skiplist_height_table_init___NAME$ (s_skiplist___NAME$ *skiplist, f64 spacing)
 {
   t_skiplist_height *height_table;
   u8 h;
-  f64 w = spacing;
-  f64 end = w;
+  f128 w = spacing;
+  f128 end = w;
   height_table = SKIPLIST_HEIGHT_TABLE___NAME$(skiplist);
   for (h = 0; h < skiplist->max_height; h++) {
     w *= spacing;
     end += w;
-    assert(end <= (f64) SKIPLIST_HEIGHT_MAX);
+    if (end > (f128) SKIPLIST_HEIGHT_MAX)
+      return NULL;
     height_table[h] = end;
   }
+  return skiplist;
 }
 
 s_skiplist___NAME$ *
 skiplist_init___NAME$ (s_skiplist___NAME$ *skiplist, u8 max_height, f64 spacing)
 {
   assert(skiplist);
+  skiplist->max_height = max_height;
+  skiplist_height_table_init___NAME$(skiplist, spacing);
   skiplist->head = skiplist_node_new___NAME$(NULL, max_height);
   if (! skiplist->head)
     return NULL;
   skiplist->compare = compare__NAME$;
   skiplist->length = 0;
-  skiplist->max_height = max_height;
-  skiplist_height_table_init___NAME$(skiplist, spacing);
   return skiplist;
 }
 
@@ -183,19 +186,22 @@ skiplist_pred___NAME$ (s_skiplist___NAME$ *skiplist, _TYPE$ _NAME$)
 u8
 skiplist_random_height___NAME$ (s_skiplist___NAME$ *skiplist)
 {
-  u8 height;
+  u16 height;
   const t_skiplist_height *height_table;
   sw i;
-  u32 j;
+  u64 j;
   sw max;
   t_skiplist_height k;
   assert(skiplist);
+  assert(skiplist->max_height);
   height_table = SKIPLIST_HEIGHT_TABLE___NAME$(skiplist);
   max = height_table[skiplist->max_height - 1];
-  u32_random_uniform(&j, max);
+  u64_random_uniform(&j, max);
   k = j;
-  for (i = 0; i < skiplist->max_height && k > height_table[i]; i++)
-    ;
+  i = 0;
+  while (i < skiplist->max_height - 1 &&
+         k > height_table[i])
+    i++;
   height = skiplist->max_height - i;
   assert(height);
   return height;
diff --git a/libc3/skiplist__fact.c b/libc3/skiplist__fact.c
index 706bfeb..28549da 100644
--- a/libc3/skiplist__fact.c
+++ b/libc3/skiplist__fact.c
@@ -94,32 +94,35 @@ skiplist_find__fact (s_skiplist__fact *skiplist, s_fact * fact)
   return NULL;
 }
 
-static void skiplist_height_table_init__fact (s_skiplist__fact *skiplist, f64 spacing)
+static s_skiplist__fact *
+skiplist_height_table_init__fact (s_skiplist__fact *skiplist, f64 spacing)
 {
   t_skiplist_height *height_table;
   u8 h;
-  f64 w = spacing;
-  f64 end = w;
+  f128 w = spacing;
+  f128 end = w;
   height_table = SKIPLIST_HEIGHT_TABLE__fact(skiplist);
   for (h = 0; h < skiplist->max_height; h++) {
     w *= spacing;
     end += w;
-    assert(end <= (f64) SKIPLIST_HEIGHT_MAX);
+    if (end > (f128) SKIPLIST_HEIGHT_MAX)
+      return NULL;
     height_table[h] = end;
   }
+  return skiplist;
 }
 
 s_skiplist__fact *
 skiplist_init__fact (s_skiplist__fact *skiplist, u8 max_height, f64 spacing)
 {
   assert(skiplist);
+  skiplist->max_height = max_height;
+  skiplist_height_table_init__fact(skiplist, spacing);
   skiplist->head = skiplist_node_new__fact(NULL, max_height);
   if (! skiplist->head)
     return NULL;
   skiplist->compare = compare_fact;
   skiplist->length = 0;
-  skiplist->max_height = max_height;
-  skiplist_height_table_init__fact(skiplist, spacing);
   return skiplist;
 }
 
@@ -183,19 +186,22 @@ skiplist_pred__fact (s_skiplist__fact *skiplist, s_fact * fact)
 u8
 skiplist_random_height__fact (s_skiplist__fact *skiplist)
 {
-  u8 height;
+  u16 height;
   const t_skiplist_height *height_table;
   sw i;
-  u32 j;
+  u64 j;
   sw max;
   t_skiplist_height k;
   assert(skiplist);
+  assert(skiplist->max_height);
   height_table = SKIPLIST_HEIGHT_TABLE__fact(skiplist);
   max = height_table[skiplist->max_height - 1];
-  u32_random_uniform(&j, max);
+  u64_random_uniform(&j, max);
   k = j;
-  for (i = 0; i < skiplist->max_height && k > height_table[i]; i++)
-    ;
+  i = 0;
+  while (i < skiplist->max_height - 1 &&
+         k > height_table[i])
+    i++;
   height = skiplist->max_height - i;
   assert(height);
   return height;