SmallInteger.st
author Claus Gittinger <cg@exept.de>
Thu, 07 Dec 1995 22:38:49 +0100
changeset 701 a309e3ef7faf
parent 587 6b0b960020d5
child 809 5eef87c2907b
permissions -rw-r--r--
checkin from browser

"
 COPYRIGHT (c) 1988 by Claus Gittinger
	      All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"

Integer subclass:#SmallInteger
	 instanceVariableNames:''
	 classVariableNames:''
	 poolDictionaries:''
	 category:'Magnitude-Numbers'
!

!SmallInteger class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 1988 by Claus Gittinger
	      All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"
!

documentation
"
    SmallIntegers are Integers in the range of at least +/- 2^30 
    (i.e. 31 bits, which is not guaranteed; it could be more on 64 bit cpus).

    These are no real objects - they have no instances (not even storage !!)
    and cannot be subclassed.
    The reason is to save both storage and runtime by not collecting
    SmallIntegers in the system. SmallInts are marked by having the TAG_INT 
    bit set, in contrast to all other objects which do not. 
    Since this knowledge is hardwired into the system (and there is no 
    class-field stored with SmallIntegers) there can be no subclass of 
    SmallInteger (sorry).

    If you really need this kind of thing, create a subclass of Integer,
    with an instance variable holding the value.
"
! !

!SmallInteger class methodsFor:'instance creation'!

basicNew
    "catch instance creation
     - SmallIntegers cannot be created with new"

    self error:'instances of SmallInteger cannot be created with new'
!

basicNew:size
    "catch instance creation
     - SmallIntegers cannot be created with new"

    self error:'instances of SmallInteger cannot be created with new'
! !

!SmallInteger class methodsFor:'binary storage'!

binaryDefinitionFrom: stream manager: manager
    "read the binary representation as stored in storeBinaryOn:"

    | value |

    value := stream next bitAnd: 16r7F.
    value > 16r3F ifTrue: [
	value := value - 16r80
    ].
    value := (value bitShift: 8) bitOr: stream next.
    value := (value bitShift: 8) bitOr: stream next.
    value := (value bitShift: 8) bitOr: stream next.
    ^ value
! !

!SmallInteger class methodsFor:'bit mask constants'!

bitMaskFor:index
    "return a bitmask for the index's bit (index starts at 1)"

    (index between:1 and:SmallInteger maxBits) ifFalse:[
	^ self error:'index out of bounds'
    ].
    ^ 1 bitShift:(index - 1)
! !

!SmallInteger class methodsFor:'constants'!

maxBits
    "return the number of bits in instances of me.
     For very special uses only - not constant across implementations"

%{  /* NOCONTEXT */
    RETURN ( _MKSMALLINT(N_INT_BITS) );
%}

    "SmallInteger maxBits"
!

maxBytes
    "return the number of bytes in instances of me.
     For very special uses only - not constant across implementations"

%{  /* NOCONTEXT */
    RETURN ( _MKSMALLINT(N_INT_BITS / 8 + 1) );
%}

    "SmallInteger maxBytes"
!

maxVal
    "return the largest Integer representable as SmallInteger.
     For very special uses only - not constant across implementations"

%{  /* NOCONTEXT */
    RETURN ( _MKSMALLINT(_MAX_INT) );
%}

    "SmallInteger maxVal"
!

minVal
    "return the smallest Integer representable as SmallInteger.
     For very special uses only - not constant across implementations"

%{  /* NOCONTEXT */
    RETURN ( _MKSMALLINT(_MIN_INT) );
%}

    "SmallInteger minVal"
! !

!SmallInteger class methodsFor:'queries'!

canBeSubclassed
    "return true, if its allowed to create subclasses of the receiver.
     Return nil here - since it is NOT possible for SmallInteger"

    ^ false
!

isBuiltInClass
    "this class is known by the run-time-system"

    ^ true
! !

!SmallInteger methodsFor:'arithmetic'!

* aNumber
    "return the product of the receivers value and the arguments value"

%{  /* NOCONTEXT */

    INT myValue, otherValue;
    unsigned INT productLow, productHi;
    int negative;

#   define lowBits(foo)  ((foo) & 0xFFFF)
#   define hiBits(foo)   ((foo) >> 16)

    /*
     * can we use long long arithmetic ?
     */
#if defined(__GNUC__) && (__GNUC__ >= 2)
    /*
     * commented, since long-long arithmetic seems to
     * be buggy in some implementations (sparc) ...
     * (took me a while to find this out :-(
     */
# ifdef NOTDEF
#   define _LONGLONG
# endif
#endif

    if (__isSmallInteger(aNumber)) {
	myValue = _intVal(self);
	otherValue = _intVal(aNumber);
#if defined(_LONGLONG)
	{
	    long long product;

	    product = (long long)myValue * (long long)otherValue;
	    if ((product >= (long long)_MIN_INT) 
	     && (product <= (long long)_MAX_INT)) {
		RETURN ( _MKSMALLINT((int)product) );
	    }
	    if (product < 0) {
		negative = 1;
		product = -product;
	    } else {
		negative = 0;
	    }
	    productHi = product >> 32;
	    productLow = product & 0xFFFFFFFF;
	}
#else
	negative = 0;
	if (myValue < 0) {
	    negative = 1;
	    myValue = -myValue;
	}
	if (otherValue < 0) {
	    negative = (1 - negative);
	    otherValue = -otherValue;
	}

# if defined(__GNUC__) && defined(mc68k)
	asm ("mulu%.l %3,%1:%0"
		: "=d"  ((unsigned long)(productLow)),
		  "=d"  ((unsigned long)(productHi))
		: "%0"  ((unsigned long)(myValue)),
		  "dmi" ((unsigned long)(otherValue)));
# else
#  if defined (__GNUC__) && defined(i386)
	asm ("mull %3"
		: "=a"  ((unsigned long)(productLow)),
		  "=d"  ((unsigned long)(productHi))
		: "%0"  ((unsigned long)(myValue)),
		  "rm"  ((unsigned long)(otherValue)));
#  else
	{
	    unsigned INT pHH, pHL, pLH, pLL;
	    unsigned INT low1, low2, hi1, hi2;
	    unsigned INT t;

	    /* unsigned multiply myValue * otherValue -> productHi, productLow
	     *
	     * this is too slow:
	     * since most machines can do 32*32 to 64 bit multiply,
	     * (or at least 32*32 with Overflow check)
	     * - need more assembler (inline) functions here 
	     */
	    low1 = lowBits(myValue);
	    hi1 = hiBits(myValue);
	    low2 = lowBits(otherValue);
	    hi2 = hiBits(otherValue);

	    pLH = low1 * hi2;
	    pHL = hi1 * low2;
	    pLL = low1 * low2;
        
	    /*
	     * the common case ...
	     */
	    if ((pHL == 0)
	     && (pLH == 0)
	     && ((pLL & 0xC0000000) == 0)) {
		if (negative) {
		    RETURN ( _MKSMALLINT(- ((INT)pLL)) );
		}
		RETURN ( _MKSMALLINT((INT)pLL) );
	    }

	    pHH = hi1 * hi2;

	    /*
	     *   pHH |--------|--------|
	     *   pLH          |--------|--------|
	     *   pHL          |--------|--------|
	     *   pLL                   |--------|--------|
	     */

	    t = lowBits(pLH) + lowBits(pHL) + hiBits(pLL);
	    productLow = (t << 16) + lowBits(pLL);
	    productHi = pHH + hiBits(t) + hiBits(pHL) + hiBits(pLH);
	}
#  endif
# endif
	if (productHi == 0) {
	    if (negative) {
		if (productLow <= -(_MIN_INT)) {
		    RETURN ( _MKSMALLINT(-((INT)productLow)) );
		}
	    } else {
		if (productLow <= _MAX_INT) {
		    RETURN ( _MKSMALLINT(productLow) );
		}
	    }
	}
#endif

	{
	    extern OBJ LargeInteger;
	    static struct inlineCache val = _ILC5;
	    OBJ aLarge;

	    aLarge = (*val.ilc_func)(LargeInteger, 
				     @symbol(sign:value16:value16:value16:value16:),
				     CON_COMMA nil, &val, 
				     negative ? _MKSMALLINT(-1) : _MKSMALLINT(1),
				     _MKSMALLINT(lowBits(productLow)),
				     _MKSMALLINT(hiBits(productLow)),
				     _MKSMALLINT(lowBits(productHi)),
				     _MKSMALLINT(hiBits(productHi)) );
	    RETURN(aLarge);
	}
    } else if (__isFloatLike(aNumber)) {
	OBJ newFloat;
	double val = (double)_intVal(self) * _floatVal(aNumber);

	_qMKFLOAT(newFloat, val, SENDER);
	RETURN ( newFloat );
    }
%}
.
    ^ aNumber productFromInteger:self
!

+ aNumber
    "return the sum of the receivers value and the arguments value"

%{  /* NOCONTEXT */

    if (__isSmallInteger(aNumber)) {
#ifdef _ADD_IO_IO
	RETURN ( _ADD_IO_IO(self, aNumber) );
#else
	REGISTER INT sum;
	extern OBJ _MKLARGEINT();

	sum =  _intVal(self) + _intVal(aNumber);
	if ((sum >= _MIN_INT) && (sum <= _MAX_INT)) {
	    RETURN ( _MKSMALLINT(sum) );
	}
	RETURN ( _MKLARGEINT(sum) );
#endif
    }
    if (__isFloatLike(aNumber)) {
	OBJ newFloat;
	double val = (double)_intVal(self) + _floatVal(aNumber);

	_qMKFLOAT(newFloat, val, SENDER);
	RETURN ( newFloat );
    }
%}
.
    ^ aNumber sumFromInteger:self
!

- aNumber
    "return the difference of the receivers value and the arguments value"

%{  /* NOCONTEXT */

    if (__isSmallInteger(aNumber)) {
#ifdef _SUB_IO_IO
	RETURN ( _SUB_IO_IO(self, aNumber) );
#else
	REGISTER INT diff;
	extern OBJ _MKLARGEINT();

	diff =  _intVal(self) - _intVal(aNumber);
	if ((diff >= _MIN_INT) && (diff <= _MAX_INT)) {
	    RETURN ( _MKSMALLINT(diff) );
	}
	RETURN ( _MKLARGEINT(diff) );
#endif
    }
    if (__isFloatLike(aNumber)) {
	OBJ newFloat;
	double val = (double)_intVal(self) - _floatVal(aNumber);

	_qMKFLOAT(newFloat, val, SENDER);
	RETURN ( newFloat );
    }
%}
.
    ^ aNumber differenceFromInteger:self
!

/ aNumber
    "return the quotient of the receivers value and the arguments value"

%{  /* NOCONTEXT */

    INT me, t, val;
    double dval;

    if (__isSmallInteger(aNumber)) {
	val = _intVal(aNumber);
	if (val != 0) {
	    me = _intVal(self);
	    t = me / val;
#ifdef GOOD_OPTIMIZER
	    if (me % val) {
#else
	    /* this is stupid - all I want is to look for a remainder ... 
	       but most compilers are too stupid and generate an extra modulu
	       instruction for "if (me % val)".
	       Even if most divide instructions already leave the remainder in
	       some register.
	       Therefore I use a multiplication which is faster than a modulu
	       on most machines. Hint to GNU people :-)
	    */
	    if ((t * val) == me) {
#endif
		RETURN ( _MKSMALLINT(t) );
	    }
	}
    } else {
	if (__isFloatLike(aNumber)) {
	    dval = _floatVal(aNumber);
	    if (dval != 0.0) {
		OBJ newFloat;
		double val = (double)_intVal(self) / dval;

		_qMKFLOAT(newFloat, val, SENDER);
		RETURN ( newFloat );
	    }
	}
    }
%}
.
    aNumber isInteger ifTrue:[
	aNumber == 0 ifTrue:[
	    ^ DivisionByZeroSignal raise.
	].
	^ Fraction numerator:self denominator:aNumber
    ].
    ^ aNumber quotientFromInteger:self
!

// aNumber
    "return the integer part of the quotient of the receivers value
     and the arguments value"

%{  /* NOCONTEXT */
    INT val;

    if (__isSmallInteger(aNumber)) {
	val = _intVal(aNumber);
	if (val != 0) {
	    RETURN ( _MKSMALLINT(_intVal(self) / val) );
	}
    } else {
	if (__isFraction(aNumber)) {
	    OBJ t;
	    INT num, den;

	    t = _FractionInstPtr(aNumber)->f_numerator;
	    if (__isSmallInteger(t)) {
		num = _intVal(t);
		t = _FractionInstPtr(aNumber)->f_denominator;
		if (__isSmallInteger(t)) {
		    den = _intVal(t);
		    RETURN ( _MKSMALLINT(_intVal(self) * den / num ));
		}
	    }
	}
    }
%}
.
    (aNumber = 0) ifTrue:[
	^ DivisionByZeroSignal raise.
    ].
    ^ self retry:#// coercing:aNumber
!

\\ aNumber
    "return the integer rest of the receivers value
     divided by the arguments value"

%{  /* NOCONTEXT */
    INT mySelf, val;

    if (__isSmallInteger(aNumber)) {
	mySelf = _intVal(self);
	if (mySelf < 0) mySelf = -mySelf;
	val = _intVal(aNumber);
	if (val != 0) {
	    if (val < 0) {
		RETURN ( _MKSMALLINT(-(mySelf % -val)) );
	    }
	    RETURN ( _MKSMALLINT(mySelf % val) );
	}
    }
%}
.
    (aNumber = 0) ifTrue:[
	^ DivisionByZeroSignal raise.
    ].
    ^ self retry:#\\ coercing:aNumber
!

abs
    "return the absolute value of the receiver
     reimplemented here for speed"

%{  /* NOCONTEXT */

    INT val = _intVal(self);

    if (val >= 0) {
	RETURN (self);
    }
    if (val != _MIN_INT) {
	RETURN ( _MKSMALLINT(-val) );
    }
%}.
    "only reached for minVal"
    ^ self negated
!

negated
    "return the negative value of the receiver
     reimplemented here for speed"

%{  /* NOCONTEXT */

    INT val = _intVal(self);

    if (val != _MIN_INT) {
	RETURN ( _MKSMALLINT(- val) );
    }
%}.
    "only reached for minVal"
    ^ (LargeInteger value:(SmallInteger maxVal)) + 1
! !

!SmallInteger methodsFor:'binary storage'!

hasSpecialBinaryRepresentation
    "return true, if the receiver has a special binary representation"

    ^ true
!

storeBinaryOn: stream manager: manager
    "append a binary representation onto stream.
     Redefined since SmallIntegers are stored as their value with the 32nd bit 
     set as a tag.
     To make the binary file a bit more compact, zeros and single byte ints
     are stored with a more compact representation (using special type-codes)."

    self == 0 ifTrue:[
	stream nextPut: manager codeForZero.
	^ self
    ].
    (self between:0 and:255) ifTrue:[
	stream nextPut: manager codeForByteInteger.
	stream nextPut: self.
	^ self
    ].
    stream nextPut: (((self bitShift: -24) bitAnd: 16rFF) bitOr: 16r80).
    stream nextPut: ((self bitShift: -16) bitAnd: 16rFF).
    stream nextPut: ((self bitShift: -8) bitAnd: 16rFF).
    stream nextPut: (self bitAnd: 16rFF)
! !

!SmallInteger methodsFor:'bit operators'!

allMask:anInteger
    "return true if all 1-bits in anInteger are also 1 in the receiver"

    ^ (self bitAnd:anInteger) == anInteger

    "2r00001111 allMask:2r00000001"
    "2r00001111 allMask:2r00011110"
    "2r00001111 allMask:2r00000000"
!

anyMask:anInteger
    "return true if any 1-bits in anInteger is also 1 in the receiver.
     (somewhat incorrect, if the mask is zero)"

    ^ (self bitAnd:anInteger) ~~ 0

    "2r00001111 anyMask:2r00000001"
    "2r00001111 anyMask:2r11110000"
!

bitAnd:anInteger
    "return the bitwise-and of the receiver and the argument, anInteger"

%{  /* NOCONTEXT */

    /* anding the tags doesn't change it */
    if (__isSmallInteger(anInteger)) {
	RETURN ( ((OBJ) ((INT)self & (INT)anInteger)) );
    }
%}
.
    ^ self retry:#bitAnd coercing:anInteger

    "(2r001010100 bitAnd:2r00001111) radixPrintStringRadix:2"
!

bitAt:index
    "return the value of the index's bit (index starts at 1).
     Notice: the result of bitAt: on negative receivers is not 
	     defined in the language standard (since the implementation
	     is free to choose any internal representation for integers)"

    |mask|

    (index between:1 and:SmallInteger maxBits) ifFalse:[
	^ self error:'index out of bounds'
    ].
    mask := 1 bitShift:(index - 1).
    ((self bitAnd:mask) == 0) ifTrue:[^ 0].
    ^ 1
!

bitInvert
    "return the value of the receiver with all bits inverted"

%{  /* NOCONTEXT */

    /* invert anything except tag bits */
    RETURN ( ((OBJ) ((INT)self ^ ~TAG_MASK)) );
%}
!

bitOr:anInteger
    "return the bitwise-or of the receiver and the argument, anInteger"

%{  /* NOCONTEXT */

    /* oring the tags doesn't change it */
    if (__isSmallInteger(anInteger)) {
	RETURN ( ((OBJ) ((INT)self | (INT)anInteger)) );
    }
%}
.
    ^ self retry:#bitOr coercing:anInteger

    "(2r000000100 bitOr:2r00000011) radixPrintStringRadix:2"
!

bitShift:shiftCount
    "return the value of the receiver shifted by shiftCount bits;
     leftShift if shiftCount > 0; rightShift otherwise.
     Notice: the result of bitShift: on negative receivers is not 
	     defined in the language standard (since the implementation
	     is free to choose any internal representation for integers)"

%{  /* NOCONTEXT */

    INT bits, count;

    if (__isSmallInteger(shiftCount)) {
	count = _intVal(shiftCount);
	bits = _intVal(self);
	if (count > 0) {
#if defined(_LONGLONG)
	    unsigned long long result;

	    result = bits;
	    if (count <= N_INT_BITS) {
		result <<= count;
		if (result <= _MAX_INT) {
		    RETURN ( _MKSMALLINT(result) );
		}
		{
		    extern OBJ LargeInteger;
		    static struct inlineCache val = _ILC5;
		    OBJ aLarge;

		    aLarge = (*val.ilc_func)(LargeInteger,
				     @symbol(sign:value16:value16:value16:value16:),
				     CON_COMMA nil, &val,
				     _MKSMALLINT(1),
				     _MKSMALLINT(lowBits(result)),
				     _MKSMALLINT(hiBits(result)),
				     _MKSMALLINT(lowBits(result >> 32)),
				     _MKSMALLINT(hiBits(result >> 32)) );
		    RETURN(aLarge);
		}
	    }
#else
	    /*
	     * check for overflow
	     */
	    if (count < (N_INT_BITS-1)) {
		if (! (bits >> (N_INT_BITS - 1 - count))) {
		    RETURN ( _MKSMALLINT(bits << count) );
		}
		/*
		 * so, there is an overflow ...
		 * handle it as largeInteger
		 */
		/* FALL THROUGH */
	    }
#endif
	} else {
	    /*
	     * right shifts cannot overflow
	     */
	    if (count < 0) {
		/*
		 * some machines ignore shifts bigger than
		 * the number of bits in an int ...
		 */
		if (count < (-N_INT_BITS-1))
		    RETURN (_MKSMALLINT(0));
		RETURN ( _MKSMALLINT(bits >> -count) );
	    }
	    RETURN (self );
	}
    }
%}.
    (shiftCount isMemberOf:SmallInteger) ifTrue:[
	^ (LargeInteger value:self) bitShift:shiftCount
    ].
    ^ self bitShift:(shiftCount coerce:1)
!

bitTest:aMask
    "return true, if any bit from aMask is set in the receiver"

%{  /* NOCONTEXT */

    /* and all bits except tag */
    if (__isSmallInteger(aMask)) {
	RETURN ( ((INT)self & ((INT)aMask & ~TAG_MASK)) ? true : false );
    }
%}
.
    ^ self retry:#bitTest coercing:aMask
!

bitXor:anInteger
    "return the bitwise-exclusive-or of the receiver and the argument, anInteger"

%{  /* NOCONTEXT */

    /* xoring the tags turns it off - or it in again */
    if (__isSmallInteger(anInteger)) {
	RETURN ( (OBJ)( ((INT)self ^ (INT)anInteger) | TAG_INT) );
    }
%}
.
    ^ self retry:#bitXor coercing:anInteger
!

highBit
    "return the bitIndex of the highest bit set. The returned bitIndex
     starts at 1 for the least significant bit. Returns -1 if no bit is set."

%{  /* NOCONTEXT */

    INT mask, index, bits;

    bits = _intVal(self);
    if (bits == 0) {
	RETURN ( _MKSMALLINT(-1) );
    }
#ifdef alpha
    mask = 0x2000000000000000;
    index = 62;
#else
    mask = 0x20000000;
    index = 30;
#endif
    while (index) {
	if (bits & mask) break;
	mask = mask >> 1;
	index--;
    }
    RETURN ( _MKSMALLINT(index) );
%}
    "2r000100 highBit"
    "2r010100 highBit"
    "2r000001 highBit"
    "0 highBit"
    "SmallInteger maxVal highBit"
!

lowBit
    "return the bitIndex of the lowest bit set. The returned bitIndex
     starts at 1 for the least significant bit. Returns -1 if no bit is set."

%{  /* NOCONTEXT */

    INT mask, index, bits;

    bits = _intVal(self);
    if (bits == 0) {
	RETURN ( _MKSMALLINT(-1) );
    }
    mask = 1;
    index = 1;
#ifdef alpha
    while (index != 63) {
#else
    while (index != 31) {
#endif
	if (bits & mask) {
	    RETURN ( _MKSMALLINT(index) );
	}
	mask = mask << 1;
	index++;
    }
    RETURN ( _MKSMALLINT(-1) );
%}
    "2r000100 lowBit"
    "2r010010 lowBit"
    "2r100001 lowBit"
    "0 lowBit"
!

noMask:anInteger
    "return true if no 1-bit in anInteger is 1 in the receiver"

    ^ (self bitAnd:anInteger) == 0

    "2r00001111 noMask:2r00000001"
    "2r00001111 noMask:2r11110000"
! !

!SmallInteger methodsFor:'byte access'!

digitAt:index
    "return 8 bits of value, starting at byte index"

%{  /* NOCONTEXT */

    REGISTER INT val;
    INT idx;

    if (__isSmallInteger(index)) {
	val = _intVal(self);
	if (val < 0)
	    val = -val;
	switch (idx = _intVal(index)) {
	    case 1:
		break;
	    case 2:
		val = (val >> 8);
		break;
	    case 3:
		val = (val >> 16);
		break;
	    case 4:
		val = (val >> 24);
		break;
#ifdef alpha
	    case 5:
		val = (val >> 32);
		break;
	    case 6:
		val = (val >> 40);
		break;
	    case 7:
		val = (val >> 48);
		break;
	    case 8:
		val = (val >> 56);
		break;
#endif
	    default:
		if (idx < 1)
		    goto bad;   /* sorry */
		val = 0;
		break;
	}
	RETURN ( _MKSMALLINT( val & 0xFF) );
    }
  bad: ;
%}.
    index > 0 ifFalse:[
	"
	 index less than 1 - not allowed
	"
	^ self primitiveFailed
    ].
    ^ 0

    "
     (16r12345678 digitAt:1) printStringRadix:16
     (16r12345678 digitAt:3) printStringRadix:16
     (16r12345678 digitAt:15) printStringRadix:16
     (16r12345678 digitAt:0) printStringRadix:16
     (16r12345678 digitAt:-10) printStringRadix:16
    "
!

digitLength
    "return the number bytes used by this Integer"

    ^ self abs highBit - 1 // 8 + 1
! !

!SmallInteger methodsFor:'catching messages'!

basicAt:index
    "catch indexed access - report an error
     defined here since basicAt: in Object ommits the SmallInteger check."

    self notIndexed
!

basicAt:index put:anObject
    "catch indexed access - report an error
     defined here since basicAt:put: in Object ommits the SmallInteger check."

    self notIndexed
!

basicSize
    "return the number of indexed instvars - SmallIntegers have none.
     Defined here since basicSize in Object ommits the SmallInteger check."

    ^ 0
!

size
    "return the number of indexed instvars - SmallIntegers have none."

    ^ 0
! !

!SmallInteger methodsFor:'coercing and converting'!

asCharacter
    "Return a character with the receiver as ascii value"

    ^ Character value:self
!

asFloat
    "return a Float with same value as receiver"

%{  /* NOCONTEXT */

    OBJ newFloat;
    double dVal = (double)_intVal(self);

    _qMKFLOAT(newFloat, dVal, SENDER);
    RETURN ( newFloat );
%}
!

asLargeInteger
    "return a LargeInteger with same value as receiver"

    ^ LargeInteger value:self
!

coerce:aNumber
    "return aNumber converted into receivers type"

    ^ aNumber asInteger
!

generality
    "return the generality value - see ArithmeticValue>>retry:coercing:"

    ^ 20
! !

!SmallInteger methodsFor:'comparing'!

< aNumber
    "return true, if the argument is greater than the receiver"

%{  /* NOCONTEXT */

    if (__isSmallInteger(aNumber)) {
#ifdef POSITIVE_ADDRESSES
	RETURN ( (_intVal(self) < _intVal(aNumber)) ? true : false );
#else
	/* tag bit does not change ordering */
	RETURN ( ((INT)self < (INT)aNumber) ? true : false );
#endif
    }
    if (__isFloatLike(aNumber)) {
	RETURN ( ((double)_intVal(self) < _floatVal(aNumber)) ? true : false );
    }
%}
.
    ^ aNumber lessFromInteger:self
    "^ self retry:#< coercing:aNumber"
!

<= aNumber
    "return true, if the argument is greater or equal"

%{  /* NOCONTEXT */

    if (__isSmallInteger(aNumber)) {
#ifdef POSITIVE_ADDRESSES
	RETURN ( (_intVal(self) <= _intVal(aNumber)) ? true : false );
#else
	/* tag bit does not change ordering */
	RETURN ( ((INT)self <= (INT)aNumber) ? true : false );
#endif
    }
    if (__isFloatLike(aNumber)) {
	RETURN ( ((double)_intVal(self) <= _floatVal(aNumber)) ? true : false );
    }
%}
.
    ^ self retry:#<= coercing:aNumber
!

= aNumber
    "return true, if the arguments value is equal to mine"

%{  /* NOCONTEXT */

    if (aNumber == self) {
	RETURN ( true );
    }
    if (! __isNonNilObject(aNumber)) {
	/* a smallint or nil */
	RETURN ( false );
    }

    if (__isFloatLike(aNumber)) {
	RETURN ( ((double)_intVal(self) == _floatVal(aNumber)) ? true : false );
    }
%}
.
    aNumber respondsToArithmetic ifFalse:[^ false].
    ^ self retry:#= coercing:aNumber
!

> aNumber
    "return true, if the argument is less than the receiver"

%{  /* NOCONTEXT */

    if (__isSmallInteger(aNumber)) {
#ifdef POSITIVE_ADDRESSES
	RETURN ( (_intVal(self) > _intVal(aNumber)) ? true : false );
#else
	/* tag bit does not change ordering */
	RETURN ( ((INT)self > (INT)aNumber) ? true : false );
#endif
    }
    if (__isFloatLike(aNumber)) {
	RETURN ( ((double)_intVal(self) > _floatVal(aNumber)) ? true : false );
    }
%}
.
    ^ self retry:#> coercing:aNumber
!

>= aNumber
    "return true, if the argument is less or equal"

%{  /* NOCONTEXT */

    if (__isSmallInteger(aNumber)) {
#ifdef POSITIVE_ADDRESSES
	RETURN ( (_intVal(self) >= _intVal(aNumber)) ? true : false );
#else
	/* tag bit does not change ordering */
	RETURN ( ((INT)self >= (INT)aNumber) ? true : false );
#endif
    }
    if (__isFloatLike(aNumber)) {
	RETURN ( ((double)_intVal(self) >= _floatVal(aNumber)) ? true : false );
    }
%}
.
    ^ self retry:#>= coercing:aNumber
!

hash
    "return an integer useful for hashing on value"

    self >= 0 ifTrue:[^ self].
    ^ self negated
!

identityHash
    "return an integer useful for hashing on identity"

    self >= 0 ifTrue:[^ self].
    ^ self negated
!

max:aNumber
    "return the receiver or the argument, whichever is greater"

%{  /* NOCONTEXT */

    if (__isSmallInteger(aNumber)) {
#ifdef POSITIVE_ADDRESSES
	if (_intVal(self) > _intVal(aNumber)) {
#else
	/* tag bit does not change ordering */
	if ((INT)(self) > (INT)(aNumber)) {
#endif
	    RETURN ( self );
	}
	RETURN ( aNumber );
    }
    if (__isFloatLike(aNumber)) {
	if ( (double)_intVal(self) > _floatVal(aNumber) ) {
	    RETURN ( self );
	}
	RETURN ( aNumber );
    }
%}
.
    (self > aNumber) ifTrue:[^ self].
    ^ aNumber
!

min:aNumber
    "return the receiver or the argument, whichever is smaller"

%{  /* NOCONTEXT */

    if (__isSmallInteger(aNumber)) {
#ifdef POSITIVE_ADDRESSES
	if (_intVal(self) < _intVal(aNumber)) {
#else
	/* tag bit does not change ordering */
	if ((INT)(self) < (INT)(aNumber)) {
#endif
	    RETURN ( self );
	}
	RETURN ( aNumber );
    }
    if (__isFloatLike(aNumber)) {
	if ( (double)_intVal(self) < _floatVal(aNumber) ) {
	    RETURN ( self );
	}
	RETURN ( aNumber );
    }
%}
.
    (self < aNumber) ifTrue:[^ self].
    ^ aNumber
!

~= aNumber
    "return true, if the arguments value is not equal to mine"

%{  /* NOCONTEXT */

    if (aNumber == self) {
	RETURN ( false );
    }
    if (! __isNonNilObject(aNumber)) {
	/* a smallint or nil */
	RETURN ( true );
    }

    if (__isFloatLike(aNumber)) {
	RETURN ( ((double)_intVal(self) == _floatVal(aNumber)) ? false : true );
    }
%}
.
    aNumber respondsToArithmetic ifFalse:[^ true].
    ^ self retry:#~= coercing:aNumber
! !

!SmallInteger methodsFor:'copying'!

deepCopy
    "return a deep copy of myself
     - reimplemented here since smallintegers are unique"

    ^ self
!

deepCopyUsing:aDictionary
    "return a deep copy of myself
     - reimplemented here since smallintegers are unique"

    ^ self
!

shallowCopy
    "return a shallow copy of myself
     - reimplemented here since smallintegers are unique"

    ^ self
!

simpleDeepCopy
    "return a deep copy of myself
     - reimplemented here since smallintegers are unique"

    ^ self
! !

!SmallInteger methodsFor:'iteration'!

timesRepeat:aBlock
    "evaluate the argument, aBlock self times.
     Reimplemented as primitive for speed"

    |home|
%{
    REGISTER INT tmp;
    REGISTER OBJFUNC code;
    extern OBJ Block;
    static struct inlineCache blockVal = __ILC0(0);
    REGISTER OBJ rHome;

    tmp = __intVal(self);
    if (tmp > 0) {
	if (__isBlockLike(aBlock)
	 && (_BlockInstPtr(aBlock)->b_nargs == _MKSMALLINT(0))) {
	    if ((code = _BlockInstPtr(aBlock)->b_code) != (OBJFUNC)nil) {
#ifdef NEW_BLOCK_CALL
		do {
		    if (InterruptPending != nil) interrupt(CONARG);
		    (*code)(aBlock COMMA_CON);
		} while(--tmp);
		RETURN (self);
#else /* old BLOCK_CALL */
		/*
		 * arg is a compiled block - 
		 * directly call it without going through "Block-value"
		 */
		rHome = _BlockInstPtr(aBlock)->b_home;
		if ((rHome == nil) || (__qSpace(rHome) >= STACKSPACE)) {
		    /*
		     * home will not move - keep in in a register
		     */
# if defined(UNROLL_LOOPS)
		    while (tmp > 4) {
			if (InterruptPending != nil) interrupt(CONARG);
			(*code)(rHome COMMA_CON);
			if (InterruptPending != nil) interrupt(CONARG);
			(*code)(rHome COMMA_CON);
			if (InterruptPending != nil) interrupt(CONARG);
			(*code)(rHome COMMA_CON);
			if (InterruptPending != nil) interrupt(CONARG);
			(*code)(rHome COMMA_CON);
			tmp -= 4;
		    }
# endif
		    do {
			if (InterruptPending != nil) interrupt(CONARG);
			(*code)(rHome COMMA_CON);
		    } while(--tmp);
		    RETURN (self);
		}
		home = rHome;
		do {
		    if (InterruptPending != nil) interrupt(CONARG);
		    (*code)(home COMMA_CON);
		} while(--tmp);
		RETURN (self);
#endif /* NEW_BLOCK_CALL */
	    }
	    if (_BlockInstPtr(aBlock)->b_bytecodes != nil) {
#ifdef PASS_ARG_POINTER
		extern OBJ __interpret();
#else
		extern OBJ interpret();
#endif

		/*
		 * an interpreted block
		 */
		home = _BlockInstPtr(aBlock)->b_home;
#if defined(mips) || defined(rs6000)
# define INDIRECT_CALL_IS_FASTER
#endif

#ifdef PASS_ARG_POINTER
# ifdef INDIRECT_CALL_IS_FASTER
		code = __interpret;
#  define       INTERPRET (*code)
# else
#  define       INTERPRET __interpret
# endif
#else
# ifdef INDIRECT_CALL_IS_FASTER
		code = interpret;
#  define       INTERPRET (*code)
# else
#  define       INTERPRET interpret
# endif
#endif
#ifdef NEW_BLOCK_CALL
# define HOME nil
#else
# define HOME home
#endif
#if defined(UNROLL_LOOPS)
		while (tmp > 4) {
		    if (InterruptPending != nil) interrupt(CONARG);
		    INTERPRET(aBlock, 0, nil, HOME COMMA_SND, nil);
		    if (InterruptPending != nil) interrupt(CONARG);
		    INTERPRET(aBlock, 0, nil, HOME COMMA_SND, nil);
		    if (InterruptPending != nil) interrupt(CONARG);
		    INTERPRET(aBlock, 0, nil, HOME COMMA_SND, nil);
		    if (InterruptPending != nil) interrupt(CONARG);
		    INTERPRET(aBlock, 0, nil, HOME COMMA_SND, nil);
		    tmp -= 4;
		}
#endif
		do {
		    if (InterruptPending != nil) interrupt(CONARG);
		    INTERPRET(aBlock, 0, nil, HOME COMMA_SND, nil);
		} while(--tmp);
		RETURN (self);
	    }
	}
	/*
	 * arg is something else - call it with value"
	 */
	do {
	    if (InterruptPending != nil) interrupt(CONARG);

	    (*blockVal.ilc_func)(aBlock, @symbol(value), CON_COMMA nil, &blockVal);
	} while(--tmp);
    }
#undef INTERPRET
#undef HOME
%}

"/    |count "{ Class: SmallInteger }" |
"/
"/    count := self.
"/    [count > 0] whileTrue:[
"/        aBlock value.
"/        count := count - 1
"/    ]
!

to:stop by:incr do:aBlock
    "reimplemented as primitive for speed"

    |home|
%{
    REGISTER INT tmp, step;
    REGISTER INT final;
    REGISTER OBJFUNC code;
    extern OBJ Block;
    static struct inlineCache blockVal = __ILC1(0);
    REGISTER OBJ rHome;

    if (__bothSmallInteger(incr, stop)) {
	tmp = _intVal(self);
	final = _intVal(stop);
	step = _intVal(incr);
	if (__isBlockLike(aBlock)
	 && ((code = _BlockInstPtr(aBlock)->b_code) != (OBJFUNC)nil)
	 && (_BlockInstPtr(aBlock)->b_nargs == _MKSMALLINT(1))) {
#ifdef NEW_BLOCK_CALL
	    if (step < 0) {
		while (tmp >= final) {
		    if (InterruptPending != nil) interrupt(CONARG);
		    (*code)(aBlock, CON_COMMA _MKSMALLINT(tmp));
		    tmp += step;
		}
	    } else {
		while (tmp <= final) {
		    if (InterruptPending != nil) interrupt(CONARG);
		    (*code)(aBlock, CON_COMMA _MKSMALLINT(tmp));
		    tmp += step;
		}
	    }
#else
	    /*
	     * arg is a compiled block - 
	     * directly call it without going through "Block-value"
	     */
	    home = _BlockInstPtr(aBlock)->b_home;
	    rHome = home;
	    if (step < 0) {
		if ((rHome == nil) || (__qSpace(rHome) >= STACKSPACE)) {
		    /*
		     * home is on stack - will not move
		     */
		    while (tmp >= final) {
			if (InterruptPending != nil) interrupt(CONARG);
			(*code)(rHome, CON_COMMA _MKSMALLINT(tmp));
			tmp += step;
		    }
		} else {
		    while (tmp >= final) {
			if (InterruptPending != nil) interrupt(CONARG);
			(*code)(home, CON_COMMA _MKSMALLINT(tmp));
			tmp += step;
		    }
		}
	    } else {
		if ((rHome == nil) || (__qSpace(rHome) >= STACKSPACE)) {
		    /*
		     * home is on stack - will not move
		     */
		    while (tmp <= final) {
			if (InterruptPending != nil) interrupt(CONARG);
			(*code)(rHome, CON_COMMA _MKSMALLINT(tmp));
			tmp += step;
		    }
		} else {
		    while (tmp <= final) {
			if (InterruptPending != nil) interrupt(CONARG);
			(*code)(home, CON_COMMA _MKSMALLINT(tmp));
			tmp += step;
		    }
		}
	    }
#endif
	} else {
	    /*
	     * arg is something else - call it with value"
	     */
	    if (step < 0) {
		while (tmp >= final) {
		    if (InterruptPending != nil) interrupt(CONARG);

		    (*blockVal.ilc_func)(aBlock, 
					 @symbol(value:), 
					 CON_COMMA nil, &blockVal,
					 _MKSMALLINT(tmp));
		    tmp += step;
		}
	    } else {
		while (tmp <= final) {
		    if (InterruptPending != nil) interrupt(CONARG);

		    (*blockVal.ilc_func)(aBlock, 
					 @symbol(value:), 
					 CON_COMMA nil, &blockVal,
					 _MKSMALLINT(tmp));
		    tmp += step;
		}
	    }
	}
	RETURN ( self );
    }
%}
.
    ^ super to:stop by:incr do:aBlock

    "
     1 to:10 by:3 do:[:i | i printNewline]
    "
!

to:stop do:aBlock
    "evaluate aBlock for every integer between (and including) the receiver
     and the argument, stop.
     Reimplemented as primitive for speed"

    |home|
%{
    REGISTER INT tmp;
    INT final;
    REGISTER OBJFUNC code;
    extern OBJ Block;
    static struct inlineCache blockVal = __ILC1(0);
    REGISTER OBJ rHome;

    if (__isSmallInteger(stop)) {
	tmp = _intVal(self);
	final = _intVal(stop);
	if (__isBlockLike(aBlock)
	 && (_BlockInstPtr(aBlock)->b_nargs == _MKSMALLINT(1))) {
	    if ((code = _BlockInstPtr(aBlock)->b_code) != (OBJFUNC)nil) {
#ifdef NEW_BLOCK_CALL
		while (tmp <= final) {
		    if (InterruptPending != nil) interrupt(CONARG);
		    (*code)(aBlock, CON_COMMA _MKSMALLINT(tmp));
		    tmp++;
		}
#else /* old BLOCK_CALL */
		/*
		 * arg is a compiled block - 
		 * directly call it without going through "Block-value"
		 */
		rHome = _BlockInstPtr(aBlock)->b_home;
		if ((rHome == nil) || (__qSpace(rHome) >= STACKSPACE)) {
		    /*
		     * home will not move - keep in in a register
		     * since this is also the most common case,
		     * its worth trading a bit memory for speed here ...
		     */
# if defined(UNROLL_LOOPS)
		    {
			int t4;

			while ((t4 = tmp+4) < final) {
			    OBJ idx = _MKSMALLINT(tmp);
			    if (InterruptPending != nil) interrupt(CONARG);
			    (*code)(rHome, CON_COMMA idx);
			    if (InterruptPending != nil) interrupt(CONARG);
			    (*code)(rHome, CON_COMMA _ADD_INT(idx, 1));
			    if (InterruptPending != nil) interrupt(CONARG);
			    (*code)(rHome, CON_COMMA _ADD_INT(idx,2));
			    if (InterruptPending != nil) interrupt(CONARG);
			    (*code)(rHome, CON_COMMA _ADD_INT(idx,3));
			    tmp = t4;
			}
		    }
# endif
		    while (tmp <= final) {
			if (InterruptPending != nil) interrupt(CONARG);
			(*code)(rHome, CON_COMMA _MKSMALLINT(tmp));
			tmp++;
		    }
		} else {
		    home = rHome;
		    while (tmp <= final) {
			if (InterruptPending != nil) interrupt(CONARG);
			(*code)(home, CON_COMMA _MKSMALLINT(tmp));
			tmp++;
		    }
		}
		RETURN (self);
#endif /* NEW_BLOCK_CALL */
	    }
	    if (_BlockInstPtr(aBlock)->b_bytecodes != nil) {
		/*
		 * an interpreted block
		 */
#ifdef PASS_ARG_POINTER
		extern OBJ __interpret();
#else
		extern OBJ interpret();
#endif
		home = _BlockInstPtr(aBlock)->b_home;
#ifdef PASS_ARG_POINTER
# ifdef INDIRECT_CALL_IS_FASTER
		code = __interpret;
#  define       INTERPRET (*code)
# else
#  define       INTERPRET __interpret
# endif
#else
# ifdef INDIRECT_CALL_IS_FASTER
		code = interpret;
#  define       INTERPRET (*code)
# else
#  define       INTERPRET interpret
# endif
#endif
#ifdef NEW_BLOCK_CALL
# define HOME nil
#else
# define HOME home
#endif
		while (tmp <= final) {

		    if (InterruptPending != nil) interrupt(CONARG);
#ifdef PASS_ARG_POINTER
		    {
		      OBJ idx;
		      idx = __MKSMALLINT(tmp);
		      INTERPRET(aBlock, 1, nil, HOME COMMA_SND, nil, &idx);
		    }
#else
		    INTERPRET(aBlock, 1, nil, HOME COMMA_SND, nil, __MKSMALLINT(tmp));
#endif
		    tmp++;
		}
		RETURN (self);
	    }
	}
	/*
	 * arg is something else - call it with value"
	 */
	while (tmp <= final) {
	    if (InterruptPending != nil) interrupt(CONARG);

	    (*blockVal.ilc_func)(aBlock, 
				     @symbol(value:), 
				     CON_COMMA nil, &blockVal, 
				     _MKSMALLINT(tmp));
	    tmp++;
	}
	RETURN ( self );
    }
%}.
    "/
    "/ arrive here if stop is not a smallInteger
    "/

    ^ super to:stop do:aBlock

    "
     1 to:10 do:[:i | i printNewline]
    "
! !

!SmallInteger methodsFor:'misc math'!

gcd:anInteger
    "return the greatest common divisor (Euclid's algorithm).
     This has been redefined here for more speed since due to the
     use of gcd in Fraction code, it has become time-critical for
     some code. (thanx to MessageTally)"

%{  /* NOCONTEXT */

    if (__isSmallInteger(anInteger)) {
	INT orgArg, ttt, selfInt, temp;

	ttt = orgArg = _intVal(anInteger);
	if (ttt) {
	    selfInt = _intVal(self);
	    while (ttt != 0) {
		temp = selfInt % ttt;
		selfInt = ttt;
		ttt = temp;
	    }
	    /*
	     * since its not defined in what the sign of
	     * a modulu result is when the arg is negative,
	     * change it explicitely here ...
	     */
	    if (orgArg < 0) {
		/* result should be negative */
		if (selfInt > 0) selfInt = -selfInt;
	    } else {
		/* result should be positive */
		if (selfInt < 0) selfInt = -selfInt;
	    }
	    RETURN ( _MKSMALLINT(selfInt) );
	}
    }
%}
.
    ^ super gcd:anInteger
!

intlog10
    "return the truncation of log10 of the receiver -
     stupid implementation; used to find out the number of digits needed
     to print a number/and for conversion to a LargeInteger.
     Implemented that way, to allow for tiny systems without a Float class
     (i.e. without log)."

    self <= 0 ifTrue:[
	self error:'logarithm of negative integer'
    ].
    self < 10 ifTrue:[^ 1].
    self < 100 ifTrue:[^ 2].
    self < 1000 ifTrue:[^ 3].
    self < 10000 ifTrue:[^ 4].
    self < 100000 ifTrue:[^ 5].
    self < 1000000 ifTrue:[^ 6].
    self < 10000000 ifTrue:[^ 7].
    self < 100000000 ifTrue:[^ 8].
    self < 1000000000 ifTrue:[^ 9].
    ^ 10
! !

!SmallInteger methodsFor:'modulu arithmetic'!

plus:aNumber
    "return the sum of the receiver and the argument, as SmallInteger.
     The argument must be another SmallInteger.
     If the result overflows the smallInteger range, the value modulu the 
     smallInteger range is returned (i.e. the low bits of the sum).
     This is of course not always correct, but some code does a modulu anyway
     and can therefore speed things up by not going through LargeIntegers."

%{  /* NOCONTEXT */

    if (__isSmallInteger(aNumber)) {
	RETURN ( _MKSMALLINT((_intVal(self) + _intVal(aNumber)) & 0x7FFFFFFF) );
    }
%}
.
    self primitiveFailed
!

subtract:aNumber
    "return the difference of the receiver and the argument, as SmallInteger.
     The argument must be another SmallInteger.
     If the result overflows the smallInteger range, the value modulu the 
     smallInteger range is returned (i.e. the low bits of the sum).
     This is of course not always correct, but some code does a modulu anyway
     and can therefore speed things up by not going through LargeIntegers."

%{  /* NOCONTEXT */

    if (__isSmallInteger(aNumber)) {
	RETURN ( _MKSMALLINT((_intVal(self) - _intVal(aNumber)) & 0x7FFFFFFF) );
    }
%}
.
    self primitiveFailed
!

times:aNumber
    "return the product of the receiver and the argument, as SmallInteger.
     The argument must be another SmallInteger.
     If the result overflows the smallInteger range, the value modulu the 
     smallInteger range is returned (i.e. the low bits of the product).
     This is of course not always correct, but some code does a modulu anyway
     and can therefore speed things up by not going through LargeIntegers."

%{  /* NOCONTEXT */

    if (__isSmallInteger(aNumber)) {
	RETURN ( _MKSMALLINT((_intVal(self) * _intVal(aNumber)) & 0x7FFFFFFF) );
    }
%}
.
    self primitiveFailed
! !

!SmallInteger methodsFor:'printing & storing'!

printOn:aStream
    "append my printstring (base 10) to aStream."

    aStream nextPutAll:(self printString)
!

printOn:aStream base:radix
    "append my printstring in any number base to aStream.
     The radix argument should be between 2 and 36."

    aStream nextPutAll:(self printStringRadix:radix)
!

printString
    "return my printstring (base 10)"

    "since printf knows pretty good how to do this,
     here is an exception to the rule of basing printString
     upon the printOn: method."

%{  /* NOCONTEXT */

    char buffer[30];
    OBJ newString;
#ifdef THISCONTEXT_IN_REGISTER
    /*
     * actually only needed on sparc: since thisContext is
     * in a global register, which gets destroyed by printf,
     * manually save it here - very stupid ...
     */
    extern OBJ __thisContext__;
    __thisContext__ = __thisContext;
#endif

    sprintf(buffer, "%d", _intVal(self));
#ifdef THISCONTEXT_IN_REGISTER
    __thisContext = __thisContext__;
    __thisContext__ = nil;
#endif

    newString = _MKSTRING(buffer COMMA_SND);
    if (newString != nil) {
	RETURN (newString);
    }
%}.
    ^ super printString
!

printStringRadix:radix
    "return my printstring (optimized for bases 16, 10 and 8)"

%{  /* NOCONTEXT */

    char *format = (char *)0;
    char buffer[30];
    OBJ newString;

    if (__isSmallInteger(radix)) {
	switch (_intVal(radix)) {
	    case 10:
		format = "%d";
		break;
	    case 16:
		format = "%x";
		break;
	    case 8:
		format = "%o";
		break;
	}
    }

    if (format) {
#ifdef THISCONTEXT_IN_REGISTER
	/*
	 * actually only needed on sparc: since thisContext is
	 * in a global register, which gets destroyed by printf,
	 * manually save it here - very stupid ...
	 */
	extern OBJ __thisContext__;
	__thisContext__ = __thisContext;
#endif
	sprintf(buffer, format, _intVal(self));
#ifdef THISCONTEXT_IN_REGISTER
	__thisContext = __thisContext__;
	__thisContext = nil;
#endif
	newString = _MKSTRING(buffer COMMA_SND);
	if (newString != nil) {
	    RETURN (newString);
	}
    }
%}.
    "
     fall back for seldom used bases
    "
    ^ super printStringRadix:radix

    "123 printStringRadix:16"
    "123 printStringRadix:8"
    "123 printStringRadix:2"
    "123 printStringRadix:3"
    "123 printStringRadix:1"
!

printfPrintString:formatString
    "non-portable, but sometimes useful.
     return a printed representation of the receiver
     as specified by formatString, which is defined by the C-
     function 'printf'.
     No checking for string overrun - the resulting string 
     must be shorter than 256 chars or else ...
     This method is NONSTANDARD and may be removed without notice."

%{  /* STACK: 400 */

    char buffer[256];
    OBJ s;

    if (__isString(formatString)) {
#ifdef THISCONTEXT_IN_REGISTER
	/*
	 * actually only needed on sparc: since thisContext is
	 * in a global register, which gets destroyed by printf,
	 * manually save it here - very stupid ...
	 */
	extern OBJ __thisContext__;
	__thisContext__ = __thisContext;
#endif
	sprintf(buffer, _stringVal(formatString), _intVal(self));
#ifdef THISCONTEXT_IN_REGISTER
	__thisContext = __thisContext__;
	__thisContext__ = nil;
#endif
	s = _MKSTRING(buffer COMMA_SND);
	if (s != nil) {
	    RETURN (s);
	}
    }
%}.
    self primitiveFailed

    "123 printfPrintString:'%%d -> %d'"
    "123 printfPrintString:'%%6d -> %6d'"
    "123 printfPrintString:'%%x -> %x'"
    "123 printfPrintString:'%%4x -> %4x'"
    "123 printfPrintString:'%%04x -> %04x'"
! !

!SmallInteger methodsFor:'testing'!

between:min and:max
    "return true if the receiver is less than or equal to the argument max
     and greater than or equal to the argument min.
     - reimplemented here for speed"

%{  /* NOCONTEXT */

    if (__bothSmallInteger(min, max)) {
	REGISTER INT selfVal;

	selfVal = _intVal(self);
	if (selfVal < _intVal(min)) {
	     RETURN ( false );
	}
	if (selfVal > _intVal(max)) {
	     RETURN ( false );
	}
	RETURN ( true );
    }
%}
.
    (self < min) ifTrue:[^ false].
    (self > max) ifTrue:[^ false].
    ^ true
!

even
    "return true, if the receiver is even"

%{  /* NOCONTEXT */

#ifdef POSITIVE_ADDRESSES
    RETURN ( ((INT)self & 1) ? false : true );
#else    
    RETURN ( ((INT)self & ((INT)_MKSMALLINT(1) & ~TAG_INT)) ? false : true );
#endif
%}
!

negative
    "return true, if the receiver is less than zero
     reimplemented here for speed"

%{  /* NOCONTEXT */

#ifdef POSITIVE_ADDRESSES
    RETURN ( (_intVal(self) < 0) ? true : false );
#else
    /* tag bit does not change sign */
    RETURN ( ((INT)(self) < 0) ? true : false );
#endif
%}
!

odd
    "return true, if the receiver is odd"

%{  /* NOCONTEXT */

#ifdef POSITIVE_ADDRESSES
    RETURN ( ((INT)self & 1) ? true : false );
#else    
    RETURN ( ((INT)self & ((INT)_MKSMALLINT(1) & ~TAG_INT)) ? true : false );
#endif
%}
!

positive
    "return true, if the receiver is not negative
     reimplemented here for speed"

%{  /* NOCONTEXT */

#ifdef POSITIVE_ADDRESSES
    RETURN ( (_intVal(self) >= 0) ? true : false );
#else
    /* tag bit does not change sign */
    RETURN ( ((INT)(self) >= 0) ? true : false );
#endif
%}
!

sign
    "return the sign of the receiver
     reimplemented here for speed"

%{  /* NOCONTEXT */

    INT val = _intVal(self);

    if (val < 0) {
	RETURN ( _MKSMALLINT(-1) ); 
    }
    if (val > 0) {
	RETURN ( _MKSMALLINT(1) );
    }
    RETURN ( _MKSMALLINT(0) );
%}
!

strictlyPositive
    "return true, if the receiver is greater than zero
     reimplemented here for speed"

%{  /* NOCONTEXT */

#ifdef POSITIVE_ADDRESSES
    RETURN ( (_intVal(self) > 0) ? true : false );
#else
    /* tag bit does not change sign */
    RETURN ( ((INT)(self) > 0) ? true : false );
#endif
%}
! !

!SmallInteger class methodsFor:'documentation'!

version
    ^ '$Header: /cvs/stx/stx/libbasic/SmallInteger.st,v 1.40 1995-12-07 21:36:33 cg Exp $'
! !