added auto-reclaim of zero indexes
authorRalph Ronnquist <ralph.ronnquist@gmail.com>
Fri, 1 Jul 2022 11:07:50 +0000 (21:07 +1000)
committerRalph Ronnquist <ralph.ronnquist@gmail.com>
Fri, 1 Jul 2022 11:07:50 +0000 (21:07 +1000)
tests/vectortests.c
vector/vector.c

index f85f7ccf8dd7940e25180f686ecc0f07bfc70796..6f8cdbd9205ade136d243b8e940a263b208c0286 100644 (file)
@@ -6,12 +6,7 @@
 #include <string.h>
 #include <vector.h>
 
-static int LINE;
-
-#define max(a,b) ((a>b)?a:b)
-#define OUT(...) {                                               \
-       fprintf( stderr, __VA_ARGS__ );                           \
-}
+#define OUT(...) fprintf( stderr, __VA_ARGS__ )
 
 // dump an item; return 0 to stop
 static void itemdump(const vector_index index,const void *slot) {
index 6f44a6425e1f3f89ba1f5fad1c4cafd971e09e07..2f1010c841791c0d66ed420e197023a238057540 100644 (file)
@@ -143,7 +143,7 @@ static unsigned long VECTOR_INDEX_PART_DEC(
 
 #define ONES  (~((vector_index) 0))
 
-// Set index to last value for all index parts at level and lower.
+// Set index to first value for all index parts at level and lower.
 static void VECTOR_INDEX_FIRST(vector *pv,vector_index *index, int level) {
     (*index) &= ONES << ( VECTOR_BITS[ pv->variant ] * level );
 }
@@ -194,26 +194,38 @@ static unsigned int vector_levels(vector *pv,unsigned int size) {
  * update the index slots accordingly. The given index is advanced
  * cyclically to match the found slot. The function returns a slot
  * pointer to the used slot, if any, and 0 otherwise.
+ * The last parameter is a flag that gets set when the scanning is
+ * partial (i.e. not the whole index page).
  */
 static void **vector_level_next_used(
     vector *pv,
     vector_page *page,
     vector_index *index,
     int level,
-    vector_index end )
+    int *partial )
 {
     void **p = (void**)&(*page)[ VECTOR_INDEX_PART( pv, index, level ) ];
-    for( ; *index < end; p++ ) {
+    if ( VECTOR_INDEX_PART( pv, index, level ) != 0 ) {
+       *partial = 1;
+    }
+    for( ; *index < pv->size; p++ ) {
        if ( *p ) {
            if ( level == 0 ) {
                return p; // This is a used entry
            }
            // *p is an index that needs to be inspected recursively
-           void **x = vector_level_next_used( pv, *p, index, level - 1, end );
+           int w = 0;
+           void **x = vector_level_next_used( pv, *p, index, level - 1, &w );
            if ( x ) {
                return x; // Used slot was found; return it.
            }
            // If the page *p is all empty, so can/should be reclaimed.
+           if ( w == 0 ) {
+               free( *p );
+               *p = 0;
+           } else {
+               *partial = 1;
+           }
        } else {
            if ( level > 0 ) {
                VECTOR_INDEX_FIRST( pv, index, level - 1 );
@@ -235,20 +247,25 @@ void **vector_next_used(vector *pv,vector_index *index) {
        return 0;
     }
     int levels = vector_levels( pv, pv->size );
-    for ( ; *index < pv->size; (*index)++ ) {
+    int partial = 0;
+    do {
        void **slot = vector_level_next_used(
-           pv, pv->entries, index, levels - 1, pv->size ) ;
+           pv, pv->entries, index, levels - 1, &partial ) ;
        if ( slot == 0 ) {
-           *index = pv->size; // reached the end of the vector
-       } else  if ( *slot == 0 ) {
-           continue;
+           break; // reached the end of the vector
+       }
+       if ( *slot ) {
+           return slot;
        }
-       return slot;
+    } while ( ++(*index) < pv->size );
+    if ( partial == 0 ) {
+       free( pv->entries );
+       pv->entries = 0;
     }
+    *index = pv->size; // reached the end of the vector
     return 0;
 }
 
-#if 1
 /**
  * Advances a vector index to the prior used slot at or below the
  * given level, starting from the indexed entry (inclusive) and down.
@@ -256,25 +273,38 @@ void **vector_next_used(vector *pv,vector_index *index) {
  * update the index slots accordingly. The given index is advanced
  * cyclically to match the found slot. The function returns a slot
  * pointer to the used slot, if any, and 0 otherwise.
+ * The last parameter is a flag that gets set when the scanning is
+ * partial (i.e. not the whole index page).
  */
 static void **vector_level_prev_used(
     vector *pv,
     vector_page *page,
     vector_index *index,
-    int level )
+    int level,
+    int *partial )
 {
     void **p = (void**)&(*page)[ VECTOR_INDEX_PART( pv, index, level ) ];
+    if ( VECTOR_INDEX_PART( pv, index, level ) != VECTOR_SLOTS( pv ) - 1 ) {
+       *partial = 1;
+    }
     do {
        if ( *p ) {
            if ( level == 0 ) {
                return p; // This is a used entry
            }
            // *p is an index that needs to be inspected recursively
-           void **x = vector_level_prev_used( pv, *p, index, level - 1 );
+           int w = 0;
+           void **x = vector_level_prev_used( pv, *p, index, level - 1, &w );
            if ( x ) {
                return x; // Used slot was found; return it.
            }
-           // If the page *p is all empty, so can/should be reclaimed.
+           // If the page *p is all empty, it can/should be reclaimed.
+           if ( w == 0 ) {
+               free( *p );
+               *p = 0;
+           } else {
+               *partial = 1;
+           }
        } else {
            if ( level > 0 ) {
                VECTOR_INDEX_LAST( pv, index, level );
@@ -294,9 +324,10 @@ void **vector_prev_used(vector *pv,vector_index *index) {
        return 0;
     }
     int levels = vector_levels( pv, pv->size );
+    int partial = 0;
     do {
        void **slot = vector_level_prev_used(
-           pv, pv->entries, index, levels - 1 ) ;
+           pv, pv->entries, index, levels - 1, &partial ) ;
        if ( slot == 0 ) {
            break; // reached the end of the vector
        }
@@ -304,49 +335,14 @@ void **vector_prev_used(vector *pv,vector_index *index) {
            return slot;
        }
     } while ( (*index)-- != 0 );
-    *index = pv->size;
-    return 0;
-}
-
-#endif
-
-#if 0
-// Find the first in-use slot at or before the index, at the level
-static void **vector_prev_used_level(vector *pv,vector_index *index,int lv) {
-    void **slot = vector_access( pv, *index, lv, 0 );
-    if ( slot == 0 ) {
-       return 0;
+    if ( partial == 0 ) {
+       free( pv->entries );
+       pv->entries = 0;
     }
-    do {
-       if ( *slot ) {
-           if ( lv == 0 ) {
-               return slot;
-           }
-           void **sub = vector_prev_used_level( pv, index, lv - 1 );
-           if ( sub ) {
-               return sub;
-           }
-       }
-       slot--;
-    } while ( VECTOR_INDEX_PART_DEC( pv, index, lv ) != 0 );
+    *index = pv->size; // reached the end of the vector
     return 0;
 }
 
-// Find nearest used slot at or prior to the given index.
-void **vector_prev_used(vector *pv,vector_index *index) {
-    if ( pv->entries == 0 || *index >= pv->size ) {
-       *index = pv->size;
-       return 0;
-    }
-    void **slot = vector_prev_used_level(
-       pv, index, vector_levels( pv, pv->size ) - 1 );
-    if ( slot == 0 ) {
-       *index = pv->size;
-    }
-    return slot;
-}
-#endif
-
 // Reclaim tree of unused pages for a given level
 static void vector_reclaim(vector *pv,vector_page *page,unsigned int level) {
     int i = 0;
@@ -615,7 +611,7 @@ void vector_iterate(vector *pv,
        int i = index & ( end - 1 );
        for ( ; i < end && index < pv->size; i++, index++ ) {
            void **slot = vector_access( pv, index, 0, 0 );
-           if ( slot && itemfn( index, *slot, data ) ) {
+           if ( itemfn( index, slot? *slot: 0, data ) ) {
                return;
            }
        }