SmallInt.st
author Claus Gittinger <cg@exept.de>
Fri, 15 Jan 1999 21:53:59 +0100
changeset 3956 51f1a9a4d63f
parent 3914 1aa1ab6edb7e
child 3984 45a76e2f4236
permissions -rw-r--r--
changes for egcs (stdio uses __new / utsname)

"
 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 a guaranteed: on an alpha, 63 bits are used,
     if the system was configured for 64bit mode).

    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.

    [author:]
	Claus Gittinger

    [see also:]
	Number
	Float Fraction FixedPoint
	LargeInteger
"
! !

!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:'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 false here - since it is NOT possible for SmallInteger
     (due to the tagged representation of SmallIntegers)"

    ^ false

    "Modified: / 5.11.1998 / 16:11:27 / cg"
!

hasImmediateInstances
    "return true if this class has immediate instances.
     Redefined from Behavior"

    ^ true

    "Created: 3.6.1997 / 12:01:26 / cg"
!

isBuiltInClass
    "return true if this class is known by the run-time-system.
     Here, true is returned."

    ^ true

    "Modified: 23.4.1996 / 16:00:33 / cg"
! !

!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 low16Bits(foo)  ((foo) & 0xFFFF)
#   define hi16Bits(foo)   ((foo) >> 16)
#   define low32Bits(foo)  ((foo) & 0xFFFFFFFFL)
#   define hi32Bits(foo)   ((foo) >> 32)

    /*
     * 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 USE_LONGLONG
# endif
#endif

    if (__isSmallInteger(aNumber)) {
        myValue = __intVal(self);
        otherValue = __intVal(aNumber);

#if defined(INT64) 
# if !defined(alpha64)
#  define USE_LONGLONG
# else
#  undef USE_LONGLONG
# endif
#endif

#if defined(USE_LONGLONG)
        {
# if defined(alpha) && !defined(alpha64)
#  define LONGLONG      INT64
# else
#  define LONGLONG      long long
# endif
            LONGLONG product;

            product = (LONGLONG)myValue * (LONGLONG)otherValue;
            if ((product >= (LONGLONG)_MIN_INT) 
             && (product <= (LONGLONG)_MAX_INT)) {
                RETURN ( __MKSMALLINT((INT)product) );
            }
            if (product < 0) {
                negative = -1;
                product = -product;
            } else {
                negative = 1;
            }
            productHi = product >> 32;
            productLow = product & 0xFFFFFFFFL;
        }
#else
        negative = 1;
        if (myValue < 0) {
            negative = -1;
            myValue = -myValue;
        }
        if (otherValue < 0) {
            negative = -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 
             */
#   ifdef alpha64
            low1 = low32Bits(myValue);
            hi1 = hi32Bits(myValue);
            low2 = low32Bits(otherValue);
            hi2 = hi32Bits(otherValue);
#    define LLMASK 0xC000000000000000L
#   else
            low1 = low16Bits(myValue);
            hi1 = hi16Bits(myValue);
            low2 = low16Bits(otherValue);
            hi2 = hi16Bits(otherValue);
#    define LLMASK 0xC0000000
#   endif

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

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

#   ifdef alpha64
            t = low32Bits(pLH) + low32Bits(pHL) + hi32Bits(pLL);
            productLow = (t << 32) + low32Bits(pLL);
            productHi = pHH + hi32Bits(t) + hi32Bits(pHL) + hi32Bits(pLH);
            if (t >= 0x100000000L) {
                productHi += t >> 32;
            }
#   else
            t = low16Bits(pLH) + low16Bits(pHL) + hi16Bits(pLL);
            productLow = (t << 16) + low16Bits(pLL);
            productHi = pHH + hi16Bits(t) + hi16Bits(pHL) + hi16Bits(pLH);
            if (t >= 0x10000L) {
                productHi += t >> 16;
            }
#   endif
        }
#  endif
# endif

        if (productHi == 0) {
            if (negative < 0) {
                if (productLow <= -(_MIN_INT)) {
                    RETURN ( __MKSMALLINT(-((INT)productLow)) );
                }
            } else {
                if (productLow <= _MAX_INT) {
                    RETURN ( __MKSMALLINT(productLow) );
                }
            }
        }
#endif

        {
# ifdef alpha64
            RETURN (__MKLARGEINT128(negative, productLow, productHi));
# else
            RETURN (__MKLARGEINT64(negative, productLow, productHi));
# endif
        }
    } else if (__isFloatLike(aNumber)) {
        OBJ newFloat;
        double val = (double)__intVal(self) * __floatVal(aNumber);

        __qMKFLOAT(newFloat, val);
        RETURN ( newFloat );
    } else if (__isShortFloat(aNumber)) {
        OBJ newFloat;
        float val = (float)__intVal(self) * __shortFloatVal(aNumber);

        __qMKSFLOAT(newFloat, val);
        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;

        sum =  __intVal(self) + __intVal(aNumber);
        if ((sum >= _MIN_INT) && (sum <= _MAX_INT)) {
            RETURN ( __MKSMALLINT(sum) );
        }
        RETURN ( __MKLARGEINT(sum) );
#endif
    } else if (__isFloatLike(aNumber)) {
        OBJ newFloat;
        double val = (double)__intVal(self) + __floatVal(aNumber);

        __qMKFLOAT(newFloat, val);
        RETURN ( newFloat );
    } else if (__isShortFloat(aNumber)) {
        OBJ newFloat;
        float val = (float)__intVal(self) + __shortFloatVal(aNumber);

        __qMKSFLOAT(newFloat, val);
        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;

        diff =  __intVal(self) - __intVal(aNumber);
        if ((diff >= _MIN_INT) && (diff <= _MAX_INT)) {
            RETURN ( __MKSMALLINT(diff) );
        }
        RETURN ( __MKLARGEINT(diff) );
#endif
    } else if (__isFloatLike(aNumber)) {
        OBJ newFloat;
        double val = (double)__intVal(self) - __floatVal(aNumber);

        __qMKFLOAT(newFloat, val);
        RETURN ( newFloat );
    } else if (__isShortFloat(aNumber)) {
        OBJ newFloat;
        float val = (float)__intVal(self) - __shortFloatVal(aNumber);

        __qMKSFLOAT(newFloat, val);
        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 modulus
               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 modulo
               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);
                RETURN ( newFloat );
            }
        }
    }
%}.
    aNumber isInteger ifTrue:[
        aNumber == 0 ifTrue:[
            ^ DivisionByZeroSignal raise.
        ].
        ^ Fraction numerator:self denominator:aNumber
    ].
    ^ aNumber quotientFromInteger:self

    "
     8 / 4
     9 / 4
     9 // 4
     9 quo:4

     -8 / 4
     -9 / 4
     -9 // 4
     -9 quo:4
    "
!

// aNumber
    "return the integer part of the quotient of the receivers value
     and the arguments value. The result is truncated toward negative infinity
     and negative, if the operands signs differ.
     Be careful with negative results: 9 // 4 = 2, 
     while -9 // 4 = -3. 
     See #quo: which returns -2 in the latter."

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

    if (__isSmallInteger(aNumber)) {
	val = __intVal(aNumber);
	if (val != 0) {
	    rslt = __intVal(self) / val;
	    if (rslt < 0) {
		if (__intVal(self) % val)
		    rslt--;
	    }
	    RETURN ( __MKSMALLINT(rslt) );
	}
    } 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

    "
     9 // 4    => 2
     -9 // 4   => -3
     9 // -4   => -3
     -9 // -4  => 2

     9 quo:4   => 2
     -9 quo:4  => -2
     9 quo:-4  => -2
     -9 quo:-4 => 2
    "
!

\\ aNumber
    "return the integer rest of the receivers value
     divided by the arguments value.
     This is not always the same as the result as obtained from #rem:"

%{  /* 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

    "
     9 \\ 4
     -9 \\ 4
     9 rem:4
     -9 rem:4
    "
!

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 */
    RETURN( __MKLARGEINT(-_MIN_INT));
%}.
"/    "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 */
    RETURN (__MKLARGEINT( -_MIN_INT));
%}.
"/    "only reached for minVal"
"/    ^ (LargeInteger value:(SmallInteger maxVal)) + 1
!

quo:aNumber
    "return the integer part of the quotient of the receivers value
     and the arguments value. The result is truncated towards zero
     and negative, if the operands signs differ.. 
     For positive results, this is the same as #//,
     for negative results, the remainder is ignored.
     I.e.: '9 // 4 = 2' and '-9 // 4 = -3'
     in contrast: '9 quo: 4 = 2' and '-9 quo: 4 = -2'"

%{  /* 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:#quo: coercing:aNumber

    "
     9 // 4
     -9 // 4
     9 quo:4
     -9 quo:4
    "
! !

!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
!

bitClear:anInteger
    "return the bitwise-and of the receiver and the complement of the argument, anInteger,
     returning the receiver with bits of the argument cleared."

%{  /* NOCONTEXT */

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

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

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"
!

bitShift32:shiftCount
    "return the value of the receiver shifted by shiftCount bits,
     but only within 32 bits, shifting into/out-of the sign bit.
     May be useful for communication interfaces, to create ST-numbers
     from a signed 32bit int value given as individual bytes."

%{  /* NOCONTEXT */

    INT bits, count;

    if (__isSmallInteger(shiftCount)) {
        count = __intVal(shiftCount);
        if (count >= 32) {
            RETURN (__MKSMALLINT(0));
        }

        bits = __intVal(self);
        if (count > 0) {
            bits = bits << count;
        } else {
            bits = bits >> (-count);
        }
#ifdef alpha64
        bits &= 0xFFFFFFFFL;
#endif
        RETURN (__MKINT(bits));
    }
%}.
    ^ self primitiveFailed

    "
     128 bitShift:24   
     128 bitShift32:24  

     1 bitShift:31   
     1 bitShift32:31  
    "
!

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)) {
        bits = __intVal(self);
        if (bits == 0) {
            RETURN (self);
        }

        count = __intVal(shiftCount);

        if (count > 0) {
            /*
             * a left shift
             */
#if defined(USE_LONGLONG)
            unsigned LONGLONG result;

            result = bits;
            if (count <= N_INT_BITS) {
                result <<= count;
                if (result <= _MAX_INT) {
                    RETURN ( __MKSMALLINT(result) );
                }
                {
                    RETURN (__MKLARGEINT64(1, (INT)(result >> 32), (INT)(result & 0xFFFFFFFF)));
                }
            }
#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 {
            if (count == 0) {
                RETURN (self);
            }

            /*
             * right shifts cannot overflow
             *
             * some machines ignore shifts bigger than
             * the number of bits in an int ...
             */
            count = -count;
            if (count > (N_INT_BITS-1)) {
                RETURN (__MKSMALLINT(0));
            }

            RETURN ( __MKSMALLINT(bits >> count) );
        }
    }
%}.
    (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
!

clearBit:anInteger
    "return a new number where the specified bit is off.
     Bits are counted from 1 starting with the least significant."

%{  /* NOCONTEXT */

    if (__isSmallInteger(anInteger)) {
        int index = __intVal(anInteger);

#ifdef alpha64
        if (index <= 63)
#else
        if (index <= 30)
#endif
        {
            INT mask = __MASKSMALLINT(1 << (index-1));

            RETURN ( ((OBJ) ((INT)self & ~(INT)mask)) );
        }
        RETURN (self);
    }
%}.
    ^ self retry:#clearBit: coercing:anInteger

    "
     (16r401 clearBit:1     ) hexPrintString
     (16r3fffffff clearBit:1) hexPrintString
     (16r3fffffff clearBit:29) hexPrintString 
     (16r3fffffff clearBit:30) hexPrintString 
     (16r3fffffff clearBit:31) hexPrintString  
     (16r3fffffff bitAt:30) hexPrintString    
     (16r3fffffff bitAt:29) hexPrintString  
     (16r40000001 clearBit:1) hexPrintString  
     (16rF0000001 clearBit:29) hexPrintString
     (16rF0000001 clearBit:30) hexPrintString
     (16rF0000001 clearBit:31) hexPrintString 
     (16rF0000001 clearBit:32) hexPrintString 
    "


!

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 alpha64
    mask = 0x2000000000000000L;
    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) );
    }

    if ((bits & 0xFFFFFF) == 0) {
        mask = 0x1000000;
        index = 25;
    } else {
        if ((bits & 0xFFFF) == 0) {
            mask = 0x10000;
            index = 17;
        } else {
            if ((bits & 0xFF) == 0) {
                mask = 0x100;
                index = 9;
            } else {
                mask = 1;
                index = 1;
            }
        }
    }

#ifdef alpha64
    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
     16r1000 lowBit 
     16r1000000 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 alpha64
            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 */
                RETURN (__MKSMALLINT(0));
        }
        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
    "
!

digitByteAt:index
    "return 8 bits of my signed value, starting at byte index.
     For positive receivers, this is the same as #digitAt:;
     for negative ones, the actual bit representation is returned."

%{  /* NOCONTEXT */

    REGISTER INT val;
    INT idx;

    if (__isSmallInteger(index)) {
        val = __intVal(self);
        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 alpha64
            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 */
                if (val < 0) {
                    RETURN (__MKSMALLINT(0xFF));
                }
                RETURN (__MKSMALLINT(0));
        }
        RETURN ( __MKSMALLINT( val & 0xFF) );
    }
  bad: ;
%}.
    index > 0 ifFalse:[
        "
         index less than 1 - not allowed
        "
        ^ self primitiveFailed
    ].
    ^ 0

    "
     (10 digitByteAt:1) printStringRadix:16 
     (10 digitByteAt:3) printStringRadix:16 
     (-10 digitByteAt:1) printStringRadix:16
     (-10 digitByteAt:3) printStringRadix:16
    "
!

digitLength
    "return the number bytes required to represent this Integer.
     For negative receivers, the digitLength of its absolute value
     is returned."

%{  /* NOCONTEXT */

    INT val = __intVal(self);

    if (val < 0) {
        val = -val;
    }
#ifdef alpha64
    if (val & 0xFFFFFFFF00000000L) {
        if (val & 0xFFFF000000000000L) {
            if (val & 0xFF00000000000000L) {
                RETURN ( __MKSMALLINT(8));
            } else {
                RETURN ( __MKSMALLINT(7));
            }
        } else {
            if (val & 0x0000FF0000000000L) {
                RETURN ( __MKSMALLINT(6));
            } else {
                RETURN ( __MKSMALLINT(5));
            }
        }
    }
#endif

    if (val & 0xFFFF0000) {
        if (val & 0xFF000000) {
            RETURN ( __MKSMALLINT(4));
        } else {
            RETURN ( __MKSMALLINT(3));
        }
    } else {
        if (val & 0x0000FF00) {
            RETURN ( __MKSMALLINT(2));
        } else {
            RETURN ( __MKSMALLINT(1));
        }
    }

%}.
    ^ self abs highBit - 1 // 8 + 1

    "
     16rFF00000000000000 digitLength
     -16rFF00000000000000 digitLength

     16rFF000000 digitLength
     16rFF0000 digitLength  
     16rFF00 digitLength    
     16rFF digitLength      
     -16rFF000000 digitLength 
     -16rFF0000 digitLength  
     -16rFF00 digitLength   
     -16rFF digitLength    
    "
! !

!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);
    RETURN ( newFloat );
%}
!

asLargeInteger
    "return a LargeInteger with same value as receiver"

    ^ LargeInteger value:self
!

asShortFloat
    "return a ShortFloat with same value as receiver"

%{  /* NOCONTEXT */

    OBJ dummy = @global(ShortFloat);
    OBJ newFloat;
    float fVal = (float)__intVal(self);

    __qMKSFLOAT(newFloat, fVal);
    RETURN ( newFloat );
%}
!

coerce:aNumber
    "return aNumber converted into receivers type"

    ^ aNumber asInteger
!

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

    ^ 20
!

signExtendedByteValue
    "return a smallInteger from sign-extending the 8'th bit.
     May be useful for communication interfaces"

%{  /* NOCONTEXT */
    INT i = __intVal(self);

    if (i & 0x80) {
        i = i | ~0xFFL;
    } else {
        i = i & 0x7F;
    }

    RETURN (__MKSMALLINT(i));
%}

    "
     16rFF signExtendedByteValue
     16r7F signExtendedByteValue
    "
!

signExtendedShortValue
    "return a smallInteger from sign-extending the 16'th bit.
     May be useful for communication interfaces"

%{  /* NOCONTEXT */
    INT i = __intVal(self);

    if (i & 0x8000) {
        i = i | ~0xFFFFL;
    } else {
        i = i & 0x7FFF;
    }

    RETURN (__MKSMALLINT(i));
%}

    "
     16rFFFF signExtendedShortValue 
     16r7FFF signExtendedShortValue
    "
! !

!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

    "Modified: 11.11.1996 / 18:42:14 / cg"
!

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

%{  /* NOCONTEXT */

    if (__isSmallInteger(aNumber)) {
#if TAG_INT == 1
	/* tag bit does not change ordering */
	if ((INT)(self) > (INT)(aNumber))
#else
	if (__intVal(self) > __intVal(aNumber))
#endif
	{
	    RETURN ( self );
	}
	RETURN ( aNumber );
    }
    if (__isFloatLike(aNumber)) {
	if ( (double)__intVal(self) > __floatVal(aNumber) ) {
	    RETURN ( self );
	}
	RETURN ( aNumber );
    }
%}.
    "/ fallback for non-smallInteger argument

    (self > aNumber) ifTrue:[^ self].
    ^ aNumber
!

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

%{  /* NOCONTEXT */

    if (__isSmallInteger(aNumber)) {
#if TAG_INT == 1
	/* tag bit does not change ordering */
	if ((INT)(self) < (INT)(aNumber))
#else
	if (__intVal(self) < __intVal(aNumber))
#endif
	{
	    RETURN ( self );
	}
	RETURN ( aNumber );
    }
    if (__isFloatLike(aNumber)) {
	if ( (double)__intVal(self) < __floatVal(aNumber) ) {
	    RETURN ( self );
	}
	RETURN ( aNumber );
    }
%}.
    "/ fallback for non-smallInteger argument

    (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"

%{
    REGISTER INT tmp;
    static struct inlineCache blockVal = __ILC0(0);

    tmp = __intVal(self);
    if (tmp > 0) {
	if (__isBlockLike(aBlock)
	 && (__BlockInstPtr(aBlock)->b_nargs == __MKSMALLINT(0))) {
	    {
		REGISTER OBJFUNC codeVal;

		/*
		 * specially tuned version for compiled blocks, 
		 * (the most common case)
		 */
                if (((codeVal = __BlockInstPtr(aBlock)->b_code) != (OBJFUNC)nil)
#ifdef PARANOIA
                 && (! ((INT)(__BlockInstPtr(aBlock)->b_flags) & __MASKSMALLINT(F_DYNAMIC)))
#endif
		) {

#ifdef NEW_BLOCK_CALL

#                   define BLOCK_ARG  aBlock

#else

#                   define BLOCK_ARG  rHome
		    REGISTER OBJ rHome;

		    /*
		     * home on stack - no need to refetch
		     */
		    rHome = __BlockInstPtr(aBlock)->b_home;
		    if ((rHome == nil) || (__qSpace(rHome) >= STACKSPACE)) 
#endif
		    {
#ifdef WIN32
# undef UNROLL_LOOPS
#endif

#ifdef UNROLL_LOOPS

			/*
			 * you are not supposed to program like this - I know what I do
			 */
			while (tmp > 8) {
			    if (InterruptPending != nil) goto interrupted0;
	continue0:
			    (*codeVal)(BLOCK_ARG);
			    if (InterruptPending != nil) goto interrupted1;
	continue1:
			    (*codeVal)(BLOCK_ARG);
			    if (InterruptPending != nil) goto interrupted2;
	continue2:
			    (*codeVal)(BLOCK_ARG);
			    if (InterruptPending != nil) goto interrupted3;
	continue3:
			    (*codeVal)(BLOCK_ARG);
			    if (InterruptPending != nil) goto interrupted4;
	continue4:
			    (*codeVal)(BLOCK_ARG);
			    if (InterruptPending != nil) goto interrupted5;
	continue5:
			    (*codeVal)(BLOCK_ARG);
			    if (InterruptPending != nil) goto interrupted6;
	continue6:
			    (*codeVal)(BLOCK_ARG);
			    if (InterruptPending != nil) goto interrupted7;
	continue7:
			    (*codeVal)(BLOCK_ARG);
			    tmp -= 8;
			}
#endif /* UNROLL_LOOPS */
			do {
			    if (InterruptPending != nil) goto interruptedX;
	continueX:
			    (*codeVal)(BLOCK_ARG);
			} while(--tmp);

			RETURN (self);
			if (0) {
#ifdef UNROLL_LOOPS
			    interrupted0:
						__interruptL(@line); goto continue0;
			    interrupted1:
						__interruptL(@line); goto continue1;
			    interrupted2:
						__interruptL(@line); goto continue2;
			    interrupted3:
						__interruptL(@line); goto continue3;
			    interrupted4:
						__interruptL(@line); goto continue4;
			    interrupted5:
						__interruptL(@line); goto continue5;
			    interrupted6:
						__interruptL(@line); goto continue6;
			    interrupted7:
						__interruptL(@line); goto continue7;
#endif /* UNROLL_LOOPS */
			    interruptedX:
						__interruptL(@line); goto continueX;
			}
		    }
		}
	    }

#           undef BLOCK_ARG

#ifdef NEW_BLOCK_CALL
#           define BLOCK_ARG  aBlock
#           define IBLOCK_ARG nil
#else
#           define BLOCK_ARG  (__BlockInstPtr(aBlock)->b_home)
#           define IBLOCK_ARG (__BlockInstPtr(aBlock)->b_home)
#endif

	    /*
	     * sorry - must check for the blocks code within the loops;
	     * it could be recompiled or flushed (in the interrupt)
	     */
	    do {
		REGISTER OBJFUNC codeVal;

		if ((codeVal = __BlockInstPtr(aBlock)->b_code) != (OBJFUNC)nil) {
		    /*
		     * arg is a compiled block with code -
		     * directly call it without going through Block>>value
		     * however, if there is an interrupt, refetch the code pointer.
		     */
		    /* stay here, while no interrupts are pending ... */
		    do {
		        (*codeVal)(BLOCK_ARG);
			if (InterruptPending != nil) goto outerLoop;
		    } while (--tmp);
	            RETURN (self);
		} else {
		    if (InterruptPending != nil) __interruptL(@line);

		    if (__BlockInstPtr(aBlock)->b_bytecodes != nil) {
			/*
			 * arg is a compiled block with bytecode -
			 * directly call interpreter without going through Block>>value
			 */
			__interpret(aBlock, 0, nil, IBLOCK_ARG, nil, nil);
		    } else {
			/*
			 * arg is something else - call it with #value
			 */
			(*blockVal.ilc_func)(aBlock, @symbol(value), nil, &blockVal);
		    }
		}
    outerLoop: ;
	    } while (--tmp);

#           undef BLOCK_ARG
#           undef IBLOCK_ARG

	    RETURN (self);
	}

	/*
	 * not a block-like thingy - call it with #value
	 */
	do {
	    if (InterruptPending != nil) __interruptL(@line);
	    (*blockVal.ilc_func)(aBlock, @symbol(value), nil, &blockVal);
	} while(--tmp);
	RETURN (self);
    }
%}

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

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

%{
    REGISTER INT tmp, step;
    REGISTER INT final;
    static struct inlineCache blockVal = __ILC1(0);

    if (__bothSmallInteger(incr, stop)) {
	tmp = __intVal(self);
	final = __intVal(stop);
	step = __intVal(incr);

	if (__isBlockLike(aBlock)
	 && (__BlockInstPtr(aBlock)->b_nargs == __MKSMALLINT(1))) {
	    {
		REGISTER OBJFUNC codeVal;

		/*
		 * specially tuned version for static compiled blocks, called with
		 * home on the stack (the most common case)
		 */
                if (((codeVal = __BlockInstPtr(aBlock)->b_code) != (OBJFUNC)nil)
#ifdef PARANOIA
                 && (! ((INT)(__BlockInstPtr(aBlock)->b_flags) & __MASKSMALLINT(F_DYNAMIC)))
#endif
		) {

#ifdef NEW_BLOCK_CALL

#                   define BLOCK_ARG  aBlock

#else

#                   define BLOCK_ARG  rHome
		    REGISTER OBJ rHome;
		    rHome = __BlockInstPtr(aBlock)->b_home;
		    if ((rHome == nil) || (__qSpace(rHome) >= STACKSPACE)) 

#endif
		    {
			if (step < 0) {
			    if (step == -1) {
				while (tmp >= final) {
				    if (InterruptPending != nil) __interruptL(@line);
				    (*codeVal)(BLOCK_ARG, __MKSMALLINT(tmp));
				    tmp--;
				}
			    } else {
				while (tmp >= final) {
				    if (InterruptPending != nil) __interruptL(@line);
				    (*codeVal)(BLOCK_ARG, __MKSMALLINT(tmp));
				    tmp += step;
				}
			    }
			} else {
			    if (step == 1) {
				while (tmp <= final) {
				    if (InterruptPending != nil) __interruptL(@line);
				    (*codeVal)(BLOCK_ARG, __MKSMALLINT(tmp));
				    tmp++;
				}
			    } else {
			        while (tmp <= final) {
				    if (InterruptPending != nil) __interruptL(@line);
				    (*codeVal)(BLOCK_ARG, __MKSMALLINT(tmp));
				    tmp += step;
				}
			    }
			}
			RETURN (self);
		    }
		}
	    }

	    /*
	     * sorry - must check for the blocks code within the loops;
	     * it could be recompiled or flushed (in the interrupt)
	     */

#           undef BLOCK_ARG

#ifdef NEW_BLOCK_CALL
#           define BLOCK_ARG  aBlock
#           define IBLOCK_ARG nil
#else
#           define BLOCK_ARG  (__BlockInstPtr(aBlock)->b_home)
#           define IBLOCK_ARG (__BlockInstPtr(aBlock)->b_home)
#endif

	    if (step < 0) {
		while (tmp >= final) {
		    REGISTER OBJFUNC codeVal;

		    if (InterruptPending != nil) __interruptL(@line);

		    if ((codeVal = __BlockInstPtr(aBlock)->b_code) != (OBJFUNC)nil) {
			/*
			 * arg is a compiled block with code -
			 * directly call it without going through Block>>value
			 */
			(*codeVal)(BLOCK_ARG, __MKSMALLINT(tmp));
		    } else {
			if (__BlockInstPtr(aBlock)->b_bytecodes != nil) {
			    /*
			     * arg is a compiled block with bytecode -
			     * directly call interpreter without going through Block>>value
			     */
#ifdef PASS_ARG_POINTER
			    {
				OBJ idx;

				idx = __MKSMALLINT(tmp);
				__interpret(aBlock, 1, nil, IBLOCK_ARG, nil, nil, &idx);
			    }
#else
			    __interpret(aBlock, 1, nil, IBLOCK_ARG, nil, nil, __MKSMALLINT(tmp));
#endif

			} else {
			    /*
			     * arg is something else - call it with #value
			     */
			    (*blockVal.ilc_func)(aBlock, @symbol(value:), nil, &blockVal, __MKSMALLINT(tmp));
			}
		    }
		    tmp += step;
		}
	    } else {
		while (tmp <= final) {
		    REGISTER OBJFUNC codeVal;

		    if (InterruptPending != nil) __interruptL(@line);

		    if ((codeVal = __BlockInstPtr(aBlock)->b_code) != (OBJFUNC)nil) {
			/*
			 * arg is a compiled block with code -
			 * directly call it without going through Block>>value
			 */
			(*codeVal)(BLOCK_ARG, __MKSMALLINT(tmp));
		    } else {
			if (__BlockInstPtr(aBlock)->b_bytecodes != nil) {
			    /*
			     * arg is a compiled block with bytecode -
			     * directly call interpreter without going through Block>>value
			     */
#ifdef PASS_ARG_POINTER
			    {
				OBJ idx;

				idx = __MKSMALLINT(tmp);
				__interpret(aBlock, 1, nil, IBLOCK_ARG, nil, nil, &idx);
			    }
#else
			    __interpret(aBlock, 1, nil, IBLOCK_ARG, nil, nil, __MKSMALLINT(tmp));
#endif

			} else {
			    /*
			     * arg is something else - call it with #value:
			     */
			    (*blockVal.ilc_func)(aBlock, @symbol(value:), nil, &blockVal, __MKSMALLINT(tmp));
			}
		    }
		    tmp += step;
		}
	    }

#           undef BLOCK_ARG
#           undef IBLOCK_ARG

	} else {
	    /*
	     * arg is something else - call it with #value:
	     */
	    if (step < 0) {
		while (tmp >= final) {
		    if (InterruptPending != nil) __interruptL(@line);

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

		    (*blockVal.ilc_func)(aBlock, 
					 @symbol(value:), 
					 nil, &blockVal,
					 __MKSMALLINT(tmp));
		    tmp += step;
		}
	    }
	}
	RETURN ( self );
    }
%}.
    "/
    "/ arrive here if stop is not a smallInteger
    "/ pass on to super ...

    ^ 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"

%{
    REGISTER INT tmp;
    INT final;
    static struct inlineCache blockVal = __ILC1(0);

    if (__isSmallInteger(stop)) {
	tmp = __intVal(self);
	final = __intVal(stop);

	if (__isBlockLike(aBlock)
	 && (__BlockInstPtr(aBlock)->b_nargs == __MKSMALLINT(1))) {
	    {
		/*
		 * specially tuned version for the most common case,
		 * where called with home on the stack
		 */
		REGISTER OBJFUNC codeVal;

                if ((codeVal = __BlockInstPtr(aBlock)->b_code) != (OBJFUNC)nil) {

#ifdef NEW_BLOCK_CALL

#                   define BLOCK_ARG  aBlock

#else

#                   define BLOCK_ARG  rHome
		    REGISTER OBJ rHome;
		    rHome = __BlockInstPtr(aBlock)->b_home;
		    if ((rHome == nil) || (__qSpace(rHome) >= STACKSPACE)) 
#endif
		    {

#ifdef PARANOIA
			if (! ((INT)(__BlockInstPtr(aBlock)->b_flags) & __MASKSMALLINT(F_DYNAMIC))) 
#endif
			{
			    /*
			     * static compiled blocks ...
			     */
#ifdef UNROLL_LOOPS
			    /*
			     * The following code is designed to run as fast as possible;
			     *  - taken branches only if interrupts are pending
			     *  - only forward branches (which are usually predicted as not taken)
			     *  - unrolled the loop
			     *
			     * you are not supposed to program like this - I know what I do
			     */
# if TAG_INT==1
			    INT t8 = (INT)(__MKSMALLINT(tmp+8));
			    tmp = (INT)(__MKSMALLINT(tmp));
			    final = (INT)(__MKSMALLINT(final));
# else
			    INT t8 = tmp+8;
# endif

			    for (;;) {

				while (t8 <= final) {
# if TAG_INT==1
				    t8 += (INT)(__MASKSMALLINT(8));
# else
				    t8 += 8;
# endif
				    if (InterruptPending != nil) goto interrupted0;
	continue0:
# if TAG_INT==1
				    (*codeVal)(BLOCK_ARG, tmp);
# else
				    (*codeVal)(BLOCK_ARG, __MKSMALLINT(tmp));
# endif
				    if (InterruptPending != nil) goto interrupted1;
	continue1:
# if TAG_INT==1
				    (*codeVal)(BLOCK_ARG, tmp+(INT)(__MASKSMALLINT(1)) );
# else
				    (*codeVal)(BLOCK_ARG, __MKSMALLINT(tmp+1));
# endif
				    if (InterruptPending != nil) goto interrupted2;
	continue2:
# if TAG_INT==1
				    (*codeVal)(BLOCK_ARG, tmp+(INT)(__MASKSMALLINT(2)) );
# else
				    (*codeVal)(BLOCK_ARG, __MKSMALLINT(tmp+2));
# endif
				    if (InterruptPending != nil) goto interrupted3;
	continue3:
# if TAG_INT==1
				    (*codeVal)(BLOCK_ARG, tmp+(INT)(__MASKSMALLINT(3)) );
# else
				    (*codeVal)(BLOCK_ARG, __MKSMALLINT(tmp+3));
# endif
				    if (InterruptPending != nil) goto interrupted4;
	continue4:
# if TAG_INT==1
				    (*codeVal)(BLOCK_ARG, tmp+(INT)(__MASKSMALLINT(4)) );
# else
				    (*codeVal)(BLOCK_ARG, __MKSMALLINT(tmp+4));
# endif
				    if (InterruptPending != nil) goto interrupted5;
	continue5:
# if TAG_INT==1
				    (*codeVal)(BLOCK_ARG, tmp+(INT)(__MASKSMALLINT(5)) );
# else
				    (*codeVal)(BLOCK_ARG, __MKSMALLINT(tmp+5));
# endif
				    if (InterruptPending != nil) goto interrupted6;
	continue6:
# if TAG_INT==1
				    (*codeVal)(BLOCK_ARG, tmp+(INT)(__MASKSMALLINT(6)) );
# else
				    (*codeVal)(BLOCK_ARG, __MKSMALLINT(tmp+6));
# endif
				    if (InterruptPending != nil) goto interrupted7;
	continue7:
# if TAG_INT==1
				    (*codeVal)(BLOCK_ARG, tmp+(INT)(__MASKSMALLINT(7)) );
# else
				    (*codeVal)(BLOCK_ARG, __MKSMALLINT(tmp+7));
# endif

# if TAG_INT==1
				    tmp += (INT)(__MASKSMALLINT(8));
# else
				    tmp += 8;
# endif
				}
			        while (tmp <= final) {
				    if (InterruptPending != nil) goto interruptedX;
	continueX:
# if TAG_INT==1
				    (*codeVal)(BLOCK_ARG, tmp);
				    tmp += (INT)(__MASKSMALLINT(1));
# else
				    (*codeVal)(BLOCK_ARG, __MKSMALLINT(tmp));
				    tmp++;
# endif
			        }
			        RETURN (self);

				if (0) {
				    /*
				     * no discussion about those gotos ...
				     * ... its better for your CPU's pipelines
				     * (if you dont understand why, just dont argue).
				     */
				    interrupted7:
						    __interruptL(@line); goto continue7;
				    interrupted6:
						    __interruptL(@line); goto continue6;
				    interrupted5:
						    __interruptL(@line); goto continue5;
				    interrupted4:
						    __interruptL(@line); goto continue4;
				    interrupted3:
						    __interruptL(@line); goto continue3;
				    interrupted2:
						    __interruptL(@line); goto continue2;
				    interrupted1:
						    __interruptL(@line); goto continue1;
				    interrupted0:
						    __interruptL(@line); goto continue0;
				    interruptedX:
						    __interruptL(@line); goto continueX;
				}
			    }
#else
			    while (tmp <= final) {
				if (InterruptPending != nil) __interruptL(@line);
				(*codeVal)(BLOCK_ARG, __MKSMALLINT(tmp));
				tmp ++;
			    }
			    RETURN (self);
#endif /* UNROLL_LOOPS */
			}

			/*
			 * mhmh - seems to be a block with dynamic code
			 * must refetch, to allow dynamic recompilation or code flush.
			 */
			while (tmp <= final) {
			    if (InterruptPending != nil) __interruptL(@line);
			    if ((codeVal = __BlockInstPtr(aBlock)->b_code) == (OBJFUNC)nil) break;
			    (*codeVal)(BLOCK_ARG, __MKSMALLINT(tmp));
			    tmp ++;
			}

			if (tmp > final) {
			    RETURN (self);
			}
		    }
		}
	    }

#           undef BLOCK_ARG

#ifdef NEW_BLOCK_CALL
#           define BLOCK_ARG  aBlock
#           define IBLOCK_ARG nil
#else
#           define BLOCK_ARG  (__BlockInstPtr(aBlock)->b_home)
#           define IBLOCK_ARG (__BlockInstPtr(aBlock)->b_home)
#endif

	    /*
	     * sorry - must check for the blocks code within the loops;
	     * it could be recompiled or flushed (in the interrupt)
	     */
	    while (tmp <= final) {
		REGISTER OBJFUNC codeVal;

		if ((codeVal = __BlockInstPtr(aBlock)->b_code) != (OBJFUNC)nil) {
		    /*
		     * arg is a compiled block with code -
		     * directly call it without going through Block>>value
		     */

                    /* stay here, while no interrupts are pending ... */
                    do {
                        (*codeVal)(BLOCK_ARG, __MKSMALLINT(tmp));
                        if (InterruptPending != nil) goto outerLoop;
			tmp++;
                    } while (tmp <= final);
		    RETURN (self);
		} else {
		    if (InterruptPending != nil) __interruptL(@line);

		    if (__BlockInstPtr(aBlock)->b_bytecodes != nil) {
			/*
			 * arg is a compiled block with bytecode -
			 * directly call interpreter without going through Block>>value
			 */
#ifdef PASS_ARG_POINTER
			{
			    OBJ idx;

			    idx = __MKSMALLINT(tmp);
			    __interpret(aBlock, 1, nil, IBLOCK_ARG, nil, nil, &idx);
			}
#else
			__interpret(aBlock, 1, nil, IBLOCK_ARG, nil, nil, __MKSMALLINT(tmp));
#endif

		    } else {
			/*
			 * arg is something else - call it with #value:
			 */
			(*blockVal.ilc_func)(aBlock, @symbol(value:), nil, &blockVal, __MKSMALLINT(tmp));
		    }
		}
	    outerLoop: ;
		tmp++;
	    }

#           undef BLOCK_ARG
#           undef IBLOCK_ARG

	    RETURN (self);
	}
	/*
	 * arg is something else - call it with #value:
	 */
	while (tmp <= final) {
	    if (InterruptPending != nil) __interruptL(@line);

	    (*blockVal.ilc_func)(aBlock, 
					 @symbol(value:), 
					 nil, &blockVal,
					 __MKSMALLINT(tmp));
	    tmp++;
	}
	RETURN ( self );
    }
%}.

    "/
    "/ arrive here if stop is not a smallInteger
    "/ pass on to super ...
    "/
    ^ super to:stop do:aBlock

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

!SmallInteger methodsFor:'misc math'!

divMod:aNumber
    "return an array filled with self // aNumber and
     self \\ aNumber.
     The result is only defined for positive receiver and
     argument."

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

    if (__isSmallInteger(aNumber)) {
	val = __intVal(aNumber);
	if (val != 0) {
	    mySelf = __intVal(self);
	    div = mySelf / val;
	    mod = mySelf % val;

	    RETURN (__ARRAY_WITH2( __MKSMALLINT(div),
				   __MKSMALLINT(mod)));
	}
    }
%}.
    ^ super divMod:aNumber

    "
     10 // 3 

     10 \\ 3  

     10 divMod:3 
    "
!

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, orgSelfInt, temp;

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

gcd_helper:anInteger
    "same as gcd - see knuth & Integer>>gcd:"

    ^ self gcd:anInteger

    "Created: 1.3.1997 / 16:58:01 / cg"
!

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:'modulo 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 modulo 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 modulo anyway
     and can therefore speed things up by not going through LargeIntegers."

%{  /* NOCONTEXT */

    if (__isSmallInteger(aNumber)) {
        INT sum;

        sum = __intVal(self) + __intVal(aNumber);
#ifdef alpha64
        sum &= 0x7FFFFFFFFFFFFFFFL;
#else
        sum &= 0x7FFFFFFF;
#endif
        RETURN ( __MKSMALLINT(sum));
    }
%}.
    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 modulo 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 modulo anyway
     and can therefore speed things up by not going through LargeIntegers."

%{  /* NOCONTEXT */

    if (__isSmallInteger(aNumber)) {
        INT diff;

        diff = __intVal(self) - __intVal(aNumber);
#ifdef alpha64
        diff &= 0x7FFFFFFFFFFFFFFFL;
#else
        diff &= 0x7FFFFFFF;
#endif
        RETURN ( __MKSMALLINT(diff));
    }
%}.
    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 modulo 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 modulo anyway
     and can therefore speed things up by not going through LargeIntegers."

%{  /* NOCONTEXT */

    if (__isSmallInteger(aNumber)) {
        INT prod;

        prod = __intVal(self) * __intVal(aNumber);
#ifdef alpha64
        prod &= 0x7FFFFFFFFFFFFFFFL;
#else
        prod &= 0x7FFFFFFF;
#endif
        RETURN ( __MKSMALLINT(prod));
    }
%}.
    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 this was heavily used in some applications,
     here is an exception to the rule of basing printString
     upon the printOn: method."

%{  /* NOCONTEXT */

    char buffer[30];
    char *cp;
    OBJ newString;
    INT myValue;
    int negative = 0;

#ifdef SLOW_CODE
    /* 
     * this takes twice as long as the code below ...
     * (printf is soooo slow)
     */
# ifdef alpha64
    sprintf(buffer, "%ld", __intVal(self));
# else
    sprintf(buffer, "%d", __intVal(self));
# endif
    newString = __MKSTRING(buffer COMMA_SND);

#else
    myValue = __intVal(self);
    if (myValue == 0) {
        RETURN (__MKSTRING_L("0", 1));
    }
    if (myValue < 0) {
        negative = 1;
        myValue = -myValue;
    }
    cp = buffer + sizeof(buffer) - 1;
    *cp-- = '\0';
    while (myValue != 0) {
        *cp = '0' + (myValue % 10);
        myValue = myValue / 10;
        cp--;
    }
    if (negative) {
        *cp-- = '-';
    }
    newString = __MKSTRING_L(cp+1, (buffer + sizeof(buffer) - 2 - cp));
#endif
    if (newString != nil) {
        RETURN (newString);
    }
%}.
    "/ only arrive here,
    "/  when having memory problems (i.e. no space for string) ...
    ^ super printString

    "
     1234 printString   
     0    printString      
     -100 printString   
    "

!

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

    |s|

%{
    char buffer[64+3];  /* for alpha, base 2 plus sign */
    char *cp;
    OBJ newString;
    INT myValue;
    int negative = 0;
    INT __base;

    if (__isSmallInteger(base)) {
	__base = __intVal(base);

#ifdef SLOW_CODE
        switch (__base) {
            case 10:
#ifdef alpha64
                format = "%ld";
#else
                format = "%d";
#endif
                break;
            case 16:
#ifdef alpha64
                format = "%lx";
#else
                format = "%x";
#endif
                break;
            case 8:
#ifdef alpha64
                format = "%lo";
#else
                format = "%o";
#endif
                break;
        }

        if (format) {
            /*
             * actually only needed on sparc: since thisContext is
             * in a global register, which gets destroyed by printf,
             * manually save it here - very stupid ...
             */
            __BEGIN_PROTECT_REGISTERS__

            sprintf(buffer, format, __intVal(self));

            __END_PROTECT_REGISTERS__

            newString = __MKSTRING(buffer COMMA_SND);
            if (newString != nil) {
                RETURN (newString);
            }
        }
#else
        if ((__base <= 36) && (__base > 1)) {
            myValue = __intVal(self);
            if (myValue == 0) {
                RETURN (__MKSTRING_L("0", 1));
            }
            if (myValue < 0) {
                negative = 1;
                myValue = -myValue;
            }
            cp = buffer + sizeof(buffer) - 1;
            *cp-- = '\0';
            while (myValue != 0) {
                int digit;

                digit = myValue % __base;
                if (digit <= 9) {
                    *cp = '0' + digit;
                } else {
                    *cp = 'A' + digit - 10;
                }
                myValue = myValue / __base;
                cp--;
            }
            if (negative) {
                *cp-- = '-';
            }
            newString = __MKSTRING_L(cp+1, (buffer + sizeof(buffer) - 2 - cp));
            if (newString != nil) {
                RETURN (newString);
            }
        }
#endif
    }
%}.
    "/ arrive here, for bad base,
    "/ or when having memory problems (i.e. no space for string) ...

    "/
    "/ fall back for seldom used bases
    "/ Notice: cannt use super>>printStringRadix: here,
    "/ since that would lead to endless recursion ...
    "/ (a consequence of reversing printOn / printString functionality)

    s := WriteStream on:(String new:10).
    super printOn:s base:base.
    ^ s contents.

    "
      127 printStringRadix:16  
      123 printStringRadix:16  
      123 printStringRadix:10  
      123 printStringRadix:8   
      123 printStringRadix:3  
      123 printStringRadix:2  
      123 printStringRadix:1

      -127 printStringRadix:16   
      -123 printStringRadix:16   
      -123 printStringRadix:10   
      -123 printStringRadix:8    
      -123 printStringRadix:3    
      -123 printStringRadix:2    
    "
!

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;
     it is provided to allow special conversions in very special
     situaltions.
     Notice that a conversion may not be portable; for example,
     to correctly convert an int on a 64-bit alpha, a %ld is required,
     while other systems may be happy with a %d ...
     Use at your own risk (if at all)"

%{  /* STACK: 400 */

    char buffer[256];
    OBJ s;

    if (__isString(formatString)) {
	/*
	 * actually only needed on sparc: since thisContext is
	 * in a global register, which gets destroyed by printf,
	 * manually save it here - very stupid ...
	 */
	__BEGIN_PROTECT_REGISTERS__

	sprintf(buffer, __stringVal(formatString), __intVal(self));

	__END_PROTECT_REGISTERS__

	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:'private'!

sign:aNumber
    "private: for protocol completeness with LargeIntegers"

    |absVal|

    absVal := self abs.
    aNumber < 0 ifTrue:[
	^ absVal negated
    ].
    aNumber == 0 ifTrue:[^ 0].
    ^ absVal

    "
     -4 sign:-1   
     -4 sign:0    
     -4 sign:1    
     -4 sign:-1   
     -4 sign:0    
     -4 sign:1    
    "
! !

!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 */

    RETURN ( ((INT)self & (INT)__MASKSMALLINT(1)) ? false : true );
%}
!

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

%{  /* NOCONTEXT */

#if TAG_INT == 1
    /* tag bit does not change sign */
    RETURN ( ((INT)(self) < 0) ? true : false );
#else
    RETURN ( (__intVal(self) < 0) ? true : false );
#endif
%}
!

odd
    "return true, if the receiver is odd"

%{  /* NOCONTEXT */

    RETURN ( ((INT)self & (INT)__MASKSMALLINT(1)) ? true : false );
%}
!

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

%{  /* NOCONTEXT */

#if TAG_INT == 1
    /* tag bit does not change sign */
    RETURN ( ((INT)(self) >= 0) ? true : false );
#else
    RETURN ( (__intVal(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 */

#if TAG_INT == 1
    /* tag bit does not change sign */
    RETURN ( ((INT)(self) > 0) ? true : false );
#else
    RETURN ( (__intVal(self) > 0) ? true : false );
#endif
%}
! !

!SmallInteger class methodsFor:'documentation'!

version
    ^ '$Header: /cvs/stx/stx/libbasic/Attic/SmallInt.st,v 1.107 1998-11-05 15:12:17 cg Exp $'
! !