implemented missing bitSetBit() and bitGetBit() - Mailing list pgsql-hackers

From David Helgason
Subject implemented missing bitSetBit() and bitGetBit()
Date
Msg-id 56656C0E-4D3F-11D8-9552-000A9566DA8A@uti.is
Whole thread Raw
Responses Re: implemented missing bitSetBit() and bitGetBit()  (Neil Conway <neilc@samurai.com>)
List pgsql-hackers
I needed these, so I went and implemented them myself. I have to admit 
I'm not so wise on PostgreSQL backend stuff, and so I abstained from 
editing the fmgrtab.c and postgres.bki.

Sorry for that, but it just seemed too complicated. Perhaps there 
should really be a script to do this? I could imagine I'm not the only 
one slightly daunted by these files...

There's seems to be no reason for changing the docs since the functions 
are documented as existing :)
I didn't add the other functions that one might expect to exist 
(get-/set_byte and others), since I don't really need them.

I tested this code under 7.4 since that's what I've got here, but 
imagine nothing much changed in this end of the world for 7.4.1...

This is to be appended to src/backend/utils/adt/varbit.c:

/*------------------------------------------------------------- * bitSetBit * * Given an instance of type 'bit' creates
anew one with * the Nth bit set to the given value. * *-------------------------------------------------------------
*/
PG_FUNCTION_INFO_V1(bitSetBit);
Datum bitSetBit(PG_FUNCTION_ARGS)
{VarBit        *arg1 = PG_GETARG_VARBIT_P(0);int32            n = PG_GETARG_INT32(1);int32            newBit =
PG_GETARG_INT32(2);VarBit       *result;int                bitlen,                bytelen,                byteNo,
        bitNo;unsigned char    oldByte,                        newByte;
 
bitlen = VARBITLEN(arg1);

/* * sanity checks! */if (newBit != 0 && newBit != 1)    ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),            errmsg("new bit must be 0 or 1")));
 
if (n < 0 || n >= bitlen)    ereport(ERROR,            (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),             errmsg("bit
%doutside of valid range, 0..%d",                    n, bitlen - 1)));
 

/* Copy input bitstring */bytelen = VARSIZE(arg1);result = (VarBit *) palloc(bytelen);memcpy(VARBITS(result),
VARBITS(arg1),VARBITBYTES(arg1));VARATT_SIZEP(result) = bytelen;VARBITLEN(result) = bitlen;
 
/* * Update the bit. */byteNo = n / 8;bitNo = 7 - (n % 8);
oldByte = ((unsigned char *) VARBITS(result))[byteNo];
if (newBit == 0)    newByte = oldByte & (~(1 << bitNo));else    newByte = oldByte | (1 << bitNo);
((unsigned char *) VARBITS(result))[byteNo] = newByte;PG_RETURN_VARBIT_P(result);
}

/*------------------------------------------------------------- * bitGetBit * * Given an instance of type 'bit' returns
theNth bit. * *------------------------------------------------------------- */
 
PG_FUNCTION_INFO_V1(bitGetBit);
Datum bitGetBit(PG_FUNCTION_ARGS)
{VarBit        *arg1 = PG_GETARG_VARBIT_P(0);int32            n = PG_GETARG_INT32(1);int                bitlen,
      bytelen,                byteNo,                bitNo;unsigned char theByte;
 
bitlen = VARBITLEN(arg1);

/* * sanity check! */if (n < 0 || n >= bitlen)    ereport(ERROR,            (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
        errmsg("bit %d outside of valid range, 0..%d",                    n, bitlen - 1)));
 

/* * Find the target bit */byteNo = n / BITS_PER_BYTE;bitNo = BITS_PER_BYTE - 1 - (n % BITS_PER_BYTE);
theByte = ((unsigned char *) VARBITS(arg1))[byteNo];
/* * Shift a set bit to target position, & with the target byte, shift 
back * to get integer 0 or 1 */PG_RETURN_INT32((int)(theByte & (1 << bitNo)) >> bitNo);
}



pgsql-hackers by date:

Previous
From: "Dann Corbit"
Date:
Subject: Re: [pgsql-hackers-win32] What's left?
Next
From: Claudio Natoli
Date:
Subject: Re: [pgsql-hackers-win32] What's left?