Use enum for variants; add "clone" and "find" and imporv doco
[rrq/rrqmisc.git] / vector / vector.c
index a9c6b63f87e787ec10c90247caf349a3dfee2b17..16d5577f19a44e17977229aa16cb6882b1bb196e 100644 (file)
@@ -39,20 +39,20 @@ typedef struct {
 unsigned long VECTOR_INDEX_PART(vector *pv,vector_index *index, int level) {
     unsigned char *px = (unsigned char *) index;
     switch ( pv->variant ) {
-    case 0: {
+    case byte_index_levels: {
        byte *pp = (byte*)(px + level);
        return pp->a;
     }
-    case 1: {
-       nibble *pp = (nibble*)(px + ( level / 2 ));
+    case nibble_index_levels: {
+       nibble *pp = (nibble*)( px + ( level / 2 ) );
        switch ( level & 1 ) {
        case 0: return pp->a;
        case 1: return pp->b;
        }
        break;
     }
-    case 2: {
-       bitpair *pp = (bitpair*)(px + ( level / 4 ));
+    case bitpair_index_levels: {
+       bitpair *pp = (bitpair*)( px + ( level / 4 ) );
        switch ( level & 3 ) {
        case 0: return pp->a;
        case 1: return pp->b;
@@ -61,7 +61,7 @@ unsigned long VECTOR_INDEX_PART(vector *pv,vector_index *index, int level) {
        }
        break;
     }
-    case 3:
+    case single_index_level:
        return (*index);
     }
     return 0;
@@ -76,11 +76,11 @@ static unsigned long VECTOR_INDEX_PART_INC(
 {
     unsigned char *px = (unsigned char *) index;
     switch ( pv->variant ) {
-    case 0: {
+    case byte_index_levels: {
        byte *pp = (byte*)( px + level );
        return ++(pp->a);
     }
-    case 1: {
+    case nibble_index_levels: {
        nibble *pp = (nibble*)( px + ( level / 2 ) );
        switch ( level & 1 ) {
        case 0: return ++(pp->a);
@@ -88,9 +88,9 @@ static unsigned long VECTOR_INDEX_PART_INC(
        }
        break;
     }
-    case 2: {
+    case bitpair_index_levels: {
        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);
@@ -98,7 +98,7 @@ static unsigned long VECTOR_INDEX_PART_INC(
        }
        break;
     }
-    case 3:
+    case single_index_level:
        return ++(*index);
     }
     return 0;
@@ -113,11 +113,11 @@ static unsigned long VECTOR_INDEX_PART_DEC(
 {
     unsigned char *px = (unsigned char *) index;
     switch ( pv->variant ) {
-    case 0: {
+    case byte_index_levels: {
        byte *pp = (byte*)( px + level );
        return (pp->a)--;
     }
-    case 1: {
+    case nibble_index_levels: {
        nibble *pp = (nibble*)( px + ( level / 2 ) );
        switch ( level & 1 ) {
        case 0: return (pp->a)--;
@@ -125,7 +125,7 @@ static unsigned long VECTOR_INDEX_PART_DEC(
        }
        break;
     }
-    case 2: {
+    case bitpair_index_levels: {
        bitpair *pp = (bitpair*)( px + level / 4 );
        switch ( level & 0xf ) {
        case 0: return (pp->a)--;
@@ -135,7 +135,7 @@ static unsigned long VECTOR_INDEX_PART_DEC(
        }
        break;
     }
-    case 3:
+    case single_index_level:
        return (*index)--;
     }
     return 0;
@@ -143,23 +143,30 @@ 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.
 unsigned long VECTOR_SLOTS(vector *pv) {
     switch ( pv->variant ) {
-    case 0: return 256;
-    case 1: return 16;
-    case 2: return 4;
-    case 3: return pv->size;
+    case byte_index_levels: return 256;
+    case nibble_index_levels: return 16;
+    case bitpair_index_levels: return 4;
+    case single_index_level: return pv->size;
     }
     return 0;
 }
@@ -170,10 +177,10 @@ static unsigned int vector_levels(vector *pv,unsigned int size) {
        return 1;
     }
     switch ( pv->variant ) {
-    case 0: return ((int)(log2( size - 1 ) / 8)) + 1;
-    case 1: return ((int)(log2( size - 1 ) / 4)) + 1;
-    case 2: return ((int)(log2( size - 1 ) / 2)) + 1;
-    case 3: return 1;
+    case byte_index_levels: return ((int)(log2( size - 1 ) / 8)) + 1;
+    case nibble_index_levels: return ((int)(log2( size - 1 ) / 4)) + 1;
+    case bitpair_index_levels: return ((int)(log2( size - 1 ) / 2)) + 1;
+    case single_index_level: return 1;
     }
     return 0;
 }
@@ -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
+       }
+       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.
@@ -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;
@@ -393,7 +396,8 @@ int vector_resize(
        // At this point we know that there are no slots used after
        // the new_size size, so now it's time to remove and reclaim
        // any superflouous top level pages.
-       if ( pv->variant == 3 ) { // Follow vector size using realloc
+       if ( pv->variant == single_index_level ) {
+           // Follow vector size using realloc
            if ( new_size > 0 ) {
                entries = (vector_page*)
                    realloc( pv->entries, new_size * sizeof( void* ) );
@@ -427,7 +431,8 @@ int vector_resize(
        }
     } else {
        // vector is growing. Maybe insert levels.
-       if ( pv->variant == 3 ) { // Follow vector size using realloc
+       if ( pv->variant == single_index_level ) {
+           // Follow vector size using realloc
            entries = (vector_page *)realloc(
                pv->entries, new_size * sizeof( void* ) );
            if ( entries == 0 ) {
@@ -526,6 +531,14 @@ void vector_copy(vector *dst,vector_index di,
     }
 }
 
+vector *vector_clone(enum vector_variant variant,vector *src) {
+    vector *dst = (vector*) malloc( sizeof( vector ) );
+    (*dst) = (vector) { .variant = variant, .size = 0, .entries = 0 };
+    vector_resize( dst, src->size, 0, 0 );
+    vector_copy( dst, 0, src, 0, src->size );
+    return dst;
+}
+
 void vector_dump(vector *pv,
                 void (*itemdump)(const vector_index,const void *)) {
     vector_index index = 0;
@@ -604,20 +617,40 @@ 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;
            }
        }
     }
 }
 
+struct find_data {
+    void *value;
+    vector_index index;
+};
+
+static int vector_find_item(vector_index index, void *item,void *data) {
+    struct find_data *fd = (struct find_data*)data;
+    if ( fd->value != item ) {
+       return 0;
+    }
+    fd->index = index;
+    return 1;
+}
+
+vector_index vector_find(vector *pv,void *value) {
+    struct find_data fd = {
+       .value = value,
+       .index = pv->size
+    };
+    vector_iterate( pv, 0, vector_find_item, &fd );
+    return fd.index;
+}
+
 // Find surrounding indexes for a given item key in a sparse vector
 void *vector_bsearch(vector *pv,vector_index *index,const void *key,
                     int (*compare)(const void *key, const void *item)) {