4046 lines
117 KiB
C
4046 lines
117 KiB
C
#include "util.h"
|
|
|
|
#include "coretype.h"
|
|
|
|
/*****************************************************************************/
|
|
/* MODULE NAME: BitVector.c MODULE TYPE: (adt) */
|
|
/*****************************************************************************/
|
|
/* MODULE IMPORTS: */
|
|
/*****************************************************************************/
|
|
#include <ctype.h> /* MODULE TYPE: (sys) */
|
|
#include <limits.h> /* MODULE TYPE: (sys) */
|
|
#include <string.h> /* MODULE TYPE: (sys) */
|
|
/*****************************************************************************/
|
|
/* MODULE INTERFACE: */
|
|
/*****************************************************************************/
|
|
#include "bitvect.h"
|
|
|
|
/* ToolBox.h */
|
|
#define and && /* logical (boolean) operators: lower case */
|
|
#define or ||
|
|
#define not !
|
|
|
|
#define AND & /* binary (bitwise) operators: UPPER CASE */
|
|
#define OR |
|
|
#define XOR ^
|
|
#define NOT ~
|
|
#define SHL <<
|
|
#define SHR >>
|
|
|
|
#ifdef ENABLE_MODULO
|
|
#define mod % /* arithmetic operators */
|
|
#endif
|
|
|
|
#define blockdef(name,size) unsigned char name[size]
|
|
#define blocktypedef(name,size) typedef unsigned char name[size]
|
|
|
|
/*****************************************************************************/
|
|
/* MODULE RESOURCES: */
|
|
/*****************************************************************************/
|
|
|
|
#define bits_(BitVector) *(BitVector-3)
|
|
#define size_(BitVector) *(BitVector-2)
|
|
#define mask_(BitVector) *(BitVector-1)
|
|
|
|
#define ERRCODE_TYPE "sizeof(word) > sizeof(size_t)"
|
|
#define ERRCODE_BITS "bits(word) != sizeof(word)*8"
|
|
#define ERRCODE_WORD "bits(word) < 16"
|
|
#define ERRCODE_LONG "bits(word) > bits(long)"
|
|
#define ERRCODE_POWR "bits(word) != 2^x"
|
|
#define ERRCODE_LOGA "bits(word) != 2^ld(bits(word))"
|
|
#define ERRCODE_NULL "unable to allocate memory"
|
|
#define ERRCODE_INDX "index out of range"
|
|
#define ERRCODE_ORDR "minimum > maximum index"
|
|
#define ERRCODE_SIZE "bit vector size mismatch"
|
|
#define ERRCODE_PARS "input string syntax error"
|
|
#define ERRCODE_OVFL "numeric overflow error"
|
|
#define ERRCODE_SAME "result vector(s) must be distinct"
|
|
#define ERRCODE_EXPO "exponent must be positive"
|
|
#define ERRCODE_ZERO "division by zero error"
|
|
#define ERRCODE_OOPS "unexpected internal error - please contact author"
|
|
|
|
const N_int BitVector_BYTENORM[256] =
|
|
{
|
|
0x00, 0x01, 0x01, 0x02, 0x01, 0x02, 0x02, 0x03,
|
|
0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, /* 0x00 */
|
|
0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04,
|
|
0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x10 */
|
|
0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04,
|
|
0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x20 */
|
|
0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
|
|
0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x30 */
|
|
0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04,
|
|
0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x40 */
|
|
0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
|
|
0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x50 */
|
|
0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
|
|
0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x60 */
|
|
0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
|
|
0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0x70 */
|
|
0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04,
|
|
0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05, /* 0x80 */
|
|
0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
|
|
0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0x90 */
|
|
0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
|
|
0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0xA0 */
|
|
0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
|
|
0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0xB0 */
|
|
0x02, 0x03, 0x03, 0x04, 0x03, 0x04, 0x04, 0x05,
|
|
0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06, /* 0xC0 */
|
|
0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
|
|
0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0xD0 */
|
|
0x03, 0x04, 0x04, 0x05, 0x04, 0x05, 0x05, 0x06,
|
|
0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07, /* 0xE0 */
|
|
0x04, 0x05, 0x05, 0x06, 0x05, 0x06, 0x06, 0x07,
|
|
0x05, 0x06, 0x06, 0x07, 0x06, 0x07, 0x07, 0x08 /* 0xF0 */
|
|
};
|
|
|
|
/*****************************************************************************/
|
|
/* MODULE IMPLEMENTATION: */
|
|
/*****************************************************************************/
|
|
|
|
/**********************************************/
|
|
/* global implementation-intrinsic constants: */
|
|
/**********************************************/
|
|
|
|
#define BIT_VECTOR_HIDDEN_WORDS 3
|
|
|
|
/*****************************************************************/
|
|
/* global machine-dependent constants (set by "BitVector_Boot"): */
|
|
/*****************************************************************/
|
|
|
|
static N_word BITS; /* = # of bits in machine word (must be power of 2) */
|
|
static N_word MODMASK; /* = BITS - 1 (mask for calculating modulo BITS) */
|
|
static N_word LOGBITS; /* = ld(BITS) (logarithmus dualis) */
|
|
static N_word FACTOR; /* = ld(BITS / 8) (ld of # of bytes) */
|
|
|
|
static N_word LSB = 1; /* = mask for least significant bit */
|
|
static N_word MSB; /* = mask for most significant bit */
|
|
|
|
static N_word LONGBITS; /* = # of bits in unsigned long */
|
|
|
|
static N_word LOG10; /* = logarithm to base 10 of BITS - 1 */
|
|
static N_word EXP10; /* = largest possible power of 10 in signed int */
|
|
|
|
/********************************************************************/
|
|
/* global bit mask table for fast access (set by "BitVector_Boot"): */
|
|
/********************************************************************/
|
|
|
|
static wordptr BITMASKTAB;
|
|
|
|
/*****************************/
|
|
/* global macro definitions: */
|
|
/*****************************/
|
|
|
|
#define BIT_VECTOR_ZERO_WORDS(target,count) \
|
|
while (count-- > 0) *target++ = 0;
|
|
|
|
#define BIT_VECTOR_FILL_WORDS(target,fill,count) \
|
|
while (count-- > 0) *target++ = fill;
|
|
|
|
#define BIT_VECTOR_FLIP_WORDS(target,flip,count) \
|
|
while (count-- > 0) *target++ ^= flip;
|
|
|
|
#define BIT_VECTOR_COPY_WORDS(target,source,count) \
|
|
while (count-- > 0) *target++ = *source++;
|
|
|
|
#define BIT_VECTOR_BACK_WORDS(target,source,count) \
|
|
{ target += count; source += count; while (count-- > 0) *--target = *--source; }
|
|
|
|
#define BIT_VECTOR_CLR_BIT(address,index) \
|
|
*(address+(index>>LOGBITS)) &= NOT BITMASKTAB[index AND MODMASK];
|
|
|
|
#define BIT_VECTOR_SET_BIT(address,index) \
|
|
*(address+(index>>LOGBITS)) |= BITMASKTAB[index AND MODMASK];
|
|
|
|
#define BIT_VECTOR_TST_BIT(address,index) \
|
|
((*(address+(index>>LOGBITS)) AND BITMASKTAB[index AND MODMASK]) != 0)
|
|
|
|
#define BIT_VECTOR_FLP_BIT(address,index,mask) \
|
|
(mask = BITMASKTAB[index AND MODMASK]), \
|
|
(((*(addr+(index>>LOGBITS)) ^= mask) AND mask) != 0)
|
|
|
|
#define BIT_VECTOR_DIGITIZE(type,value,digit) \
|
|
value = (type) ((digit = value) / 10); \
|
|
digit -= value * 10; \
|
|
digit += (type) '0';
|
|
|
|
/*********************************************************/
|
|
/* private low-level functions (potentially dangerous!): */
|
|
/*********************************************************/
|
|
|
|
static N_word power10(N_word x)
|
|
{
|
|
N_word y = 1;
|
|
|
|
while (x-- > 0) y *= 10;
|
|
return(y);
|
|
}
|
|
|
|
static void BIT_VECTOR_zro_words(wordptr addr, N_word count)
|
|
{
|
|
BIT_VECTOR_ZERO_WORDS(addr,count)
|
|
}
|
|
|
|
static void BIT_VECTOR_cpy_words(wordptr target, wordptr source, N_word count)
|
|
{
|
|
BIT_VECTOR_COPY_WORDS(target,source,count)
|
|
}
|
|
|
|
static void BIT_VECTOR_mov_words(wordptr target, wordptr source, N_word count)
|
|
{
|
|
if (target != source)
|
|
{
|
|
if (target < source) BIT_VECTOR_COPY_WORDS(target,source,count)
|
|
else BIT_VECTOR_BACK_WORDS(target,source,count)
|
|
}
|
|
}
|
|
|
|
static void BIT_VECTOR_ins_words(wordptr addr, N_word total, N_word count,
|
|
boolean clear)
|
|
{
|
|
N_word length;
|
|
|
|
if ((total > 0) and (count > 0))
|
|
{
|
|
if (count > total) count = total;
|
|
length = total - count;
|
|
if (length > 0) BIT_VECTOR_mov_words(addr+count,addr,length);
|
|
if (clear) BIT_VECTOR_zro_words(addr,count);
|
|
}
|
|
}
|
|
|
|
static void BIT_VECTOR_del_words(wordptr addr, N_word total, N_word count,
|
|
boolean clear)
|
|
{
|
|
N_word length;
|
|
|
|
if ((total > 0) and (count > 0))
|
|
{
|
|
if (count > total) count = total;
|
|
length = total - count;
|
|
if (length > 0) BIT_VECTOR_mov_words(addr,addr+count,length);
|
|
if (clear) BIT_VECTOR_zro_words(addr+length,count);
|
|
}
|
|
}
|
|
|
|
static void BIT_VECTOR_reverse(charptr string, N_word length)
|
|
{
|
|
charptr last;
|
|
N_char temp;
|
|
|
|
if (length > 1)
|
|
{
|
|
last = string + length - 1;
|
|
while (string < last)
|
|
{
|
|
temp = *string;
|
|
*string = *last;
|
|
*last = temp;
|
|
string++;
|
|
last--;
|
|
}
|
|
}
|
|
}
|
|
|
|
static N_word BIT_VECTOR_int2str(charptr string, N_word value)
|
|
{
|
|
N_word length;
|
|
N_word digit;
|
|
charptr work;
|
|
|
|
work = string;
|
|
if (value > 0)
|
|
{
|
|
length = 0;
|
|
while (value > 0)
|
|
{
|
|
BIT_VECTOR_DIGITIZE(N_word,value,digit)
|
|
*work++ = (N_char) digit;
|
|
length++;
|
|
}
|
|
BIT_VECTOR_reverse(string,length);
|
|
}
|
|
else
|
|
{
|
|
length = 1;
|
|
*work++ = (N_char) '0';
|
|
}
|
|
return(length);
|
|
}
|
|
|
|
static N_word BIT_VECTOR_str2int(charptr string, N_word *value)
|
|
{
|
|
N_word length;
|
|
N_word digit;
|
|
|
|
*value = 0;
|
|
length = 0;
|
|
digit = (N_word) *string++;
|
|
/* separate because isdigit() is likely a macro! */
|
|
while (isdigit((int)digit) != 0)
|
|
{
|
|
length++;
|
|
digit -= (N_word) '0';
|
|
if (*value) *value *= 10;
|
|
*value += digit;
|
|
digit = (N_word) *string++;
|
|
}
|
|
return(length);
|
|
}
|
|
|
|
/********************************************/
|
|
/* routine to convert error code to string: */
|
|
/********************************************/
|
|
|
|
const char * BitVector_Error(ErrCode error)
|
|
{
|
|
switch (error)
|
|
{
|
|
case ErrCode_Ok: return( NULL ); break;
|
|
case ErrCode_Type: return( ERRCODE_TYPE ); break;
|
|
case ErrCode_Bits: return( ERRCODE_BITS ); break;
|
|
case ErrCode_Word: return( ERRCODE_WORD ); break;
|
|
case ErrCode_Long: return( ERRCODE_LONG ); break;
|
|
case ErrCode_Powr: return( ERRCODE_POWR ); break;
|
|
case ErrCode_Loga: return( ERRCODE_LOGA ); break;
|
|
case ErrCode_Null: return( ERRCODE_NULL ); break;
|
|
case ErrCode_Indx: return( ERRCODE_INDX ); break;
|
|
case ErrCode_Ordr: return( ERRCODE_ORDR ); break;
|
|
case ErrCode_Size: return( ERRCODE_SIZE ); break;
|
|
case ErrCode_Pars: return( ERRCODE_PARS ); break;
|
|
case ErrCode_Ovfl: return( ERRCODE_OVFL ); break;
|
|
case ErrCode_Same: return( ERRCODE_SAME ); break;
|
|
case ErrCode_Expo: return( ERRCODE_EXPO ); break;
|
|
case ErrCode_Zero: return( ERRCODE_ZERO ); break;
|
|
default: return( ERRCODE_OOPS ); break;
|
|
}
|
|
}
|
|
|
|
/*****************************************/
|
|
/* automatic self-configuration routine: */
|
|
/*****************************************/
|
|
|
|
/*******************************************************/
|
|
/* */
|
|
/* MUST be called once prior to any other function */
|
|
/* to initialize the machine dependent constants */
|
|
/* of this package! (But call only ONCE, or you */
|
|
/* will suffer memory leaks!) */
|
|
/* */
|
|
/*******************************************************/
|
|
|
|
ErrCode BitVector_Boot(void)
|
|
{
|
|
N_long longsample = 1L;
|
|
N_word sample = LSB;
|
|
N_word lsb;
|
|
|
|
if (sizeof(N_word) > sizeof(size_t)) return(ErrCode_Type);
|
|
|
|
BITS = 1;
|
|
while (sample <<= 1) BITS++; /* determine # of bits in a machine word */
|
|
|
|
if (BITS != (sizeof(N_word) << 3)) return(ErrCode_Bits);
|
|
|
|
if (BITS < 16) return(ErrCode_Word);
|
|
|
|
LONGBITS = 1;
|
|
while (longsample <<= 1) LONGBITS++; /* = # of bits in an unsigned long */
|
|
|
|
if (BITS > LONGBITS) return(ErrCode_Long);
|
|
|
|
LOGBITS = 0;
|
|
sample = BITS;
|
|
lsb = (sample AND LSB);
|
|
while ((sample >>= 1) and (not lsb))
|
|
{
|
|
LOGBITS++;
|
|
lsb = (sample AND LSB);
|
|
}
|
|
|
|
if (sample) return(ErrCode_Powr); /* # of bits is not a power of 2! */
|
|
|
|
if (BITS != (LSB << LOGBITS)) return(ErrCode_Loga);
|
|
|
|
MODMASK = BITS - 1;
|
|
FACTOR = LOGBITS - 3; /* ld(BITS / 8) = ld(BITS) - ld(8) = ld(BITS) - 3 */
|
|
MSB = (LSB << MODMASK);
|
|
|
|
BITMASKTAB = (wordptr) yasm_xmalloc((size_t) (BITS << FACTOR));
|
|
|
|
if (BITMASKTAB == NULL) return(ErrCode_Null);
|
|
|
|
for ( sample = 0; sample < BITS; sample++ )
|
|
{
|
|
BITMASKTAB[sample] = (LSB << sample);
|
|
}
|
|
|
|
LOG10 = (N_word) (MODMASK * 0.30103); /* = (BITS - 1) * ( ln 2 / ln 10 ) */
|
|
EXP10 = power10(LOG10);
|
|
|
|
return(ErrCode_Ok);
|
|
}
|
|
|
|
void BitVector_Shutdown(void)
|
|
{
|
|
if (BITMASKTAB) yasm_xfree(BITMASKTAB);
|
|
}
|
|
|
|
N_word BitVector_Size(N_int bits) /* bit vector size (# of words) */
|
|
{
|
|
N_word size;
|
|
|
|
size = bits >> LOGBITS;
|
|
if (bits AND MODMASK) size++;
|
|
return(size);
|
|
}
|
|
|
|
N_word BitVector_Mask(N_int bits) /* bit vector mask (unused bits) */
|
|
{
|
|
N_word mask;
|
|
|
|
mask = bits AND MODMASK;
|
|
if (mask) mask = (N_word) ~(~0L << mask); else mask = (N_word) ~0L;
|
|
return(mask);
|
|
}
|
|
|
|
const char * BitVector_Version(void)
|
|
{
|
|
return("6.4");
|
|
}
|
|
|
|
N_int BitVector_Word_Bits(void)
|
|
{
|
|
return(BITS);
|
|
}
|
|
|
|
N_int BitVector_Long_Bits(void)
|
|
{
|
|
return(LONGBITS);
|
|
}
|
|
|
|
/********************************************************************/
|
|
/* */
|
|
/* WARNING: Do not "free()" constant character strings, i.e., */
|
|
/* don't call "BitVector_Dispose()" for strings returned */
|
|
/* by "BitVector_Error()" or "BitVector_Version()"! */
|
|
/* */
|
|
/* ONLY call this function for strings allocated with "malloc()", */
|
|
/* i.e., the strings returned by the functions "BitVector_to_*()" */
|
|
/* and "BitVector_Block_Read()"! */
|
|
/* */
|
|
/********************************************************************/
|
|
|
|
void BitVector_Dispose(charptr string) /* free string */
|
|
{
|
|
if (string != NULL) yasm_xfree((voidptr) string);
|
|
}
|
|
|
|
void BitVector_Destroy(wordptr addr) /* free bitvec */
|
|
{
|
|
if (addr != NULL)
|
|
{
|
|
addr -= BIT_VECTOR_HIDDEN_WORDS;
|
|
yasm_xfree((voidptr) addr);
|
|
}
|
|
}
|
|
|
|
void BitVector_Destroy_List(listptr list, N_int count) /* free list */
|
|
{
|
|
listptr slot;
|
|
|
|
if (list != NULL)
|
|
{
|
|
slot = list;
|
|
while (count-- > 0)
|
|
{
|
|
BitVector_Destroy(*slot++);
|
|
}
|
|
free((voidptr) list);
|
|
}
|
|
}
|
|
|
|
wordptr BitVector_Create(N_int bits, boolean clear) /* malloc */
|
|
{
|
|
N_word size;
|
|
N_word mask;
|
|
N_word bytes;
|
|
wordptr addr;
|
|
wordptr zero;
|
|
|
|
size = BitVector_Size(bits);
|
|
mask = BitVector_Mask(bits);
|
|
bytes = (size + BIT_VECTOR_HIDDEN_WORDS) << FACTOR;
|
|
addr = (wordptr) yasm_xmalloc((size_t) bytes);
|
|
if (addr != NULL)
|
|
{
|
|
*addr++ = bits;
|
|
*addr++ = size;
|
|
*addr++ = mask;
|
|
if (clear)
|
|
{
|
|
zero = addr;
|
|
BIT_VECTOR_ZERO_WORDS(zero,size)
|
|
}
|
|
}
|
|
return(addr);
|
|
}
|
|
|
|
listptr BitVector_Create_List(N_int bits, boolean clear, N_int count)
|
|
{
|
|
listptr list = NULL;
|
|
listptr slot;
|
|
wordptr addr;
|
|
N_int i;
|
|
|
|
if (count > 0)
|
|
{
|
|
list = (listptr) malloc(sizeof(wordptr) * count);
|
|
if (list != NULL)
|
|
{
|
|
slot = list;
|
|
for ( i = 0; i < count; i++ )
|
|
{
|
|
addr = BitVector_Create(bits,clear);
|
|
if (addr == NULL)
|
|
{
|
|
BitVector_Destroy_List(list,i);
|
|
return(NULL);
|
|
}
|
|
*slot++ = addr;
|
|
}
|
|
}
|
|
}
|
|
return(list);
|
|
}
|
|
|
|
wordptr BitVector_Resize(wordptr oldaddr, N_int bits) /* realloc */
|
|
{
|
|
N_word bytes;
|
|
N_word oldsize;
|
|
N_word oldmask;
|
|
N_word newsize;
|
|
N_word newmask;
|
|
wordptr newaddr;
|
|
wordptr source;
|
|
wordptr target;
|
|
|
|
oldsize = size_(oldaddr);
|
|
oldmask = mask_(oldaddr);
|
|
newsize = BitVector_Size(bits);
|
|
newmask = BitVector_Mask(bits);
|
|
if (oldsize > 0) *(oldaddr+oldsize-1) &= oldmask;
|
|
if (newsize <= oldsize)
|
|
{
|
|
newaddr = oldaddr;
|
|
bits_(newaddr) = bits;
|
|
size_(newaddr) = newsize;
|
|
mask_(newaddr) = newmask;
|
|
if (newsize > 0) *(newaddr+newsize-1) &= newmask;
|
|
}
|
|
else
|
|
{
|
|
bytes = (newsize + BIT_VECTOR_HIDDEN_WORDS) << FACTOR;
|
|
newaddr = (wordptr) yasm_xmalloc((size_t) bytes);
|
|
if (newaddr != NULL)
|
|
{
|
|
*newaddr++ = bits;
|
|
*newaddr++ = newsize;
|
|
*newaddr++ = newmask;
|
|
target = newaddr;
|
|
source = oldaddr;
|
|
newsize -= oldsize;
|
|
BIT_VECTOR_COPY_WORDS(target,source,oldsize)
|
|
BIT_VECTOR_ZERO_WORDS(target,newsize)
|
|
}
|
|
BitVector_Destroy(oldaddr);
|
|
}
|
|
return(newaddr);
|
|
}
|
|
|
|
wordptr BitVector_Shadow(wordptr addr) /* makes new, same size but empty */
|
|
{
|
|
return( BitVector_Create(bits_(addr),true) );
|
|
}
|
|
|
|
wordptr BitVector_Clone(wordptr addr) /* makes exact duplicate */
|
|
{
|
|
N_word bits;
|
|
wordptr twin;
|
|
|
|
bits = bits_(addr);
|
|
twin = BitVector_Create(bits,false);
|
|
if ((twin != NULL) and (bits > 0))
|
|
BIT_VECTOR_cpy_words(twin,addr,size_(addr));
|
|
return(twin);
|
|
}
|
|
|
|
wordptr BitVector_Concat(wordptr X, wordptr Y) /* returns concatenation */
|
|
{
|
|
/* BEWARE that X = most significant part, Y = least significant part! */
|
|
|
|
N_word bitsX;
|
|
N_word bitsY;
|
|
N_word bitsZ;
|
|
wordptr Z;
|
|
|
|
bitsX = bits_(X);
|
|
bitsY = bits_(Y);
|
|
bitsZ = bitsX + bitsY;
|
|
Z = BitVector_Create(bitsZ,false);
|
|
if ((Z != NULL) and (bitsZ > 0))
|
|
{
|
|
BIT_VECTOR_cpy_words(Z,Y,size_(Y));
|
|
BitVector_Interval_Copy(Z,X,bitsY,0,bitsX);
|
|
*(Z+size_(Z)-1) &= mask_(Z);
|
|
}
|
|
return(Z);
|
|
}
|
|
|
|
void BitVector_Copy(wordptr X, wordptr Y) /* X = Y */
|
|
{
|
|
N_word sizeX = size_(X);
|
|
N_word sizeY = size_(Y);
|
|
N_word maskX = mask_(X);
|
|
N_word maskY = mask_(Y);
|
|
N_word fill = 0;
|
|
wordptr lastX;
|
|
wordptr lastY;
|
|
|
|
if ((X != Y) and (sizeX > 0))
|
|
{
|
|
lastX = X + sizeX - 1;
|
|
if (sizeY > 0)
|
|
{
|
|
lastY = Y + sizeY - 1;
|
|
if ( (*lastY AND (maskY AND NOT (maskY >> 1))) == 0 ) *lastY &= maskY;
|
|
else
|
|
{
|
|
fill = (N_word) ~0L;
|
|
*lastY |= NOT maskY;
|
|
}
|
|
while ((sizeX > 0) and (sizeY > 0))
|
|
{
|
|
*X++ = *Y++;
|
|
sizeX--;
|
|
sizeY--;
|
|
}
|
|
*lastY &= maskY;
|
|
}
|
|
while (sizeX-- > 0) *X++ = fill;
|
|
*lastX &= maskX;
|
|
}
|
|
}
|
|
|
|
void BitVector_Empty(wordptr addr) /* X = {} clr all */
|
|
{
|
|
N_word size = size_(addr);
|
|
|
|
BIT_VECTOR_ZERO_WORDS(addr,size)
|
|
}
|
|
|
|
void BitVector_Fill(wordptr addr) /* X = ~{} set all */
|
|
{
|
|
N_word size = size_(addr);
|
|
N_word mask = mask_(addr);
|
|
N_word fill = (N_word) ~0L;
|
|
|
|
if (size > 0)
|
|
{
|
|
BIT_VECTOR_FILL_WORDS(addr,fill,size)
|
|
*(--addr) &= mask;
|
|
}
|
|
}
|
|
|
|
void BitVector_Flip(wordptr addr) /* X = ~X flip all */
|
|
{
|
|
N_word size = size_(addr);
|
|
N_word mask = mask_(addr);
|
|
N_word flip = (N_word) ~0L;
|
|
|
|
if (size > 0)
|
|
{
|
|
BIT_VECTOR_FLIP_WORDS(addr,flip,size)
|
|
*(--addr) &= mask;
|
|
}
|
|
}
|
|
|
|
void BitVector_Primes(wordptr addr)
|
|
{
|
|
N_word bits = bits_(addr);
|
|
N_word size = size_(addr);
|
|
wordptr work;
|
|
N_word temp;
|
|
N_word i,j;
|
|
|
|
if (size > 0)
|
|
{
|
|
temp = 0xAAAA;
|
|
i = BITS >> 4;
|
|
while (--i > 0)
|
|
{
|
|
temp <<= 16;
|
|
temp |= 0xAAAA;
|
|
}
|
|
i = size;
|
|
work = addr;
|
|
*work++ = temp XOR 0x0006;
|
|
while (--i > 0) *work++ = temp;
|
|
for ( i = 3; (j = i * i) < bits; i += 2 )
|
|
{
|
|
for ( ; j < bits; j += i ) BIT_VECTOR_CLR_BIT(addr,j)
|
|
}
|
|
*(addr+size-1) &= mask_(addr);
|
|
}
|
|
}
|
|
|
|
void BitVector_Reverse(wordptr X, wordptr Y)
|
|
{
|
|
N_word bits = bits_(X);
|
|
N_word mask;
|
|
N_word bit;
|
|
N_word value;
|
|
|
|
if (bits > 0)
|
|
{
|
|
if (X == Y) BitVector_Interval_Reverse(X,0,bits-1);
|
|
else if (bits == bits_(Y))
|
|
{
|
|
/* mask = mask_(Y); */
|
|
/* mask &= NOT (mask >> 1); */
|
|
mask = BITMASKTAB[(bits-1) AND MODMASK];
|
|
Y += size_(Y) - 1;
|
|
value = 0;
|
|
bit = LSB;
|
|
while (bits-- > 0)
|
|
{
|
|
if ((*Y AND mask) != 0)
|
|
{
|
|
value |= bit;
|
|
}
|
|
if (not (mask >>= 1))
|
|
{
|
|
Y--;
|
|
mask = MSB;
|
|
}
|
|
if (not (bit <<= 1))
|
|
{
|
|
*X++ = value;
|
|
value = 0;
|
|
bit = LSB;
|
|
}
|
|
}
|
|
if (bit > LSB) *X = value;
|
|
}
|
|
}
|
|
}
|
|
|
|
void BitVector_Interval_Empty(wordptr addr, N_int lower, N_int upper)
|
|
{ /* X = X \ [lower..upper] */
|
|
N_word bits = bits_(addr);
|
|
N_word size = size_(addr);
|
|
wordptr loaddr;
|
|
wordptr hiaddr;
|
|
N_word lobase;
|
|
N_word hibase;
|
|
N_word lomask;
|
|
N_word himask;
|
|
N_word diff;
|
|
|
|
if ((size > 0) and (lower < bits) and (upper < bits) and (lower <= upper))
|
|
{
|
|
lobase = lower >> LOGBITS;
|
|
hibase = upper >> LOGBITS;
|
|
diff = hibase - lobase;
|
|
loaddr = addr + lobase;
|
|
hiaddr = addr + hibase;
|
|
|
|
lomask = (N_word) (~0L << (lower AND MODMASK));
|
|
himask = (N_word) ~((~0L << (upper AND MODMASK)) << 1);
|
|
|
|
if (diff == 0)
|
|
{
|
|
*loaddr &= NOT (lomask AND himask);
|
|
}
|
|
else
|
|
{
|
|
*loaddr++ &= NOT lomask;
|
|
while (--diff > 0)
|
|
{
|
|
*loaddr++ = 0;
|
|
}
|
|
*hiaddr &= NOT himask;
|
|
}
|
|
}
|
|
}
|
|
|
|
void BitVector_Interval_Fill(wordptr addr, N_int lower, N_int upper)
|
|
{ /* X = X + [lower..upper] */
|
|
N_word bits = bits_(addr);
|
|
N_word size = size_(addr);
|
|
N_word fill = (N_word) ~0L;
|
|
wordptr loaddr;
|
|
wordptr hiaddr;
|
|
N_word lobase;
|
|
N_word hibase;
|
|
N_word lomask;
|
|
N_word himask;
|
|
N_word diff;
|
|
|
|
if ((size > 0) and (lower < bits) and (upper < bits) and (lower <= upper))
|
|
{
|
|
lobase = lower >> LOGBITS;
|
|
hibase = upper >> LOGBITS;
|
|
diff = hibase - lobase;
|
|
loaddr = addr + lobase;
|
|
hiaddr = addr + hibase;
|
|
|
|
lomask = (N_word) (~0L << (lower AND MODMASK));
|
|
himask = (N_word) ~((~0L << (upper AND MODMASK)) << 1);
|
|
|
|
if (diff == 0)
|
|
{
|
|
*loaddr |= (lomask AND himask);
|
|
}
|
|
else
|
|
{
|
|
*loaddr++ |= lomask;
|
|
while (--diff > 0)
|
|
{
|
|
*loaddr++ = fill;
|
|
}
|
|
*hiaddr |= himask;
|
|
}
|
|
*(addr+size-1) &= mask_(addr);
|
|
}
|
|
}
|
|
|
|
void BitVector_Interval_Flip(wordptr addr, N_int lower, N_int upper)
|
|
{ /* X = X ^ [lower..upper] */
|
|
N_word bits = bits_(addr);
|
|
N_word size = size_(addr);
|
|
N_word flip = (N_word) ~0L;
|
|
wordptr loaddr;
|
|
wordptr hiaddr;
|
|
N_word lobase;
|
|
N_word hibase;
|
|
N_word lomask;
|
|
N_word himask;
|
|
N_word diff;
|
|
|
|
if ((size > 0) and (lower < bits) and (upper < bits) and (lower <= upper))
|
|
{
|
|
lobase = lower >> LOGBITS;
|
|
hibase = upper >> LOGBITS;
|
|
diff = hibase - lobase;
|
|
loaddr = addr + lobase;
|
|
hiaddr = addr + hibase;
|
|
|
|
lomask = (N_word) (~0L << (lower AND MODMASK));
|
|
himask = (N_word) ~((~0L << (upper AND MODMASK)) << 1);
|
|
|
|
if (diff == 0)
|
|
{
|
|
*loaddr ^= (lomask AND himask);
|
|
}
|
|
else
|
|
{
|
|
*loaddr++ ^= lomask;
|
|
while (--diff > 0)
|
|
{
|
|
*loaddr++ ^= flip;
|
|
}
|
|
*hiaddr ^= himask;
|
|
}
|
|
*(addr+size-1) &= mask_(addr);
|
|
}
|
|
}
|
|
|
|
void BitVector_Interval_Reverse(wordptr addr, N_int lower, N_int upper)
|
|
{
|
|
N_word bits = bits_(addr);
|
|
wordptr loaddr;
|
|
wordptr hiaddr;
|
|
N_word lomask;
|
|
N_word himask;
|
|
|
|
if ((bits > 0) and (lower < bits) and (upper < bits) and (lower < upper))
|
|
{
|
|
loaddr = addr + (lower >> LOGBITS);
|
|
hiaddr = addr + (upper >> LOGBITS);
|
|
lomask = BITMASKTAB[lower AND MODMASK];
|
|
himask = BITMASKTAB[upper AND MODMASK];
|
|
for ( bits = upper - lower + 1; bits > 1; bits -= 2 )
|
|
{
|
|
if (((*loaddr AND lomask) != 0) XOR ((*hiaddr AND himask) != 0))
|
|
{
|
|
*loaddr ^= lomask; /* swap bits only if they differ! */
|
|
*hiaddr ^= himask;
|
|
}
|
|
if (not (lomask <<= 1))
|
|
{
|
|
lomask = LSB;
|
|
loaddr++;
|
|
}
|
|
if (not (himask >>= 1))
|
|
{
|
|
himask = MSB;
|
|
hiaddr--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
boolean BitVector_interval_scan_inc(wordptr addr, N_int start,
|
|
N_intptr min, N_intptr max)
|
|
{
|
|
N_word size = size_(addr);
|
|
N_word mask = mask_(addr);
|
|
N_word offset;
|
|
N_word bitmask;
|
|
N_word value;
|
|
boolean empty;
|
|
|
|
if ((size == 0) or (start >= bits_(addr))) return(FALSE);
|
|
|
|
*min = start;
|
|
*max = start;
|
|
|
|
offset = start >> LOGBITS;
|
|
|
|
*(addr+size-1) &= mask;
|
|
|
|
addr += offset;
|
|
size -= offset;
|
|
|
|
bitmask = BITMASKTAB[start AND MODMASK];
|
|
mask = NOT (bitmask OR (bitmask - 1));
|
|
|
|
value = *addr++;
|
|
if ((value AND bitmask) == 0)
|
|
{
|
|
value &= mask;
|
|
if (value == 0)
|
|
{
|
|
offset++;
|
|
empty = TRUE;
|
|
while (empty and (--size > 0))
|
|
{
|
|
if ((value = *addr++)) empty = false; else offset++;
|
|
}
|
|
if (empty) return(FALSE);
|
|
}
|
|
start = offset << LOGBITS;
|
|
bitmask = LSB;
|
|
mask = value;
|
|
while (not (mask AND LSB))
|
|
{
|
|
bitmask <<= 1;
|
|
mask >>= 1;
|
|
start++;
|
|
}
|
|
mask = NOT (bitmask OR (bitmask - 1));
|
|
*min = start;
|
|
*max = start;
|
|
}
|
|
value = NOT value;
|
|
value &= mask;
|
|
if (value == 0)
|
|
{
|
|
offset++;
|
|
empty = TRUE;
|
|
while (empty and (--size > 0))
|
|
{
|
|
if ((value = NOT *addr++)) empty = false; else offset++;
|
|
}
|
|
if (empty) value = LSB;
|
|
}
|
|
start = offset << LOGBITS;
|
|
while (not (value AND LSB))
|
|
{
|
|
value >>= 1;
|
|
start++;
|
|
}
|
|
*max = --start;
|
|
return(TRUE);
|
|
}
|
|
|
|
boolean BitVector_interval_scan_dec(wordptr addr, N_int start,
|
|
N_intptr min, N_intptr max)
|
|
{
|
|
N_word size = size_(addr);
|
|
N_word mask = mask_(addr);
|
|
N_word offset;
|
|
N_word bitmask;
|
|
N_word value;
|
|
boolean empty;
|
|
|
|
if ((size == 0) or (start >= bits_(addr))) return(FALSE);
|
|
|
|
*min = start;
|
|
*max = start;
|
|
|
|
offset = start >> LOGBITS;
|
|
|
|
if (offset >= size) return(FALSE);
|
|
|
|
*(addr+size-1) &= mask;
|
|
|
|
addr += offset;
|
|
size = ++offset;
|
|
|
|
bitmask = BITMASKTAB[start AND MODMASK];
|
|
mask = (bitmask - 1);
|
|
|
|
value = *addr--;
|
|
if ((value AND bitmask) == 0)
|
|
{
|
|
value &= mask;
|
|
if (value == 0)
|
|
{
|
|
offset--;
|
|
empty = TRUE;
|
|
while (empty and (--size > 0))
|
|
{
|
|
if ((value = *addr--)) empty = false; else offset--;
|
|
}
|
|
if (empty) return(FALSE);
|
|
}
|
|
start = offset << LOGBITS;
|
|
bitmask = MSB;
|
|
mask = value;
|
|
while (not (mask AND MSB))
|
|
{
|
|
bitmask >>= 1;
|
|
mask <<= 1;
|
|
start--;
|
|
}
|
|
mask = (bitmask - 1);
|
|
*max = --start;
|
|
*min = start;
|
|
}
|
|
value = NOT value;
|
|
value &= mask;
|
|
if (value == 0)
|
|
{
|
|
offset--;
|
|
empty = TRUE;
|
|
while (empty and (--size > 0))
|
|
{
|
|
if ((value = NOT *addr--)) empty = false; else offset--;
|
|
}
|
|
if (empty) value = MSB;
|
|
}
|
|
start = offset << LOGBITS;
|
|
while (not (value AND MSB))
|
|
{
|
|
value <<= 1;
|
|
start--;
|
|
}
|
|
*min = start;
|
|
return(TRUE);
|
|
}
|
|
|
|
void BitVector_Interval_Copy(wordptr X, wordptr Y, N_int Xoffset,
|
|
N_int Yoffset, N_int length)
|
|
{
|
|
N_word bitsX = bits_(X);
|
|
N_word bitsY = bits_(Y);
|
|
N_word source = 0; /* silence compiler warning */
|
|
N_word target = 0; /* silence compiler warning */
|
|
N_word s_lo_base;
|
|
N_word s_hi_base;
|
|
N_word s_lo_bit;
|
|
N_word s_hi_bit;
|
|
N_word s_base;
|
|
N_word s_lower = 0; /* silence compiler warning */
|
|
N_word s_upper = 0; /* silence compiler warning */
|
|
N_word s_bits;
|
|
N_word s_min;
|
|
N_word s_max;
|
|
N_word t_lo_base;
|
|
N_word t_hi_base;
|
|
N_word t_lo_bit;
|
|
N_word t_hi_bit;
|
|
N_word t_base;
|
|
N_word t_lower = 0; /* silence compiler warning */
|
|
N_word t_upper = 0; /* silence compiler warning */
|
|
N_word t_bits;
|
|
N_word t_min;
|
|
N_word mask;
|
|
N_word bits;
|
|
N_word sel;
|
|
boolean ascending;
|
|
boolean notfirst;
|
|
wordptr Z = X;
|
|
|
|
if ((length > 0) and (Xoffset < bitsX) and (Yoffset < bitsY))
|
|
{
|
|
if ((Xoffset + length) > bitsX) length = bitsX - Xoffset;
|
|
if ((Yoffset + length) > bitsY) length = bitsY - Yoffset;
|
|
|
|
ascending = (Xoffset <= Yoffset);
|
|
|
|
s_lo_base = Yoffset >> LOGBITS;
|
|
s_lo_bit = Yoffset AND MODMASK;
|
|
Yoffset += --length;
|
|
s_hi_base = Yoffset >> LOGBITS;
|
|
s_hi_bit = Yoffset AND MODMASK;
|
|
|
|
t_lo_base = Xoffset >> LOGBITS;
|
|
t_lo_bit = Xoffset AND MODMASK;
|
|
Xoffset += length;
|
|
t_hi_base = Xoffset >> LOGBITS;
|
|
t_hi_bit = Xoffset AND MODMASK;
|
|
|
|
if (ascending)
|
|
{
|
|
s_base = s_lo_base;
|
|
t_base = t_lo_base;
|
|
}
|
|
else
|
|
{
|
|
s_base = s_hi_base;
|
|
t_base = t_hi_base;
|
|
}
|
|
s_bits = 0;
|
|
t_bits = 0;
|
|
Y += s_base;
|
|
X += t_base;
|
|
notfirst = FALSE;
|
|
while (TRUE)
|
|
{
|
|
if (t_bits == 0)
|
|
{
|
|
if (notfirst)
|
|
{
|
|
*X = target;
|
|
if (ascending)
|
|
{
|
|
if (t_base == t_hi_base) break;
|
|
t_base++;
|
|
X++;
|
|
}
|
|
else
|
|
{
|
|
if (t_base == t_lo_base) break;
|
|
t_base--;
|
|
X--;
|
|
}
|
|
}
|
|
sel = ((t_base == t_hi_base) << 1) OR (t_base == t_lo_base);
|
|
switch (sel)
|
|
{
|
|
case 0:
|
|
t_lower = 0;
|
|
t_upper = BITS - 1;
|
|
t_bits = BITS;
|
|
target = 0;
|
|
break;
|
|
case 1:
|
|
t_lower = t_lo_bit;
|
|
t_upper = BITS - 1;
|
|
t_bits = BITS - t_lo_bit;
|
|
mask = (N_word) (~0L << t_lower);
|
|
target = *X AND NOT mask;
|
|
break;
|
|
case 2:
|
|
t_lower = 0;
|
|
t_upper = t_hi_bit;
|
|
t_bits = t_hi_bit + 1;
|
|
mask = (N_word) ((~0L << t_upper) << 1);
|
|
target = *X AND mask;
|
|
break;
|
|
case 3:
|
|
t_lower = t_lo_bit;
|
|
t_upper = t_hi_bit;
|
|
t_bits = t_hi_bit - t_lo_bit + 1;
|
|
mask = (N_word) (~0L << t_lower);
|
|
mask &= (N_word) ~((~0L << t_upper) << 1);
|
|
target = *X AND NOT mask;
|
|
break;
|
|
}
|
|
}
|
|
if (s_bits == 0)
|
|
{
|
|
if (notfirst)
|
|
{
|
|
if (ascending)
|
|
{
|
|
if (s_base == s_hi_base) break;
|
|
s_base++;
|
|
Y++;
|
|
}
|
|
else
|
|
{
|
|
if (s_base == s_lo_base) break;
|
|
s_base--;
|
|
Y--;
|
|
}
|
|
}
|
|
source = *Y;
|
|
sel = ((s_base == s_hi_base) << 1) OR (s_base == s_lo_base);
|
|
switch (sel)
|
|
{
|
|
case 0:
|
|
s_lower = 0;
|
|
s_upper = BITS - 1;
|
|
s_bits = BITS;
|
|
break;
|
|
case 1:
|
|
s_lower = s_lo_bit;
|
|
s_upper = BITS - 1;
|
|
s_bits = BITS - s_lo_bit;
|
|
break;
|
|
case 2:
|
|
s_lower = 0;
|
|
s_upper = s_hi_bit;
|
|
s_bits = s_hi_bit + 1;
|
|
break;
|
|
case 3:
|
|
s_lower = s_lo_bit;
|
|
s_upper = s_hi_bit;
|
|
s_bits = s_hi_bit - s_lo_bit + 1;
|
|
break;
|
|
}
|
|
}
|
|
notfirst = TRUE;
|
|
if (s_bits > t_bits)
|
|
{
|
|
bits = t_bits - 1;
|
|
if (ascending)
|
|
{
|
|
s_min = s_lower;
|
|
s_max = s_lower + bits;
|
|
}
|
|
else
|
|
{
|
|
s_max = s_upper;
|
|
s_min = s_upper - bits;
|
|
}
|
|
t_min = t_lower;
|
|
}
|
|
else
|
|
{
|
|
bits = s_bits - 1;
|
|
if (ascending) t_min = t_lower;
|
|
else t_min = t_upper - bits;
|
|
s_min = s_lower;
|
|
s_max = s_upper;
|
|
}
|
|
bits++;
|
|
mask = (N_word) (~0L << s_min);
|
|
mask &= (N_word) ~((~0L << s_max) << 1);
|
|
if (s_min == t_min) target |= (source AND mask);
|
|
else
|
|
{
|
|
if (s_min < t_min) target |= (source AND mask) << (t_min-s_min);
|
|
else target |= (source AND mask) >> (s_min-t_min);
|
|
}
|
|
if (ascending)
|
|
{
|
|
s_lower += bits;
|
|
t_lower += bits;
|
|
}
|
|
else
|
|
{
|
|
s_upper -= bits;
|
|
t_upper -= bits;
|
|
}
|
|
s_bits -= bits;
|
|
t_bits -= bits;
|
|
}
|
|
*(Z+size_(Z)-1) &= mask_(Z);
|
|
}
|
|
}
|
|
|
|
|
|
wordptr BitVector_Interval_Substitute(wordptr X, wordptr Y,
|
|
N_int Xoffset, N_int Xlength,
|
|
N_int Yoffset, N_int Ylength)
|
|
{
|
|
N_word Xbits = bits_(X);
|
|
N_word Ybits = bits_(Y);
|
|
N_word limit;
|
|
N_word diff;
|
|
|
|
if ((Xoffset <= Xbits) and (Yoffset <= Ybits))
|
|
{
|
|
limit = Xoffset + Xlength;
|
|
if (limit > Xbits)
|
|
{
|
|
limit = Xbits;
|
|
Xlength = Xbits - Xoffset;
|
|
}
|
|
if ((Yoffset + Ylength) > Ybits)
|
|
{
|
|
Ylength = Ybits - Yoffset;
|
|
}
|
|
if (Xlength == Ylength)
|
|
{
|
|
if ((Ylength > 0) and ((X != Y) or (Xoffset != Yoffset)))
|
|
{
|
|
BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength);
|
|
}
|
|
}
|
|
else /* Xlength != Ylength */
|
|
{
|
|
if (Xlength > Ylength)
|
|
{
|
|
diff = Xlength - Ylength;
|
|
if (Ylength > 0) BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength);
|
|
if (limit < Xbits) BitVector_Delete(X,Xoffset+Ylength,diff,FALSE);
|
|
if ((X = BitVector_Resize(X,Xbits-diff)) == NULL) return(NULL);
|
|
}
|
|
else /* Ylength > Xlength ==> Ylength > 0 */
|
|
{
|
|
diff = Ylength - Xlength;
|
|
if (X != Y)
|
|
{
|
|
if ((X = BitVector_Resize(X,Xbits+diff)) == NULL) return(NULL);
|
|
if (limit < Xbits) BitVector_Insert(X,limit,diff,FALSE);
|
|
BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength);
|
|
}
|
|
else /* in-place */
|
|
{
|
|
if ((Y = X = BitVector_Resize(X,Xbits+diff)) == NULL) return(NULL);
|
|
if (limit >= Xbits)
|
|
{
|
|
BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength);
|
|
}
|
|
else /* limit < Xbits */
|
|
{
|
|
BitVector_Insert(X,limit,diff,FALSE);
|
|
if ((Yoffset+Ylength) <= limit)
|
|
{
|
|
BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength);
|
|
}
|
|
else /* overlaps or lies above critical area */
|
|
{
|
|
if (limit <= Yoffset)
|
|
{
|
|
Yoffset += diff;
|
|
BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength);
|
|
}
|
|
else /* Yoffset < limit */
|
|
{
|
|
Xlength = limit - Yoffset;
|
|
BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Xlength);
|
|
Yoffset = Xoffset + Ylength; /* = limit + diff */
|
|
Xoffset += Xlength;
|
|
Ylength -= Xlength;
|
|
BitVector_Interval_Copy(X,Y,Xoffset,Yoffset,Ylength);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return(X);
|
|
}
|
|
|
|
boolean BitVector_is_empty(wordptr addr) /* X == {} ? */
|
|
{
|
|
N_word size = size_(addr);
|
|
boolean r = TRUE;
|
|
|
|
if (size > 0)
|
|
{
|
|
*(addr+size-1) &= mask_(addr);
|
|
while (r and (size-- > 0)) r = ( *addr++ == 0 );
|
|
}
|
|
return(r);
|
|
}
|
|
|
|
boolean BitVector_is_full(wordptr addr) /* X == ~{} ? */
|
|
{
|
|
N_word size = size_(addr);
|
|
N_word mask = mask_(addr);
|
|
boolean r = FALSE;
|
|
wordptr last;
|
|
|
|
if (size > 0)
|
|
{
|
|
r = TRUE;
|
|
last = addr + size - 1;
|
|
*last |= NOT mask;
|
|
while (r and (size-- > 0)) r = ( NOT *addr++ == 0 );
|
|
*last &= mask;
|
|
}
|
|
return(r);
|
|
}
|
|
|
|
boolean BitVector_equal(wordptr X, wordptr Y) /* X == Y ? */
|
|
{
|
|
N_word size = size_(X);
|
|
N_word mask = mask_(X);
|
|
boolean r = FALSE;
|
|
|
|
if (bits_(X) == bits_(Y))
|
|
{
|
|
r = TRUE;
|
|
if (size > 0)
|
|
{
|
|
*(X+size-1) &= mask;
|
|
*(Y+size-1) &= mask;
|
|
while (r and (size-- > 0)) r = (*X++ == *Y++);
|
|
}
|
|
}
|
|
return(r);
|
|
}
|
|
|
|
Z_int BitVector_Lexicompare(wordptr X, wordptr Y) /* X <,=,> Y ? */
|
|
{ /* unsigned */
|
|
N_word bitsX = bits_(X);
|
|
N_word bitsY = bits_(Y);
|
|
N_word size = size_(X);
|
|
boolean r = TRUE;
|
|
|
|
if (bitsX == bitsY)
|
|
{
|
|
if (size > 0)
|
|
{
|
|
X += size;
|
|
Y += size;
|
|
while (r and (size-- > 0)) r = (*(--X) == *(--Y));
|
|
}
|
|
if (r) return((Z_int) 0);
|
|
else
|
|
{
|
|
if (*X < *Y) return((Z_int) -1); else return((Z_int) 1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (bitsX < bitsY) return((Z_int) -1); else return((Z_int) 1);
|
|
}
|
|
}
|
|
|
|
Z_int BitVector_Compare(wordptr X, wordptr Y) /* X <,=,> Y ? */
|
|
{ /* signed */
|
|
N_word bitsX = bits_(X);
|
|
N_word bitsY = bits_(Y);
|
|
N_word size = size_(X);
|
|
N_word mask = mask_(X);
|
|
N_word sign;
|
|
boolean r = TRUE;
|
|
|
|
if (bitsX == bitsY)
|
|
{
|
|
if (size > 0)
|
|
{
|
|
X += size;
|
|
Y += size;
|
|
mask &= NOT (mask >> 1);
|
|
if ((sign = (*(X-1) AND mask)) != (*(Y-1) AND mask))
|
|
{
|
|
if (sign) return((Z_int) -1); else return((Z_int) 1);
|
|
}
|
|
while (r and (size-- > 0)) r = (*(--X) == *(--Y));
|
|
}
|
|
if (r) return((Z_int) 0);
|
|
else
|
|
{
|
|
if (*X < *Y) return((Z_int) -1); else return((Z_int) 1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (bitsX < bitsY) return((Z_int) -1); else return((Z_int) 1);
|
|
}
|
|
}
|
|
|
|
charptr BitVector_to_Hex(wordptr addr)
|
|
{
|
|
N_word bits = bits_(addr);
|
|
N_word size = size_(addr);
|
|
N_word value;
|
|
N_word count;
|
|
N_word digit;
|
|
N_word length;
|
|
charptr string;
|
|
|
|
length = bits >> 2;
|
|
if (bits AND 0x0003) length++;
|
|
string = (charptr) yasm_xmalloc((size_t) (length+1));
|
|
if (string == NULL) return(NULL);
|
|
string += length;
|
|
*string = (N_char) '\0';
|
|
if (size > 0)
|
|
{
|
|
*(addr+size-1) &= mask_(addr);
|
|
while ((size-- > 0) and (length > 0))
|
|
{
|
|
value = *addr++;
|
|
count = BITS >> 2;
|
|
while ((count-- > 0) and (length > 0))
|
|
{
|
|
digit = value AND 0x000F;
|
|
if (digit > 9) digit += (N_word) 'A' - 10;
|
|
else digit += (N_word) '0';
|
|
*(--string) = (N_char) digit; length--;
|
|
if ((count > 0) and (length > 0)) value >>= 4;
|
|
}
|
|
}
|
|
}
|
|
return(string);
|
|
}
|
|
|
|
ErrCode BitVector_from_Hex(wordptr addr, charptr string)
|
|
{
|
|
N_word size = size_(addr);
|
|
N_word mask = mask_(addr);
|
|
boolean ok = TRUE;
|
|
size_t length;
|
|
N_word value;
|
|
N_word count;
|
|
int digit;
|
|
|
|
if (size > 0)
|
|
{
|
|
length = strlen((char *) string);
|
|
string += length;
|
|
while (size-- > 0)
|
|
{
|
|
value = 0;
|
|
for ( count = 0; (ok and (length > 0) and (count < BITS)); count += 4 )
|
|
{
|
|
digit = (int) *(--string); length--;
|
|
/* separate because toupper() is likely a macro! */
|
|
digit = toupper(digit);
|
|
if (digit == '_')
|
|
count -= 4;
|
|
else if ((ok = (isxdigit(digit) != 0)))
|
|
{
|
|
if (digit >= (int) 'A') digit -= (int) 'A' - 10;
|
|
else digit -= (int) '0';
|
|
value |= (((N_word) digit) << count);
|
|
}
|
|
}
|
|
*addr++ = value;
|
|
}
|
|
*(--addr) &= mask;
|
|
}
|
|
if (ok) return(ErrCode_Ok);
|
|
else return(ErrCode_Pars);
|
|
}
|
|
|
|
ErrCode BitVector_from_Oct(wordptr addr, charptr string)
|
|
{
|
|
N_word size = size_(addr);
|
|
N_word mask = mask_(addr);
|
|
boolean ok = TRUE;
|
|
size_t length;
|
|
N_word value;
|
|
N_word value_fill = 0;
|
|
N_word count;
|
|
Z_word count_fill = 0;
|
|
int digit = 0;
|
|
|
|
if (size > 0)
|
|
{
|
|
length = strlen((char *) string);
|
|
string += length;
|
|
while (size-- > 0)
|
|
{
|
|
value = value_fill;
|
|
for ( count = count_fill; (ok and (length > 0) and (count < BITS)); count += 3 )
|
|
{
|
|
digit = (int) *(--string); length--;
|
|
if (digit == '_')
|
|
count -= 3;
|
|
else if ((ok = (isdigit(digit) && digit != '8' && digit != '9')) != 0)
|
|
{
|
|
digit -= (int) '0';
|
|
value |= (((N_word) digit) << count);
|
|
}
|
|
}
|
|
count_fill = (Z_word)count-(Z_word)BITS;
|
|
if (count_fill > 0)
|
|
value_fill = (((N_word) digit) >> (3-count_fill));
|
|
else
|
|
value_fill = 0;
|
|
*addr++ = value;
|
|
}
|
|
*(--addr) &= mask;
|
|
}
|
|
if (ok) return(ErrCode_Ok);
|
|
else return(ErrCode_Pars);
|
|
}
|
|
|
|
charptr BitVector_to_Bin(wordptr addr)
|
|
{
|
|
N_word size = size_(addr);
|
|
N_word value;
|
|
N_word count;
|
|
N_word digit;
|
|
N_word length;
|
|
charptr string;
|
|
|
|
length = bits_(addr);
|
|
string = (charptr) yasm_xmalloc((size_t) (length+1));
|
|
if (string == NULL) return(NULL);
|
|
string += length;
|
|
*string = (N_char) '\0';
|
|
if (size > 0)
|
|
{
|
|
*(addr+size-1) &= mask_(addr);
|
|
while (size-- > 0)
|
|
{
|
|
value = *addr++;
|
|
count = BITS;
|
|
if (count > length) count = length;
|
|
while (count-- > 0)
|
|
{
|
|
digit = value AND 0x0001;
|
|
digit += (N_word) '0';
|
|
*(--string) = (N_char) digit; length--;
|
|
if (count > 0) value >>= 1;
|
|
}
|
|
}
|
|
}
|
|
return(string);
|
|
}
|
|
|
|
ErrCode BitVector_from_Bin(wordptr addr, charptr string)
|
|
{
|
|
N_word size = size_(addr);
|
|
N_word mask = mask_(addr);
|
|
boolean ok = TRUE;
|
|
size_t length;
|
|
N_word value;
|
|
N_word count;
|
|
int digit;
|
|
|
|
if (size > 0)
|
|
{
|
|
length = strlen((char *) string);
|
|
string += length;
|
|
while (size-- > 0)
|
|
{
|
|
value = 0;
|
|
for ( count = 0; (ok and (length > 0) and (count < BITS)); count++ )
|
|
{
|
|
digit = (int) *(--string); length--;
|
|
switch (digit)
|
|
{
|
|
case (int) '0':
|
|
break;
|
|
case (int) '1':
|
|
value |= BITMASKTAB[count];
|
|
break;
|
|
case (int) '_':
|
|
count--;
|
|
break;
|
|
default:
|
|
ok = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
*addr++ = value;
|
|
}
|
|
*(--addr) &= mask;
|
|
}
|
|
if (ok) return(ErrCode_Ok);
|
|
else return(ErrCode_Pars);
|
|
}
|
|
|
|
charptr BitVector_to_Dec(wordptr addr)
|
|
{
|
|
N_word bits = bits_(addr);
|
|
N_word length;
|
|
N_word digits;
|
|
N_word count;
|
|
N_word q;
|
|
N_word r;
|
|
boolean loop;
|
|
charptr result;
|
|
charptr string;
|
|
wordptr quot;
|
|
wordptr rest;
|
|
wordptr temp;
|
|
wordptr base;
|
|
Z_int sign;
|
|
|
|
length = (N_word) (bits / 3.3); /* digits = bits * ln(2) / ln(10) */
|
|
length += 2; /* compensate for truncating & provide space for minus sign */
|
|
result = (charptr) yasm_xmalloc((size_t) (length+1)); /* remember the '\0'! */
|
|
if (result == NULL) return(NULL);
|
|
string = result;
|
|
sign = BitVector_Sign(addr);
|
|
if ((bits < 4) or (sign == 0))
|
|
{
|
|
if (bits > 0) digits = *addr; else digits = (N_word) 0;
|
|
if (sign < 0) digits = ((N_word)(-((Z_word)digits))) AND mask_(addr);
|
|
*string++ = (N_char) digits + (N_char) '0';
|
|
digits = 1;
|
|
}
|
|
else
|
|
{
|
|
quot = BitVector_Create(bits,FALSE);
|
|
if (quot == NULL)
|
|
{
|
|
BitVector_Dispose(result);
|
|
return(NULL);
|
|
}
|
|
rest = BitVector_Create(bits,FALSE);
|
|
if (rest == NULL)
|
|
{
|
|
BitVector_Dispose(result);
|
|
BitVector_Destroy(quot);
|
|
return(NULL);
|
|
}
|
|
temp = BitVector_Create(bits,FALSE);
|
|
if (temp == NULL)
|
|
{
|
|
BitVector_Dispose(result);
|
|
BitVector_Destroy(quot);
|
|
BitVector_Destroy(rest);
|
|
return(NULL);
|
|
}
|
|
base = BitVector_Create(bits,TRUE);
|
|
if (base == NULL)
|
|
{
|
|
BitVector_Dispose(result);
|
|
BitVector_Destroy(quot);
|
|
BitVector_Destroy(rest);
|
|
BitVector_Destroy(temp);
|
|
return(NULL);
|
|
}
|
|
if (sign < 0) BitVector_Negate(quot,addr);
|
|
else BitVector_Copy(quot,addr);
|
|
digits = 0;
|
|
*base = EXP10;
|
|
loop = (bits >= BITS);
|
|
do
|
|
{
|
|
if (loop)
|
|
{
|
|
BitVector_Copy(temp,quot);
|
|
if (BitVector_Div_Pos(quot,temp,base,rest))
|
|
{
|
|
BitVector_Dispose(result); /* emergency exit */
|
|
BitVector_Destroy(quot);
|
|
BitVector_Destroy(rest); /* should never occur */
|
|
BitVector_Destroy(temp); /* under normal operation */
|
|
BitVector_Destroy(base);
|
|
return(NULL);
|
|
}
|
|
loop = not BitVector_is_empty(quot);
|
|
q = *rest;
|
|
}
|
|
else q = *quot;
|
|
count = LOG10;
|
|
while (((loop and (count-- > 0)) or ((not loop) and (q != 0))) and
|
|
(digits < length))
|
|
{
|
|
if (q != 0)
|
|
{
|
|
BIT_VECTOR_DIGITIZE(N_word,q,r)
|
|
}
|
|
else r = (N_word) '0';
|
|
*string++ = (N_char) r;
|
|
digits++;
|
|
}
|
|
}
|
|
while (loop and (digits < length));
|
|
BitVector_Destroy(quot);
|
|
BitVector_Destroy(rest);
|
|
BitVector_Destroy(temp);
|
|
BitVector_Destroy(base);
|
|
}
|
|
if ((sign < 0) and (digits < length))
|
|
{
|
|
*string++ = (N_char) '-';
|
|
digits++;
|
|
}
|
|
*string = (N_char) '\0';
|
|
BIT_VECTOR_reverse(result,digits);
|
|
return(result);
|
|
}
|
|
|
|
struct BitVector_from_Dec_static_data {
|
|
wordptr term;
|
|
wordptr base;
|
|
wordptr prod;
|
|
wordptr rank;
|
|
wordptr temp;
|
|
};
|
|
|
|
BitVector_from_Dec_static_data *BitVector_from_Dec_static_Boot(N_word bits)
|
|
{
|
|
BitVector_from_Dec_static_data *data;
|
|
|
|
data = yasm_xmalloc(sizeof(BitVector_from_Dec_static_data));
|
|
|
|
if (bits > 0)
|
|
{
|
|
data->term = BitVector_Create(BITS,FALSE);
|
|
data->base = BitVector_Create(BITS,FALSE);
|
|
data->prod = BitVector_Create(bits,FALSE);
|
|
data->rank = BitVector_Create(bits,FALSE);
|
|
data->temp = BitVector_Create(bits,FALSE);
|
|
} else {
|
|
data->term = NULL;
|
|
data->base = NULL;
|
|
data->prod = NULL;
|
|
data->rank = NULL;
|
|
data->temp = NULL;
|
|
}
|
|
return data;
|
|
}
|
|
|
|
void BitVector_from_Dec_static_Shutdown(BitVector_from_Dec_static_data *data)
|
|
{
|
|
if (data) {
|
|
BitVector_Destroy(data->term);
|
|
BitVector_Destroy(data->base);
|
|
BitVector_Destroy(data->prod);
|
|
BitVector_Destroy(data->rank);
|
|
BitVector_Destroy(data->temp);
|
|
}
|
|
yasm_xfree(data);
|
|
}
|
|
|
|
ErrCode BitVector_from_Dec_static(BitVector_from_Dec_static_data *data,
|
|
wordptr addr, charptr string)
|
|
{
|
|
ErrCode error = ErrCode_Ok;
|
|
N_word bits = bits_(addr);
|
|
N_word mask = mask_(addr);
|
|
boolean init = (bits > BITS);
|
|
boolean minus;
|
|
boolean shift;
|
|
boolean carry;
|
|
wordptr term;
|
|
wordptr base;
|
|
wordptr prod;
|
|
wordptr rank;
|
|
wordptr temp;
|
|
N_word accu;
|
|
N_word powr;
|
|
N_word count;
|
|
size_t length;
|
|
int digit;
|
|
|
|
if (bits > 0)
|
|
{
|
|
term = data->term;
|
|
base = data->base;
|
|
prod = data->prod;
|
|
rank = data->rank;
|
|
temp = data->temp;
|
|
|
|
length = strlen((char *) string);
|
|
if (length == 0) return(ErrCode_Pars);
|
|
digit = (int) *string;
|
|
if ((minus = (digit == (int) '-')) or
|
|
(digit == (int) '+'))
|
|
{
|
|
string++;
|
|
if (--length == 0) return(ErrCode_Pars);
|
|
}
|
|
string += length;
|
|
if (init)
|
|
{
|
|
BitVector_Empty(prod);
|
|
BitVector_Empty(rank);
|
|
}
|
|
BitVector_Empty(addr);
|
|
*base = EXP10;
|
|
shift = FALSE;
|
|
while ((not error) and (length > 0))
|
|
{
|
|
accu = 0;
|
|
powr = 1;
|
|
count = LOG10;
|
|
while ((not error) and (length > 0) and (count-- > 0))
|
|
{
|
|
digit = (int) *(--string); length--;
|
|
/* separate because isdigit() is likely a macro! */
|
|
if (isdigit(digit) != 0)
|
|
{
|
|
accu += ((N_word) digit - (N_word) '0') * powr;
|
|
powr *= 10;
|
|
}
|
|
else error = ErrCode_Pars;
|
|
}
|
|
if (not error)
|
|
{
|
|
if (shift)
|
|
{
|
|
*term = accu;
|
|
BitVector_Copy(temp,rank);
|
|
error = BitVector_Mul_Pos(prod,temp,term,FALSE);
|
|
}
|
|
else
|
|
{
|
|
*prod = accu;
|
|
if ((not init) and ((accu AND NOT mask) != 0)) error = ErrCode_Ovfl;
|
|
}
|
|
if (not error)
|
|
{
|
|
carry = FALSE;
|
|
BitVector_compute(addr,addr,prod,FALSE,&carry);
|
|
/* ignores sign change (= overflow) but not */
|
|
/* numbers too large (= carry) for resulting bit vector */
|
|
if (carry) error = ErrCode_Ovfl;
|
|
else
|
|
{
|
|
if (length > 0)
|
|
{
|
|
if (shift)
|
|
{
|
|
BitVector_Copy(temp,rank);
|
|
error = BitVector_Mul_Pos(rank,temp,base,FALSE);
|
|
}
|
|
else
|
|
{
|
|
*rank = *base;
|
|
shift = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (not error and minus)
|
|
{
|
|
BitVector_Negate(addr,addr);
|
|
if ((*(addr + size_(addr) - 1) AND mask AND NOT (mask >> 1)) == 0)
|
|
error = ErrCode_Ovfl;
|
|
}
|
|
}
|
|
return(error);
|
|
}
|
|
|
|
ErrCode BitVector_from_Dec(wordptr addr, charptr string)
|
|
{
|
|
ErrCode error = ErrCode_Ok;
|
|
N_word bits = bits_(addr);
|
|
N_word mask = mask_(addr);
|
|
boolean init = (bits > BITS);
|
|
boolean minus;
|
|
boolean shift;
|
|
boolean carry;
|
|
wordptr term;
|
|
wordptr base;
|
|
wordptr prod;
|
|
wordptr rank;
|
|
wordptr temp;
|
|
N_word accu;
|
|
N_word powr;
|
|
N_word count;
|
|
size_t length;
|
|
int digit;
|
|
|
|
if (bits > 0)
|
|
{
|
|
length = strlen((char *) string);
|
|
if (length == 0) return(ErrCode_Pars);
|
|
digit = (int) *string;
|
|
if ((minus = (digit == (int) '-')) or
|
|
(digit == (int) '+'))
|
|
{
|
|
string++;
|
|
if (--length == 0) return(ErrCode_Pars);
|
|
}
|
|
string += length;
|
|
term = BitVector_Create(BITS,FALSE);
|
|
if (term == NULL)
|
|
{
|
|
return(ErrCode_Null);
|
|
}
|
|
base = BitVector_Create(BITS,FALSE);
|
|
if (base == NULL)
|
|
{
|
|
BitVector_Destroy(term);
|
|
return(ErrCode_Null);
|
|
}
|
|
prod = BitVector_Create(bits,init);
|
|
if (prod == NULL)
|
|
{
|
|
BitVector_Destroy(term);
|
|
BitVector_Destroy(base);
|
|
return(ErrCode_Null);
|
|
}
|
|
rank = BitVector_Create(bits,init);
|
|
if (rank == NULL)
|
|
{
|
|
BitVector_Destroy(term);
|
|
BitVector_Destroy(base);
|
|
BitVector_Destroy(prod);
|
|
return(ErrCode_Null);
|
|
}
|
|
temp = BitVector_Create(bits,FALSE);
|
|
if (temp == NULL)
|
|
{
|
|
BitVector_Destroy(term);
|
|
BitVector_Destroy(base);
|
|
BitVector_Destroy(prod);
|
|
BitVector_Destroy(rank);
|
|
return(ErrCode_Null);
|
|
}
|
|
BitVector_Empty(addr);
|
|
*base = EXP10;
|
|
shift = FALSE;
|
|
while ((not error) and (length > 0))
|
|
{
|
|
accu = 0;
|
|
powr = 1;
|
|
count = LOG10;
|
|
while ((not error) and (length > 0) and (count-- > 0))
|
|
{
|
|
digit = (int) *(--string); length--;
|
|
/* separate because isdigit() is likely a macro! */
|
|
if (isdigit(digit) != 0)
|
|
{
|
|
accu += ((N_word) digit - (N_word) '0') * powr;
|
|
powr *= 10;
|
|
}
|
|
else error = ErrCode_Pars;
|
|
}
|
|
if (not error)
|
|
{
|
|
if (shift)
|
|
{
|
|
*term = accu;
|
|
BitVector_Copy(temp,rank);
|
|
error = BitVector_Mul_Pos(prod,temp,term,FALSE);
|
|
}
|
|
else
|
|
{
|
|
*prod = accu;
|
|
if ((not init) and ((accu AND NOT mask) != 0)) error = ErrCode_Ovfl;
|
|
}
|
|
if (not error)
|
|
{
|
|
carry = FALSE;
|
|
BitVector_compute(addr,addr,prod,FALSE,&carry);
|
|
/* ignores sign change (= overflow) but not */
|
|
/* numbers too large (= carry) for resulting bit vector */
|
|
if (carry) error = ErrCode_Ovfl;
|
|
else
|
|
{
|
|
if (length > 0)
|
|
{
|
|
if (shift)
|
|
{
|
|
BitVector_Copy(temp,rank);
|
|
error = BitVector_Mul_Pos(rank,temp,base,FALSE);
|
|
}
|
|
else
|
|
{
|
|
*rank = *base;
|
|
shift = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
BitVector_Destroy(term);
|
|
BitVector_Destroy(base);
|
|
BitVector_Destroy(prod);
|
|
BitVector_Destroy(rank);
|
|
BitVector_Destroy(temp);
|
|
if (not error and minus)
|
|
{
|
|
BitVector_Negate(addr,addr);
|
|
if ((*(addr + size_(addr) - 1) AND mask AND NOT (mask >> 1)) == 0)
|
|
error = ErrCode_Ovfl;
|
|
}
|
|
}
|
|
return(error);
|
|
}
|
|
|
|
charptr BitVector_to_Enum(wordptr addr)
|
|
{
|
|
N_word bits = bits_(addr);
|
|
N_word sample;
|
|
N_word length;
|
|
N_word digits;
|
|
N_word factor;
|
|
N_word power;
|
|
N_word start;
|
|
N_word min;
|
|
N_word max;
|
|
charptr string;
|
|
charptr target;
|
|
boolean comma;
|
|
|
|
if (bits > 0)
|
|
{
|
|
sample = bits - 1; /* greatest possible index */
|
|
length = 2; /* account for index 0 and terminating '\0' */
|
|
digits = 1; /* account for intervening dashes and commas */
|
|
factor = 1;
|
|
power = 10;
|
|
while (sample >= (power-1))
|
|
{
|
|
length += ++digits * factor * 6; /* 9,90,900,9000,... (9*2/3 = 6) */
|
|
factor = power;
|
|
power *= 10;
|
|
}
|
|
if (sample > --factor)
|
|
{
|
|
sample -= factor;
|
|
factor = (N_word) ( sample / 3 );
|
|
factor = (factor << 1) + (sample - (factor * 3));
|
|
length += ++digits * factor;
|
|
}
|
|
}
|
|
else length = 1;
|
|
string = (charptr) yasm_xmalloc((size_t) length);
|
|
if (string == NULL) return(NULL);
|
|
start = 0;
|
|
comma = FALSE;
|
|
target = string;
|
|
while ((start < bits) and BitVector_interval_scan_inc(addr,start,&min,&max))
|
|
{
|
|
start = max + 2;
|
|
if (comma) *target++ = (N_char) ',';
|
|
if (min == max)
|
|
{
|
|
target += BIT_VECTOR_int2str(target,min);
|
|
}
|
|
else
|
|
{
|
|
if (min+1 == max)
|
|
{
|
|
target += BIT_VECTOR_int2str(target,min);
|
|
*target++ = (N_char) ',';
|
|
target += BIT_VECTOR_int2str(target,max);
|
|
}
|
|
else
|
|
{
|
|
target += BIT_VECTOR_int2str(target,min);
|
|
*target++ = (N_char) '-';
|
|
target += BIT_VECTOR_int2str(target,max);
|
|
}
|
|
}
|
|
comma = TRUE;
|
|
}
|
|
*target = (N_char) '\0';
|
|
return(string);
|
|
}
|
|
|
|
ErrCode BitVector_from_Enum(wordptr addr, charptr string)
|
|
{
|
|
ErrCode error = ErrCode_Ok;
|
|
N_word bits = bits_(addr);
|
|
N_word state = 1;
|
|
N_word token;
|
|
N_word indx = 0; /* silence compiler warning */
|
|
N_word start = 0; /* silence compiler warning */
|
|
|
|
if (bits > 0)
|
|
{
|
|
BitVector_Empty(addr);
|
|
while ((not error) and (state != 0))
|
|
{
|
|
token = (N_word) *string;
|
|
/* separate because isdigit() is likely a macro! */
|
|
if (isdigit((int)token) != 0)
|
|
{
|
|
string += BIT_VECTOR_str2int(string,&indx);
|
|
if (indx < bits) token = (N_word) '0';
|
|
else error = ErrCode_Indx;
|
|
}
|
|
else string++;
|
|
if (not error)
|
|
switch (state)
|
|
{
|
|
case 1:
|
|
switch (token)
|
|
{
|
|
case (N_word) '0':
|
|
state = 2;
|
|
break;
|
|
case (N_word) '\0':
|
|
state = 0;
|
|
break;
|
|
default:
|
|
error = ErrCode_Pars;
|
|
break;
|
|
}
|
|
break;
|
|
case 2:
|
|
switch (token)
|
|
{
|
|
case (N_word) '-':
|
|
start = indx;
|
|
state = 3;
|
|
break;
|
|
case (N_word) ',':
|
|
BIT_VECTOR_SET_BIT(addr,indx)
|
|
state = 5;
|
|
break;
|
|
case (N_word) '\0':
|
|
BIT_VECTOR_SET_BIT(addr,indx)
|
|
state = 0;
|
|
break;
|
|
default:
|
|
error = ErrCode_Pars;
|
|
break;
|
|
}
|
|
break;
|
|
case 3:
|
|
switch (token)
|
|
{
|
|
case (N_word) '0':
|
|
if (start < indx)
|
|
BitVector_Interval_Fill(addr,start,indx);
|
|
else if (start == indx)
|
|
BIT_VECTOR_SET_BIT(addr,indx)
|
|
else error = ErrCode_Ordr;
|
|
state = 4;
|
|
break;
|
|
default:
|
|
error = ErrCode_Pars;
|
|
break;
|
|
}
|
|
break;
|
|
case 4:
|
|
switch (token)
|
|
{
|
|
case (N_word) ',':
|
|
state = 5;
|
|
break;
|
|
case (N_word) '\0':
|
|
state = 0;
|
|
break;
|
|
default:
|
|
error = ErrCode_Pars;
|
|
break;
|
|
}
|
|
break;
|
|
case 5:
|
|
switch (token)
|
|
{
|
|
case (N_word) '0':
|
|
state = 2;
|
|
break;
|
|
default:
|
|
error = ErrCode_Pars;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return(error);
|
|
}
|
|
|
|
void BitVector_Bit_Off(wordptr addr, N_int indx) /* X = X \ {x} */
|
|
{
|
|
if (indx < bits_(addr)) BIT_VECTOR_CLR_BIT(addr,indx)
|
|
}
|
|
|
|
void BitVector_Bit_On(wordptr addr, N_int indx) /* X = X + {x} */
|
|
{
|
|
if (indx < bits_(addr)) BIT_VECTOR_SET_BIT(addr,indx)
|
|
}
|
|
|
|
boolean BitVector_bit_flip(wordptr addr, N_int indx) /* X=(X+{x})\(X*{x}) */
|
|
{
|
|
N_word mask;
|
|
|
|
if (indx < bits_(addr)) return( BIT_VECTOR_FLP_BIT(addr,indx,mask) );
|
|
else return( FALSE );
|
|
}
|
|
|
|
boolean BitVector_bit_test(wordptr addr, N_int indx) /* {x} in X ? */
|
|
{
|
|
if (indx < bits_(addr)) return( BIT_VECTOR_TST_BIT(addr,indx) );
|
|
else return( FALSE );
|
|
}
|
|
|
|
void BitVector_Bit_Copy(wordptr addr, N_int indx, boolean bit)
|
|
{
|
|
if (indx < bits_(addr))
|
|
{
|
|
if (bit) BIT_VECTOR_SET_BIT(addr,indx)
|
|
else BIT_VECTOR_CLR_BIT(addr,indx)
|
|
}
|
|
}
|
|
|
|
void BitVector_LSB(wordptr addr, boolean bit)
|
|
{
|
|
if (bits_(addr) > 0)
|
|
{
|
|
if (bit) *addr |= LSB;
|
|
else *addr &= NOT LSB;
|
|
}
|
|
}
|
|
|
|
void BitVector_MSB(wordptr addr, boolean bit)
|
|
{
|
|
N_word size = size_(addr);
|
|
N_word mask = mask_(addr);
|
|
|
|
if (size-- > 0)
|
|
{
|
|
if (bit) *(addr+size) |= mask AND NOT (mask >> 1);
|
|
else *(addr+size) &= NOT mask OR (mask >> 1);
|
|
}
|
|
}
|
|
|
|
boolean BitVector_lsb_(wordptr addr)
|
|
{
|
|
if (size_(addr) > 0) return( (*addr AND LSB) != 0 );
|
|
else return( FALSE );
|
|
}
|
|
|
|
boolean BitVector_msb_(wordptr addr)
|
|
{
|
|
N_word size = size_(addr);
|
|
N_word mask = mask_(addr);
|
|
|
|
if (size-- > 0)
|
|
return( (*(addr+size) AND (mask AND NOT (mask >> 1))) != 0 );
|
|
else
|
|
return( FALSE );
|
|
}
|
|
|
|
boolean BitVector_rotate_left(wordptr addr)
|
|
{
|
|
N_word size = size_(addr);
|
|
N_word mask = mask_(addr);
|
|
N_word msb;
|
|
boolean carry_in;
|
|
boolean carry_out = FALSE;
|
|
|
|
if (size > 0)
|
|
{
|
|
msb = mask AND NOT (mask >> 1);
|
|
carry_in = ((*(addr+size-1) AND msb) != 0);
|
|
while (size-- > 1)
|
|
{
|
|
carry_out = ((*addr AND MSB) != 0);
|
|
*addr <<= 1;
|
|
if (carry_in) *addr |= LSB;
|
|
carry_in = carry_out;
|
|
addr++;
|
|
}
|
|
carry_out = ((*addr AND msb) != 0);
|
|
*addr <<= 1;
|
|
if (carry_in) *addr |= LSB;
|
|
*addr &= mask;
|
|
}
|
|
return(carry_out);
|
|
}
|
|
|
|
boolean BitVector_rotate_right(wordptr addr)
|
|
{
|
|
N_word size = size_(addr);
|
|
N_word mask = mask_(addr);
|
|
N_word msb;
|
|
boolean carry_in;
|
|
boolean carry_out = FALSE;
|
|
|
|
if (size > 0)
|
|
{
|
|
msb = mask AND NOT (mask >> 1);
|
|
carry_in = ((*addr AND LSB) != 0);
|
|
addr += size-1;
|
|
*addr &= mask;
|
|
carry_out = ((*addr AND LSB) != 0);
|
|
*addr >>= 1;
|
|
if (carry_in) *addr |= msb;
|
|
carry_in = carry_out;
|
|
addr--;
|
|
size--;
|
|
while (size-- > 0)
|
|
{
|
|
carry_out = ((*addr AND LSB) != 0);
|
|
*addr >>= 1;
|
|
if (carry_in) *addr |= MSB;
|
|
carry_in = carry_out;
|
|
addr--;
|
|
}
|
|
}
|
|
return(carry_out);
|
|
}
|
|
|
|
boolean BitVector_shift_left(wordptr addr, boolean carry_in)
|
|
{
|
|
N_word size = size_(addr);
|
|
N_word mask = mask_(addr);
|
|
N_word msb;
|
|
boolean carry_out = carry_in;
|
|
|
|
if (size > 0)
|
|
{
|
|
msb = mask AND NOT (mask >> 1);
|
|
while (size-- > 1)
|
|
{
|
|
carry_out = ((*addr AND MSB) != 0);
|
|
*addr <<= 1;
|
|
if (carry_in) *addr |= LSB;
|
|
carry_in = carry_out;
|
|
addr++;
|
|
}
|
|
carry_out = ((*addr AND msb) != 0);
|
|
*addr <<= 1;
|
|
if (carry_in) *addr |= LSB;
|
|
*addr &= mask;
|
|
}
|
|
return(carry_out);
|
|
}
|
|
|
|
boolean BitVector_shift_right(wordptr addr, boolean carry_in)
|
|
{
|
|
N_word size = size_(addr);
|
|
N_word mask = mask_(addr);
|
|
N_word msb;
|
|
boolean carry_out = carry_in;
|
|
|
|
if (size > 0)
|
|
{
|
|
msb = mask AND NOT (mask >> 1);
|
|
addr += size-1;
|
|
*addr &= mask;
|
|
carry_out = ((*addr AND LSB) != 0);
|
|
*addr >>= 1;
|
|
if (carry_in) *addr |= msb;
|
|
carry_in = carry_out;
|
|
addr--;
|
|
size--;
|
|
while (size-- > 0)
|
|
{
|
|
carry_out = ((*addr AND LSB) != 0);
|
|
*addr >>= 1;
|
|
if (carry_in) *addr |= MSB;
|
|
carry_in = carry_out;
|
|
addr--;
|
|
}
|
|
}
|
|
return(carry_out);
|
|
}
|
|
|
|
void BitVector_Move_Left(wordptr addr, N_int bits)
|
|
{
|
|
N_word count;
|
|
N_word words;
|
|
|
|
if (bits > 0)
|
|
{
|
|
count = bits AND MODMASK;
|
|
words = bits >> LOGBITS;
|
|
if (bits >= bits_(addr)) BitVector_Empty(addr);
|
|
else
|
|
{
|
|
while (count-- > 0) BitVector_shift_left(addr,0);
|
|
BitVector_Word_Insert(addr,0,words,TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
void BitVector_Move_Right(wordptr addr, N_int bits)
|
|
{
|
|
N_word count;
|
|
N_word words;
|
|
|
|
if (bits > 0)
|
|
{
|
|
count = bits AND MODMASK;
|
|
words = bits >> LOGBITS;
|
|
if (bits >= bits_(addr)) BitVector_Empty(addr);
|
|
else
|
|
{
|
|
while (count-- > 0) BitVector_shift_right(addr,0);
|
|
BitVector_Word_Delete(addr,0,words,TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
void BitVector_Insert(wordptr addr, N_int offset, N_int count, boolean clear)
|
|
{
|
|
N_word bits = bits_(addr);
|
|
N_word last;
|
|
|
|
if ((count > 0) and (offset < bits))
|
|
{
|
|
last = offset + count;
|
|
if (last < bits)
|
|
{
|
|
BitVector_Interval_Copy(addr,addr,last,offset,(bits-last));
|
|
}
|
|
else last = bits;
|
|
if (clear) BitVector_Interval_Empty(addr,offset,(last-1));
|
|
}
|
|
}
|
|
|
|
void BitVector_Delete(wordptr addr, N_int offset, N_int count, boolean clear)
|
|
{
|
|
N_word bits = bits_(addr);
|
|
N_word last;
|
|
|
|
if ((count > 0) and (offset < bits))
|
|
{
|
|
last = offset + count;
|
|
if (last < bits)
|
|
{
|
|
BitVector_Interval_Copy(addr,addr,offset,last,(bits-last));
|
|
}
|
|
else count = bits - offset;
|
|
if (clear) BitVector_Interval_Empty(addr,(bits-count),(bits-1));
|
|
}
|
|
}
|
|
|
|
boolean BitVector_increment(wordptr addr) /* X++ */
|
|
{
|
|
N_word size = size_(addr);
|
|
N_word mask = mask_(addr);
|
|
wordptr last = addr + size - 1;
|
|
boolean carry = TRUE;
|
|
|
|
if (size > 0)
|
|
{
|
|
*last |= NOT mask;
|
|
while (carry and (size-- > 0))
|
|
{
|
|
carry = (++(*addr++) == 0);
|
|
}
|
|
*last &= mask;
|
|
}
|
|
return(carry);
|
|
}
|
|
|
|
boolean BitVector_decrement(wordptr addr) /* X-- */
|
|
{
|
|
N_word size = size_(addr);
|
|
N_word mask = mask_(addr);
|
|
wordptr last = addr + size - 1;
|
|
boolean carry = TRUE;
|
|
|
|
if (size > 0)
|
|
{
|
|
*last &= mask;
|
|
while (carry and (size-- > 0))
|
|
{
|
|
carry = (*addr == 0);
|
|
--(*addr++);
|
|
}
|
|
*last &= mask;
|
|
}
|
|
return(carry);
|
|
}
|
|
|
|
boolean BitVector_compute(wordptr X, wordptr Y, wordptr Z, boolean minus, boolean *carry)
|
|
{
|
|
N_word size = size_(X);
|
|
N_word mask = mask_(X);
|
|
N_word vv = 0;
|
|
N_word cc;
|
|
N_word mm;
|
|
N_word yy;
|
|
N_word zz;
|
|
N_word lo;
|
|
N_word hi;
|
|
|
|
if (size > 0)
|
|
{
|
|
if (minus) cc = (*carry == 0);
|
|
else cc = (*carry != 0);
|
|
/* deal with (size-1) least significant full words first: */
|
|
while (--size > 0)
|
|
{
|
|
yy = *Y++;
|
|
if (minus) zz = (N_word) NOT ( Z ? *Z++ : 0 );
|
|
else zz = (N_word) ( Z ? *Z++ : 0 );
|
|
lo = (yy AND LSB) + (zz AND LSB) + cc;
|
|
hi = (yy >> 1) + (zz >> 1) + (lo >> 1);
|
|
cc = ((hi AND MSB) != 0);
|
|
*X++ = (hi << 1) OR (lo AND LSB);
|
|
}
|
|
/* deal with most significant word (may be used only partially): */
|
|
yy = *Y AND mask;
|
|
if (minus) zz = (N_word) NOT ( Z ? *Z : 0 );
|
|
else zz = (N_word) ( Z ? *Z : 0 );
|
|
zz &= mask;
|
|
if (mask == LSB) /* special case, only one bit used */
|
|
{
|
|
vv = cc;
|
|
lo = yy + zz + cc;
|
|
cc = (lo >> 1);
|
|
vv ^= cc;
|
|
*X = lo AND LSB;
|
|
}
|
|
else
|
|
{
|
|
if (NOT mask) /* not all bits are used, but more than one */
|
|
{
|
|
mm = (mask >> 1);
|
|
vv = (yy AND mm) + (zz AND mm) + cc;
|
|
mm = mask AND NOT mm;
|
|
lo = yy + zz + cc;
|
|
cc = (lo >> 1);
|
|
vv ^= cc;
|
|
vv &= mm;
|
|
cc &= mm;
|
|
*X = lo AND mask;
|
|
}
|
|
else /* other special case, all bits are used */
|
|
{
|
|
mm = NOT MSB;
|
|
lo = (yy AND mm) + (zz AND mm) + cc;
|
|
vv = lo AND MSB;
|
|
hi = ((yy AND MSB) >> 1) + ((zz AND MSB) >> 1) + (vv >> 1);
|
|
cc = hi AND MSB;
|
|
vv ^= cc;
|
|
*X = (hi << 1) OR (lo AND mm);
|
|
}
|
|
}
|
|
if (minus) *carry = (cc == 0);
|
|
else *carry = (cc != 0);
|
|
}
|
|
return(vv != 0);
|
|
}
|
|
|
|
boolean BitVector_add(wordptr X, wordptr Y, wordptr Z, boolean *carry)
|
|
{
|
|
return(BitVector_compute(X,Y,Z,FALSE,carry));
|
|
}
|
|
|
|
boolean BitVector_sub(wordptr X, wordptr Y, wordptr Z, boolean *carry)
|
|
{
|
|
return(BitVector_compute(X,Y,Z,TRUE,carry));
|
|
}
|
|
|
|
boolean BitVector_inc(wordptr X, wordptr Y)
|
|
{
|
|
boolean carry = TRUE;
|
|
|
|
return(BitVector_compute(X,Y,NULL,FALSE,&carry));
|
|
}
|
|
|
|
boolean BitVector_dec(wordptr X, wordptr Y)
|
|
{
|
|
boolean carry = TRUE;
|
|
|
|
return(BitVector_compute(X,Y,NULL,TRUE,&carry));
|
|
}
|
|
|
|
void BitVector_Negate(wordptr X, wordptr Y)
|
|
{
|
|
N_word size = size_(X);
|
|
N_word mask = mask_(X);
|
|
boolean carry = TRUE;
|
|
|
|
if (size > 0)
|
|
{
|
|
while (size-- > 0)
|
|
{
|
|
*X = NOT *Y++;
|
|
if (carry)
|
|
{
|
|
carry = (++(*X) == 0);
|
|
}
|
|
X++;
|
|
}
|
|
*(--X) &= mask;
|
|
}
|
|
}
|
|
|
|
void BitVector_Absolute(wordptr X, wordptr Y)
|
|
{
|
|
N_word size = size_(Y);
|
|
N_word mask = mask_(Y);
|
|
|
|
if (size > 0)
|
|
{
|
|
if (*(Y+size-1) AND (mask AND NOT (mask >> 1))) BitVector_Negate(X,Y);
|
|
else BitVector_Copy(X,Y);
|
|
}
|
|
}
|
|
|
|
Z_int BitVector_Sign(wordptr addr)
|
|
{
|
|
N_word size = size_(addr);
|
|
N_word mask = mask_(addr);
|
|
wordptr last = addr + size - 1;
|
|
boolean r = TRUE;
|
|
|
|
if (size > 0)
|
|
{
|
|
*last &= mask;
|
|
while (r and (size-- > 0)) r = ( *addr++ == 0 );
|
|
}
|
|
if (r) return((Z_int) 0);
|
|
else
|
|
{
|
|
if (*last AND (mask AND NOT (mask >> 1))) return((Z_int) -1);
|
|
else return((Z_int) 1);
|
|
}
|
|
}
|
|
|
|
ErrCode BitVector_Mul_Pos(wordptr X, wordptr Y, wordptr Z, boolean strict)
|
|
{
|
|
N_word mask;
|
|
N_word limit;
|
|
N_word count;
|
|
Z_long last;
|
|
wordptr sign;
|
|
boolean carry;
|
|
boolean overflow;
|
|
boolean ok = TRUE;
|
|
|
|
/*
|
|
Requirements:
|
|
- X, Y and Z must be distinct
|
|
- X and Y must have equal sizes (whereas Z may be any size!)
|
|
- Z should always contain the SMALLER of the two factors Y and Z
|
|
Constraints:
|
|
- The contents of Y (and of X, of course) are destroyed
|
|
(only Z is preserved!)
|
|
*/
|
|
|
|
if ((X == Y) or (X == Z) or (Y == Z)) return(ErrCode_Same);
|
|
if (bits_(X) != bits_(Y)) return(ErrCode_Size);
|
|
BitVector_Empty(X);
|
|
if (BitVector_is_empty(Y)) return(ErrCode_Ok); /* exit also taken if bits_(Y)==0 */
|
|
if ((last = Set_Max(Z)) < 0L) return(ErrCode_Ok);
|
|
limit = (N_word) last;
|
|
sign = Y + size_(Y) - 1;
|
|
mask = mask_(Y);
|
|
*sign &= mask;
|
|
mask &= NOT (mask >> 1);
|
|
for ( count = 0; (ok and (count <= limit)); count++ )
|
|
{
|
|
if ( BIT_VECTOR_TST_BIT(Z,count) )
|
|
{
|
|
carry = false;
|
|
overflow = BitVector_compute(X,X,Y,false,&carry);
|
|
if (strict) ok = not (carry or overflow);
|
|
else ok = not carry;
|
|
}
|
|
if (ok and (count < limit))
|
|
{
|
|
carry = BitVector_shift_left(Y,0);
|
|
if (strict)
|
|
{
|
|
overflow = ((*sign AND mask) != 0);
|
|
ok = not (carry or overflow);
|
|
}
|
|
else ok = not carry;
|
|
}
|
|
}
|
|
if (ok) return(ErrCode_Ok); else return(ErrCode_Ovfl);
|
|
}
|
|
|
|
ErrCode BitVector_Multiply(wordptr X, wordptr Y, wordptr Z)
|
|
{
|
|
ErrCode error = ErrCode_Ok;
|
|
N_word bit_x = bits_(X);
|
|
N_word bit_y = bits_(Y);
|
|
N_word bit_z = bits_(Z);
|
|
N_word size;
|
|
N_word mask;
|
|
N_word msb;
|
|
wordptr ptr_y;
|
|
wordptr ptr_z;
|
|
boolean sgn_x;
|
|
boolean sgn_y;
|
|
boolean sgn_z;
|
|
boolean zero;
|
|
wordptr A;
|
|
wordptr B;
|
|
|
|
/*
|
|
Requirements:
|
|
- Y and Z must have equal sizes
|
|
- X must have at least the same size as Y and Z but may be larger (!)
|
|
Features:
|
|
- The contents of Y and Z are preserved
|
|
- X may be identical with Y or Z (or both!)
|
|
(in-place multiplication is possible!)
|
|
*/
|
|
|
|
if ((bit_y != bit_z) or (bit_x < bit_y)) return(ErrCode_Size);
|
|
if (BitVector_is_empty(Y) or BitVector_is_empty(Z))
|
|
{
|
|
BitVector_Empty(X);
|
|
}
|
|
else
|
|
{
|
|
A = BitVector_Create(bit_y,FALSE);
|
|
if (A == NULL) return(ErrCode_Null);
|
|
B = BitVector_Create(bit_z,FALSE);
|
|
if (B == NULL) { BitVector_Destroy(A); return(ErrCode_Null); }
|
|
size = size_(Y);
|
|
mask = mask_(Y);
|
|
msb = (mask AND NOT (mask >> 1));
|
|
sgn_y = (((*(Y+size-1) &= mask) AND msb) != 0);
|
|
sgn_z = (((*(Z+size-1) &= mask) AND msb) != 0);
|
|
sgn_x = sgn_y XOR sgn_z;
|
|
if (sgn_y) BitVector_Negate(A,Y); else BitVector_Copy(A,Y);
|
|
if (sgn_z) BitVector_Negate(B,Z); else BitVector_Copy(B,Z);
|
|
ptr_y = A + size;
|
|
ptr_z = B + size;
|
|
zero = TRUE;
|
|
while (zero and (size-- > 0))
|
|
{
|
|
zero &= (*(--ptr_y) == 0);
|
|
zero &= (*(--ptr_z) == 0);
|
|
}
|
|
if (*ptr_y > *ptr_z)
|
|
{
|
|
if (bit_x > bit_y)
|
|
{
|
|
A = BitVector_Resize(A,bit_x);
|
|
if (A == NULL) { BitVector_Destroy(B); return(ErrCode_Null); }
|
|
}
|
|
error = BitVector_Mul_Pos(X,A,B,TRUE);
|
|
}
|
|
else
|
|
{
|
|
if (bit_x > bit_z)
|
|
{
|
|
B = BitVector_Resize(B,bit_x);
|
|
if (B == NULL) { BitVector_Destroy(A); return(ErrCode_Null); }
|
|
}
|
|
error = BitVector_Mul_Pos(X,B,A,TRUE);
|
|
}
|
|
if ((not error) and sgn_x) BitVector_Negate(X,X);
|
|
BitVector_Destroy(A);
|
|
BitVector_Destroy(B);
|
|
}
|
|
return(error);
|
|
}
|
|
|
|
ErrCode BitVector_Div_Pos(wordptr Q, wordptr X, wordptr Y, wordptr R)
|
|
{
|
|
N_word bits = bits_(Q);
|
|
N_word mask;
|
|
wordptr addr;
|
|
Z_long last;
|
|
boolean flag;
|
|
boolean copy = FALSE; /* flags whether valid rest is in R (0) or X (1) */
|
|
|
|
/*
|
|
Requirements:
|
|
- All bit vectors must have equal sizes
|
|
- Q, X, Y and R must all be distinct bit vectors
|
|
- Y must be non-zero (of course!)
|
|
Constraints:
|
|
- The contents of X (and Q and R, of course) are destroyed
|
|
(only Y is preserved!)
|
|
*/
|
|
|
|
if ((bits != bits_(X)) or (bits != bits_(Y)) or (bits != bits_(R)))
|
|
return(ErrCode_Size);
|
|
if ((Q == X) or (Q == Y) or (Q == R) or (X == Y) or (X == R) or (Y == R))
|
|
return(ErrCode_Same);
|
|
if (BitVector_is_empty(Y))
|
|
return(ErrCode_Zero);
|
|
|
|
BitVector_Empty(R);
|
|
BitVector_Copy(Q,X);
|
|
if ((last = Set_Max(Q)) < 0L) return(ErrCode_Ok);
|
|
bits = (N_word) ++last;
|
|
while (bits-- > 0)
|
|
{
|
|
addr = Q + (bits >> LOGBITS);
|
|
mask = BITMASKTAB[bits AND MODMASK];
|
|
flag = ((*addr AND mask) != 0);
|
|
if (copy)
|
|
{
|
|
BitVector_shift_left(X,flag);
|
|
flag = FALSE;
|
|
BitVector_compute(R,X,Y,TRUE,&flag);
|
|
}
|
|
else
|
|
{
|
|
BitVector_shift_left(R,flag);
|
|
flag = FALSE;
|
|
BitVector_compute(X,R,Y,TRUE,&flag);
|
|
}
|
|
if (flag) *addr &= NOT mask;
|
|
else
|
|
{
|
|
*addr |= mask;
|
|
copy = not copy;
|
|
}
|
|
}
|
|
if (copy) BitVector_Copy(R,X);
|
|
return(ErrCode_Ok);
|
|
}
|
|
|
|
ErrCode BitVector_Divide(wordptr Q, wordptr X, wordptr Y, wordptr R)
|
|
{
|
|
ErrCode error = ErrCode_Ok;
|
|
N_word bits = bits_(Q);
|
|
N_word size = size_(Q);
|
|
N_word mask = mask_(Q);
|
|
N_word msb = (mask AND NOT (mask >> 1));
|
|
boolean sgn_q;
|
|
boolean sgn_x;
|
|
boolean sgn_y;
|
|
wordptr A;
|
|
wordptr B;
|
|
|
|
/*
|
|
Requirements:
|
|
- All bit vectors must have equal sizes
|
|
- Q and R must be two distinct bit vectors
|
|
- Y must be non-zero (of course!)
|
|
Features:
|
|
- The contents of X and Y are preserved
|
|
- Q may be identical with X or Y (or both)
|
|
(in-place division is possible!)
|
|
- R may be identical with X or Y (or both)
|
|
(but not identical with Q!)
|
|
*/
|
|
|
|
if ((bits != bits_(X)) or (bits != bits_(Y)) or (bits != bits_(R)))
|
|
return(ErrCode_Size);
|
|
if (Q == R)
|
|
return(ErrCode_Same);
|
|
if (BitVector_is_empty(Y))
|
|
return(ErrCode_Zero);
|
|
|
|
if (BitVector_is_empty(X))
|
|
{
|
|
BitVector_Empty(Q);
|
|
BitVector_Empty(R);
|
|
}
|
|
else
|
|
{
|
|
A = BitVector_Create(bits,FALSE);
|
|
if (A == NULL) return(ErrCode_Null);
|
|
B = BitVector_Create(bits,FALSE);
|
|
if (B == NULL) { BitVector_Destroy(A); return(ErrCode_Null); }
|
|
size--;
|
|
sgn_x = (((*(X+size) &= mask) AND msb) != 0);
|
|
sgn_y = (((*(Y+size) &= mask) AND msb) != 0);
|
|
sgn_q = sgn_x XOR sgn_y;
|
|
if (sgn_x) BitVector_Negate(A,X); else BitVector_Copy(A,X);
|
|
if (sgn_y) BitVector_Negate(B,Y); else BitVector_Copy(B,Y);
|
|
if (not (error = BitVector_Div_Pos(Q,A,B,R)))
|
|
{
|
|
if (sgn_q) BitVector_Negate(Q,Q);
|
|
if (sgn_x) BitVector_Negate(R,R);
|
|
}
|
|
BitVector_Destroy(A);
|
|
BitVector_Destroy(B);
|
|
}
|
|
return(error);
|
|
}
|
|
|
|
ErrCode BitVector_GCD(wordptr X, wordptr Y, wordptr Z)
|
|
{
|
|
ErrCode error = ErrCode_Ok;
|
|
N_word bits = bits_(X);
|
|
N_word size = size_(X);
|
|
N_word mask = mask_(X);
|
|
N_word msb = (mask AND NOT (mask >> 1));
|
|
boolean sgn_a;
|
|
boolean sgn_b;
|
|
boolean sgn_r;
|
|
wordptr Q;
|
|
wordptr R;
|
|
wordptr A;
|
|
wordptr B;
|
|
wordptr T;
|
|
|
|
/*
|
|
Requirements:
|
|
- All bit vectors must have equal sizes
|
|
Features:
|
|
- The contents of Y and Z are preserved
|
|
- X may be identical with Y or Z (or both)
|
|
(in-place is possible!)
|
|
- GCD(0,z) == GCD(z,0) == z
|
|
- negative values are handled correctly
|
|
*/
|
|
|
|
if ((bits != bits_(Y)) or (bits != bits_(Z))) return(ErrCode_Size);
|
|
if (BitVector_is_empty(Y))
|
|
{
|
|
if (X != Z) BitVector_Copy(X,Z);
|
|
return(ErrCode_Ok);
|
|
}
|
|
if (BitVector_is_empty(Z))
|
|
{
|
|
if (X != Y) BitVector_Copy(X,Y);
|
|
return(ErrCode_Ok);
|
|
}
|
|
Q = BitVector_Create(bits,false);
|
|
if (Q == NULL)
|
|
{
|
|
return(ErrCode_Null);
|
|
}
|
|
R = BitVector_Create(bits,FALSE);
|
|
if (R == NULL)
|
|
{
|
|
BitVector_Destroy(Q);
|
|
return(ErrCode_Null);
|
|
}
|
|
A = BitVector_Create(bits,FALSE);
|
|
if (A == NULL)
|
|
{
|
|
BitVector_Destroy(Q);
|
|
BitVector_Destroy(R);
|
|
return(ErrCode_Null);
|
|
}
|
|
B = BitVector_Create(bits,FALSE);
|
|
if (B == NULL)
|
|
{
|
|
BitVector_Destroy(Q);
|
|
BitVector_Destroy(R);
|
|
BitVector_Destroy(A);
|
|
return(ErrCode_Null);
|
|
}
|
|
size--;
|
|
sgn_a = (((*(Y+size) &= mask) AND msb) != 0);
|
|
sgn_b = (((*(Z+size) &= mask) AND msb) != 0);
|
|
if (sgn_a) BitVector_Negate(A,Y); else BitVector_Copy(A,Y);
|
|
if (sgn_b) BitVector_Negate(B,Z); else BitVector_Copy(B,Z);
|
|
while (not error)
|
|
{
|
|
if (not (error = BitVector_Div_Pos(Q,A,B,R)))
|
|
{
|
|
if (BitVector_is_empty(R)) break;
|
|
T = A; sgn_r = sgn_a;
|
|
A = B; sgn_a = sgn_b;
|
|
B = R; sgn_b = sgn_r;
|
|
R = T;
|
|
}
|
|
}
|
|
if (not error)
|
|
{
|
|
if (sgn_b) BitVector_Negate(X,B); else BitVector_Copy(X,B);
|
|
}
|
|
BitVector_Destroy(Q);
|
|
BitVector_Destroy(R);
|
|
BitVector_Destroy(A);
|
|
BitVector_Destroy(B);
|
|
return(error);
|
|
}
|
|
|
|
ErrCode BitVector_GCD2(wordptr U, wordptr V, wordptr W, wordptr X, wordptr Y)
|
|
{
|
|
ErrCode error = ErrCode_Ok;
|
|
N_word bits = bits_(U);
|
|
N_word size = size_(U);
|
|
N_word mask = mask_(U);
|
|
N_word msb = (mask AND NOT (mask >> 1));
|
|
boolean minus;
|
|
boolean carry;
|
|
boolean sgn_q;
|
|
boolean sgn_r;
|
|
boolean sgn_a;
|
|
boolean sgn_b;
|
|
boolean sgn_x;
|
|
boolean sgn_y;
|
|
listptr L;
|
|
wordptr Q;
|
|
wordptr R;
|
|
wordptr A;
|
|
wordptr B;
|
|
wordptr T;
|
|
wordptr X1;
|
|
wordptr X2;
|
|
wordptr X3;
|
|
wordptr Y1;
|
|
wordptr Y2;
|
|
wordptr Y3;
|
|
wordptr Z;
|
|
|
|
/*
|
|
Requirements:
|
|
- All bit vectors must have equal sizes
|
|
- U, V, and W must all be distinct bit vectors
|
|
Features:
|
|
- The contents of X and Y are preserved
|
|
- U, V and W may be identical with X or Y (or both,
|
|
provided that U, V and W are mutually distinct)
|
|
(i.e., in-place is possible!)
|
|
- GCD(0,z) == GCD(z,0) == z
|
|
- negative values are handled correctly
|
|
*/
|
|
|
|
if ((bits != bits_(V)) or
|
|
(bits != bits_(W)) or
|
|
(bits != bits_(X)) or
|
|
(bits != bits_(Y)))
|
|
{
|
|
return(ErrCode_Size);
|
|
}
|
|
if ((U == V) or (U == W) or (V == W))
|
|
{
|
|
return(ErrCode_Same);
|
|
}
|
|
if (BitVector_is_empty(X))
|
|
{
|
|
if (U != Y) BitVector_Copy(U,Y);
|
|
BitVector_Empty(V);
|
|
BitVector_Empty(W);
|
|
*W = 1;
|
|
return(ErrCode_Ok);
|
|
}
|
|
if (BitVector_is_empty(Y))
|
|
{
|
|
if (U != X) BitVector_Copy(U,X);
|
|
BitVector_Empty(V);
|
|
BitVector_Empty(W);
|
|
*V = 1;
|
|
return(ErrCode_Ok);
|
|
}
|
|
if ((L = BitVector_Create_List(bits,false,11)) == NULL)
|
|
{
|
|
return(ErrCode_Null);
|
|
}
|
|
Q = L[0];
|
|
R = L[1];
|
|
A = L[2];
|
|
B = L[3];
|
|
X1 = L[4];
|
|
X2 = L[5];
|
|
X3 = L[6];
|
|
Y1 = L[7];
|
|
Y2 = L[8];
|
|
Y3 = L[9];
|
|
Z = L[10];
|
|
size--;
|
|
sgn_a = (((*(X+size) &= mask) AND msb) != 0);
|
|
sgn_b = (((*(Y+size) &= mask) AND msb) != 0);
|
|
if (sgn_a) BitVector_Negate(A,X); else BitVector_Copy(A,X);
|
|
if (sgn_b) BitVector_Negate(B,Y); else BitVector_Copy(B,Y);
|
|
BitVector_Empty(X1);
|
|
BitVector_Empty(X2);
|
|
*X1 = 1;
|
|
BitVector_Empty(Y1);
|
|
BitVector_Empty(Y2);
|
|
*Y2 = 1;
|
|
sgn_x = false;
|
|
sgn_y = false;
|
|
while (not error)
|
|
{
|
|
if ((error = BitVector_Div_Pos(Q,A,B,R)))
|
|
{
|
|
break;
|
|
}
|
|
if (BitVector_is_empty(R))
|
|
{
|
|
break;
|
|
}
|
|
sgn_q = sgn_a XOR sgn_b;
|
|
|
|
if (sgn_x) BitVector_Negate(Z,X2); else BitVector_Copy(Z,X2);
|
|
if ((error = BitVector_Mul_Pos(X3,Z,Q,true)))
|
|
{
|
|
break;
|
|
}
|
|
minus = not (sgn_x XOR sgn_q);
|
|
carry = 0;
|
|
if (BitVector_compute(X3,X1,X3,minus,&carry))
|
|
{
|
|
error = ErrCode_Ovfl;
|
|
break;
|
|
}
|
|
sgn_x = (((*(X3+size) &= mask) AND msb) != 0);
|
|
|
|
if (sgn_y) BitVector_Negate(Z,Y2); else BitVector_Copy(Z,Y2);
|
|
if ((error = BitVector_Mul_Pos(Y3,Z,Q,true)))
|
|
{
|
|
break;
|
|
}
|
|
minus = not (sgn_y XOR sgn_q);
|
|
carry = 0;
|
|
if (BitVector_compute(Y3,Y1,Y3,minus,&carry))
|
|
{
|
|
error = ErrCode_Ovfl;
|
|
break;
|
|
}
|
|
sgn_y = (((*(Y3+size) &= mask) AND msb) != 0);
|
|
|
|
T = A; sgn_r = sgn_a;
|
|
A = B; sgn_a = sgn_b;
|
|
B = R; sgn_b = sgn_r;
|
|
R = T;
|
|
|
|
T = X1;
|
|
X1 = X2;
|
|
X2 = X3;
|
|
X3 = T;
|
|
|
|
T = Y1;
|
|
Y1 = Y2;
|
|
Y2 = Y3;
|
|
Y3 = T;
|
|
}
|
|
if (not error)
|
|
{
|
|
if (sgn_b) BitVector_Negate(U,B); else BitVector_Copy(U,B);
|
|
BitVector_Copy(V,X2);
|
|
BitVector_Copy(W,Y2);
|
|
}
|
|
BitVector_Destroy_List(L,11);
|
|
return(error);
|
|
}
|
|
|
|
ErrCode BitVector_Power(wordptr X, wordptr Y, wordptr Z)
|
|
{
|
|
ErrCode error = ErrCode_Ok;
|
|
N_word bits = bits_(X);
|
|
boolean first = TRUE;
|
|
Z_long last;
|
|
N_word limit;
|
|
N_word count;
|
|
wordptr T;
|
|
|
|
/*
|
|
Requirements:
|
|
- X must have at least the same size as Y but may be larger (!)
|
|
- X may not be identical with Z
|
|
- Z must be positive
|
|
Features:
|
|
- The contents of Y and Z are preserved
|
|
*/
|
|
|
|
if (X == Z) return(ErrCode_Same);
|
|
if (bits < bits_(Y)) return(ErrCode_Size);
|
|
if (BitVector_msb_(Z)) return(ErrCode_Expo);
|
|
if ((last = Set_Max(Z)) < 0L)
|
|
{
|
|
if (bits < 2) return(ErrCode_Ovfl);
|
|
BitVector_Empty(X);
|
|
*X |= LSB;
|
|
return(ErrCode_Ok); /* anything ^ 0 == 1 */
|
|
}
|
|
if (BitVector_is_empty(Y))
|
|
{
|
|
if (X != Y) BitVector_Empty(X);
|
|
return(ErrCode_Ok); /* 0 ^ anything not zero == 0 */
|
|
}
|
|
T = BitVector_Create(bits,FALSE);
|
|
if (T == NULL) return(ErrCode_Null);
|
|
limit = (N_word) last;
|
|
for ( count = 0; ((!error) and (count <= limit)); count++ )
|
|
{
|
|
if ( BIT_VECTOR_TST_BIT(Z,count) )
|
|
{
|
|
if (first)
|
|
{
|
|
first = FALSE;
|
|
if (count) { BitVector_Copy(X,T); }
|
|
else { if (X != Y) BitVector_Copy(X,Y); }
|
|
}
|
|
else error = BitVector_Multiply(X,T,X); /* order important because T > X */
|
|
}
|
|
if ((!error) and (count < limit))
|
|
{
|
|
if (count) error = BitVector_Multiply(T,T,T);
|
|
else error = BitVector_Multiply(T,Y,Y);
|
|
}
|
|
}
|
|
BitVector_Destroy(T);
|
|
return(error);
|
|
}
|
|
|
|
void BitVector_Block_Store(wordptr addr, charptr buffer, N_int length)
|
|
{
|
|
N_word size = size_(addr);
|
|
N_word mask = mask_(addr);
|
|
N_word value;
|
|
N_word count;
|
|
|
|
/* provide translation for independence of endian-ness: */
|
|
if (size > 0)
|
|
{
|
|
while (size-- > 0)
|
|
{
|
|
value = 0;
|
|
for ( count = 0; (length > 0) and (count < BITS); count += 8 )
|
|
{
|
|
value |= (((N_word) *buffer++) << count); length--;
|
|
}
|
|
*addr++ = value;
|
|
}
|
|
*(--addr) &= mask;
|
|
}
|
|
}
|
|
|
|
charptr BitVector_Block_Read(wordptr addr, N_intptr length)
|
|
{
|
|
N_word size = size_(addr);
|
|
N_word value;
|
|
N_word count;
|
|
charptr buffer;
|
|
charptr target;
|
|
|
|
/* provide translation for independence of endian-ness: */
|
|
*length = size << FACTOR;
|
|
buffer = (charptr) yasm_xmalloc((size_t) ((*length)+1));
|
|
if (buffer == NULL) return(NULL);
|
|
target = buffer;
|
|
if (size > 0)
|
|
{
|
|
*(addr+size-1) &= mask_(addr);
|
|
while (size-- > 0)
|
|
{
|
|
value = *addr++;
|
|
count = BITS >> 3;
|
|
while (count-- > 0)
|
|
{
|
|
*target++ = (N_char) (value AND 0x00FF);
|
|
if (count > 0) value >>= 8;
|
|
}
|
|
}
|
|
}
|
|
*target = (N_char) '\0';
|
|
return(buffer);
|
|
}
|
|
|
|
void BitVector_Word_Store(wordptr addr, N_int offset, N_int value)
|
|
{
|
|
N_word size = size_(addr);
|
|
|
|
if (size > 0)
|
|
{
|
|
if (offset < size) *(addr+offset) = value;
|
|
*(addr+size-1) &= mask_(addr);
|
|
}
|
|
}
|
|
|
|
N_int BitVector_Word_Read(wordptr addr, N_int offset)
|
|
{
|
|
N_word size = size_(addr);
|
|
|
|
if (size > 0)
|
|
{
|
|
*(addr+size-1) &= mask_(addr);
|
|
if (offset < size) return( *(addr+offset) );
|
|
}
|
|
return( (N_int) 0 );
|
|
}
|
|
|
|
void BitVector_Word_Insert(wordptr addr, N_int offset, N_int count,
|
|
boolean clear)
|
|
{
|
|
N_word size = size_(addr);
|
|
N_word mask = mask_(addr);
|
|
wordptr last = addr+size-1;
|
|
|
|
if (size > 0)
|
|
{
|
|
*last &= mask;
|
|
if (offset > size) offset = size;
|
|
BIT_VECTOR_ins_words(addr+offset,size-offset,count,clear);
|
|
*last &= mask;
|
|
}
|
|
}
|
|
|
|
void BitVector_Word_Delete(wordptr addr, N_int offset, N_int count,
|
|
boolean clear)
|
|
{
|
|
N_word size = size_(addr);
|
|
N_word mask = mask_(addr);
|
|
wordptr last = addr+size-1;
|
|
|
|
if (size > 0)
|
|
{
|
|
*last &= mask;
|
|
if (offset > size) offset = size;
|
|
BIT_VECTOR_del_words(addr+offset,size-offset,count,clear);
|
|
*last &= mask;
|
|
}
|
|
}
|
|
|
|
void BitVector_Chunk_Store(wordptr addr, N_int chunksize, N_int offset,
|
|
N_long value)
|
|
{
|
|
N_word bits = bits_(addr);
|
|
N_word mask;
|
|
N_word temp;
|
|
|
|
if ((chunksize > 0) and (offset < bits))
|
|
{
|
|
if (chunksize > LONGBITS) chunksize = LONGBITS;
|
|
if ((offset + chunksize) > bits) chunksize = bits - offset;
|
|
addr += offset >> LOGBITS;
|
|
offset &= MODMASK;
|
|
while (chunksize > 0)
|
|
{
|
|
mask = (N_word) (~0L << offset);
|
|
bits = offset + chunksize;
|
|
if (bits < BITS)
|
|
{
|
|
mask &= (N_word) ~(~0L << bits);
|
|
bits = chunksize;
|
|
}
|
|
else bits = BITS - offset;
|
|
temp = (N_word) (value << offset);
|
|
temp &= mask;
|
|
*addr &= NOT mask;
|
|
*addr++ |= temp;
|
|
value >>= bits;
|
|
chunksize -= bits;
|
|
offset = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
N_long BitVector_Chunk_Read(wordptr addr, N_int chunksize, N_int offset)
|
|
{
|
|
N_word bits = bits_(addr);
|
|
N_word chunkbits = 0;
|
|
N_long value = 0L;
|
|
N_long temp;
|
|
N_word mask;
|
|
|
|
if ((chunksize > 0) and (offset < bits))
|
|
{
|
|
if (chunksize > LONGBITS) chunksize = LONGBITS;
|
|
if ((offset + chunksize) > bits) chunksize = bits - offset;
|
|
addr += offset >> LOGBITS;
|
|
offset &= MODMASK;
|
|
while (chunksize > 0)
|
|
{
|
|
bits = offset + chunksize;
|
|
if (bits < BITS)
|
|
{
|
|
mask = (N_word) ~(~0L << bits);
|
|
bits = chunksize;
|
|
}
|
|
else
|
|
{
|
|
mask = (N_word) ~0L;
|
|
bits = BITS - offset;
|
|
}
|
|
temp = (N_long) ((*addr++ AND mask) >> offset);
|
|
value |= temp << chunkbits;
|
|
chunkbits += bits;
|
|
chunksize -= bits;
|
|
offset = 0;
|
|
}
|
|
}
|
|
return(value);
|
|
}
|
|
|
|
/*******************/
|
|
/* set operations: */
|
|
/*******************/
|
|
|
|
void Set_Union(wordptr X, wordptr Y, wordptr Z) /* X = Y + Z */
|
|
{
|
|
N_word bits = bits_(X);
|
|
N_word size = size_(X);
|
|
N_word mask = mask_(X);
|
|
|
|
if ((size > 0) and (bits == bits_(Y)) and (bits == bits_(Z)))
|
|
{
|
|
while (size-- > 0) *X++ = *Y++ OR *Z++;
|
|
*(--X) &= mask;
|
|
}
|
|
}
|
|
|
|
void Set_Intersection(wordptr X, wordptr Y, wordptr Z) /* X = Y * Z */
|
|
{
|
|
N_word bits = bits_(X);
|
|
N_word size = size_(X);
|
|
N_word mask = mask_(X);
|
|
|
|
if ((size > 0) and (bits == bits_(Y)) and (bits == bits_(Z)))
|
|
{
|
|
while (size-- > 0) *X++ = *Y++ AND *Z++;
|
|
*(--X) &= mask;
|
|
}
|
|
}
|
|
|
|
void Set_Difference(wordptr X, wordptr Y, wordptr Z) /* X = Y \ Z */
|
|
{
|
|
N_word bits = bits_(X);
|
|
N_word size = size_(X);
|
|
N_word mask = mask_(X);
|
|
|
|
if ((size > 0) and (bits == bits_(Y)) and (bits == bits_(Z)))
|
|
{
|
|
while (size-- > 0) *X++ = *Y++ AND NOT *Z++;
|
|
*(--X) &= mask;
|
|
}
|
|
}
|
|
|
|
void Set_ExclusiveOr(wordptr X, wordptr Y, wordptr Z) /* X=(Y+Z)\(Y*Z) */
|
|
{
|
|
N_word bits = bits_(X);
|
|
N_word size = size_(X);
|
|
N_word mask = mask_(X);
|
|
|
|
if ((size > 0) and (bits == bits_(Y)) and (bits == bits_(Z)))
|
|
{
|
|
while (size-- > 0) *X++ = *Y++ XOR *Z++;
|
|
*(--X) &= mask;
|
|
}
|
|
}
|
|
|
|
void Set_Complement(wordptr X, wordptr Y) /* X = ~Y */
|
|
{
|
|
N_word size = size_(X);
|
|
N_word mask = mask_(X);
|
|
|
|
if ((size > 0) and (bits_(X) == bits_(Y)))
|
|
{
|
|
while (size-- > 0) *X++ = NOT *Y++;
|
|
*(--X) &= mask;
|
|
}
|
|
}
|
|
|
|
/******************/
|
|
/* set functions: */
|
|
/******************/
|
|
|
|
boolean Set_subset(wordptr X, wordptr Y) /* X subset Y ? */
|
|
{
|
|
N_word size = size_(X);
|
|
boolean r = FALSE;
|
|
|
|
if ((size > 0) and (bits_(X) == bits_(Y)))
|
|
{
|
|
r = TRUE;
|
|
while (r and (size-- > 0)) r = ((*X++ AND NOT *Y++) == 0);
|
|
}
|
|
return(r);
|
|
}
|
|
|
|
N_int Set_Norm(wordptr addr) /* = | X | */
|
|
{
|
|
byteptr byte;
|
|
N_word bytes;
|
|
N_int n;
|
|
|
|
byte = (byteptr) addr;
|
|
bytes = size_(addr) << FACTOR;
|
|
n = 0;
|
|
while (bytes-- > 0)
|
|
{
|
|
n += BitVector_BYTENORM[*byte++];
|
|
}
|
|
return(n);
|
|
}
|
|
|
|
N_int Set_Norm2(wordptr addr) /* = | X | */
|
|
{
|
|
N_word size = size_(addr);
|
|
N_word w0,w1;
|
|
N_int n,k;
|
|
|
|
n = 0;
|
|
while (size-- > 0)
|
|
{
|
|
k = 0;
|
|
w1 = NOT (w0 = *addr++);
|
|
while (w0 and w1)
|
|
{
|
|
w0 &= w0 - 1;
|
|
w1 &= w1 - 1;
|
|
k++;
|
|
}
|
|
if (w0 == 0) n += k;
|
|
else n += BITS - k;
|
|
}
|
|
return(n);
|
|
}
|
|
|
|
N_int Set_Norm3(wordptr addr) /* = | X | */
|
|
{
|
|
N_word size = size_(addr);
|
|
N_int count = 0;
|
|
N_word c;
|
|
|
|
while (size-- > 0)
|
|
{
|
|
c = *addr++;
|
|
while (c)
|
|
{
|
|
c &= c - 1;
|
|
count++;
|
|
}
|
|
}
|
|
return(count);
|
|
}
|
|
|
|
Z_long Set_Min(wordptr addr) /* = min(X) */
|
|
{
|
|
boolean empty = TRUE;
|
|
N_word size = size_(addr);
|
|
N_word i = 0;
|
|
N_word c = 0; /* silence compiler warning */
|
|
|
|
while (empty and (size-- > 0))
|
|
{
|
|
if ((c = *addr++)) empty = false; else i++;
|
|
}
|
|
if (empty) return((Z_long) LONG_MAX); /* plus infinity */
|
|
i <<= LOGBITS;
|
|
while (not (c AND LSB))
|
|
{
|
|
c >>= 1;
|
|
i++;
|
|
}
|
|
return((Z_long) i);
|
|
}
|
|
|
|
Z_long Set_Max(wordptr addr) /* = max(X) */
|
|
{
|
|
boolean empty = TRUE;
|
|
N_word size = size_(addr);
|
|
N_word i = size;
|
|
N_word c = 0; /* silence compiler warning */
|
|
|
|
addr += size-1;
|
|
while (empty and (size-- > 0))
|
|
{
|
|
if ((c = *addr--)) empty = false; else i--;
|
|
}
|
|
if (empty) return((Z_long) LONG_MIN); /* minus infinity */
|
|
i <<= LOGBITS;
|
|
while (not (c AND MSB))
|
|
{
|
|
c <<= 1;
|
|
i--;
|
|
}
|
|
return((Z_long) --i);
|
|
}
|
|
|
|
/**********************************/
|
|
/* matrix-of-booleans operations: */
|
|
/**********************************/
|
|
|
|
void Matrix_Multiplication(wordptr X, N_int rowsX, N_int colsX,
|
|
wordptr Y, N_int rowsY, N_int colsY,
|
|
wordptr Z, N_int rowsZ, N_int colsZ)
|
|
{
|
|
N_word i;
|
|
N_word j;
|
|
N_word k;
|
|
N_word indxX;
|
|
N_word indxY;
|
|
N_word indxZ;
|
|
N_word termX;
|
|
N_word termY;
|
|
N_word sum;
|
|
|
|
if ((colsY == rowsZ) and (rowsX == rowsY) and (colsX == colsZ) and
|
|
(bits_(X) == rowsX*colsX) and
|
|
(bits_(Y) == rowsY*colsY) and
|
|
(bits_(Z) == rowsZ*colsZ))
|
|
{
|
|
for ( i = 0; i < rowsY; i++ )
|
|
{
|
|
termX = i * colsX;
|
|
termY = i * colsY;
|
|
for ( j = 0; j < colsZ; j++ )
|
|
{
|
|
indxX = termX + j;
|
|
sum = 0;
|
|
for ( k = 0; k < colsY; k++ )
|
|
{
|
|
indxY = termY + k;
|
|
indxZ = k * colsZ + j;
|
|
if ( BIT_VECTOR_TST_BIT(Y,indxY) &&
|
|
BIT_VECTOR_TST_BIT(Z,indxZ) ) sum ^= 1;
|
|
}
|
|
if (sum) BIT_VECTOR_SET_BIT(X,indxX)
|
|
else BIT_VECTOR_CLR_BIT(X,indxX)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Matrix_Product(wordptr X, N_int rowsX, N_int colsX,
|
|
wordptr Y, N_int rowsY, N_int colsY,
|
|
wordptr Z, N_int rowsZ, N_int colsZ)
|
|
{
|
|
N_word i;
|
|
N_word j;
|
|
N_word k;
|
|
N_word indxX;
|
|
N_word indxY;
|
|
N_word indxZ;
|
|
N_word termX;
|
|
N_word termY;
|
|
N_word sum;
|
|
|
|
if ((colsY == rowsZ) and (rowsX == rowsY) and (colsX == colsZ) and
|
|
(bits_(X) == rowsX*colsX) and
|
|
(bits_(Y) == rowsY*colsY) and
|
|
(bits_(Z) == rowsZ*colsZ))
|
|
{
|
|
for ( i = 0; i < rowsY; i++ )
|
|
{
|
|
termX = i * colsX;
|
|
termY = i * colsY;
|
|
for ( j = 0; j < colsZ; j++ )
|
|
{
|
|
indxX = termX + j;
|
|
sum = 0;
|
|
for ( k = 0; k < colsY; k++ )
|
|
{
|
|
indxY = termY + k;
|
|
indxZ = k * colsZ + j;
|
|
if ( BIT_VECTOR_TST_BIT(Y,indxY) &&
|
|
BIT_VECTOR_TST_BIT(Z,indxZ) ) sum |= 1;
|
|
}
|
|
if (sum) BIT_VECTOR_SET_BIT(X,indxX)
|
|
else BIT_VECTOR_CLR_BIT(X,indxX)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Matrix_Closure(wordptr addr, N_int rows, N_int cols)
|
|
{
|
|
N_word i;
|
|
N_word j;
|
|
N_word k;
|
|
N_word ii;
|
|
N_word ij;
|
|
N_word ik;
|
|
N_word kj;
|
|
N_word termi;
|
|
N_word termk;
|
|
|
|
if ((rows == cols) and (bits_(addr) == rows*cols))
|
|
{
|
|
for ( i = 0; i < rows; i++ )
|
|
{
|
|
ii = i * cols + i;
|
|
BIT_VECTOR_SET_BIT(addr,ii)
|
|
}
|
|
for ( k = 0; k < rows; k++ )
|
|
{
|
|
termk = k * cols;
|
|
for ( i = 0; i < rows; i++ )
|
|
{
|
|
termi = i * cols;
|
|
ik = termi + k;
|
|
for ( j = 0; j < rows; j++ )
|
|
{
|
|
ij = termi + j;
|
|
kj = termk + j;
|
|
if ( BIT_VECTOR_TST_BIT(addr,ik) &&
|
|
BIT_VECTOR_TST_BIT(addr,kj) )
|
|
BIT_VECTOR_SET_BIT(addr,ij)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Matrix_Transpose(wordptr X, N_int rowsX, N_int colsX,
|
|
wordptr Y, N_int rowsY, N_int colsY)
|
|
{
|
|
N_word i;
|
|
N_word j;
|
|
N_word ii;
|
|
N_word ij;
|
|
N_word ji;
|
|
N_word addii;
|
|
N_word addij;
|
|
N_word addji;
|
|
N_word bitii;
|
|
N_word bitij;
|
|
N_word bitji;
|
|
N_word termi;
|
|
N_word termj;
|
|
boolean swap;
|
|
|
|
/* BEWARE that "in-place" is ONLY possible if the matrix is quadratic!! */
|
|
|
|
if ((rowsX == colsY) and (colsX == rowsY) and
|
|
(bits_(X) == rowsX*colsX) and
|
|
(bits_(Y) == rowsY*colsY))
|
|
{
|
|
if (rowsY == colsY) /* in-place is possible! */
|
|
{
|
|
for ( i = 0; i < rowsY; i++ )
|
|
{
|
|
termi = i * colsY;
|
|
for ( j = 0; j < i; j++ )
|
|
{
|
|
termj = j * colsX;
|
|
ij = termi + j;
|
|
ji = termj + i;
|
|
addij = ij >> LOGBITS;
|
|
addji = ji >> LOGBITS;
|
|
bitij = BITMASKTAB[ij AND MODMASK];
|
|
bitji = BITMASKTAB[ji AND MODMASK];
|
|
swap = ((*(Y+addij) AND bitij) != 0);
|
|
if ((*(Y+addji) AND bitji) != 0)
|
|
*(X+addij) |= bitij;
|
|
else
|
|
*(X+addij) &= NOT bitij;
|
|
if (swap)
|
|
*(X+addji) |= bitji;
|
|
else
|
|
*(X+addji) &= NOT bitji;
|
|
}
|
|
ii = termi + i;
|
|
addii = ii >> LOGBITS;
|
|
bitii = BITMASKTAB[ii AND MODMASK];
|
|
if ((*(Y+addii) AND bitii) != 0)
|
|
*(X+addii) |= bitii;
|
|
else
|
|
*(X+addii) &= NOT bitii;
|
|
}
|
|
}
|
|
else /* rowsX != colsX, in-place is NOT possible! */
|
|
{
|
|
for ( i = 0; i < rowsY; i++ )
|
|
{
|
|
termi = i * colsY;
|
|
for ( j = 0; j < colsY; j++ )
|
|
{
|
|
termj = j * colsX;
|
|
ij = termi + j;
|
|
ji = termj + i;
|
|
addij = ij >> LOGBITS;
|
|
addji = ji >> LOGBITS;
|
|
bitij = BITMASKTAB[ij AND MODMASK];
|
|
bitji = BITMASKTAB[ji AND MODMASK];
|
|
if ((*(Y+addij) AND bitij) != 0)
|
|
*(X+addji) |= bitji;
|
|
else
|
|
*(X+addji) &= NOT bitji;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* VERSION: 6.4 */
|
|
/*****************************************************************************/
|
|
/* VERSION HISTORY: */
|
|
/*****************************************************************************/
|
|
/* */
|
|
/* Version 6.4 03.10.04 Added C++ comp. directives. Improved "Norm()". */
|
|
/* Version 6.3 28.09.02 Added "Create_List()" and "GCD2()". */
|
|
/* Version 6.2 15.09.02 Overhauled error handling. Fixed "GCD()". */
|
|
/* Version 6.1 08.10.01 Make VMS linker happy: _lsb,_msb => _lsb_,_msb_ */
|
|
/* Version 6.0 08.10.00 Corrected overflow handling. */
|
|
/* Version 5.8 14.07.00 Added "Power()". Changed "Copy()". */
|
|
/* Version 5.7 19.05.99 Quickened "Div_Pos()". Added "Product()". */
|
|
/* Version 5.6 02.11.98 Leading zeros eliminated in "to_Hex()". */
|
|
/* Version 5.5 21.09.98 Fixed bug of uninitialized "error" in Multiply. */
|
|
/* Version 5.4 07.09.98 Fixed bug of uninitialized "error" in Divide. */
|
|
/* Version 5.3 12.05.98 Improved Norm. Completed history. */
|
|
/* Version 5.2 31.03.98 Improved Norm. */
|
|
/* Version 5.1 09.03.98 No changes. */
|
|
/* Version 5.0 01.03.98 Major additions and rewrite. */
|
|
/* Version 4.2 16.07.97 Added is_empty, is_full. */
|
|
/* Version 4.1 30.06.97 Added word-ins/del, move-left/right, inc/dec. */
|
|
/* Version 4.0 23.04.97 Rewrite. Added bit shift and bool. matrix ops. */
|
|
/* Version 3.2 04.02.97 Added interval methods. */
|
|
/* Version 3.1 21.01.97 Fixed bug on 64 bit machines. */
|
|
/* Version 3.0 12.01.97 Added flip. */
|
|
/* Version 2.0 14.12.96 Efficiency and consistency improvements. */
|
|
/* Version 1.1 08.01.96 Added Resize and ExclusiveOr. */
|
|
/* Version 1.0 14.12.95 First version under UNIX (with Perl module). */
|
|
/* Version 0.9 01.11.93 First version of C library under MS-DOS. */
|
|
/* Version 0.1 ??.??.89 First version in Turbo Pascal under CP/M. */
|
|
/* */
|
|
/*****************************************************************************/
|
|
/* AUTHOR: */
|
|
/*****************************************************************************/
|
|
/* */
|
|
/* Steffen Beyer */
|
|
/* mailto:sb@engelschall.com */
|
|
/* http://www.engelschall.com/u/sb/download/ */
|
|
/* */
|
|
/*****************************************************************************/
|
|
/* COPYRIGHT: */
|
|
/*****************************************************************************/
|
|
/* */
|
|
/* Copyright (c) 1995 - 2004 by Steffen Beyer. */
|
|
/* All rights reserved. */
|
|
/* */
|
|
/*****************************************************************************/
|
|
/* LICENSE: */
|
|
/*****************************************************************************/
|
|
/* This package is free software; you can use, modify and redistribute */
|
|
/* it under the same terms as Perl itself, i.e., under the terms of */
|
|
/* the "Artistic License" or the "GNU General Public License". */
|
|
/* */
|
|
/* The C library at the core of this Perl module can additionally */
|
|
/* be used, modified and redistributed under the terms of the */
|
|
/* "GNU Library General Public License". */
|
|
/* */
|
|
/*****************************************************************************/
|
|
/* ARTISTIC LICENSE: */
|
|
/*****************************************************************************/
|
|
/*
|
|
The "Artistic License"
|
|
|
|
Preamble
|
|
|
|
The intent of this document is to state the conditions under which a
|
|
Package may be copied, such that the Copyright Holder maintains some
|
|
semblance of artistic control over the development of the package,
|
|
while giving the users of the package the right to use and distribute
|
|
the Package in a more-or-less customary fashion, plus the right to make
|
|
reasonable modifications.
|
|
|
|
Definitions:
|
|
|
|
"Package" refers to the collection of files distributed by the
|
|
Copyright Holder, and derivatives of that collection of files
|
|
created through textual modification.
|
|
|
|
"Standard Version" refers to such a Package if it has not been
|
|
modified, or has been modified in accordance with the wishes
|
|
of the Copyright Holder as specified below.
|
|
|
|
"Copyright Holder" is whoever is named in the copyright or
|
|
copyrights for the package.
|
|
|
|
"You" is you, if you're thinking about copying or distributing
|
|
this Package.
|
|
|
|
"Reasonable copying fee" is whatever you can justify on the
|
|
basis of media cost, duplication charges, time of people involved,
|
|
and so on. (You will not be required to justify it to the
|
|
Copyright Holder, but only to the computing community at large
|
|
as a market that must bear the fee.)
|
|
|
|
"Freely Available" means that no fee is charged for the item
|
|
itself, though there may be fees involved in handling the item.
|
|
It also means that recipients of the item may redistribute it
|
|
under the same conditions they received it.
|
|
|
|
1. You may make and give away verbatim copies of the source form of the
|
|
Standard Version of this Package without restriction, provided that you
|
|
duplicate all of the original copyright notices and associated disclaimers.
|
|
|
|
2. You may apply bug fixes, portability fixes and other modifications
|
|
derived from the Public Domain or from the Copyright Holder. A Package
|
|
modified in such a way shall still be considered the Standard Version.
|
|
|
|
3. You may otherwise modify your copy of this Package in any way, provided
|
|
that you insert a prominent notice in each changed file stating how and
|
|
when you changed that file, and provided that you do at least ONE of the
|
|
following:
|
|
|
|
a) place your modifications in the Public Domain or otherwise make them
|
|
Freely Available, such as by posting said modifications to Usenet or
|
|
an equivalent medium, or placing the modifications on a major archive
|
|
site such as uunet.uu.net, or by allowing the Copyright Holder to include
|
|
your modifications in the Standard Version of the Package.
|
|
|
|
b) use the modified Package only within your corporation or organization.
|
|
|
|
c) rename any non-standard executables so the names do not conflict
|
|
with standard executables, which must also be provided, and provide
|
|
a separate manual page for each non-standard executable that clearly
|
|
documents how it differs from the Standard Version.
|
|
|
|
d) make other distribution arrangements with the Copyright Holder.
|
|
|
|
4. You may distribute the programs of this Package in object code or
|
|
executable form, provided that you do at least ONE of the following:
|
|
|
|
a) distribute a Standard Version of the executables and library files,
|
|
together with instructions (in the manual page or equivalent) on where
|
|
to get the Standard Version.
|
|
|
|
b) accompany the distribution with the machine-readable source of
|
|
the Package with your modifications.
|
|
|
|
c) give non-standard executables non-standard names, and clearly
|
|
document the differences in manual pages (or equivalent), together
|
|
with instructions on where to get the Standard Version.
|
|
|
|
d) make other distribution arrangements with the Copyright Holder.
|
|
|
|
5. You may charge a reasonable copying fee for any distribution of this
|
|
Package. You may charge any fee you choose for support of this
|
|
Package. You may not charge a fee for this Package itself. However,
|
|
you may distribute this Package in aggregate with other (possibly
|
|
commercial) programs as part of a larger (possibly commercial) software
|
|
distribution provided that you do not advertise this Package as a
|
|
product of your own. You may embed this Package's interpreter within
|
|
an executable of yours (by linking); this shall be construed as a mere
|
|
form of aggregation, provided that the complete Standard Version of the
|
|
interpreter is so embedded.
|
|
|
|
6. The scripts and library files supplied as input to or produced as
|
|
output from the programs of this Package do not automatically fall
|
|
under the copyright of this Package, but belong to whoever generated
|
|
them, and may be sold commercially, and may be aggregated with this
|
|
Package. If such scripts or library files are aggregated with this
|
|
Package via the so-called "undump" or "unexec" methods of producing a
|
|
binary executable image, then distribution of such an image shall
|
|
neither be construed as a distribution of this Package nor shall it
|
|
fall under the restrictions of Paragraphs 3 and 4, provided that you do
|
|
not represent such an executable image as a Standard Version of this
|
|
Package.
|
|
|
|
7. C subroutines (or comparably compiled subroutines in other
|
|
languages) supplied by you and linked into this Package in order to
|
|
emulate subroutines and variables of the language defined by this
|
|
Package shall not be considered part of this Package, but are the
|
|
equivalent of input as in Paragraph 6, provided these subroutines do
|
|
not change the language in any way that would cause it to fail the
|
|
regression tests for the language.
|
|
|
|
8. Aggregation of this Package with a commercial distribution is always
|
|
permitted provided that the use of this Package is embedded; that is,
|
|
when no overt attempt is made to make this Package's interfaces visible
|
|
to the end user of the commercial distribution. Such use shall not be
|
|
construed as a distribution of this Package.
|
|
|
|
9. The name of the Copyright Holder may not be used to endorse or promote
|
|
products derived from this software without specific prior written permission.
|
|
|
|
10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
|
|
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
|
WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
The End
|
|
*/
|
|
/*****************************************************************************/
|
|
/* GNU GENERAL PUBLIC LICENSE: */
|
|
/*****************************************************************************/
|
|
/* This program is free software; you can redistribute it and/or */
|
|
/* modify it under the terms of the GNU General Public License */
|
|
/* as published by the Free Software Foundation; either version 2 */
|
|
/* of the License, or (at your option) any later version. */
|
|
/* */
|
|
/* This program is distributed in the hope that it will be useful, */
|
|
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
|
|
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
|
|
/* GNU General Public License for more details. */
|
|
/* */
|
|
/* You should have received a copy of the GNU General Public License */
|
|
/* along with this program; if not, write to the */
|
|
/* Free Software Foundation, Inc., */
|
|
/* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
|
/* */
|
|
/*****************************************************************************/
|
|
/* GNU LIBRARY GENERAL PUBLIC LICENSE: */
|
|
/*****************************************************************************/
|
|
/* This library is free software; you can redistribute it and/or */
|
|
/* modify it under the terms of the GNU Library General Public */
|
|
/* License as published by the Free Software Foundation; either */
|
|
/* version 2 of the License, or (at your option) any later version. */
|
|
/* */
|
|
/* This library is distributed in the hope that it will be useful, */
|
|
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
|
|
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU */
|
|
/* Library General Public License for more details. */
|
|
/* */
|
|
/* You should have received a copy of the GNU Library General Public */
|
|
/* License along with this library; if not, write to the */
|
|
/* Free Software Foundation, Inc., */
|
|
/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
/* */
|
|
/* or download a copy from ftp://ftp.gnu.org/pub/gnu/COPYING.LIB-2.0 */
|
|
/* */
|
|
/*****************************************************************************/
|