diff --git a/Source/GNUmakefile b/Source/GNUmakefile index c2287af85..9ee47291b 100644 --- a/Source/GNUmakefile +++ b/Source/GNUmakefile @@ -185,7 +185,6 @@ NSCopyObject.m \ NSCountedSet.m \ NSConcreteHashTable.m \ NSConcreteMapTable.m \ -NSConcreteNumber.m \ NSConnection.m \ NSData.m \ NSDate.m \ diff --git a/Source/NSConcreteNumber.m b/Source/NSConcreteNumber.m deleted file mode 100644 index 4de222358..000000000 --- a/Source/NSConcreteNumber.m +++ /dev/null @@ -1,85 +0,0 @@ -/* NSConcreteNumber - Handle preprocessor magic for NSConcreteNumberTemplate - Copyright (C) 1993,1994 Free Software Foundation, Inc. - - Written by: Andrew Ruder - Date: May 2006 - - This file is part of the GNUstep Base Library. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02111 USA. -*/ - -#import "config.h" -#import "GNUstepBase/preface.h" -#import "GNUstepBase/GSConfig.h" -#import "Foundation/NSObjCRuntime.h" -#import "Foundation/NSString.h" -#import "Foundation/NSException.h" -#import "Foundation/NSCoder.h" -#import "NSConcreteNumber.h" -#import "GSPrivate.h" - -#define TYPE_ORDER 0 -#include "NSConcreteNumberTemplate.m" -#undef TYPE_ORDER - -#define TYPE_ORDER 1 -#include "NSConcreteNumberTemplate.m" -#undef TYPE_ORDER - -#define TYPE_ORDER 2 -#include "NSConcreteNumberTemplate.m" -#undef TYPE_ORDER - -#define TYPE_ORDER 3 -#include "NSConcreteNumberTemplate.m" -#undef TYPE_ORDER - -#define TYPE_ORDER 4 -#include "NSConcreteNumberTemplate.m" -#undef TYPE_ORDER - -#define TYPE_ORDER 5 -#include "NSConcreteNumberTemplate.m" -#undef TYPE_ORDER - -#define TYPE_ORDER 6 -#include "NSConcreteNumberTemplate.m" -#undef TYPE_ORDER - -#define TYPE_ORDER 7 -#include "NSConcreteNumberTemplate.m" -#undef TYPE_ORDER - -#define TYPE_ORDER 8 -#include "NSConcreteNumberTemplate.m" -#undef TYPE_ORDER - -#define TYPE_ORDER 9 -#include "NSConcreteNumberTemplate.m" -#undef TYPE_ORDER - -#define TYPE_ORDER 10 -#include "NSConcreteNumberTemplate.m" -#undef TYPE_ORDER - -#define TYPE_ORDER 11 -#include "NSConcreteNumberTemplate.m" -#undef TYPE_ORDER - -#define TYPE_ORDER 12 -#include "NSConcreteNumberTemplate.m" -#undef TYPE_ORDER diff --git a/Source/NSConcreteNumberTemplate.m b/Source/NSConcreteNumberTemplate.m deleted file mode 100644 index 2eb402709..000000000 --- a/Source/NSConcreteNumberTemplate.m +++ /dev/null @@ -1,613 +0,0 @@ -# line 1 "NSConcreteNumberTemplate.m" /* So gdb knows which file we are in */ -/* NSConcreteNumberTemplate - Object encapsulation of numbers - - Copyright (C) 1993, 1994, 1996, 2000 Free Software Foundation, Inc. - - Written by: Adam Fedor - Date: Mar 1995 - Rewrite: Richard Frith-Macdonald - Date: Mar 2000 - - This file is part of the GNUstep Base Library. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free - Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - Boston, MA 02111 USA. -*/ - -/* This file should be run through a preprocessor with the macro TYPE_ORDER - defined to a number from 0 to 12 corresponding to each number type */ -#if TYPE_ORDER == 0 -# define NumberTemplate NSBoolNumber -# define TYPE_TYPE BOOL -#elif TYPE_ORDER == 1 -# define NumberTemplate NSCharNumber -# define TYPE_TYPE signed char -#elif TYPE_ORDER == 2 -# define NumberTemplate NSUCharNumber -# define TYPE_TYPE unsigned char -#elif TYPE_ORDER == 3 -# define NumberTemplate NSShortNumber -# define TYPE_TYPE signed short -#elif TYPE_ORDER == 4 -# define NumberTemplate NSUShortNumber -# define TYPE_TYPE unsigned short -#elif TYPE_ORDER == 5 -# define NumberTemplate NSIntNumber -# define TYPE_TYPE signed int -#elif TYPE_ORDER == 6 -# define NumberTemplate NSUIntNumber -# define TYPE_TYPE unsigned int -#elif TYPE_ORDER == 7 -# define NumberTemplate NSLongNumber -# define TYPE_TYPE signed long -#elif TYPE_ORDER == 8 -# define NumberTemplate NSULongNumber -# define TYPE_TYPE unsigned long -#elif TYPE_ORDER == 9 -# define NumberTemplate NSLongLongNumber -# define TYPE_TYPE signed long long -#elif TYPE_ORDER == 10 -# define NumberTemplate NSULongLongNumber -# define TYPE_TYPE unsigned long long -#elif TYPE_ORDER == 11 -# define NumberTemplate NSFloatNumber -# define TYPE_TYPE float -#elif TYPE_ORDER == 12 -# define NumberTemplate NSDoubleNumber -# define TYPE_TYPE double -#endif - -@implementation NumberTemplate - -- (id) initWithBytes: (const void*)value objCType: (const char*)type -{ - typedef __typeof__(data) _dt; - data = *(const _dt*)value; - return self; -} - -/* - * Because of the rule that two numbers which are the same according to - * [-isEqual: ] must generate the same hash, we must generate the hash - * from the most general representation of the number. - * NB. Don't change this without changing the matching function in - * NSNumber.m - */ -- (unsigned) hash -{ - union { - double d; - unsigned char c[sizeof(double)]; - } val; - unsigned hash = 0; - unsigned i; - -/* - * If possible use a cached hash value for small integers. - */ -#if TYPE_ORDER < 11 -#if (TYPE_ORDER & 1) - if (data <= GS_SMALL && data >= -GS_SMALL) -#else - if (data <= GS_SMALL) -#endif - { - return GSPrivateSmallHash((int)data); - } -#endif - - val.d = [self doubleValue]; - for (i = 0; i < sizeof(double); i++) - { - hash = (hash << 5) + hash + val.c[i]; - } - return hash; -} - -- (BOOL) boolValue -{ - return (BOOL)data; -} - -- (signed char) charValue -{ - return (signed char)data; -} - -- (double) doubleValue -{ - return (double)data; -} - -- (float) floatValue -{ - return (float)data; -} - -- (signed int) intValue -{ - return (signed int)data; -} - -- (signed long long) longLongValue -{ - return (signed long long)data; -} - -- (signed long) longValue -{ - return (signed long)data; -} - -- (signed short) shortValue -{ - return (signed short)data; -} - -- (unsigned char) unsignedCharValue -{ - return (unsigned char)data; -} - -- (unsigned int) unsignedIntValue -{ - return (unsigned int)data; -} - -- (unsigned long long) unsignedLongLongValue -{ - return (unsigned long long)data; -} - -- (unsigned long) unsignedLongValue -{ - return (unsigned long)data; -} - -- (unsigned short) unsignedShortValue -{ - return (unsigned short)data; -} - -- (NSComparisonResult) compare: (NSNumber*)other -{ - if (other == self) - { - return NSOrderedSame; - } - else if (other == nil) - { - [NSException raise: NSInvalidArgumentException - format: @"nil argument for compare:"]; - } - else - { - GSNumberInfo *info = GSNumberInfoFromObject(other); - - switch (info->typeLevel) - { - case 0: - { - BOOL oData; - - (*(info->getValue))(other, @selector(getValue:), (void*)&oData); -#undef PT -#if (TYPE_ORDER & 1) == 1 -#if GS_SIZEOF_CHAR < GS_SIZEOF_SHORT && TYPE_ORDER < 3 -#define PT (short) -#elif GS_SIZEOF_CHAR < GS_SIZEOF_INT && TYPE_ORDER < 5 -#define PT (int) -#elif GS_SIZEOF_CHAR < GS_SIZEOF_LONG && TYPE_ORDER < 7 -#define PT (long) -#elif GS_SIZEOF_CHAR < GS_SIZEOF_LONG_LONG && TYPE_ORDER < 9 -#define PT (long long) -#else -#define PT (double) -#endif -#else -#define PT -#endif - if (PT data == PT oData) - return NSOrderedSame; - else if (PT data < PT oData) - return NSOrderedAscending; - else - return NSOrderedDescending; - } - case 1: - { - signed char oData; - - (*(info->getValue))(other, @selector(getValue:), (void*)&oData); -#undef PT -#if (TYPE_ORDER & 1) == 0 -#if GS_SIZEOF_CHAR < GS_SIZEOF_SHORT && TYPE_ORDER < 3 -#define PT (short) -#elif GS_SIZEOF_CHAR < GS_SIZEOF_INT && TYPE_ORDER < 5 -#define PT (int) -#elif GS_SIZEOF_CHAR < GS_SIZEOF_LONG && TYPE_ORDER < 7 -#define PT (long) -#elif GS_SIZEOF_CHAR < GS_SIZEOF_LONG_LONG && TYPE_ORDER < 9 -#define PT (long long) -#else -#define PT (double) -#endif -#else -#define PT -#endif - if (PT data == PT oData) - return NSOrderedSame; - else if (PT data < PT oData) - return NSOrderedAscending; - else - return NSOrderedDescending; - } - case 2: - { - unsigned char oData; - - (*(info->getValue))(other, @selector(getValue:), (void*)&oData); -#undef PT -#if (TYPE_ORDER & 1) == 1 -#if GS_SIZEOF_CHAR < GS_SIZEOF_SHORT && TYPE_ORDER < 3 -#define PT (short) -#elif GS_SIZEOF_CHAR < GS_SIZEOF_INT && TYPE_ORDER < 5 -#define PT (int) -#elif GS_SIZEOF_CHAR < GS_SIZEOF_LONG && TYPE_ORDER < 7 -#define PT (long) -#elif GS_SIZEOF_CHAR < GS_SIZEOF_LONG_LONG && TYPE_ORDER < 9 -#define PT (long long) -#else -#define PT (double) -#endif -#else -#define PT -#endif - if (PT data == PT oData) - return NSOrderedSame; - else if (PT data < PT oData) - return NSOrderedAscending; - else - return NSOrderedDescending; - } - case 3: - { - signed short oData; - - (*(info->getValue))(other, @selector(getValue:), (void*)&oData); -#undef PT -#if (TYPE_ORDER & 1) == 0 -#if GS_SIZEOF_SHORT < GS_SIZEOF_INT && TYPE_ORDER < 5 -#define PT (int) -#elif GS_SIZEOF_SHORT < GS_SIZEOF_LONG && TYPE_ORDER < 7 -#define PT (long) -#elif GS_SIZEOF_SHORT < GS_SIZEOF_LONG_LONG && TYPE_ORDER < 9 -#define PT (long long) -#else -#define PT (double) -#endif -#else -#define PT -#endif - if (PT data == PT oData) - return NSOrderedSame; - else if (PT data < PT oData) - return NSOrderedAscending; - else - return NSOrderedDescending; - } - case 4: - { - unsigned short oData; - - (*(info->getValue))(other, @selector(getValue:), (void*)&oData); -#undef PT -#if (TYPE_ORDER & 1) == 1 -#if GS_SIZEOF_SHORT < GS_SIZEOF_INT && TYPE_ORDER < 5 -#define PT (int) -#elif GS_SIZEOF_SHORT < GS_SIZEOF_LONG && TYPE_ORDER < 7 -#define PT (long) -#elif GS_SIZEOF_SHORT < GS_SIZEOF_LONG_LONG && TYPE_ORDER < 9 -#define PT (long long) -#else -#define PT (double) -#endif -#else -#define PT -#endif - if (PT data == PT oData) - return NSOrderedSame; - else if (PT data < PT oData) - return NSOrderedAscending; - else - return NSOrderedDescending; - } - case 5: - { - signed int oData; - - (*(info->getValue))(other, @selector(getValue:), (void*)&oData); -#undef PT -#if (TYPE_ORDER & 1) == 0 -#if GS_SIZEOF_INT < GS_SIZEOF_LONG && TYPE_ORDER < 7 -#define PT (long) -#elif GS_SIZEOF_INT < GS_SIZEOF_LONG_LONG && TYPE_ORDER < 9 -#define PT (long long) -#else -#define PT (double) -#endif -#else -#define PT -#endif - if (PT data == PT oData) - return NSOrderedSame; - else if (PT data < PT oData) - return NSOrderedAscending; - else - return NSOrderedDescending; - } - case 6: - { - unsigned int oData; - - (*(info->getValue))(other, @selector(getValue:), (void*)&oData); -#undef PT -#if (TYPE_ORDER & 1) == 1 -#if GS_SIZEOF_INT < GS_SIZEOF_LONG && TYPE_ORDER < 7 -#define PT (long) -#elif GS_SIZEOF_INT < GS_SIZEOF_LONG_LONG && TYPE_ORDER < 9 -#define PT (long long) -#else -#define PT (double) -#endif -#else -#define PT -#endif - if (PT data == PT oData) - return NSOrderedSame; - else if (PT data < PT oData) - return NSOrderedAscending; - else - return NSOrderedDescending; - } - case 7: - { - signed long oData; - - (*(info->getValue))(other, @selector(getValue:), (void*)&oData); -#undef PT -#if (TYPE_ORDER & 1) == 0 -#if GS_SIZEOF_LONG < GS_SIZEOF_LONG_LONG && TYPE_ORDER < 9 -#define PT (long long) -#else -#define PT (double) -#endif -#else -#define PT -#endif - if (PT data == PT oData) - return NSOrderedSame; - else if (PT data < PT oData) - return NSOrderedAscending; - else - return NSOrderedDescending; - } - case 8: - { - unsigned long oData; - - (*(info->getValue))(other, @selector(getValue:), (void*)&oData); -#undef PT -#if (TYPE_ORDER & 1) == 1 -#if GS_SIZEOF_LONG < GS_SIZEOF_LONG_LONG && TYPE_ORDER < 9 -#define PT (long long) -#else -#define PT (double) -#endif -#else -#define PT -#endif - if (PT data == PT oData) - return NSOrderedSame; - else if (PT data < PT oData) - return NSOrderedAscending; - else - return NSOrderedDescending; - } - case 9: - { - signed long long oData; - - (*(info->getValue))(other, @selector(getValue:), (void*)&oData); -#undef PT -#if (TYPE_ORDER & 1) == 0 -#define PT (double) -#else -#define PT -#endif - if (PT data == PT oData) - return NSOrderedSame; - else if (PT data < PT oData) - return NSOrderedAscending; - else - return NSOrderedDescending; - } - case 10: - { - unsigned long long oData; - - (*(info->getValue))(other, @selector(getValue:), (void*)&oData); -#undef PT -#if (TYPE_ORDER & 1) == 1 -#define PT (double) -#else -#define PT -#endif - if (PT data == PT oData) - return NSOrderedSame; - else if (PT data < PT oData) - return NSOrderedAscending; - else - return NSOrderedDescending; - } - case 11: - { - float oData; - - (*(info->getValue))(other, @selector(getValue:), (void*)&oData); -#undef PT -#if TYPE_ORDER != 11 -#define PT (double) -#else -#define PT -#endif - if (PT data == PT oData) - return NSOrderedSame; - else if (PT data < PT oData) - return NSOrderedAscending; - else - return NSOrderedDescending; - } - case 12: - { - double oData; - - (*(info->getValue))(other, @selector(getValue:), (void*)&oData); -#undef PT -#define PT (double) - if (PT data == PT oData) - return NSOrderedSame; - else if (PT data < PT oData) - return NSOrderedAscending; - else - return NSOrderedDescending; - } - default: - [NSException raise: NSInvalidArgumentException - format: @"number type value for comparison"]; - return NSOrderedSame; - } - } - return 0; /* Quiet warnings */ -} - -- (NSString*) descriptionWithLocale: (NSDictionary*)locale -{ -#if TYPE_ORDER == 0 - return (data) ? @"YES" : @"NO"; -#else - NSString *result = [NSString alloc]; - -#if TYPE_ORDER == 1 - result = [result initWithFormat: @"%i" locale: locale, (int)data]; -#elif TYPE_ORDER == 2 - result = [result initWithFormat: @"%u" locale: locale, (unsigned int)data]; -#elif TYPE_ORDER == 3 - result = [result initWithFormat: @"%hi" locale: locale, data]; -#elif TYPE_ORDER == 4 - result = [result initWithFormat: @"%hu" locale: locale, data]; -#elif TYPE_ORDER == 5 - result = [result initWithFormat: @"%i" locale: locale, data]; -#elif TYPE_ORDER == 6 - result = [result initWithFormat: @"%u" locale: locale, data]; -#elif TYPE_ORDER == 7 - result = [result initWithFormat: @"%li" locale: locale, data]; -#elif TYPE_ORDER == 8 - result = [result initWithFormat: @"%lu" locale: locale, data]; -#elif TYPE_ORDER == 9 - result = [result initWithFormat: @"%lli" locale: locale, data]; -#elif TYPE_ORDER == 10 - result = [result initWithFormat: @"%llu" locale: locale, data]; -#elif TYPE_ORDER == 11 - result = [result initWithFormat: @"%0.7g" locale: locale, (double)data]; -#elif TYPE_ORDER == 12 - result = [result initWithFormat: @"%0.16g" locale: locale, data]; -#endif - return AUTORELEASE(result); -#endif -} - -- (id) copy -{ - if (NSShouldRetainWithZone(self, NSDefaultMallocZone())) - return RETAIN(self); - else - return NSCopyObject(self, 0, NSDefaultMallocZone()); -} - -- (id) copyWithZone: (NSZone*)zone -{ - if (NSShouldRetainWithZone(self, zone)) - return RETAIN(self); - else - return NSCopyObject(self, 0, zone); -} - -// Override these from NSValue -- (void) getValue: (void*)value -{ - if (value == 0) - { - [NSException raise: NSInvalidArgumentException - format: @"Cannot copy value into NULL pointer"]; - /* NOT REACHED */ - } - memcpy(value, &data, objc_sizeof_type(@encode(TYPE_TYPE))); -} - -- (const char*) objCType -{ - return @encode(TYPE_TYPE); -} - -- (id) nonretainedObjectValue -{ - return (id)(void*)&data; -} - -- (void*) pointerValue -{ - return (void*)&data; -} - -// NSCoding - -/* - * Exact mirror of NSNumber abstract class coding method. - */ -- (void) encodeWithCoder: (NSCoder*)coder -{ - const char *t = @encode(TYPE_TYPE); - - [coder encodeValueOfObjCType: @encode(signed char) at: t]; - [coder encodeValueOfObjCType: t at: &data]; -} - -/* - * NSNumber objects should have been encoded with their class set to the - * abstract class. If they haven't then we must be encoding from an old - * archive, so we must implement the old initWithCoder: method. - */ -- (id) initWithCoder: (NSCoder*)coder -{ - [coder decodeValueOfObjCType: @encode(TYPE_TYPE) at: &data]; - return self; -} - -@end - -#undef TYPE_TYPE -#undef NumberTemplate -#undef PT diff --git a/Source/NSNumber.m b/Source/NSNumber.m index 83aa173fb..8912357f7 100644 --- a/Source/NSNumber.m +++ b/Source/NSNumber.m @@ -1,11 +1,11 @@ -/** NSNumber - Object encapsulation of numbers +/** Implementation of NSNumber for GNUStep + Copyright (C) 2010 Free Software Foundation, Inc. - Copyright (C) 1993, 1994, 1996, 2000 Free Software Foundation, Inc. - - Written by: Adam Fedor - Created: Mar 1995 - Rewrite: Richard Frith-Macdonald - Date: Mar 2000 + Written by: David Chisnall + Partial rewrite: Richard Frith-Macdonld + (to compile on gnu/linux and mswindows, to meet coding/style standards) + + Date: February 2010 This file is part of the GNUstep Base Library. @@ -24,1977 +24,352 @@ Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111 USA. - NSNumber class reference - $Date$ $Revision$ -*/ + */ + -#include #import "config.h" -#import "GNUstepBase/preface.h" -#import "Foundation/NSException.h" -#import "Foundation/NSString.h" -#import "Foundation/NSNotification.h" -#import "Foundation/NSMapTable.h" -#import "Foundation/NSThread.h" -#import "Foundation/NSCoder.h" -#import "Foundation/NSPortCoder.h" -#import "Foundation/NSObjCRuntime.h" -#import "NSConcreteNumber.h" -#import "GSPrivate.h" +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#if defined(HAVE_STDINT_H) +#include +#endif +#if defined(HAVE_LIMITS_H) +#include +#endif + +#import "Foundation/NSCoder.h" +#import "Foundation/NSDecimalNumber.h" +#import "Foundation/NSException.h" +#import "Foundation/NSValue.h" #import "GNUstepBase/NSObject+GNUstepBase.h" -@interface GSCachedBool : NSBoolNumber +#if defined(HANDLE_LLONG_MAX) && !defined(HANDLE_LONG_LONG_MAX) +#define LONG_LONG_MAX LLONG_MAX +#define LONG_LONG_MIN LLONG_MIN +#define ULONG_LONG_MAX ULLONG_MAX +#endif + +/* + * NSNumber implementation. This matches the behaviour of Apple's + * implementation. Values in the range -1 to 12 inclusive are mapped to + * singletons. All other values are mapped to the smallest signed value that + * will store them, unless they are greater than LONG_LONG_MAX, in which case + * they are stored in an unsigned long long. + */ + +@interface NSSignedIntegerNumber : NSNumber @end -@interface GSCachedInt : NSIntNumber -@end -@implementation GSCachedBool -- (id) copyWithZone: (NSZone*)zone + +@interface NSIntNumber : NSSignedIntegerNumber { - return RETAIN(self); -} -- (void) dealloc -{ - [NSException raise: NSGenericException - format: @"Attempt to deallocate bool number owned by cache"]; - GSNOSUPERDEALLOC; +@public + int value; } @end -@implementation GSCachedInt -- (id) copyWithZone: (NSZone*)zone + +@interface NSLongLongNumber : NSSignedIntegerNumber { - return RETAIN(self); +@public + long long int value; } -- (void) dealloc +@end + +@interface NSUnsignedLongLongNumber : NSNumber { - [NSException raise: NSGenericException - format: @"Attempt to deallocate int number owned by cache"]; - GSNOSUPERDEALLOC; +@public + unsigned long long int value; } @end +// The value ivar in all of the concrete classes contains the real value. +#define VALUE value +#define COMPARE(value, other) \ +if (value < other)\ + {\ + return NSOrderedAscending;\ + }\ +if (value > other)\ + {\ + return NSOrderedDescending;\ + }\ +return NSOrderedSame; + +@implementation NSSignedIntegerNumber +- (NSComparisonResult) compare: (NSNumber*)aNumber +{ + if (aNumber == self) + { + return NSOrderedSame; + } + if (aNumber == nil) + { + [NSException raise: NSInvalidArgumentException + format: @"nil argument for compare:"]; + } + + switch ([aNumber objCType][0]) + { + /* For cases smaller than or equal to an int, we could get the int + * value and compare. + */ + case 'c': + case 'C': + case 's': + case 'S': + case 'i': + case 'I': + case 'l': + case 'L': + case 'q': + { + long long value = [self longLongValue]; + long long other = [aNumber longLongValue]; + + COMPARE (value, other); + } + case 'Q': + { + unsigned long long other; + unsigned long long value; + long long v; + + /* According to the C type promotion rules, we should cast this to + * an unsigned long long, however Apple's code does not do this. + * Instead, it performs a real comparison. + */ + v = [self longLongValue]; + + /* If this value is less than 0, then it is less than any value + * that can possibly be stored in an unsigned value. + */ + if (v < 0) + { + return NSOrderedAscending; + } + + other = [aNumber unsignedLongLongValue]; + value = (unsigned long long) v; + COMPARE (value, other); + } + case 'f': + case 'd': + { + double other = [aNumber doubleValue]; + double value = [self doubleValue]; + + COMPARE (value, other); + } + default: + [NSException raise: NSInvalidArgumentException + format: @"unrecognised type for compare:"]; + } + return 0; // Not reached. +} +@end + +@implementation NSIntNumber +#define FORMAT @"%i" +#include "NSNumberMethods.h" +@end + +@implementation NSLongLongNumber +#define FORMAT @"%lli" +#include "NSNumberMethods.h" +@end + +@implementation NSUnsignedLongLongNumber +#define FORMAT @"%llu" +#include "NSNumberMethods.h" +- (NSComparisonResult) compare: (NSNumber*)aNumber +{ + if (aNumber == self) + { + return NSOrderedSame; + } + if (aNumber == nil) + { + [NSException raise: NSInvalidArgumentException + format: @"nil argument for compare:"]; + } + + switch ([aNumber objCType][0]) + { + /* For cases smaller than or equal to an int, we could get the int + * value and compare. + */ + case 'c': + case 'C': + case 's': + case 'S': + case 'i': + case 'I': + case 'l': + case 'L': + case 'q': + { + long long other = [aNumber longLongValue]; + + if (other < 0) + { + return NSOrderedDescending; + } + COMPARE (value, ((unsigned long long) other)); + } + case 'Q': + { + unsigned long long other = [aNumber unsignedLongLongValue]; + + COMPARE (value, other); + } + case 'f': + case 'd': + { + double other = [aNumber doubleValue]; + + COMPARE (((double) value), other); + } + default: + [NSException raise: NSInvalidArgumentException + format: @"unrecognised type for compare:"]; + } + return 0; // Not reached. +} +@end + +/* + * Abstract superclass for floating point numbers. + */ +@interface NSFloatingPointNumber : NSNumber +@end + +@implementation NSFloatingPointNumber +/* For floats, the type promotion rules say that we always promote to a + * floating point type, even if the other value is really an integer. + */ +- (BOOL) isEqualToNumber: (NSNumber*)aNumber +{ + return [self doubleValue] == [aNumber doubleValue]; +} + +- (NSComparisonResult) compare: (NSNumber*)aNumber +{ + double other; + double value; + + if (aNumber == self) + { + return NSOrderedSame; + } + if (aNumber == nil) + { + [NSException raise: NSInvalidArgumentException + format: @"nil argument for compare:"]; + } + other = [aNumber doubleValue]; + value = [self doubleValue]; + COMPARE (value, other); +} +@end + +@interface NSFloatNumber : NSFloatingPointNumber +{ +@public + float value; +} +@end + +@implementation NSFloatNumber +#define FORMAT @"%0.7g" +#include "NSNumberMethods.h" +@end + +@interface NSDoubleNumber : NSFloatingPointNumber +{ +@public + double value; +} +@end + +@implementation NSDoubleNumber +#define FORMAT @"%0.16g" +#include "NSNumberMethods.h" +@end + @implementation NSNumber -static NSMapTable *numberMap; -static BOOL multiThreaded = NO; -static NSNumber *boolN; -static NSNumber *boolY; -static NSNumber *smallIntegers[GS_SMALL * 2 + 1]; -static unsigned int smallHashes[GS_SMALL * 2 + 1]; - /* - * Cache info for each number class. - * In a multi-threaded system we may waste some memory in order to get speed. + * Numbers from -1 to 12 inclusive that are reused. */ -GSNumberInfo* -GSNumberInfoFromObject(NSNumber *o) -{ - Class c; - GSNumberInfo *info; - - if (o == nil) - return 0; - c = GSObjCClass(o); - info = (GSNumberInfo*)NSMapGet (numberMap, (void*)c); - if (info == 0) - { - const char *t = [o objCType]; - int order = -1; - - if (strlen(t) != 1) - { - NSLog(@"Invalid return value (%s) from [%@ objCType]", t, c); - } - else - { - switch (*t) - { - case 'c': order = 1; break; - case 'C': order = 2; break; - case 's': order = 3; break; - case 'S': order = 4; break; - case 'i': order = 5; break; - case 'I': order = 6; break; - case 'l': order = 7; break; - case 'L': order = 8; break; - case 'q': order = 9; break; - case 'Q': order = 10; break; - case 'f': order = 11; break; - case 'd': order = 12; break; - default: - NSLog(@"Invalid return value (%s) from [%@ objCType]", t, c); - break; - } - } - info = (GSNumberInfo*)NSZoneMalloc(NSDefaultMallocZone(), - (sizeof(GSNumberInfo))); - info->typeLevel = order; - - info->getValue = (void (*)(NSNumber*, SEL, void*)) - [o methodForSelector: @selector(getValue:)]; - - if (multiThreaded == YES) - { - NSMapTable *table; - - /* - * Memory leak for efficiency - the old map table is never - * deallocated, so we don't have to do any locking. - */ - table = NSCopyMapTableWithZone(numberMap, NSDefaultMallocZone()); - NSMapInsert(table, (void*)c, (void*)info); - numberMap = table; - } - else - { - NSMapInsert(numberMap, (void*)c, (void*)info); - } - } - return info; -} - -unsigned int -GSPrivateSmallHash(int n) -{ - return smallHashes[n + GS_SMALL]; -} - -static Class abstractClass; -static Class boolNumberClass; -static Class charNumberClass; -static Class uCharNumberClass; -static Class shortNumberClass; -static Class uShortNumberClass; -static Class intNumberClass; -static Class uIntNumberClass; -static Class integerNumberClass; -static Class uIntegerNumberClass; -static Class longNumberClass; -static Class uLongNumberClass; -static Class longLongNumberClass; -static Class uLongLongNumberClass; -static Class floatNumberClass; -static Class doubleNumberClass; - -+ (void) _becomeThreaded: (NSNotification*)notification -{ - multiThreaded = YES; -} +static NSNumber *ReusedInstances[14]; +static Class NSNumberClass; +static Class NSIntNumberClass; +static Class NSLongLongNumberClass; +static Class NSUnsignedLongLongNumberClass; +static Class NSFloatNumberClass; +static Class NSDoubleNumberClass; + (void) initialize { - if (self == [NSNumber class]) + int i; + + if ([NSNumber class] != self) { - BOOL boolean; - int integer; - unsigned (*hasher)(NSNumber*, SEL); - GSNumberInfo *info; - CREATE_AUTORELEASE_POOL(pool); + return; + } - abstractClass = self; - hasher = (unsigned (*)(NSNumber*, SEL)) - [self instanceMethodForSelector: @selector(hash)]; + NSNumberClass = self; + NSIntNumberClass = [NSIntNumber class]; + NSLongLongNumberClass = [NSLongLongNumber class]; + NSUnsignedLongLongNumberClass = [NSUnsignedLongLongNumber class]; + NSFloatNumberClass = [NSFloatNumber class]; + NSDoubleNumberClass = [NSDoubleNumber class]; - /* - * Create cache for per-subclass method implementations etc. - */ - numberMap = NSCreateMapTable (NSNonOwnedPointerMapKeyCallBacks, - NSOwnedPointerMapValueCallBacks, 0); + for (i = 0; i < 14; i++) + { + NSIntNumber *n = NSAllocateObject (NSIntNumberClass, 0,[self zone]); - /* - * cache standard subclass info. - */ - boolNumberClass = [NSBoolNumber class]; - info = GSNumberInfoFromObject(AUTORELEASE([boolNumberClass alloc])); - /* - * Set the typeLevel for a boolean to be '0' - */ - info->typeLevel = 0; - charNumberClass = [NSCharNumber class]; - GSNumberInfoFromObject(AUTORELEASE([charNumberClass alloc])); - uCharNumberClass = [NSUCharNumber class]; - GSNumberInfoFromObject(AUTORELEASE([uCharNumberClass alloc])); - shortNumberClass = [NSShortNumber class]; - GSNumberInfoFromObject(AUTORELEASE([shortNumberClass alloc])); - uShortNumberClass = [NSUShortNumber class]; - GSNumberInfoFromObject(AUTORELEASE([uShortNumberClass alloc])); - intNumberClass = [NSIntNumber class]; - GSNumberInfoFromObject(AUTORELEASE([intNumberClass alloc])); - uIntNumberClass = [NSUIntNumber class]; - GSNumberInfoFromObject(AUTORELEASE([uIntNumberClass alloc])); - longNumberClass = [NSLongNumber class]; - GSNumberInfoFromObject(AUTORELEASE([longNumberClass alloc])); - uLongNumberClass = [NSULongNumber class]; - GSNumberInfoFromObject(AUTORELEASE([uLongNumberClass alloc])); - longLongNumberClass = [NSLongLongNumber class]; - GSNumberInfoFromObject(AUTORELEASE([longLongNumberClass alloc])); - uLongLongNumberClass = [NSULongLongNumber class]; - GSNumberInfoFromObject(AUTORELEASE([uLongLongNumberClass alloc])); - floatNumberClass = [NSFloatNumber class]; - GSNumberInfoFromObject(AUTORELEASE([floatNumberClass alloc])); - doubleNumberClass = [NSDoubleNumber class]; - GSNumberInfoFromObject(AUTORELEASE([doubleNumberClass alloc])); - - if (sizeof(NSInteger) == sizeof(int)) - { - integerNumberClass = intNumberClass; - uIntegerNumberClass = uIntNumberClass; - } - else if (sizeof(NSInteger) == sizeof(long)) - { - integerNumberClass = longNumberClass; - uIntegerNumberClass = uLongNumberClass; - } - else - { - integerNumberClass = longLongNumberClass; - uIntegerNumberClass = uLongLongNumberClass; - } - - /* - * cache bool values. - */ - boolN = (NSNumber*)NSAllocateObject([GSCachedBool class], 0, - NSDefaultMallocZone()); - boolean = NO; - boolN = [boolN initWithBytes: &boolean objCType: NULL]; - - boolY = (NSNumber*)NSAllocateObject([GSCachedBool class], 0, - NSDefaultMallocZone()); - boolean = YES; - boolY = [boolY initWithBytes: &boolean objCType: NULL]; - - /* - * cache small integer values. - */ - for (integer = -GS_SMALL; integer <= GS_SMALL; integer++) - { - NSNumber *num; - - num = (NSNumber*)NSAllocateObject([GSCachedInt class], 0, - NSDefaultMallocZone()); - num = [num initWithBytes: &integer objCType: NULL]; - smallIntegers[integer + GS_SMALL] = num; - smallHashes[integer + GS_SMALL] = (*hasher)(num, @selector(hash)); - } - - /* - * Make sure we know if we are multi-threaded so that if the caches - * need to grow, we do it by copying and replacing without deleting - * an old cache that may be in use by another thread. - */ - if ([NSThread isMultiThreaded]) - { - [self _becomeThreaded: nil]; - } - else - { - [[NSNotificationCenter defaultCenter] - addObserver: self - selector: @selector(_becomeThreaded:) - name: NSWillBecomeMultiThreadedNotification - object: nil]; - } - RELEASE(pool); + n->value = i - 1; + ReusedInstances[i] = n; } } -/* Returns the concrete class associated with the type encoding. Note - that we don't allow NSNumber to instantiate any class but its own - concrete subclasses (see check at end of method) */ -+ (Class) valueClassWithObjCType: (const char*)type +- (const char *) objCType { - Class theClass = Nil; - - switch (*type) - { - case _C_CHR: return charNumberClass; - case _C_UCHR: return uCharNumberClass; - case _C_SHT: return shortNumberClass; - case _C_USHT: return uShortNumberClass; - case _C_INT: return intNumberClass; - case _C_UINT: return uIntNumberClass; - case _C_LNG: return longNumberClass; - case _C_ULNG: return uLongNumberClass; -#ifdef _C_LNGLNG - case _C_LNGLNG: -#else - case 'q': -#endif - return longLongNumberClass; -#ifdef _C_ULNGLNG - case _C_ULNGLNG: -#else - case 'Q': -#endif - return uLongLongNumberClass; - case _C_FLT: return floatNumberClass; - case _C_DBL: return doubleNumberClass; - default: - break; - } - - if (theClass == Nil && self == abstractClass) - { - [NSException raise: NSInvalidArgumentException - format: @"Invalid number type"]; - /* NOT REACHED */ - } - else if (theClass == Nil) - { - theClass = [super valueClassWithObjCType: type]; - } - return theClass; -} - -+ (NSNumber*) numberWithBool: (BOOL)value -{ - // if class is NSNumber, replace by appropriate object - if (self == abstractClass) - { - if (value == NO) - { - return boolN; - } - else - { - return boolY; - } - } - else // alloc class and init with object intWithXX method - { - return AUTORELEASE([[self allocWithZone: NSDefaultMallocZone()] - initWithBool: value]); - } -} - -+ (NSNumber*) numberWithChar: (signed char)value -{ - NSNumber *theObj = nil; - - // if class is NSNumber, replace by appropriate object - if (self == abstractClass) - { - if (value <= GS_SMALL && value >= -GS_SMALL) - { - return smallIntegers[value + GS_SMALL]; - } - theObj = (NSNumber*)NSAllocateObject(charNumberClass, 0, - NSDefaultMallocZone()); - theObj = [theObj initWithBytes: &value objCType: NULL]; - } - else // alloc class and init with object intWithXX method - { - theObj = [[self allocWithZone: NSDefaultMallocZone()] - initWithChar: value]; - } - - return AUTORELEASE(theObj); -} - -+ (NSNumber*) numberWithDouble: (double)value -{ - NSNumber *theObj = nil; - - // if class is NSNumber, replace by appropriate object - if (self == abstractClass) - { - theObj = (NSNumber*)NSAllocateObject(doubleNumberClass, 0, - NSDefaultMallocZone()); - theObj = [theObj initWithBytes: &value objCType: NULL]; - } - else // alloc class and init with object intWithXX method - { - theObj = [[self allocWithZone: NSDefaultMallocZone()] - initWithDouble: value]; - } - - return AUTORELEASE(theObj); -} - -+ (NSNumber*) numberWithFloat: (float)value -{ - NSNumber *theObj = nil; - - // if class is NSNumber, replace by appropriate object - if (self == abstractClass) - { - theObj = (NSNumber*)NSAllocateObject(floatNumberClass, 0, - NSDefaultMallocZone()); - theObj = [theObj initWithBytes: &value objCType: NULL]; - } - else // alloc class and init with object intWithXX method - { - theObj = [[self allocWithZone: NSDefaultMallocZone()] - initWithFloat: value]; - } - - return AUTORELEASE(theObj); -} - -+ (NSNumber*) numberWithInt: (signed int)value -{ - NSNumber *theObj = nil; - - // if class is NSNumber, replace by appropriate object - if (self == abstractClass) - { - if (value <= GS_SMALL && value >= -GS_SMALL) - { - return smallIntegers[value + GS_SMALL]; - } - theObj = (NSNumber*)NSAllocateObject(intNumberClass, 0, - NSDefaultMallocZone()); - theObj = [theObj initWithBytes: &value objCType: NULL]; - } - else // alloc class and init with object intWithXX method - { - theObj = [[self allocWithZone: NSDefaultMallocZone()] - initWithInt: value]; - } - - return AUTORELEASE(theObj); -} - -+ (NSNumber*) numberWithInteger: (NSInteger)value -{ - NSNumber *theObj = nil; - - // if class is NSNumber, replace by appropriate object - if (self == abstractClass) - { - if (value <= GS_SMALL && value >= -GS_SMALL) - { - return smallIntegers[value + GS_SMALL]; - } - theObj = (NSNumber*)NSAllocateObject(integerNumberClass, 0, - NSDefaultMallocZone()); - theObj = [theObj initWithBytes: &value objCType: NULL]; - } - else // alloc class and init with object intWithXX method - { - theObj = [[self allocWithZone: NSDefaultMallocZone()] - initWithInteger: value]; - } - - return AUTORELEASE(theObj); -} - -+ (NSNumber*) numberWithLong: (signed long)value -{ - NSNumber *theObj = nil; - - // if class is NSNumber, replace by appropriate object - if (self == abstractClass) - { - if (value <= GS_SMALL && value >= -GS_SMALL) - { - return smallIntegers[value + GS_SMALL]; - } - theObj = (NSNumber*)NSAllocateObject(longNumberClass, 0, - NSDefaultMallocZone()); - theObj = [theObj initWithBytes: &value objCType: NULL]; - } - else // alloc class and init with object intWithXX method - { - theObj = [[self allocWithZone: NSDefaultMallocZone()] - initWithLong: value]; - } - - return AUTORELEASE(theObj); -} - -+ (NSNumber*) numberWithLongLong: (signed long long)value -{ - NSNumber *theObj = nil; - - // if class is NSNumber, replace by appropriate object - if (self == abstractClass) - { - if (value <= GS_SMALL && value >= -GS_SMALL) - { - return smallIntegers[value + GS_SMALL]; - } - theObj = (NSNumber*)NSAllocateObject(longLongNumberClass, 0, - NSDefaultMallocZone()); - theObj = [theObj initWithBytes: &value objCType: NULL]; - } - else // alloc class and init with object intWithXX method - { - theObj = [[self allocWithZone: NSDefaultMallocZone()] - initWithLongLong: value]; - } - - return AUTORELEASE(theObj); -} - -+ (NSNumber*) numberWithShort: (signed short)value -{ - NSNumber *theObj = nil; - - // if class is NSNumber, replace by appropriate object - if (self == abstractClass) - { - if (value <= GS_SMALL && value >= -GS_SMALL) - { - return smallIntegers[value + GS_SMALL]; - } - theObj = (NSNumber*)NSAllocateObject(shortNumberClass, 0, - NSDefaultMallocZone()); - theObj = [theObj initWithBytes: &value objCType: NULL]; - } - else // alloc class and init with object intWithXX method - { - theObj = [[self allocWithZone: NSDefaultMallocZone()] - initWithShort: value]; - } - - return AUTORELEASE(theObj); -} - -+ (NSNumber*) numberWithUnsignedChar: (unsigned char)value -{ - NSNumber *theObj = nil; - - // if class is NSNumber, replace by appropriate object - if (self == abstractClass) - { - if (value <= GS_SMALL) - { - return smallIntegers[value + GS_SMALL]; - } - theObj = (NSNumber*)NSAllocateObject(uCharNumberClass, 0, - NSDefaultMallocZone()); - theObj = [theObj initWithBytes: &value objCType: NULL]; - } - else // alloc class and init with object intWithXX method - { - theObj = [[self allocWithZone: NSDefaultMallocZone()] - initWithUnsignedChar: value]; - } - - return AUTORELEASE(theObj); -} - -+ (NSNumber*) numberWithUnsignedInt: (unsigned int)value -{ - NSNumber *theObj = nil; - - // if class is NSNumber, replace by appropriate object - if (self == abstractClass) - { - if (value <= GS_SMALL) - { - return smallIntegers[value + GS_SMALL]; - } - theObj = (NSNumber*)NSAllocateObject(uIntNumberClass, 0, - NSDefaultMallocZone()); - theObj = [theObj initWithBytes: &value objCType: NULL]; - } - else // alloc class and init with object intWithXX method - { - theObj = [[self allocWithZone: NSDefaultMallocZone()] - initWithUnsignedInt: value]; - } - - return AUTORELEASE(theObj); -} - -+ (NSNumber*) numberWithUnsignedInteger: (NSUInteger)value -{ - NSNumber *theObj = nil; - - // if class is NSNumber, replace by appropriate object - if (self == abstractClass) - { - if (value <= GS_SMALL) - { - return smallIntegers[value + GS_SMALL]; - } - theObj = (NSNumber*)NSAllocateObject(uIntegerNumberClass, 0, - NSDefaultMallocZone()); - theObj = [theObj initWithBytes: &value objCType: NULL]; - } - else // alloc class and init with object intWithXX method - { - theObj = [[self allocWithZone: NSDefaultMallocZone()] - initWithUnsignedInteger: value]; - } - - return AUTORELEASE(theObj); -} - -+ (NSNumber*) numberWithUnsignedLong: (unsigned long)value -{ - NSNumber *theObj = nil; - - // if class is NSNumber, replace by appropriate object - if (self == abstractClass) - { - if (value <= GS_SMALL) - { - return smallIntegers[value + GS_SMALL]; - } - theObj = (NSNumber*)NSAllocateObject(uLongNumberClass, 0, - NSDefaultMallocZone()); - theObj = [theObj initWithBytes: &value objCType: NULL]; - } - else // alloc class and init with object intWithXX method - { - theObj = [[self allocWithZone: NSDefaultMallocZone()] - initWithUnsignedLong: value]; - } - - return AUTORELEASE(theObj); -} - -+ (NSNumber*) numberWithUnsignedLongLong: (unsigned long long)value -{ - NSNumber *theObj = nil; - - // if class is NSNumber, replace by appropriate object - if (self == abstractClass) - { - if (value <= GS_SMALL) - { - return smallIntegers[value + GS_SMALL]; - } - theObj = (NSNumber*)NSAllocateObject(uLongLongNumberClass, 0, - NSDefaultMallocZone()); - theObj = [theObj initWithBytes: &value objCType: NULL]; - } - else // alloc class and init with object intWithXX method - { - theObj = [[self allocWithZone: NSDefaultMallocZone()] - initWithUnsignedLongLong: value]; - } - - return AUTORELEASE(theObj); -} - -+ (NSNumber*) numberWithUnsignedShort: (unsigned short)value -{ - NSNumber *theObj = nil; - - // if class is NSNumber, replace by appropriate object - if (self == abstractClass) - { - if (value <= GS_SMALL) - { - return smallIntegers[value + GS_SMALL]; - } - theObj = (NSNumber*)NSAllocateObject(uShortNumberClass, 0, - NSDefaultMallocZone()); - theObj = [theObj initWithBytes: &value objCType: NULL]; - } - else // alloc class and init with object intWithXX method - { - theObj = [[self allocWithZone: NSDefaultMallocZone()] - initWithUnsignedShort: value]; - } - - return AUTORELEASE(theObj); -} - -/* - * A moderately sane default init method - a zero value integer. - */ -- (id) init -{ - return [self initWithInt: 0]; -} - -- (id) initWithBool: (BOOL)value -{ - RELEASE(self); - if (value == NO) - { - self = boolN; - } - else - { - self = boolY; - } - return RETAIN(self); -} - -- (id) initWithBytes: (const void*)data objCType: (const char*)type -{ - if (GSObjCClass(self) == abstractClass) - { - Class c = [abstractClass valueClassWithObjCType: type]; - - [self release]; - self = (id)NSAllocateObject(c, 0, GSObjCZone(self)); - return [self initWithBytes: data objCType: type]; - } + /* All concrete NSNumber types must implement this so we know which oen + * they are. + */ [self subclassResponsibility: _cmd]; - return nil; + return NULL; // Not reached } -- (id) initWithChar: (signed char)value +- (BOOL) isEqualToNumber: (NSNumber*)aNumber { - RELEASE(self); - if (value <= GS_SMALL && value >= -GS_SMALL) + return [self compare: aNumber] == NSOrderedSame; +} + +- (BOOL) isEqual: (id)anObject +{ + if ([anObject isKindOfClass: NSNumberClass]) { - return RETAIN(smallIntegers[value + GS_SMALL]); + return [self isEqualToNumber: anObject]; } - self = (NSNumber*)NSAllocateObject(charNumberClass, 0, - NSDefaultMallocZone()); - self = [self initWithBytes: &value objCType: NULL]; - return self; + return [super isEqual: anObject]; } -- (id) initWithDouble: (double)value +- (BOOL) isEqualToValue: (NSValue*)aValue { - RELEASE(self); - self = (NSNumber*)NSAllocateObject(doubleNumberClass, 0, - NSDefaultMallocZone()); - self = [self initWithBytes: &value objCType: NULL]; - return self; -} - -- (id) initWithFloat: (float)value -{ - RELEASE(self); - self = (NSNumber*)NSAllocateObject(floatNumberClass, 0, - NSDefaultMallocZone()); - self = [self initWithBytes: &value objCType: NULL]; - return self; -} - -- (id) initWithInt: (signed int)value -{ - RELEASE(self); - if (value <= GS_SMALL && value >= -GS_SMALL) + if ([aValue isKindOfClass: NSNumberClass]) { - return RETAIN(smallIntegers[value + GS_SMALL]); - } - self = (NSNumber*)NSAllocateObject(intNumberClass, 0, - NSDefaultMallocZone()); - self = [self initWithBytes: &value objCType: NULL]; - return self; -} - -- (id) initWithInteger: (NSInteger)value -{ - RELEASE(self); - if (value <= GS_SMALL && value >= -GS_SMALL) - { - return RETAIN(smallIntegers[value + GS_SMALL]); - } - self = (NSNumber*)NSAllocateObject(integerNumberClass, 0, - NSDefaultMallocZone()); - self = [self initWithBytes: &value objCType: NULL]; - return self; -} - -- (id) initWithLong: (signed long)value -{ - RELEASE(self); - if (value <= GS_SMALL && value >= -GS_SMALL) - { - return RETAIN(smallIntegers[value + GS_SMALL]); - } - self = (NSNumber*)NSAllocateObject(longNumberClass, 0, - NSDefaultMallocZone()); - self = [self initWithBytes: &value objCType: NULL]; - return self; -} - -- (id) initWithLongLong: (signed long long)value -{ - RELEASE(self); - if (value <= GS_SMALL && value >= -GS_SMALL) - { - return RETAIN(smallIntegers[value + GS_SMALL]); - } - self = (NSNumber*)NSAllocateObject(longLongNumberClass, 0, - NSDefaultMallocZone()); - self = [self initWithBytes: &value objCType: NULL]; - return self; -} - -- (id) initWithShort: (signed short)value -{ - RELEASE(self); - if (value <= GS_SMALL && value >= -GS_SMALL) - { - return RETAIN(smallIntegers[value + GS_SMALL]); - } - self = (NSNumber*)NSAllocateObject(shortNumberClass, 0, - NSDefaultMallocZone()); - self = [self initWithBytes: &value objCType: NULL]; - return self; -} - -- (id) initWithUnsignedChar: (unsigned char)value -{ - RELEASE(self); - if (value <= GS_SMALL) - { - return RETAIN(smallIntegers[value + GS_SMALL]); - } - self = (NSNumber*)NSAllocateObject(uCharNumberClass, 0, - NSDefaultMallocZone()); - self = [self initWithBytes: &value objCType: NULL]; - return self; -} - -- (id) initWithUnsignedInt: (unsigned int)value -{ - RELEASE(self); - if (value <= GS_SMALL) - { - return RETAIN(smallIntegers[value + GS_SMALL]); - } - self = (NSNumber*)NSAllocateObject(uIntNumberClass, 0, - NSDefaultMallocZone()); - self = [self initWithBytes: &value objCType: NULL]; - return self; -} - -- (id) initWithUnsignedInteger: (NSUInteger)value -{ - RELEASE(self); - if (value <= GS_SMALL) - { - return RETAIN(smallIntegers[value + GS_SMALL]); - } - self = (NSNumber*)NSAllocateObject(uIntegerNumberClass, 0, - NSDefaultMallocZone()); - self = [self initWithBytes: &value objCType: NULL]; - return self; -} - -- (id) initWithUnsignedLong: (unsigned long)value -{ - RELEASE(self); - if (value <= GS_SMALL) - { - return RETAIN(smallIntegers[value + GS_SMALL]); - } - self = (NSNumber*)NSAllocateObject(uLongNumberClass, 0, - NSDefaultMallocZone()); - self = [self initWithBytes: &value objCType: NULL]; - return self; -} - -- (id) initWithUnsignedLongLong: (unsigned long long)value -{ - RELEASE(self); - if (value <= GS_SMALL) - { - return RETAIN(smallIntegers[value + GS_SMALL]); - } - self = (NSNumber*)NSAllocateObject(uLongLongNumberClass, 0, - NSDefaultMallocZone()); - self = [self initWithBytes: &value objCType: NULL]; - return self; -} - -- (id) initWithUnsignedShort: (unsigned short)value -{ - RELEASE(self); - if (value <= GS_SMALL) - { - return RETAIN(smallIntegers[value + GS_SMALL]); - } - self = (NSNumber*)NSAllocateObject(uShortNumberClass, 0, - NSDefaultMallocZone()); - self = [self initWithBytes: &value objCType: NULL]; - return self; -} - -- (id) copyWithZone: (NSZone*)zone -{ - if (NSShouldRetainWithZone(self, zone)) - return RETAIN(self); - else - return NSCopyObject(self, 0, zone); -} - -- (NSString*) description -{ - return [self descriptionWithLocale: nil]; -} - -- (NSString*) descriptionWithLocale: (NSDictionary*)locale -{ - NSString *result = nil; - - if (GSObjCClass(self) == abstractClass) - { - [NSException raise: NSInternalInconsistencyException - format: @"descriptionWithLocale: for abstract NSNumber"]; - } - else - { - GSNumberInfo *info = GSNumberInfoFromObject(self); - - switch (info->typeLevel) - { - case 0: - return [self boolValue] ? @"1" : @"0"; - break; - - case 1: - result = [[NSString alloc] initWithFormat: @"%i" locale: locale, - (int)[self charValue]]; - break; - - case 2: - result = [[NSString alloc] initWithFormat: @"%u" locale: locale, - (unsigned int)[self unsignedCharValue]]; - break; - - case 3: - result = [[NSString alloc] initWithFormat: @"%hi" locale: locale, - [self shortValue]]; - break; - - case 4: - result = [[NSString alloc] initWithFormat: @"%hu" locale: locale, - [self unsignedShortValue]]; - break; - - case 5: - result = [[NSString alloc] initWithFormat: @"%i" locale: locale, - [self intValue]]; - break; - - case 6: - result = [[NSString alloc] initWithFormat: @"%u" locale: locale, - [self unsignedIntValue]]; - break; - - case 7: - result = [[NSString alloc] initWithFormat: @"%li" locale: locale, - [self longValue]]; - break; - - case 8: - result = [[NSString alloc] initWithFormat: @"%lu" locale: locale, - [self unsignedLongValue]]; - break; - - case 9: - result = [[NSString alloc] initWithFormat: @"%lli" locale: locale, - [self longLongValue]]; - break; - - case 10: - result = [[NSString alloc] initWithFormat: @"%llu" locale: locale, - [self unsignedLongLongValue]]; - break; - - case 11: - result = [[NSString alloc] initWithFormat: @"%0.7g" locale: locale, - (double)[self floatValue]]; - break; - - case 12: - result = [[NSString alloc] initWithFormat: @"%0.16g" locale: locale, - [self doubleValue]]; - break; - - default: - [NSException raise: NSInvalidArgumentException - format: @"unknown number type value for description"]; - } - } - return AUTORELEASE(result); -} - -/* All the rest of these methods must be implemented by a subclass */ -- (BOOL) boolValue -{ - if (GSObjCClass(self) == abstractClass) - [NSException raise: NSInternalInconsistencyException - format: @"get boolValue from abstract NSNumber"]; - else - { - GSNumberInfo *info = GSNumberInfoFromObject(self); - - switch (info->typeLevel) - { - case 0: - { - BOOL oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return (oData == 0) ? NO : YES; - } - case 1: - { - signed char oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return (oData == 0) ? NO : YES; - } - case 2: - { - unsigned char oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return (oData == 0) ? NO : YES; - } - case 3: - { - signed short oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return (oData == 0) ? NO : YES; - } - case 4: - { - unsigned short oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return (oData == 0) ? NO : YES; - } - case 5: - { - signed int oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return (oData == 0) ? NO : YES; - } - case 6: - { - unsigned int oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return (oData == 0) ? NO : YES; - } - case 7: - { - signed long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return (oData == 0) ? NO : YES; - } - case 8: - { - unsigned long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return (oData == 0) ? NO : YES; - } - case 9: - { - signed long long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return (oData == 0) ? NO : YES; - } - case 10: - { - unsigned long long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return (oData == 0) ? NO : YES; - } - case 11: - { - float oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return (oData == 0) ? NO : YES; - } - case 12: - { - double oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return (oData == 0) ? NO : YES; - } - default: - [NSException raise: NSInvalidArgumentException - format: @"unknown number type value for get"]; - } + return [self isEqualToNumber: (NSNumber*)aValue]; } return NO; } -- (signed char) charValue +- (unsigned) hash { - if (GSObjCClass(self) == abstractClass) - [NSException raise: NSInternalInconsistencyException - format: @"get charValue from abstract NSNumber"]; - else - { - GSNumberInfo *info = GSNumberInfoFromObject(self); - - switch (info->typeLevel) - { - case 0: - { - BOOL oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 1: - { - signed char oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 2: - { - unsigned char oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 3: - { - signed short oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 4: - { - unsigned short oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 5: - { - signed int oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 6: - { - unsigned int oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 7: - { - signed long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 8: - { - unsigned long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 9: - { - signed long long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 10: - { - unsigned long long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 11: - { - float oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 12: - { - double oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - default: - [NSException raise: NSInvalidArgumentException - format: @"unknown number type value for get"]; - } - } - return 0; -} - -- (double) doubleValue -{ - if (GSObjCClass(self) == abstractClass) - [NSException raise: NSInternalInconsistencyException - format: @"get doubleValue from abstract NSNumber"]; - else - { - GSNumberInfo *info = GSNumberInfoFromObject(self); - - switch (info->typeLevel) - { - case 0: - { - BOOL oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 1: - { - signed char oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 2: - { - unsigned char oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 3: - { - signed short oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 4: - { - unsigned short oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 5: - { - signed int oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 6: - { - unsigned int oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 7: - { - signed long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 8: - { - unsigned long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 9: - { - signed long long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 10: - { - unsigned long long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 11: - { - float oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 12: - { - double oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - default: - [NSException raise: NSInvalidArgumentException - format: @"unknown number type value for get"]; - } - } - return 0; -} - -- (float) floatValue -{ - if (GSObjCClass(self) == abstractClass) - [NSException raise: NSInternalInconsistencyException - format: @"get floatValue from abstract NSNumber"]; - else - { - GSNumberInfo *info = GSNumberInfoFromObject(self); - - switch (info->typeLevel) - { - case 0: - { - BOOL oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 1: - { - signed char oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 2: - { - unsigned char oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 3: - { - signed short oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 4: - { - unsigned short oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 5: - { - signed int oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 6: - { - unsigned int oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 7: - { - signed long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 8: - { - unsigned long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 9: - { - signed long long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 10: - { - unsigned long long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 11: - { - float oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 12: - { - double oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - default: - [NSException raise: NSInvalidArgumentException - format: @"unknown number type value for get"]; - } - } - return 0; -} - -- (signed int) intValue -{ - if (GSObjCClass(self) == abstractClass) - [NSException raise: NSInternalInconsistencyException - format: @"get intValue from abstract NSNumber"]; - else - { - GSNumberInfo *info = GSNumberInfoFromObject(self); - - switch (info->typeLevel) - { - case 0: - { - BOOL oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 1: - { - signed char oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 2: - { - unsigned char oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 3: - { - signed short oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 4: - { - unsigned short oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 5: - { - signed int oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 6: - { - unsigned int oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 7: - { - signed long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 8: - { - unsigned long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 9: - { - signed long long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 10: - { - unsigned long long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 11: - { - float oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 12: - { - double oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - default: - [NSException raise: NSInvalidArgumentException - format: @"unknown number type value for get"]; - } - } - return 0; -} - -- (NSInteger) integerValue -{ - if (GSObjCClass(self) == abstractClass) - [NSException raise: NSInternalInconsistencyException - format: @"get integerValue from abstract NSNumber"]; - else - { - GSNumberInfo *info = GSNumberInfoFromObject(self); - - switch (info->typeLevel) - { - case 0: - { - BOOL oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 1: - { - signed char oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 2: - { - unsigned char oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 3: - { - signed short oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 4: - { - unsigned short oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 5: - { - signed int oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 6: - { - unsigned int oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 7: - { - signed long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 8: - { - unsigned long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 9: - { - signed long long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 10: - { - unsigned long long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 11: - { - float oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 12: - { - double oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - default: - [NSException raise: NSInvalidArgumentException - format: @"unknown number type value for get"]; - } - } - return 0; -} - -- (signed long long) longLongValue -{ - if (GSObjCClass(self) == abstractClass) - [NSException raise: NSInternalInconsistencyException - format: @"get longLongValue from abstract NSNumber"]; - else - { - GSNumberInfo *info = GSNumberInfoFromObject(self); - - switch (info->typeLevel) - { - case 0: - { - BOOL oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 1: - { - signed char oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 2: - { - unsigned char oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 3: - { - signed short oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 4: - { - unsigned short oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 5: - { - signed int oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 6: - { - unsigned int oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 7: - { - signed long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 8: - { - unsigned long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 9: - { - signed long long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 10: - { - unsigned long long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 11: - { - float oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 12: - { - double oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - default: - [NSException raise: NSInvalidArgumentException - format: @"unknown number type value for get"]; - } - } - return 0; -} - -- (signed long) longValue -{ - if (GSObjCClass(self) == abstractClass) - [NSException raise: NSInternalInconsistencyException - format: @"get longValue from abstract NSNumber"]; - else - { - GSNumberInfo *info = GSNumberInfoFromObject(self); - - switch (info->typeLevel) - { - case 0: - { - BOOL oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 1: - { - signed char oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 2: - { - unsigned char oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 3: - { - signed short oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 4: - { - unsigned short oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 5: - { - signed int oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 6: - { - unsigned int oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 7: - { - signed long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 8: - { - unsigned long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 9: - { - signed long long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 10: - { - unsigned long long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 11: - { - float oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 12: - { - double oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - default: - [NSException raise: NSInvalidArgumentException - format: @"unknown number type value for get"]; - } - } - return 0; -} - -- (signed short) shortValue -{ - if (GSObjCClass(self) == abstractClass) - [NSException raise: NSInternalInconsistencyException - format: @"get shortValue from abstract NSNumber"]; - else - { - GSNumberInfo *info = GSNumberInfoFromObject(self); - - switch (info->typeLevel) - { - case 0: - { - BOOL oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 1: - { - signed char oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 2: - { - unsigned char oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 3: - { - signed short oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 4: - { - unsigned short oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 5: - { - signed int oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 6: - { - unsigned int oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 7: - { - signed long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 8: - { - unsigned long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 9: - { - signed long long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 10: - { - unsigned long long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 11: - { - float oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 12: - { - double oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - default: - [NSException raise: NSInvalidArgumentException - format: @"unknown number type value for get"]; - } - } - return 0; + return (unsigned)[self doubleValue]; } - (NSString*) stringValue @@ -2002,841 +377,279 @@ static Class doubleNumberClass; return [self descriptionWithLocale: nil]; } -- (unsigned char) unsignedCharValue +- (NSString*) descriptionWithLocale: (id)aLocale { - if (GSObjCClass(self) == abstractClass) - [NSException raise: NSInternalInconsistencyException - format: @"get unsignedCharrValue from abstract NSNumber"]; - else - { - GSNumberInfo *info = GSNumberInfoFromObject(self); - - switch (info->typeLevel) - { - case 0: - { - BOOL oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 1: - { - signed char oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 2: - { - unsigned char oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 3: - { - signed short oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 4: - { - unsigned short oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 5: - { - signed int oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 6: - { - unsigned int oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 7: - { - signed long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 8: - { - unsigned long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 9: - { - signed long long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 10: - { - unsigned long long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 11: - { - float oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 12: - { - double oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - default: - [NSException raise: NSInvalidArgumentException - format: @"unknown number type value for get"]; - } - } - return 0; + [self subclassResponsibility: _cmd]; + return nil; // Not reached } -- (unsigned int) unsignedIntValue +- (NSComparisonResult) compare: (NSNumber*)aNumber { - if (GSObjCClass(self) == abstractClass) - [NSException raise: NSInternalInconsistencyException - format: @"get unsignedIntValue from abstract NSNumber"]; - else - { - GSNumberInfo *info = GSNumberInfoFromObject(self); - - switch (info->typeLevel) - { - case 0: - { - BOOL oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 1: - { - signed char oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 2: - { - unsigned char oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 3: - { - signed short oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 4: - { - unsigned short oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 5: - { - signed int oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 6: - { - unsigned int oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 7: - { - signed long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 8: - { - unsigned long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 9: - { - signed long long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 10: - { - unsigned long long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 11: - { - float oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 12: - { - double oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - default: - [NSException raise: NSInvalidArgumentException - format: @"unknown number type value for get"]; - } - } - return 0; + [self subclassResponsibility: _cmd]; + return 0; // Not reached } -- (NSUInteger) unsignedIntegerValue -{ - if (GSObjCClass(self) == abstractClass) - [NSException raise: NSInternalInconsistencyException - format: @"get unsignedIntegerValue from abstract NSNumber"]; - else - { - GSNumberInfo *info = GSNumberInfoFromObject(self); - - switch (info->typeLevel) - { - case 0: - { - BOOL oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 1: - { - signed char oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 2: - { - unsigned char oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 3: - { - signed short oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 4: - { - unsigned short oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 5: - { - signed int oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 6: - { - unsigned int oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 7: - { - signed long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 8: - { - unsigned long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 9: - { - signed long long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 10: - { - unsigned long long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 11: - { - float oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 12: - { - double oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - default: - [NSException raise: NSInvalidArgumentException - format: @"unknown number type value for get"]; - } - } - return 0; +#define INTEGER_MACRO(type, ignored, name) \ +- (id) initWith ## name: (type)aValue \ +{\ + [self release];\ + return [[NSNumberClass numberWith ## name: aValue] retain];\ } -- (unsigned long long) unsignedLongLongValue -{ - if (GSObjCClass(self) == abstractClass) - [NSException raise: NSInternalInconsistencyException - format: @"get unsignedLongLongValue from abstract NSNumber"]; - else - { - GSNumberInfo *info = GSNumberInfoFromObject(self); - - switch (info->typeLevel) - { - case 0: - { - BOOL oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 1: - { - signed char oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 2: - { - unsigned char oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 3: - { - signed short oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 4: - { - unsigned short oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 5: - { - signed int oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 6: - { - unsigned int oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 7: - { - signed long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 8: - { - unsigned long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 9: - { - signed long long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 10: - { - unsigned long long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 11: - { - float oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 12: - { - double oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - default: - [NSException raise: NSInvalidArgumentException - format: @"unknown number type value for get"]; - } - } - return 0; -} - -- (unsigned long) unsignedLongValue -{ - if (GSObjCClass(self) == abstractClass) - [NSException raise: NSInternalInconsistencyException - format: @"get unsignedLongValue from abstract NSNumber"]; - else - { - GSNumberInfo *info = GSNumberInfoFromObject(self); - - switch (info->typeLevel) - { - case 0: - { - BOOL oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 1: - { - signed char oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 2: - { - unsigned char oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 3: - { - signed short oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 4: - { - unsigned short oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 5: - { - signed int oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 6: - { - unsigned int oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 7: - { - signed long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 8: - { - unsigned long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 9: - { - signed long long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 10: - { - unsigned long long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 11: - { - float oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 12: - { - double oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - default: - [NSException raise: NSInvalidArgumentException - format: @"unknown number type value for get"]; - } - } - return 0; -} - -- (unsigned short) unsignedShortValue -{ - if (GSObjCClass(self) == abstractClass) - [NSException raise: NSInternalInconsistencyException - format: @"get unsignedShortValue from abstract NSNumber"]; - else - { - GSNumberInfo *info = GSNumberInfoFromObject(self); - - switch (info->typeLevel) - { - case 0: - { - BOOL oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 1: - { - signed char oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 2: - { - unsigned char oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 3: - { - signed short oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 4: - { - unsigned short oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 5: - { - signed int oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 6: - { - unsigned int oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 7: - { - signed long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 8: - { - unsigned long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 9: - { - signed long long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 10: - { - unsigned long long oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 11: - { - float oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - case 12: - { - double oData; - - (*(info->getValue))(self, @selector(getValue:), &oData); - return oData; - } - default: - [NSException raise: NSInvalidArgumentException - format: @"unknown number type value for get"]; - } - } - return 0; -} - -- (NSComparisonResult) compare: (NSNumber*)other -{ - double otherValue; - double myValue; - - if (other == self) - { - return NSOrderedSame; - } - else if (other == nil) - { - [NSException raise: NSInvalidArgumentException - format: @"nil argument for compare:"]; - } - - myValue = [self doubleValue]; - otherValue = [other doubleValue]; - - if (myValue == otherValue) - { - return NSOrderedSame; - } - else if (myValue < otherValue) - { - return NSOrderedAscending; - } - else - { - return NSOrderedDescending; - } -} +#include "GSNumberTypes.h" /* - * Because of the rule that two numbers which are the same according to - * [-isEqual: ] must generate the same hash, we must generate the hash - * from the most general representation of the number. - * NB. Don't change this without changing the matching function in - * NSConcreteNumber.m + * Macro for checking whether this value is the same as one of the singleton + * instances. */ -- (unsigned) hash -{ - union { - double d; - unsigned char c[sizeof(double)]; - } val; - unsigned hash = 0; - unsigned i; - - val.d = [self doubleValue]; - for (i = 0; i < sizeof(double); i++) - { - hash = (hash << 5) + hash + val.c[i]; - } - return hash; +#define CHECK_SINGLETON(aValue) \ +if (aValue >= -1 && aValue <= 12)\ +{\ + return ReusedInstances[aValue+1];\ } -- (BOOL) isEqual: (id)o ++ (NSNumber *) numberWithBool: (BOOL)aValue { - if (o == self) - { - return YES; - } - else if (o == nil) - { - return NO; - } - else if (GSObjCIsInstance(o) == YES - && GSObjCIsKindOf(GSObjCClass(o), abstractClass)) - { - return [self isEqualToNumber: (NSNumber*)o]; - } - else - { - return [super isEqual: o]; - } + CHECK_SINGLETON (((signed char) aValue)); + return [self numberWithInt: aValue]; + // Not reached (BOOL is always 0 or 1) } -- (BOOL) isEqualToNumber: (NSNumber*)o ++ (NSNumber *) numberWithChar: (signed char)aValue { - if (o == self) - { - return YES; - } - else if (o == nil) - { - return NO; - } - else if ([self compare: o] == NSOrderedSame) - { - return YES; - } - return NO; + return [self numberWithInt: aValue]; } -- (BOOL) isEqualToValue: (NSValue*)o ++ (NSNumber *) numberWithUnsignedChar: (unsigned char)aValue { - if (o == self) - { - return YES; - } - else if (o == nil) - { - return NO; - } - else if (GSObjCIsInstance(o) == YES - && GSObjCIsKindOf(GSObjCClass(o), abstractClass)) - { - return [self isEqualToNumber: (NSNumber*)o]; - } - return NO; + return [self numberWithInt: aValue]; } -/* - * NSCoding - */ ++ (NSNumber *) numberWithShort: (short)aValue +{ + return [self numberWithInt: aValue]; +} + ++ (NSNumber *) numberWithUnsignedShort: (unsigned short)aValue +{ + return [self numberWithInt: aValue]; +} + ++ (NSNumber *) numberWithInt: (int)aValue +{ + NSIntNumber *n; + + CHECK_SINGLETON (aValue); + n = NSAllocateObject (NSIntNumberClass, 0,[self zone]); + n->value = aValue; + return n; +} + ++ (NSNumber *) numberWithUnsignedInt: (unsigned int)aValue +{ + CHECK_SINGLETON (aValue); + + if (aValue < (unsigned int) INT_MAX) + { + return [self numberWithInt: (int)aValue]; + } + return [self numberWithLongLong: aValue]; +} + ++ (NSNumber *) numberWithLong: (long)aValue +{ + return [self numberWithLongLong: aValue]; +} + ++ (NSNumber *) numberWithUnsignedLong: (unsigned long)aValue +{ + return [self numberWithUnsignedLongLong: aValue]; +} + ++ (NSNumber *) numberWithLongLong: (long long)aValue +{ + NSLongLongNumber *n; + + CHECK_SINGLETON (aValue); + if (aValue < (long long)INT_MAX && aValue > (long long)INT_MIN) + { + return [self numberWithInt: (int) aValue]; + } + n = NSAllocateObject (NSLongLongNumberClass, 0,[self zone]); + n->value = aValue; + return n; +} + ++ (NSNumber *) numberWithUnsignedLongLong: (unsigned long long)aValue +{ + NSUnsignedLongLongNumber *n; + + if (aValue < (unsigned long long) LONG_LONG_MAX) + { + return [self numberWithLongLong: (long long) aValue]; + } + n = NSAllocateObject (NSUnsignedLongLongNumberClass, 0,[self zone]); + n->value = aValue; + return n; +} + ++ (NSNumber *) numberWithFloat: (float)aValue +{ + NSFloatNumber *n = NSAllocateObject (NSFloatNumberClass, 0,[self zone]); + + n->value = aValue; + return n; +} + ++ (NSNumber *) numberWithDouble: (double)aValue +{ + NSDoubleNumber *n = NSAllocateObject (NSDoubleNumberClass, 0,[self zone]); + + n->value = aValue; + return n; +} + ++ (NSNumber *) numberWithInteger: (NSInteger)aValue +{ + // Compile time constant; the compiler will remove this conditional + if (sizeof (NSInteger) == sizeof (int)) + { + return [self numberWithInt: aValue]; + } + return [self numberWithLongLong: aValue]; +} + ++ (NSNumber *) numberWithUnsignedInteger: (NSUInteger)aValue +{ + // Compile time constant; the compiler will remove this conditional + if (sizeof (NSUInteger) == sizeof (unsigned int)) + { + return [self numberWithUnsignedInt: aValue]; + } + return [self numberWithUnsignedLongLong: aValue]; +} + +- (id) initWithBytes: (const void *) + value objCType: (const char *)type +{ + switch (type[0]) + { + case 'c': + return [self initWithInteger: *(char *) value]; + case 'C': + return [self initWithInteger: *(unsigned char *) value]; + case 's': + return [self initWithInteger: *(short *) value]; + case 'S': + return [self initWithInteger: *(unsigned short *) value]; + case 'i': + return [self initWithInteger: *(int *) value]; + case 'I': + return [self initWithInteger: *(unsigned int *) value]; + case 'l': + return [self initWithLong: *(long *) value]; + case 'L': + return [self initWithUnsignedLong: *(unsigned long *) value]; + case 'q': + return [self initWithLongLong: *(long long *) value]; + case 'Q': + return [self initWithUnsignedLongLong: *(unsigned long long *) value]; + case 'f': + return [self initWithFloat: *(float *) value]; + case 'd': + return [self initWithDouble: *(double *) value]; + } + return [super initWithBytes: value objCType: type]; +} + +- (void *) pointerValue +{ + return (void *)[self unsignedIntegerValue]; +} + +- (id) replacementObjectForPortCoder: (NSPortCoder *) encoder +{ + return self; +} - (Class) classForCoder { - return abstractClass; + return NSNumberClass; } -- (id) replacementObjectForPortCoder: (NSPortCoder*)aCoder +- (void) encodeWithCoder: (NSCoder *) coder { - if ([aCoder isByref] == NO) - return self; - return [super replacementObjectForPortCoder: aCoder]; + const char *type = [self objCType]; + char buffer[16]; + + [coder encodeValueOfObjCType: @encode (char) at: type]; + /* The most we currently store in an NSNumber is 8 bytes (double or long + * long), but we may add support for vectors or long doubles in future, so + * make this 16 bytes now so stuff doesn't break in fun and exciting ways + * later. + */ + [self getValue: buffer]; + [coder encodeValueOfObjCType: type at: buffer]; } -- (void) encodeWithCoder: (NSCoder*)coder +- (id) copyWithZone: (NSZone *) aZone { - const char *t = [self objCType]; - - [coder encodeValueOfObjCType: @encode(signed char) at: t]; - [coder encodeValueOfObjCType: t at: [self pointerValue]]; -} - -- (id) initWithCoder: (NSCoder*)coder -{ - char t[2]; - union { - signed char c; - unsigned char C; - signed short s; - unsigned short S; - signed int i; - unsigned int I; - signed long l; - unsigned long L; - signed long long q; - unsigned long long Q; - float f; - double d; - } data; - - [coder decodeValueOfObjCType: @encode(signed char) at: t]; - t[1] = '\0'; - [coder decodeValueOfObjCType: t at: &data]; - switch (*t) + if (NSShouldRetainWithZone (self, aZone)) { - case 'c': self = [self initWithChar: data.c]; break; - case 'C': self = [self initWithUnsignedChar: data.C]; break; - case 's': self = [self initWithShort: data.s]; break; - case 'S': self = [self initWithUnsignedShort: data.S]; break; - case 'i': self = [self initWithInt: data.i]; break; - case 'I': self = [self initWithUnsignedInt: data.I]; break; - case 'l': self = [self initWithLong: data.l]; break; - case 'L': self = [self initWithUnsignedLong: data.L]; break; - case 'q': self = [self initWithLongLong: data.q]; break; - case 'Q': self = [self initWithUnsignedLongLong: data.Q]; break; - case 'f': self = [self initWithFloat: data.f]; break; - case 'd': self = [self initWithDouble: data.d]; break; - default: - DESTROY(self); - NSLog(@"Attempt to decode number with unknown ObjC type"); + return RETAIN (self); + } + else + { + return NSCopyObject (self, 0, aZone); } - return self; } + +- (id) initWithCoder: (NSCoder *) coder +{ + char type[2] = { 0 }; + char buffer[16]; + + [coder decodeValueOfObjCType: @encode (char) at: type]; + [coder decodeValueOfObjCType: type at: buffer]; + return [self initWithBytes: buffer objCType: type]; +} + +- (NSString *) description +{ + return [self stringValue]; +} + +/* Return nil for an NSNumber that is allocated and initalized without + * providing a real value. Yes, this seems weird, but it is actually what + * happens on OS X. + */ +- (id) init +{ + [self release]; + return nil; +} + +/* Stop the compiler complaining about unimplemented methods. Throwing an + * exception here matches OS X behaviour, although they throw an invalid + * argument exception. + */ +#define INTEGER_MACRO(type, name, ignored) \ +- (type) name ## Value\ +{\ + [self subclassResponsibility: _cmd];\ + return (type)0;\ +} + +#include "GSNumberTypes.h" +- (NSDecimal) decimalValue +{ + NSDecimalNumber *dn; + NSDecimal decimal; + + dn = [[NSDecimalNumber alloc] initWithString: [self stringValue]]; + decimal = [dn decimalValue]; + [dn release]; + return decimal; +} + @end