
/******************************************************************************************************************************************************************************************
                                                                                      BITWISE.JS

Copyright © 2006 Illusionator, Inc.

JavaScript code that implements bitwise operators on values up to 53 bits (max value of 0x1FFFFFFFFFFFFF), which is the largest integer value that can be represented exactly as JavaScript
numbers, rather than just 32-bit integers that the built-in bitwise operators support.

These functions are given very short names (e.g., IlsAnd) rather than more sensible longer names (e.g., IlsBitwiseAnd), so that they can be more easily used as operators in large data
tables without taking up too much room in the code.

******************************************************************************************************************************************************************************************/

// CONSTANTS
var iIlsBitwiseHexDigitsLow = 8			// Number of hexadecimal digits that can be used with the built-in JavaScript bitwise operators
var iIlsBitwiseMaxLow = 0xFFFFFFFF;		// Maximum integer that can be used with the built-in JavaScript bitwise operators; equal to (2^32 - 1)
var iIlsBitwiseMaxHigh = 0x1FFFFF;		// Maximum integer in the high-order 21 bits of a 53 bit integer; equal to (2^21 - 1)


// IlsBitwiseLow(i)
//		i:		Integer value, between 0 and 0x1FFFFFFFFFFFFF (2^53 - 1) inclusive.
//	returns:	Value of the low-order 32 bits of "i".
//
// Returns the integer value of the low-order 32 bits of "i".  Useful when disassembling a 53-bit integer into its low-order 32 bits, and the remaining upper 21 bits, for bitwise
// operations.

function IlsBitwiseLow(i)
{
	// If the value of "i" already fits in its low-order 32 bits, just return itself
	if (i <= iIlsBitwiseMaxLow) {
		return i;
	}

	// Normally, we would compute the value of the low-order 32 bits using integer division and (possibly) rounding.  However, in at least the IE 6.0 implementation of JavaScript, number
	// division is not very accurate when the numbers are close to 53 bits; for example, Math.round(0xFFFFFFFFFFFFF / 0x100000000) = 0x1000000, which is one greater than it should be
	// and wreaks havoc.  We assume that the "%" modulo operator may have similar problems.  To avoid these math computation problems, we simply use the number-to-string-to-number
	// functions in JavaScript, which seem to be reliable even for 53-bit numbers.
	var s = i.toString(16);
	return parseInt('0x' + s.substring(s.length - iIlsBitwiseHexDigitsLow));
} // IlsBitwiseLow


// IlsBitwiseHigh(i)
//		i:		Integer value, between 0 and 0x1FFFFFFFFFFFFF (2^53 - 1) inclusive.
//	returns:	Value of the high-order 21 bits of "i".
//
// Returns the integer value of the high-order 21 bits of "i".  Useful when disassembling a 53-bit integer into its low-order 32 bits, and the remaining upper 21 bits, for bitwise
// operations.

function IlsBitwiseHigh(i)
{
	// If the value of "i" fits in its low-order 32 bits, the value of the high-order 21 bits is zero
	if (i <= iIlsBitwiseMaxLow) {
		return 0;
	}

	// Normally, we would compute the value of the high-order 21 bits using integer division and (possibly) rounding.  However, in at least the IE 6.0 implementation of JavaScript, number
	// division is not very accurate when the numbers are close to 53 bits; for example, Math.round(0xFFFFFFFFFFFFF / 0x100000000) = 0x1000000, which is one greater than it should be
	// and wreaks havoc.  We assume that the "%" modulo operator may have similar problems.  To avoid these math computation problems, we simply use the number-to-string-to-number
	// functions in JavaScript, which seem to be reliable even for 53-bit numbers.
	var s = i.toString(16);
	return (parseInt('0x' + s.substring(0, s.length - iIlsBitwiseHexDigitsLow)) & iIlsBitwiseMaxHigh);
} // IlsBitwiseHigh


// IlsBitwise(iHigh, iLow)
//		iHigh:	Integer value, between 0 and 0x1FFFFF (2^21 - 1) inclusive, representing the high-order 21 bits of the integer value to be returned.
//		iLow:	Integer value, between 0 and 0xFFFFFFFF (2^32 - 1) inclusive, representing the low-order 32-bits of the integer value to be returned.
//	returns:	53-bit integer value
//
// Returns the 53-bit integer value, between 0 and 0x1FFFFFFFFFFFFF (2^53 - 1) inclusive, whose high-order 21-bits have the value "iHigh" and whose low-order 32 bits have the value
// "iLow".

function IlsBitwise(iHigh, iLow)
{
	// Use only the low-order 21 bits of "iHigh".  If the result is zero, use the empty string rather than "0" for its string representation, so that we don't try to parse an integer
	// that begins with "0x0" (which would probably still yield a correct result, but no need to chance it).
	iHigh &= iIlsBitwiseMaxHigh;
	var sHigh = (iHigh == 0) ? "" : iHigh.toString(16);

	// To fill out the string representation of "iLow" to its full 8 hexadecimal digits (including leading zeroes), add (iIlsBitwiseMaxLow + 1) to "iLow", and then take the last
	// 8 characters in the string
	iLow += (iIlsBitwiseMaxLow + 1)
	var sLow = iLow.toString(16);
	sLow = sLow.substring(sLow.length - iIlsBitwiseHexDigitsLow)
	
	// The assembled 53-bit value is the parsed value of the string representation of "iHigh" followed by the string representation of "iLow"
	return parseInt('0x' + sHigh + sLow)
} // IlsBitwise


// IlsNot(i)
//		i:		Integer value, between 0 and 0x1FFFFFFFFFFFFF (2^53 - 1) inclusive.
//	returns:	Bitwise "not" of "i".
//
// Returns the bitwise "not" of "i", which is just like the JavaScript "~" operator, but extended to 53 bits.  For example, IlsNot(0x0F) = 0x1FFFFFFFFFFFF0.

function IlsNot(i)
{
	// Compute the "not" of the 53-bit value by computing the "not" of the high-order 21 bits and the low-order 32 bits, and combining them
	return IlsBitwise((~IlsBitwiseHigh(i)) & iIlsBitwiseMaxHigh, ~IlsBitwiseLow(i));
} // IlsNot


// IlsAnd(i1, ...)
//		i1, ...:	Any number of arguments, each of which is between 0 and 0x1FFFFFFFFFFFFF (2^53 - 1) inclusive
//	returns:		Bitwise "and" of all of the arguments, or zero if there are no arguments
//
// Returns the bitwise "and" of all arguments passed to this function, just like the JavaScript "&" operator but extended to 53 bits.  For example, IlsAnd(0x17100000000007,
// 0x1F00000000000F) = 0x17000000000007.

function IlsAnd()
{
	// There should be at least one argument, but in case there isn't, return zero
	if (arguments.length == 0) {
		return 0;
	}
	
	// Start with both "iHigh" and "iLow" having all their bits set
	var iHigh = iIlsBitwiseMaxHigh;
	var iLow = iIlsBitwiseMaxLow;
	
	// Perform an "and" of the high and low portions of all arguments into "iHigh" and "iLow"
	for (var i = 0; i < arguments.length; i++) {
		iHigh &= IlsBitwiseHigh(arguments[i]);
		iLow &= IlsBitwiseLow(arguments[i]);
	}

	// Return the number whose high-order 21 bits is "iHigh" and whose low-order 32 bits is "iLow"
	return IlsBitwise(iHigh, iLow);
} // IlsAnd


// IlsOr(i1, ...)
//		i1, ...:	Any number of arguments, each of which is between 0 and 0x1FFFFFFFFFFFFF (2^53 - 1) inclusive
//	returns:		Bitwise "or" of all of the arguments, or zero if there are no arguments
//
// Returns the bitwise "or" of all arguments passed to this function, just like the JavaScript "|" operator but extended to 53 bits.  For example, IlsOr(0x0F, 0x1F000000000000) =
// 0x1F00000000000F.

function IlsOr()
{
	// There should be at least one argument, but in case there isn't, return zero
	if (arguments.length == 0) {
		return 0;
	}
	
	// Start with both "iHigh" and "iLow" having none of their bits set
	var iHigh = 0;
	var iLow = 0;
	
	// Perform an "or" of the high and low portions of all arguments into "iHigh" and "iLow"
	for (var i = 0; i < arguments.length; i++) {
		iHigh |= IlsBitwiseHigh(arguments[i]);
		iLow |= IlsBitwiseLow(arguments[i]);
	}

	// Return the number whose high-order 21 bits is "iHigh" and whose low-order 32 bits is "iLow"
	return IlsBitwise(iHigh, iLow);
} // IlsOr


// IlsXor(i1, ...)
//		i1, ...:	Any number of arguments, each of which is between 0 and 0x1FFFFFFFFFFFFF (2^53 - 1) inclusive
//	returns:		Bitwise "xor" of all of the arguments, or zero if there are no arguments
//
// Returns the bitwise "xor" of all arguments passed to this function, just like the JavaScript "^" operator but extended to 53 bits.  For example, IlsXor(0x7000000000007,
// 0x1F00000000000F) = 0x18000000000008.

function IlsXor()
{
	// There should be at least one argument, but in case there isn't, return zero
	if (arguments.length == 0) {
		return 0;
	}
	
	// Start with both "iHigh" and "iLow" having none of their bits set
	var iHigh = 0;
	var iLow = 0;
	
	// Perform an "xor" of the high and low portions of all arguments into "iHigh" and "iLow"
	for (var i = 0; i < arguments.length; i++) {
		iHigh ^= IlsBitwiseHigh(arguments[i]);
		iLow ^= IlsBitwiseLow(arguments[i]);
	}

	// Return the number whose high-order 21 bits is "iHigh" and whose low-order 32 bits is "iLow"
	return IlsBitwise(iHigh, iLow);
} // IlsXor
