/* ** Clear the i-th bit. ** ** pBuf must be a pointer to at least BITVEC_SZ bytes of temporary storage ** that BitvecClear can use to rebuilt its hash table. */ void sqlite3BitvecClear(Bitvec *p, u32 i, void *pBuf){ if( p==0 ) return; assert( i>0 ); i--; while( p->iDivisor ){ u32 bin = i/p->iDivisor; i = i%p->iDivisor; p = p->u.apSub[bin]; if (!p) { return; } } if( p->iSize<=BITVEC_NBIT ){ p->u.aBitmap[i/BITVEC_SZELEM] &= ~(1 << (i&(BITVEC_SZELEM-1))); }else{ unsigned int j; u32 *aiValues = pBuf; memcpy(aiValues, p->u.aHash, sizeof(p->u.aHash)); memset(p->u.aHash, 0, sizeof(p->u.aHash)); p->nSet = 0; for(j=0; j<BITVEC_NINT; j++){ if( aiValues[j] && aiValues[j]!=(i+1) ){ u32 h = BITVEC_HASH(aiValues[j]-1); p->nSet++; while( p->u.aHash[h] ){ h++; if( h>=BITVEC_NINT ) h = 0; } p->u.aHash[h] = aiValues[j]; } } } }
/* ** Set the i-th bit. Return 0 on success and an error code if ** anything goes wrong. */ int sqlite3BitvecSet(Bitvec *p, u32 i){ u32 h; assert( p!=0 ); assert( i>0 ); assert( i<=p->iSize ); if( p->iSize<=BITVEC_NBIT ){ i--; p->u.aBitmap[i/8] |= 1 << (i&7); return SQLITE_OK; } if( p->iDivisor ){ u32 bin = (i-1)/p->iDivisor; i = (i-1)%p->iDivisor + 1; if( p->u.apSub[bin]==0 ){ sqlite3FaultBeginBenign(SQLITE_FAULTINJECTOR_MALLOC); p->u.apSub[bin] = sqlite3BitvecCreate( p->iDivisor ); sqlite3FaultEndBenign(SQLITE_FAULTINJECTOR_MALLOC); if( p->u.apSub[bin]==0 ) return SQLITE_NOMEM; } return sqlite3BitvecSet(p->u.apSub[bin], i); } h = BITVEC_HASH(i); while( p->u.aHash[h] ){ if( p->u.aHash[h]==i ) return SQLITE_OK; h++; if( h==BITVEC_NINT ) h = 0; } p->nSet++; if( p->nSet>=BITVEC_MXHASH ){ int j, rc; u32 aiValues[BITVEC_NINT]; memcpy(aiValues, p->u.aHash, sizeof(aiValues)); memset(p->u.apSub, 0, sizeof(p->u.apSub[0])*BITVEC_NPTR); p->iDivisor = (p->iSize + BITVEC_NPTR - 1)/BITVEC_NPTR; rc = sqlite3BitvecSet(p, i); for(j=0; j<BITVEC_NINT; j++){ if( aiValues[j] ) rc |= sqlite3BitvecSet(p, aiValues[j]); } return rc; } p->u.aHash[h] = i; return SQLITE_OK; }
/* ** Check to see if the i-th bit is set. Return true or false. ** If p is NULL (if the bitmap has not been created) or if ** i is out of range, then return false. */ int sqlite3BitvecTest(Bitvec *p, u32 i){ if( p==0 ) return 0; if( i>p->iSize || i==0 ) return 0; if( p->iSize<=BITVEC_NBIT ){ i--; return (p->u.aBitmap[i/8] & (1<<(i&7)))!=0; } if( p->iDivisor>0 ){ u32 bin = (i-1)/p->iDivisor; i = (i-1)%p->iDivisor + 1; return sqlite3BitvecTest(p->u.apSub[bin], i); }else{ u32 h = BITVEC_HASH(i); while( p->u.aHash[h] ){ if( p->u.aHash[h]==i ) return 1; h++; if( h>=BITVEC_NINT ) h = 0; } return 0; } }
/* ** Check to see if the i-th bit is set. Return true or false. ** If p is NULL (if the bitmap has not been created) or if ** i is out of range, then return false. */ int sqlite3BitvecTest(Bitvec *p, u32 i){ if( p==0 ) return 0; if( i>p->iSize || i==0 ) return 0; i--; while( p->iDivisor ){ u32 bin = i/p->iDivisor; i = i%p->iDivisor; p = p->u.apSub[bin]; if (!p) { return 0; } } if( p->iSize<=BITVEC_NBIT ){ return (p->u.aBitmap[i/BITVEC_SZELEM] & (1<<(i&(BITVEC_SZELEM-1))))!=0; } else{ u32 h = BITVEC_HASH(i++); while( p->u.aHash[h] ){ if( p->u.aHash[h]==i ) return 1; h = (h+1) % BITVEC_NINT; } return 0; } }
/* ** Set the i-th bit. Return 0 on success and an error code if ** anything goes wrong. ** ** This routine might cause sub-bitmaps to be allocated. Failing ** to get the memory needed to hold the sub-bitmap is the only ** that can go wrong with an insert, assuming p and i are valid. ** ** The calling function must ensure that p is a valid Bitvec object ** and that the value for "i" is within range of the Bitvec object. ** Otherwise the behavior is undefined. */ int sqlite3BitvecSet(Bitvec *p, u32 i){ u32 h; if( p==0 ) return SQLITE_OK; assert( i>0 ); assert( i<=p->iSize ); i--; while((p->iSize > BITVEC_NBIT) && p->iDivisor) { u32 bin = i/p->iDivisor; i = i%p->iDivisor; if( p->u.apSub[bin]==0 ){ p->u.apSub[bin] = sqlite3BitvecCreate( p->iDivisor ); if( p->u.apSub[bin]==0 ) return SQLITE_NOMEM; } p = p->u.apSub[bin]; } if( p->iSize<=BITVEC_NBIT ){ p->u.aBitmap[i/BITVEC_SZELEM] |= 1 << (i&(BITVEC_SZELEM-1)); return SQLITE_OK; } h = BITVEC_HASH(i++); /* if there wasn't a hash collision, and this doesn't */ /* completely fill the hash, then just add it without */ /* worring about sub-dividing and re-hashing. */ if( !p->u.aHash[h] ){ if (p->nSet<(BITVEC_NINT-1)) { goto bitvec_set_end; } else { goto bitvec_set_rehash; } } /* there was a collision, check to see if it's already */ /* in hash, if not, try to find a spot for it */ do { if( p->u.aHash[h]==i ) return SQLITE_OK; h++; if( h>=BITVEC_NINT ) h = 0; } while( p->u.aHash[h] ); /* we didn't find it in the hash. h points to the first */ /* available free spot. check to see if this is going to */ /* make our hash too "full". */ bitvec_set_rehash: if( p->nSet>=BITVEC_MXHASH ){ unsigned int j; int rc; u32 *aiValues = sqlite3StackAllocRaw(0, sizeof(p->u.aHash)); if( aiValues==0 ){ return SQLITE_NOMEM; }else{ memcpy(aiValues, p->u.aHash, sizeof(p->u.aHash)); memset(p->u.apSub, 0, sizeof(p->u.apSub)); p->iDivisor = (p->iSize + BITVEC_NPTR - 1)/BITVEC_NPTR; rc = sqlite3BitvecSet(p, i); for(j=0; j<BITVEC_NINT; j++){ if( aiValues[j] ) rc |= sqlite3BitvecSet(p, aiValues[j]); } sqlite3StackFree(0, aiValues); return rc; } } bitvec_set_end: p->nSet++; p->u.aHash[h] = i; return SQLITE_OK; }