7 * Representing a vector of void* accessible via an indexing structure
8 * as levels of same-size pages. A "vector_page" is a contiguous array
9 * void*, and an index is "unsigned long" (64 bits).
12 /** ============================================================ **/
14 static int VECTOR_BITS[4] = { 8, 4, 2, 64 };
33 * Return the index part for the given level of the vector's leveling
36 * The vector variant indicates whether indexing uses 8, 4, or 2 bits
39 unsigned long VECTOR_INDEX_PART(vector *pv,vector_index *index, int level) {
40 unsigned char *px = (unsigned char *) index;
41 switch ( pv->variant ) {
43 byte *pp = (byte*)(px + level);
47 nibble *pp = (nibble*)( px + ( level / 2 ) );
48 switch ( level & 1 ) {
55 bitpair *pp = (bitpair*)( px + ( level / 4 ) );
56 switch ( level & 3 ) {
71 * Increment the index part at the indivated level, cyclic but not
72 * carrying over to the upper level. Returns the new level index.
74 static unsigned long VECTOR_INDEX_PART_INC(
75 vector *pv,vector_index *index, int level)
77 unsigned char *px = (unsigned char *) index;
78 switch ( pv->variant ) {
80 byte *pp = (byte*)( px + level );
84 nibble *pp = (nibble*)( px + ( level / 2 ) );
85 switch ( level & 1 ) {
86 case 0: return ++(pp->a);
87 case 1: return ++(pp->b);
92 bitpair *pp = (bitpair*)( px + level / 4 );
93 switch ( level & 3 ) {
94 case 0: return ++(pp->a);
95 case 1: return ++(pp->b);
96 case 2: return ++(pp->c);
97 case 3: return ++(pp->d);
108 * Decrement the index part at the indicated level, cyclic but not
109 * carrying over to the upper level. Returns the prior level index.
111 static unsigned long VECTOR_INDEX_PART_DEC(
112 vector *pv,vector_index *index, int level)
114 unsigned char *px = (unsigned char *) index;
115 switch ( pv->variant ) {
117 byte *pp = (byte*)( px + level );
121 nibble *pp = (nibble*)( px + ( level / 2 ) );
122 switch ( level & 1 ) {
123 case 0: return (pp->a)--;
124 case 1: return (pp->b)--;
129 bitpair *pp = (bitpair*)( px + level / 4 );
130 switch ( level & 0xf ) {
131 case 0: return (pp->a)--;
132 case 1: return (pp->b)--;
133 case 2: return (pp->c)--;
134 case 3: return (pp->d)--;
144 #define ONES (~((vector_index) 0))
146 // Set index to last value for all index parts at level and lower.
147 static void VECTOR_INDEX_FIRST(vector *pv,vector_index *index, int level) {
148 (*index) &= ONES << ( VECTOR_BITS[ pv->variant ] * level );
151 // Set index to last value for all index parts at level and lower.
152 static void VECTOR_INDEX_LAST(vector *pv,vector_index *index, int level) {
153 static unsigned long ones[] = { 255, 15, 3 };
154 unsigned long x = ones[ pv->variant ];
157 x <<= VECTOR_BITS[ pv->variant ];
160 //(*index) |= ONES >> ( 64 - ( VECTOR_BITS[ pv->variant ] * level ) );
163 // Return number of slots for a vector variant.
164 unsigned long VECTOR_SLOTS(vector *pv) {
165 switch ( pv->variant ) {
169 case 3: return pv->size;
174 // The number of levels to span vector pv wrt its size and variant
175 static unsigned int vector_levels(vector *pv,unsigned int size) {
179 switch ( pv->variant ) {
180 case 0: return ((int)(log2( size - 1 ) / 8)) + 1;
181 case 1: return ((int)(log2( size - 1 ) / 4)) + 1;
182 case 2: return ((int)(log2( size - 1 ) / 2)) + 1;
188 /** ============================================================ **/
191 * Advances a vector index to the next used slot at or below the
192 * given level, starting from the indexed entry (inclusive) and up.
193 * The function will free any empty pages it discovers, and then
194 * update the index slots accordingly. The given index is advanced
195 * cyclically to match the found slot. The function returns a slot
196 * pointer to the used slot, if any, and 0 otherwise.
198 static void **vector_level_next_used(
205 void **p = (void**)&(*page)[ VECTOR_INDEX_PART( pv, index, level ) ];
206 for( ; *index < end; p++ ) {
209 return p; // This is a used entry
211 // *p is an index that needs to be inspected recursively
212 void **x = vector_level_next_used( pv, *p, index, level - 1, end );
214 return x; // Used slot was found; return it.
216 // If the page *p is all empty, so can/should be reclaimed.
219 VECTOR_INDEX_FIRST( pv, index, level - 1 );
222 if ( VECTOR_INDEX_PART_INC( pv, index, level ) == 0 ) {
223 break; // cycling this level => nothing found
229 // Find the next used slot at given index or later. Returns pointer to
230 // the slot. This allows for a reclaim function that may reclaim slot
231 // items on the way to next used slot.
232 void **vector_next_used(vector *pv,vector_index *index) {
233 if ( pv->entries == 0 || *index >= pv->size ) {
237 int levels = vector_levels( pv, pv->size );
238 for ( ; *index < pv->size; (*index)++ ) {
239 void **slot = vector_level_next_used(
240 pv, pv->entries, index, levels - 1, pv->size ) ;
242 *index = pv->size; // reached the end of the vector
243 } else if ( *slot == 0 ) {
253 * Advances a vector index to the prior used slot at or below the
254 * given level, starting from the indexed entry (inclusive) and down.
255 * The function will free any empty pages it discovers, and then
256 * update the index slots accordingly. The given index is advanced
257 * cyclically to match the found slot. The function returns a slot
258 * pointer to the used slot, if any, and 0 otherwise.
260 static void **vector_level_prev_used(
266 void **p = (void**)&(*page)[ VECTOR_INDEX_PART( pv, index, level ) ];
270 return p; // This is a used entry
272 // *p is an index that needs to be inspected recursively
273 void **x = vector_level_prev_used( pv, *p, index, level - 1 );
275 return x; // Used slot was found; return it.
277 // If the page *p is all empty, so can/should be reclaimed.
280 VECTOR_INDEX_LAST( pv, index, level );
284 } while ( VECTOR_INDEX_PART_DEC( pv, index, level ) != 0 );
288 // Find the next used slot at given index or later. Returns pointer to
289 // the slot. This allows for a reclaim function that may reclaim slot
290 // items on the way to next used slot.
291 void **vector_prev_used(vector *pv,vector_index *index) {
292 if ( pv->entries == 0 || *index >= pv->size ) {
296 int levels = vector_levels( pv, pv->size );
298 void **slot = vector_level_prev_used(
299 pv, pv->entries, index, levels - 1 ) ;
301 break; // reached the end of the vector
306 } while ( (*index)-- != 0 );
314 // Find the first in-use slot at or before the index, at the level
315 static void **vector_prev_used_level(vector *pv,vector_index *index,int lv) {
316 void **slot = vector_access( pv, *index, lv, 0 );
325 void **sub = vector_prev_used_level( pv, index, lv - 1 );
331 } while ( VECTOR_INDEX_PART_DEC( pv, index, lv ) != 0 );
335 // Find nearest used slot at or prior to the given index.
336 void **vector_prev_used(vector *pv,vector_index *index) {
337 if ( pv->entries == 0 || *index >= pv->size ) {
341 void **slot = vector_prev_used_level(
342 pv, index, vector_levels( pv, pv->size ) - 1 );
350 // Reclaim tree of unused pages for a given level
351 static void vector_reclaim(vector *pv,vector_page *page,unsigned int level) {
354 for ( ; i < VECTOR_SLOTS( pv ); i++ ) {
356 vector_reclaim( pv, (vector_page *) (*page)[i], level - 1 );
363 // Resize vector, using the reclaim function as needed, to handle any
364 // excess items or to veto the resize. Returns the index of the veto,
365 // if any, or <0 otherwise, with -1 indicating success and -2
368 // Note that resizing may result in the introduction/removal of
369 // indexing levels and pages, so as to keep the leveling accurate for
372 vector *pv,vector_index new_size,
373 int (*reclaim)(vector *pv,vector_index index,void *item,void *data),
380 vector_levels( pv, pv->size ),
381 vector_levels( pv, new_size )
383 vector_page *entries = 0;
384 if ( pv->entries == 0 ) {
388 // A shrinking vector might be veto-ed
389 if ( new_size < pv->size ) {
390 vector_index index = new_size;
391 void **slot = vector_next_used( pv, &index );
393 if ( *slot && reclaim && reclaim( pv, index, *slot, data ) == 0 ) {
395 slot = vector_next_used( pv, &index );
400 // At this point we know that there are no slots used after
401 // the new_size size, so now it's time to remove and reclaim
402 // any superflouous top level pages.
403 if ( pv->variant == 3 ) { // Follow vector size using realloc
404 if ( new_size > 0 ) {
405 entries = (vector_page*)
406 realloc( pv->entries, new_size * sizeof( void* ) );
407 if ( entries == 0 ) {
411 pv->entries = entries;
413 vector_page **pp = &pv->entries;
415 while ( i-- > level.new ) {
417 pp = (vector_page **)(*pp);
420 if ( pp != &pv->entries ) {
421 entries = pv->entries;
424 *pp = 0; // Detach subtree
428 vector_reclaim( pv, entries, level.old - 1 );
430 if ( new_size == 0 && pv->entries ) {
436 // vector is growing. Maybe insert levels.
437 if ( pv->variant == 3 ) { // Follow vector size using realloc
438 entries = (vector_page *)realloc(
439 pv->entries, new_size * sizeof( void* ) );
440 if ( entries == 0 ) {
443 pv->entries = entries;
444 memset( &(*entries)[ pv->size ], 0,
445 ( new_size - pv->size ) * sizeof( void* ) );
447 for ( ; level.old < level.new; level.old++ ) {
448 vector_page *p = (vector_page *)
449 calloc( VECTOR_SLOTS( pv ), sizeof( void* ) );
453 (*p)[0] = pv->entries;
455 // Should maybe change the size to match the level?
456 // otherwise recovery from OOM is impossible
464 // Return pointer to the indexed page slot at the requested level, and
465 // adding intermediate index pages if so requested. Returns 0 if
466 // addition fails (OOM), or if not requested and page is missing.
467 void **vector_access(vector *pv,vector_index index,int level,int add) {
468 if ( index >= pv->size ) {
471 void **page = (void**) &pv->entries;
472 int i = vector_levels( pv, pv->size );
473 while ( i-- > level ) {
474 if ( add && (*page) == 0 ) {
475 (*page) = calloc( VECTOR_SLOTS( pv ), sizeof( void* ) );
481 page += VECTOR_INDEX_PART( pv, &index, i );
486 // Map index into a value slot
487 void **vector_entry(vector *pv,vector_index index) {
488 return vector_access( pv, index, 0, 1 );
491 inline void vector_set(vector *pv,vector_index index,void *value) {
492 void **p = vector_entry( pv, index );
496 // Set value at index but return the old value
497 void *vector_get_set(vector *pv,vector_index index,void *value) {
498 void **p = vector_entry( pv, index );
504 inline void *vector_get(vector *pv,vector_index index) {
505 void **p = vector_entry( pv, index );
509 int vector_reclaim_any(vector *pv,vector_index ix,void *item,void *data) {
514 void vector_append(vector *pv,void *value) {
515 vector_resize( pv, pv->size + 1, 0, 0 );
516 vector_set( pv, pv->size - 1, value );
519 // copy block of n items from src[si] to dst[di]
520 // no efficiency hacks
521 void vector_copy(vector *dst,vector_index di,
522 vector *src,vector_index si,vector_index n) {
523 if ( dst != src || di < si ) {
525 vector_set( dst, di++, vector_get( src, si++ ) );
527 } else if ( di > si ){
531 vector_set( dst, di--, vector_get( src, si-- ) );
536 void vector_dump(vector *pv,
537 void (*itemdump)(const vector_index,const void *)) {
538 vector_index index = 0;
539 for ( ; index < pv->size; index++ ) {
540 void **slot = vector_next_used( pv, &index );
544 itemdump( index, *slot );
550 // Returns 1 for "in order", 0 for equal, and -1 for "wrong order"
551 typedef int (*comparfn)(const void *,const void *);
553 static void vector_qsort_part(
554 vector *pv,comparfn compar,
555 vector_index low,vector_index high)
560 vector_index lo = low;
561 vector_index m = high - 1;
567 vector_index hi = m - 1;
568 void **mp = vector_entry( pv, m );
571 // Find index of first item "above" mp scanning from lo and up
572 for ( ; lo < m; lo++ ) {
573 lop = vector_entry( pv, lo );
574 if ( compar( *lop, *mp ) < 0 ) {
578 // if lo == m, then lop is wrong!!
579 // Find index of first item "below" mp scanning from hi and down
580 for ( ; hi > lo; hi-- ) {
581 hip = vector_entry( pv, hi );
582 if ( compar( *mp, *hip ) < 0 ) {
599 vector_qsort_part( pv, compar, low, m );
600 vector_qsort_part( pv, compar, m+1, high );
603 void vector_qsort(vector *pv,comparfn compar) {
604 vector_qsort_part( pv, compar, 0, pv->size );
607 void vector_iterate(vector *pv,
609 int (*itemfn)(vector_index,void*,void*),
612 vector_index index = start;
613 while ( index < pv->size ) {
614 int end = VECTOR_SLOTS( pv );
615 int i = index & ( end - 1 );
616 for ( ; i < end && index < pv->size; i++, index++ ) {
617 void **slot = vector_access( pv, index, 0, 0 );
618 if ( slot && itemfn( index, *slot, data ) ) {
625 // Find surrounding indexes for a given item key in a sparse vector
626 void *vector_bsearch(vector *pv,vector_index *index,const void *key,
627 int (*compare)(const void *key, const void *item)) {
629 vector_index hi = pv->size;
630 if ( hi-- == 0 || vector_prev_used( pv, &hi ) == 0 ) {
635 vector_index m = lo + ( hi - lo ) / 2;
636 void **slot = vector_next_used( pv, &m );
637 int c = compare( key, *slot );
651 // Iterator callback.
652 static int checkunused(vector_index index,void *item,void *data) {
653 vector_index *last = (vector_index*) data;
658 if ( *last > index ) {
659 // Only on the first iteration, with *last = vector_sie
665 } else if ( index == (*last) ) {
672 // Scan forward for the next unused vector slot
673 vector_index vector_next_unused(vector *pv,vector_index index) {
674 vector_index unused = vector_size( pv );
675 vector_iterate( pv, index, checkunused, &unused );