added auto-reclaim of zero indexes
[rrq/rrqmisc.git] / vector / vector.c
index a9c6b63f87e787ec10c90247caf349a3dfee2b17..2f1010c841791c0d66ed420e197023a238057540 100644 (file)
@@ -44,7 +44,7 @@ unsigned long VECTOR_INDEX_PART(vector *pv,vector_index *index, int level) {
        return pp->a;
     }
     case 1: {
-       nibble *pp = (nibble*)(px + ( level / 2 ));
+       nibble *pp = (nibble*)( px + ( level / 2 ) );
        switch ( level & 1 ) {
        case 0: return pp->a;
        case 1: return pp->b;
@@ -52,7 +52,7 @@ unsigned long VECTOR_INDEX_PART(vector *pv,vector_index *index, int level) {
        break;
     }
     case 2: {
-       bitpair *pp = (bitpair*)(px + ( level / 4 ));
+       bitpair *pp = (bitpair*)( px + ( level / 4 ) );
        switch ( level & 3 ) {
        case 0: return pp->a;
        case 1: return pp->b;
@@ -90,7 +90,7 @@ static unsigned long VECTOR_INDEX_PART_INC(
     }
     case 2: {
        bitpair *pp = (bitpair*)( px + level / 4 );
-       switch ( level & 0xf ) {
+       switch ( level & 3 ) {
        case 0: return ++(pp->a);
        case 1: return ++(pp->b);
        case 2: return ++(pp->c);
@@ -143,14 +143,21 @@ 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 );
 }
 
 // Set index to last value for all index parts at level and lower.
 static void VECTOR_INDEX_LAST(vector *pv,vector_index *index, int level) {
-    (*index) |= ONES >> ( 64 - VECTOR_BITS[ pv->variant ] * level );
+    static unsigned long ones[] = { 255, 15, 3 };
+    unsigned long x = ones[ pv->variant ];
+    while ( level-- ) {
+       (*index) |= x;
+       x <<= VECTOR_BITS[ pv->variant ];
+    }
+    // 255, 25, 3
+    //(*index) |= ONES >> ( 64 - ( VECTOR_BITS[ pv->variant ] * level ) );
 }
 
 // Return number of slots for a vector variant.
@@ -187,29 +194,41 @@ 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 );
+               VECTOR_INDEX_FIRST( pv, index, level - 1 );
            }
        }
        if ( VECTOR_INDEX_PART_INC( pv, index, level ) == 0 ) {
@@ -228,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
        }
-       return slot;
+       if ( *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.
@@ -249,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 );
@@ -287,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
        }
@@ -297,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;
@@ -604,14 +607,11 @@ void vector_iterate(vector *pv,
 {
     vector_index index = start;
     while ( index < pv->size ) {
-       void **slot = vector_next_used( pv, &index );
-       if ( slot == 0 ) {
-           break;
-       }
        int end = VECTOR_SLOTS( pv );
        int i = index & ( end - 1 );
-       for ( ; i < end && index < pv->size; i++, index++, slot++ ) {
-           if ( itemfn( index, *slot, data ) ) {
+       for ( ; i < end && index < pv->size; i++, index++ ) {
+           void **slot = vector_access( pv, index, 0, 0 );
+           if ( itemfn( index, slot? *slot: 0, data ) ) {
                return;
            }
        }