mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-08-17 18:43:24 +02:00
here is an updated version of the bit type with a bugfix and all the necessa ry SQL functions defined. This should replace what is currently in contrib. I'd appreciate any comments on what is there. Kind regards, Adriaan
827 lines
20 KiB
C
827 lines
20 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* varbit.c
|
|
* Functions for the built-in type bit() and varying bit().
|
|
*
|
|
* IDENTIFICATION
|
|
* $Header: /cvsroot/pgsql/contrib/bit/Attic/varbit.c,v 1.2 2000/04/03 20:56:40 momjian Exp $
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#include "varbit.h"
|
|
#include "access/htup.h"
|
|
/*#include "catalog/pg_type.h" */
|
|
/*#include "utils/builtins.h" */
|
|
|
|
|
|
/*
|
|
Prefixes:
|
|
zp -- zero-padded fixed length bit string
|
|
var -- varying bit string
|
|
|
|
attypmod -- contains the length of the bit string in bits, or for
|
|
varying bits the maximum length.
|
|
|
|
The data structure contains the following elements:
|
|
header -- length of the whole data structure (incl header)
|
|
in bytes. (as with all varying length datatypes)
|
|
data section -- private data section for the bits data structures
|
|
bitlength -- lenght of the bit string in bits
|
|
bitdata -- least significant byte first string
|
|
*/
|
|
|
|
/*
|
|
* zpbitin -
|
|
|
|
* converts a string to the internal representation of a bitstring.
|
|
* The length is determined by the number of bits required plus
|
|
* VARHDRSZ bytes or from atttypmod.
|
|
* (XXX dummy is here because we pass typelem as the second argument
|
|
* for array_in. copied this, no idea what it means??)
|
|
*/
|
|
bits8 *
|
|
zpbitin(char *s, int dummy, int32 atttypmod)
|
|
{
|
|
bits8 *result; /* the bits string that was read in */
|
|
char *sp; /* pointer into the character string */
|
|
bits8 *r;
|
|
int len, /* Length of the whole data structure */
|
|
bitlen, /* Number of bits in the bit string */
|
|
slen; /* Length of the input string */
|
|
int bit_not_hex = 0; /* 0 = hex string 1=bit string */
|
|
int bc, ipad;
|
|
bits8 x = 0;
|
|
|
|
|
|
if (s == NULL)
|
|
return (bits8 *) NULL;
|
|
|
|
/* Check that the first character is a b or an x */
|
|
if (s[0]=='b' || s[0]=='B')
|
|
bit_not_hex = 1;
|
|
else if (s[0]=='x' || s[0]=='X')
|
|
bit_not_hex = 0;
|
|
else
|
|
elog(ERROR, "zpbitin: %s is not a valid bitstring",s);
|
|
|
|
slen = strlen(s) - 1;
|
|
/* Determine bitlength from input string */
|
|
bitlen = slen;
|
|
if (!bit_not_hex)
|
|
bitlen *= 4;
|
|
|
|
/* Sometimes atttypmod is not supplied. If it is supplied we need to make
|
|
sure that the bitstring fits. Note that the number of infered bits can
|
|
be larger than the number of actual bits needed, but only if we are
|
|
reading a hex string and not by more than 3 bits, as a hex string gives
|
|
and accurate length upto 4 bits */
|
|
if (atttypmod == -1)
|
|
atttypmod = bitlen;
|
|
else
|
|
if ((bitlen>atttypmod && bit_not_hex) ||
|
|
(bitlen>atttypmod+3 && !bit_not_hex))
|
|
elog(ERROR, "zpbitin: bit string of size %d cannot be written into bits(%d)",
|
|
bitlen,atttypmod);
|
|
|
|
|
|
len = VARBITDATALEN(atttypmod);
|
|
|
|
if (len > MaxAttrSize)
|
|
elog(ERROR, "zpbitin: length of bit() must be less than %ld",
|
|
(MaxAttrSize-VARHDRSZ-VARBITHDRSZ)*BITSPERBYTE);
|
|
|
|
result = (bits8 *) palloc(len);
|
|
/* set to 0 so that *r is always initialised and strin is zero-padded */
|
|
memset(result, 0, len);
|
|
VARSIZE(result) = len;
|
|
VARBITLEN(result) = atttypmod;
|
|
|
|
/* We need to read the bitstring from the end, as we store it least
|
|
significant byte first. s points to the byte before the beginning
|
|
of the bitstring */
|
|
sp = s+1;
|
|
r = VARBITS(result);
|
|
if (bit_not_hex)
|
|
{
|
|
/* Parse the bit representation of the string */
|
|
/* We know it fits, as bitlen was compared to atttypmod */
|
|
x = BITHIGH;
|
|
for (bc = 0; sp != s+slen+1; sp++, bc++)
|
|
{
|
|
if (*sp=='1')
|
|
*r |= x;
|
|
if (bc==7) {
|
|
bc = 0;
|
|
x = BITHIGH;
|
|
r++;
|
|
} else
|
|
x >>= 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Parse the hex representation of the string */
|
|
for (bc = 0; sp != s+slen+1; sp++)
|
|
{
|
|
if (*sp>='0' && *sp<='9')
|
|
x = (bits8) (*sp - '0');
|
|
else if (*sp>='A' && *sp<='F')
|
|
x = (bits8) (*sp - 'A') + 10;
|
|
else if (*sp>='a' && *sp<='f')
|
|
x = (bits8) (*sp - 'a') + 10;
|
|
else
|
|
elog(ERROR,"Cannot parse %c as a hex digit",*sp);
|
|
if (bc) {
|
|
bc = 0;
|
|
*r++ |= x;
|
|
} else {
|
|
bc++;
|
|
*r = x<<4;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bitlen > atttypmod) {
|
|
/* Check that this fitted */
|
|
r = (bits8 *) (result + len - 1);
|
|
ipad = VARBITPAD(result);
|
|
/* The bottom ipad bits of the byte pointed to by r need to be zero */
|
|
/* printf("Byte %X shift %X %d\n",*r,(*r << (8-ipad)) & BITMASK,
|
|
(*r << (8-ipad)) & BITMASK > 0);
|
|
*/
|
|
if (((*r << (BITSPERBYTE-ipad)) & BITMASK) > 0)
|
|
elog(ERROR, "zpbitin: bit string too large for bit(%d) data type",
|
|
atttypmod);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/* zpbitout -
|
|
* for the time being we print everything as hex strings, as this is likely
|
|
* to be more compact than bit strings, and consequently much more efficient
|
|
* for long strings
|
|
*/
|
|
char *
|
|
zpbitout(bits8 *s)
|
|
{
|
|
char *result, *r;
|
|
bits8 *sp;
|
|
int i, len, bitlen;
|
|
|
|
if (s == NULL)
|
|
{
|
|
result = (char *) palloc(2);
|
|
result[0] = '-';
|
|
result[1] = '\0';
|
|
}
|
|
else
|
|
{
|
|
bitlen = VARBITLEN(s);
|
|
len = bitlen/4 + (bitlen%4>0 ? 1 : 0);
|
|
result = (char *) palloc(len + 4);
|
|
sp = VARBITS(s);
|
|
r = result;
|
|
*r++ = 'X';
|
|
*r++ = '\'';
|
|
/* we cheat by knowing that we store full bytes zero padded */
|
|
for (i=0; i<len; i+=2, sp++) {
|
|
*r++ = HEXDIG((*sp)>>4);
|
|
*r++ = HEXDIG((*sp) & 0xF);
|
|
}
|
|
/* Go back one step if we printed a hex number that was not part
|
|
of the bitstring anymore */
|
|
if (i==len+1)
|
|
r--;
|
|
*r++ = '\'';
|
|
*r = '\0';
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/* zpbitsout -
|
|
* Prints the string a bits
|
|
*/
|
|
char *
|
|
zpbitsout(bits8 *s)
|
|
{
|
|
char *result, *r;
|
|
bits8 *sp;
|
|
bits8 x;
|
|
int i, k, len;
|
|
|
|
if (s == NULL)
|
|
{
|
|
result = (char *) palloc(2);
|
|
result[0] = '-';
|
|
result[1] = '\0';
|
|
}
|
|
else
|
|
{
|
|
len = VARBITLEN(s);
|
|
result = (char *) palloc(len + 4);
|
|
sp = VARBITS(s);
|
|
r = result;
|
|
*r++ = 'B';
|
|
*r++ = '\'';
|
|
for (i=0; i<len-BITSPERBYTE; i+=BITSPERBYTE, sp++) {
|
|
x = *sp;
|
|
for (k=0; k<BITSPERBYTE; k++)
|
|
{
|
|
*r++ = (x & BITHIGH) ? '1' : '0';
|
|
x <<= 1;
|
|
}
|
|
}
|
|
x = *sp;
|
|
for (k=i; k<len; k++)
|
|
{
|
|
*r++ = (x & BITHIGH) ? '1' : '0';
|
|
x <<= 1;
|
|
}
|
|
*r++ = '\'';
|
|
*r = '\0';
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
/*
|
|
* varbitin -
|
|
* converts a string to the internal representation of a bitstring.
|
|
*/
|
|
bits8 *
|
|
varbitin(char *s, int dummy, int32 atttypmod)
|
|
{
|
|
bits8 *result; /* The resulting bit string */
|
|
char *sp; /* pointer into the character string */
|
|
bits8 *r;
|
|
int len, /* Length of the whole data structure */
|
|
bitlen, /* Number of bits in the bit string */
|
|
slen; /* Length of the input string */
|
|
int bit_not_hex = 0;
|
|
int bc, ipad;
|
|
bits8 x = 0;
|
|
|
|
|
|
if (s == NULL)
|
|
return (bits8 *) NULL;
|
|
|
|
/* Check that the first character is a b or an x */
|
|
if (s[0]=='b' || s[0]=='B')
|
|
bit_not_hex = 1;
|
|
else if (s[0]=='x' || s[0]=='X')
|
|
bit_not_hex = 0;
|
|
else
|
|
elog(ERROR, "zpbitin: %s is not a valid bitstring",s);
|
|
|
|
slen = strlen(s) - 1;
|
|
/* Determine bitlength from input string */
|
|
bitlen = slen;
|
|
if (!bit_not_hex)
|
|
bitlen *= 4;
|
|
|
|
/* Sometimes atttypmod is not supplied. If it is supplied we need to make
|
|
sure that the bitstring fits. Note that the number of infered bits can
|
|
be larger than the number of actual bits needed, but only if we are
|
|
reading a hex string and not by more than 3 bits, as a hex string gives
|
|
and accurate length upto 4 bits */
|
|
if (atttypmod > -1)
|
|
if ((bitlen>atttypmod && bit_not_hex) ||
|
|
(bitlen>atttypmod+3 && !bit_not_hex))
|
|
elog(ERROR, "varbitin: bit string of size %d cannot be written into varying bits(%d)",
|
|
bitlen,atttypmod);
|
|
|
|
|
|
len = VARBITDATALEN(bitlen);
|
|
|
|
if (len > MaxAttrSize)
|
|
elog(ERROR, "varbitin: length of bit() must be less than %ld",
|
|
(MaxAttrSize-VARHDRSZ-VARBITHDRSZ)*BITSPERBYTE);
|
|
|
|
result = (bits8 *) palloc(len);
|
|
/* set to 0 so that *r is always initialised and strin is zero-padded */
|
|
memset(result, 0, len);
|
|
VARSIZE(result) = len;
|
|
VARBITLEN(result) = bitlen;
|
|
|
|
/* We need to read the bitstring from the end, as we store it least
|
|
significant byte first. s points to the byte before the beginning
|
|
of the bitstring */
|
|
sp = s + 1;
|
|
r = VARBITS(result);
|
|
if (bit_not_hex)
|
|
{
|
|
/* Parse the bit representation of the string */
|
|
x = BITHIGH;
|
|
for (bc = 0; sp != s+slen+1; sp++, bc++)
|
|
{
|
|
if (*sp=='1')
|
|
*r |= x;
|
|
if (bc==7) {
|
|
bc = 0;
|
|
x = BITHIGH;
|
|
r++;
|
|
} else
|
|
x >>= 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (bc = 0; sp != s+slen+1; sp++)
|
|
{
|
|
if (*sp>='0' && *sp<='9')
|
|
x = (bits8) (*sp - '0');
|
|
else if (*sp>='A' && *sp<='F')
|
|
x = (bits8) (*sp - 'A') + 10;
|
|
else if (*sp>='a' && *sp<='f')
|
|
x = (bits8) (*sp - 'a') + 10;
|
|
else
|
|
elog(ERROR,"Cannot parse %c as a hex digit",*sp);
|
|
if (bc) {
|
|
bc = 0;
|
|
*r++ |= x;
|
|
} else {
|
|
bc++;
|
|
*r = x<<4;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bitlen > atttypmod) {
|
|
/* Check that this fitted */
|
|
r = (bits8 *) (result + len - 1);
|
|
ipad = VARBITPAD(result);
|
|
/* The bottom ipad bits of the byte pointed to by r need to be zero */
|
|
if (((*r << (BITSPERBYTE-ipad)) & BITMASK) > 0)
|
|
elog(ERROR, "varbitin: bit string too large for varying bit(%d) data type",
|
|
atttypmod);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
the zpbitout routines are fine for varying bits as well
|
|
*/
|
|
|
|
|
|
/*
|
|
* Comparison operators
|
|
*
|
|
* We only need one set of comparison operators for bitstrings, as the lengths
|
|
* are stored in the same way for zero-padded and varying bit strings.
|
|
*
|
|
* Note that the standard is not unambiguous about the comparison between
|
|
* zero-padded bit strings and varying bitstrings. If the same value is written
|
|
* into a zero padded bitstring as into a varying bitstring, but the zero
|
|
* padded bitstring has greater length, it will be bigger.
|
|
*
|
|
* Zeros from the beginning of a bitstring cannot simply be ignored, as they
|
|
* may be part of a bit string and may be significant.
|
|
*/
|
|
|
|
bool
|
|
biteq (bits8 *arg1, bits8 *arg2)
|
|
{
|
|
int bitlen1,
|
|
bitlen2;
|
|
|
|
if (!PointerIsValid(arg1) || !PointerIsValid(arg2))
|
|
return (bool) 0;
|
|
bitlen1 = VARBITLEN(arg1);
|
|
bitlen2 = VARBITLEN(arg2);
|
|
if (bitlen1 != bitlen2)
|
|
return (bool) 0;
|
|
|
|
/* bit strings are always stored in a full number of bytes */
|
|
return memcmp((void *)VARBITS(arg1),(void *)VARBITS(arg2),
|
|
VARBITBYTES(arg1)) == 0;
|
|
}
|
|
|
|
bool
|
|
bitne (bits8 *arg1, bits8 *arg2)
|
|
{
|
|
int bitlen1,
|
|
bitlen2;
|
|
|
|
if (!PointerIsValid(arg1) || !PointerIsValid(arg2))
|
|
return (bool) 0;
|
|
bitlen1 = VARBITLEN(arg1);
|
|
bitlen2 = VARBITLEN(arg2);
|
|
if (bitlen1 != bitlen2)
|
|
return (bool) 1;
|
|
|
|
/* bit strings are always stored in a full number of bytes */
|
|
return memcmp((void *)VARBITS(arg1),(void *)VARBITS(arg2),
|
|
VARBITBYTES(arg1)) != 0;
|
|
}
|
|
|
|
/* bitcmp
|
|
*
|
|
* Compares two bitstrings and returns -1, 0, 1 depending on whether the first
|
|
* string is smaller, equal, or bigger than the second. All bits are considered
|
|
* and additional zero bits may make one string smaller/larger than the other,
|
|
* even if their zero-padded values would be the same.
|
|
* Anything is equal to undefined.
|
|
*/
|
|
int
|
|
bitcmp (bits8 *arg1, bits8 *arg2)
|
|
{
|
|
int bitlen1, bytelen1,
|
|
bitlen2, bytelen2;
|
|
int cmp;
|
|
|
|
if (!PointerIsValid(arg1) || !PointerIsValid(arg2))
|
|
return (bool) 0;
|
|
bytelen1 = VARBITBYTES(arg1);
|
|
bytelen2 = VARBITBYTES(arg2);
|
|
|
|
cmp = memcmp(VARBITS(arg1),VARBITS(arg2),Min(bytelen1,bytelen2));
|
|
if (cmp==0) {
|
|
bitlen1 = VARBITLEN(arg1);
|
|
bitlen2 = VARBITLEN(arg2);
|
|
if (bitlen1 != bitlen2)
|
|
return bitlen1 < bitlen2 ? -1 : 1;
|
|
}
|
|
return cmp;
|
|
}
|
|
|
|
bool
|
|
bitlt (bits8 *arg1, bits8 *arg2)
|
|
{
|
|
return (bool) (bitcmp(arg1,arg2) == -1);
|
|
}
|
|
|
|
bool
|
|
bitle (bits8 *arg1, bits8 *arg2)
|
|
{
|
|
return (bool) (bitcmp(arg1,arg2) <= 0);
|
|
}
|
|
|
|
bool
|
|
bitge (bits8 *arg1, bits8 *arg2)
|
|
{
|
|
return (bool) (bitcmp(arg1,arg2) >= 0);
|
|
}
|
|
|
|
bool
|
|
bitgt (bits8 *arg1, bits8 *arg2)
|
|
{
|
|
return (bool) (bitcmp(arg1,arg2) == 1);
|
|
}
|
|
|
|
/* bitcat
|
|
* Concatenation of bit strings
|
|
*/
|
|
bits8 *
|
|
bitcat (bits8 *arg1, bits8 *arg2)
|
|
{
|
|
int bitlen1, bitlen2, bytelen, bit1pad, bit2shift;
|
|
bits8 *result;
|
|
bits8 *pr, *pa;
|
|
|
|
if (!PointerIsValid(arg1) || !PointerIsValid(arg2))
|
|
return NULL;
|
|
|
|
bitlen1 = VARBITLEN(arg1);
|
|
bitlen2 = VARBITLEN(arg2);
|
|
|
|
bytelen = VARBITDATALEN(bitlen1+bitlen2);
|
|
|
|
result = (bits8 *) palloc(bytelen*sizeof(bits8));
|
|
VARSIZE(result) = bytelen;
|
|
VARBITLEN(result) = bitlen1+bitlen2;
|
|
printf("%d %d %d \n",VARBITBYTES(arg1),VARBITLEN(arg1),VARBITPAD(arg1));
|
|
/* Copy the first bitstring in */
|
|
memcpy(VARBITS(result),VARBITS(arg1),VARBITBYTES(arg1));
|
|
/* Copy the second bit string */
|
|
bit1pad = VARBITPAD(arg1);
|
|
if (bit1pad==0)
|
|
{
|
|
memcpy(VARBITS(result)+VARBITBYTES(arg1),VARBITS(arg2),
|
|
VARBITBYTES(arg2));
|
|
}
|
|
else if (bitlen2>0)
|
|
{
|
|
/* We need to shift all the results to fit */
|
|
bit2shift = BITSPERBYTE - bit1pad;
|
|
pa = VARBITS(arg2);
|
|
pr = VARBITS(result)+VARBITBYTES(arg1)-1;
|
|
for ( ; pa < VARBITEND(arg2); pa++) {
|
|
*pr |= ((*pa >> bit2shift) & BITMASK);
|
|
pr++;
|
|
if (pr < VARBITEND(result))
|
|
*pr = (*pa << bit1pad) & BITMASK;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/* bitsubstr
|
|
* retrieve a substring from the bit string.
|
|
* Note, s is 1-based.
|
|
* SQL draft 6.10 9)
|
|
*/
|
|
bits8 *
|
|
bitsubstr (bits8 *arg, int32 s, int32 l)
|
|
{
|
|
int bitlen,
|
|
rbitlen,
|
|
len,
|
|
ipad = 0,
|
|
ishift,
|
|
i;
|
|
int e, s1, e1;
|
|
bits8 * result;
|
|
bits8 mask, *r, *ps;
|
|
|
|
if (!PointerIsValid(arg))
|
|
return NULL;
|
|
|
|
bitlen = VARBITLEN(arg);
|
|
e = s+l;
|
|
s1 = Max(s,1);
|
|
e1 = Min(e,bitlen+1);
|
|
if (s1>bitlen || e1<1)
|
|
{
|
|
/* Need to return a null string */
|
|
len = VARBITDATALEN(0);
|
|
result = (bits8 *) palloc(len);
|
|
VARBITLEN(result) = 0;
|
|
VARSIZE(result) = len;
|
|
}
|
|
else
|
|
{
|
|
/* OK, we've got a true substring starting at position s1-1 and
|
|
ending at position e1-1 */
|
|
rbitlen = e1-s1;
|
|
len = VARBITDATALEN(rbitlen);
|
|
result = (bits8 *) palloc(len);
|
|
VARBITLEN(result) = rbitlen;
|
|
VARSIZE(result) = len;
|
|
len -= VARHDRSZ + VARBITHDRSZ;
|
|
/* Are we copying from a byte boundary? */
|
|
if ((s1-1)%BITSPERBYTE==0)
|
|
{
|
|
/* Yep, we are copying bytes */
|
|
memcpy(VARBITS(result),VARBITS(arg)+(s1-1)/BITSPERBYTE,len);
|
|
}
|
|
else
|
|
{
|
|
/* Figure out how much we need to shift the sequence by */
|
|
ishift = (s1-1)%BITSPERBYTE;
|
|
r = VARBITS(result);
|
|
ps = VARBITS(arg) + (s1-1)/BITSPERBYTE;
|
|
for (i=0; i<len; i++)
|
|
{
|
|
*r = (*ps <<ishift) & BITMASK;
|
|
if ((++ps) < VARBITEND(arg))
|
|
*r |= *ps >>(BITSPERBYTE-ishift);
|
|
r++;
|
|
}
|
|
}
|
|
/* Do we need to pad at the end? */
|
|
ipad = VARBITPAD(result);
|
|
if (ipad > 0)
|
|
{
|
|
mask = BITMASK << ipad;
|
|
*(VARBITS(result) + len - 1) &= mask;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/* bitand
|
|
* perform a logical AND on two bit strings. The result is automatically
|
|
* truncated to the shorter bit string
|
|
*/
|
|
bits8 *
|
|
bitand (bits8 * arg1, bits8 * arg2)
|
|
{
|
|
int len,
|
|
i;
|
|
bits8 *result;
|
|
bits8 *p1,
|
|
*p2,
|
|
*r;
|
|
|
|
if (!PointerIsValid(arg1) || !PointerIsValid(arg2))
|
|
return (bool) 0;
|
|
|
|
len = Min(VARSIZE(arg1),VARSIZE(arg2));
|
|
result = (bits8 *) palloc(len);
|
|
VARSIZE(result) = len;
|
|
VARBITLEN(result) = Min(VARBITLEN(arg1),VARBITLEN(arg2));
|
|
|
|
p1 = (bits8 *) VARBITS(arg1);
|
|
p2 = (bits8 *) VARBITS(arg2);
|
|
r = (bits8 *) VARBITS(result);
|
|
for (i=0; i<Min(VARBITBYTES(arg1),VARBITBYTES(arg2)); i++)
|
|
*r++ = *p1++ & *p2++;
|
|
|
|
/* Padding is not needed as & of 0 pad is 0 */
|
|
|
|
return result;
|
|
}
|
|
|
|
/* bitor
|
|
* perform a logical OR on two bit strings. The result is automatically
|
|
* truncated to the shorter bit string.
|
|
*/
|
|
bits8 *
|
|
bitor (bits8 * arg1, bits8 * arg2)
|
|
{
|
|
int len,
|
|
i;
|
|
bits8 *result;
|
|
bits8 *p1,
|
|
*p2,
|
|
*r;
|
|
bits8 mask;
|
|
|
|
if (!PointerIsValid(arg1) || !PointerIsValid(arg2))
|
|
return (bool) 0;
|
|
|
|
len = Min(VARSIZE(arg1),VARSIZE(arg2));
|
|
result = (bits8 *) palloc(len);
|
|
VARSIZE(result) = len;
|
|
VARBITLEN(result) = Min(VARBITLEN(arg1),VARBITLEN(arg2));
|
|
|
|
p1 = (bits8 *) VARBITS(arg1);
|
|
p2 = (bits8 *) VARBITS(arg2);
|
|
r = (bits8 *) VARBITS(result);
|
|
for (i=0; i<Min(VARBITBYTES(arg1),VARBITBYTES(arg2)); i++)
|
|
*r++ = *p1++ | *p2++;
|
|
|
|
/* Pad the result */
|
|
mask = BITMASK << VARBITPAD(result);
|
|
*r &= mask;
|
|
|
|
return result;
|
|
}
|
|
|
|
/* bitxor
|
|
* perform a logical XOR on two bit strings. The result is automatically
|
|
* truncated to the shorter bit string.
|
|
*/
|
|
bits8 *
|
|
bitxor (bits8 * arg1, bits8 * arg2)
|
|
{
|
|
int len,
|
|
i;
|
|
bits8 *result;
|
|
bits8 *p1,
|
|
*p2,
|
|
*r;
|
|
bits8 mask;
|
|
|
|
if (!PointerIsValid(arg1) || !PointerIsValid(arg2))
|
|
return (bool) 0;
|
|
|
|
len = Min(VARSIZE(arg1),VARSIZE(arg2));
|
|
result = (bits8 *) palloc(len);
|
|
VARSIZE(result) = len;
|
|
VARBITLEN(result) = Min(VARBITLEN(arg1),VARBITLEN(arg2));
|
|
|
|
p1 = (bits8 *) VARBITS(arg1);
|
|
p2 = (bits8 *) VARBITS(arg2);
|
|
r = (bits8 *) VARBITS(result);
|
|
for (i=0; i<Min(VARBITBYTES(arg1),VARBITBYTES(arg2)); i++)
|
|
{
|
|
*r++ = *p1++ ^ *p2++;
|
|
}
|
|
|
|
/* Pad the result */
|
|
mask = BITMASK << VARBITPAD(result);
|
|
*r &= mask;
|
|
|
|
return result;
|
|
}
|
|
|
|
/* bitnot
|
|
* perform a logical NOT on a bit strings.
|
|
*/
|
|
bits8 *
|
|
bitnot (bits8 * arg)
|
|
{
|
|
bits8 *result;
|
|
bits8 *p,
|
|
*r;
|
|
bits8 mask;
|
|
|
|
if (!PointerIsValid(arg))
|
|
return (bool) 0;
|
|
|
|
result = (bits8 *) palloc(VARSIZE(arg));
|
|
VARSIZE(result) = VARSIZE(arg);
|
|
VARBITLEN(result) = VARBITLEN(arg);
|
|
|
|
p = (bits8 *) VARBITS(arg);
|
|
r = (bits8 *) VARBITS(result);
|
|
for ( ; p < VARBITEND(arg); p++, r++)
|
|
*r = ~*p;
|
|
|
|
/* Pad the result */
|
|
mask = BITMASK << VARBITPAD(result);
|
|
*r &= mask;
|
|
|
|
return result;
|
|
}
|
|
|
|
/* bitshiftleft
|
|
* do a left shift (i.e. to the beginning of the string) of the bit string
|
|
*/
|
|
bits8 *
|
|
bitshiftleft (bits8 * arg, int shft)
|
|
{
|
|
int byte_shift, ishift, len;
|
|
bits8 *result;
|
|
bits8 *p,
|
|
*r;
|
|
|
|
if (!PointerIsValid(arg))
|
|
return (bool) 0;
|
|
|
|
/* Negative shift is a shift to the right */
|
|
if (shft < 0)
|
|
return bitshiftright(arg, -shft);
|
|
|
|
result = (bits8 *) palloc(VARSIZE(arg));
|
|
VARSIZE(result) = VARSIZE(arg);
|
|
VARBITLEN(result) = VARBITLEN(arg);
|
|
r = (bits8 *) VARBITS(result);
|
|
|
|
byte_shift = shft/BITSPERBYTE;
|
|
ishift = shft % BITSPERBYTE;
|
|
p = ((bits8 *) VARBITS(arg)) + byte_shift;
|
|
|
|
if (ishift == 0) {
|
|
/* Special case: we can do a memcpy */
|
|
len = VARBITBYTES(arg) - byte_shift;
|
|
memcpy(r, p, len);
|
|
memset(r+len, 0, byte_shift);
|
|
} else {
|
|
for ( ; p < VARBITEND(arg); r++) {
|
|
*r = *p <<ishift;
|
|
if ((++p) < VARBITEND(arg))
|
|
*r |= *p >>(BITSPERBYTE-ishift);
|
|
}
|
|
for ( ; r < VARBITEND(result) ; r++ )
|
|
*r = (bits8) 0;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/* bitshiftright
|
|
* do a right shift (i.e. to the beginning of the string) of the bit string
|
|
*/
|
|
bits8 *
|
|
bitshiftright (bits8 * arg, int shft)
|
|
{
|
|
int byte_shift, ishift, len;
|
|
bits8 *result;
|
|
bits8 *p,
|
|
*r;
|
|
|
|
if (!PointerIsValid(arg))
|
|
return (bits8 *) 0;
|
|
|
|
/* Negative shift is a shift to the left */
|
|
if (shft < 0)
|
|
return bitshiftleft(arg, -shft);
|
|
|
|
result = (bits8 *) palloc(VARSIZE(arg));
|
|
VARSIZE(result) = VARSIZE(arg);
|
|
VARBITLEN(result) = VARBITLEN(arg);
|
|
r = (bits8 *) VARBITS(result);
|
|
|
|
byte_shift = shft/BITSPERBYTE;
|
|
ishift = shft % BITSPERBYTE;
|
|
p = (bits8 *) VARBITS(arg);
|
|
|
|
/* Set the first part of the result to 0 */
|
|
memset(r, 0, byte_shift);
|
|
|
|
if (ishift == 0)
|
|
{
|
|
/* Special case: we can do a memcpy */
|
|
len = VARBITBYTES(arg) - byte_shift;
|
|
memcpy(r+byte_shift, p, len);
|
|
}
|
|
else
|
|
{
|
|
r += byte_shift;
|
|
*r = 0; /* Initialise first byte */
|
|
for ( ; r < VARBITEND(result); p++) {
|
|
*r |= *p >> ishift;
|
|
if ((++r) < VARBITEND(result))
|
|
*r = (*p <<(BITSPERBYTE-ishift)) & BITMASK;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|