diff options
author | somov <somov@yandex-team.ru> | 2022-02-10 16:45:47 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:47 +0300 |
commit | a5950576e397b1909261050b8c7da16db58f10b1 (patch) | |
tree | 7ba7677f6a4c3e19e2cefab34d16df2c8963b4d4 /contrib/tools/yasm/libyasm/bitvect.c | |
parent | 81eddc8c0b55990194e112b02d127b87d54164a9 (diff) | |
download | ydb-a5950576e397b1909261050b8c7da16db58f10b1.tar.gz |
Restoring authorship annotation for <somov@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/tools/yasm/libyasm/bitvect.c')
-rw-r--r-- | contrib/tools/yasm/libyasm/bitvect.c | 8090 |
1 files changed, 4045 insertions, 4045 deletions
diff --git a/contrib/tools/yasm/libyasm/bitvect.c b/contrib/tools/yasm/libyasm/bitvect.c index dfb08252b0..b1d5bdae11 100644 --- a/contrib/tools/yasm/libyasm/bitvect.c +++ b/contrib/tools/yasm/libyasm/bitvect.c @@ -1,4045 +1,4045 @@ -#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 */ -/* */ -/*****************************************************************************/ +#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 */ +/* */ +/*****************************************************************************/ |