@@ -11,68 +11,47 @@ * Public License, either version 2 or 3, which can be found in the file * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this * file. */ -#define OF_NUMBER_M - #include "config.h" #include #import "OFNumber.h" +#import "OFConcreteNumber.h" #import "OFData.h" #import "OFString.h" +#import "OFTaggedPointerNumber.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFOutOfRangeException.h" @interface OFNumber () -+ (instancetype)of_alloc; - (OFString *) of_JSONRepresentationWithOptions: (OFJSONRepresentationOptions)options depth: (size_t)depth; @end @interface OFPlaceholderNumber: OFNumber @end -@interface OFNumberSingleton: OFNumber -@end - -#ifdef OF_OBJFW_RUNTIME -enum Tag { - tagChar, - tagShort, - tagInt, - tagLong, - tagLongLong, - tagUnsignedChar, - tagUnsignedShort, - tagUnsignedInt, - tagUnsignedLong, - tagUnsignedLongLong, -}; -static const uint_fast8_t tagBits = 4; -static const uintptr_t tagMask = 0xF; - -@interface OFTaggedPointerNumber: OFNumberSingleton -@end -#endif +@interface OFConcreteNumberSingleton: OFConcreteNumber +@end static struct { Class isa; } placeholder; -#define SINGLETON(var, sel, val) \ - static OFNumberSingleton *var; \ - \ - static void \ - var##Init(void) \ - { \ - var = [[OFNumberSingleton alloc] sel val]; \ +#define SINGLETON(var, sel, val) \ + static OFConcreteNumberSingleton *var; \ + \ + static void \ + var##Init(void) \ + { \ + var = [[OFConcreteNumberSingleton alloc] sel val]; \ } SINGLETON(falseNumber, initWithBool:, false) SINGLETON(trueNumber, initWithBool:, true) SINGLETON(charZeroNumber, initWithChar:, 0) SINGLETON(shortZeroNumber, initWithShort:, 0) @@ -86,28 +65,19 @@ SINGLETON(unsignedLongLongZeroNumber, initWithUnsignedLongLong:, 0) SINGLETON(floatZeroNumber, initWithFloat:, 0) SINGLETON(doubleZeroNumber, initWithDouble:, 0) #undef SINGLETON -#ifdef OF_OBJFW_RUNTIME -static int numberTag; -#endif - static bool isUnsigned(OFNumber *number) { switch (*number.objCType) { case 'B': - return true; case 'C': - return true; case 'S': - return true; case 'I': - return true; case 'L': - return true; case 'Q': return true; default: return false; } @@ -116,17 +86,13 @@ static bool isSigned(OFNumber *number) { switch (*number.objCType) { case 'c': - return true; case 's': - return true; case 'i': - return true; case 'l': - return true; case 'q': return true; default: return false; } @@ -135,11 +101,10 @@ static bool isFloat(OFNumber *number) { switch (*number.objCType) { case 'f': - return true; case 'd': return true; default: return false; } @@ -168,192 +133,187 @@ if (value == 0) { static OFOnceControl onceControl = OFOnceControlInitValue; OFOnce(&onceControl, charZeroNumberInit); return (id)charZeroNumber; #ifdef OF_OBJFW_RUNTIME - } else if ((unsigned char)value <= (UINTPTR_MAX >> tagBits)) { - id ret = objc_createTaggedPointer(numberTag, - ((uintptr_t)(unsigned char)value << tagBits) | tagChar); + } else if ((unsigned char)value <= + (UINTPTR_MAX >> OFTaggedPointerNumberTagBits)) { + id ret = [OFTaggedPointerNumber numberWithChar: value]; if (ret != nil) return ret; #endif } - return (id)[[OFNumber of_alloc] initWithChar: value]; + return (id)[[OFConcreteNumber alloc] initWithChar: value]; } - (instancetype)initWithShort: (short)value { if (value == 0) { static OFOnceControl onceControl = OFOnceControlInitValue; OFOnce(&onceControl, shortZeroNumberInit); return (id)shortZeroNumber; #ifdef OF_OBJFW_RUNTIME - } else if ((unsigned short)value <= (UINTPTR_MAX >> tagBits)) { - id ret = objc_createTaggedPointer(numberTag, - ((uintptr_t)(unsigned short)value << tagBits) | tagShort); + } else if ((unsigned short)value <= + (UINTPTR_MAX >> OFTaggedPointerNumberTagBits)) { + id ret = [OFTaggedPointerNumber numberWithShort: value]; if (ret != nil) return ret; #endif } - return (id)[[OFNumber of_alloc] initWithShort: value]; + return (id)[[OFConcreteNumber alloc] initWithShort: value]; } - (instancetype)initWithInt: (int)value { if (value == 0) { static OFOnceControl onceControl = OFOnceControlInitValue; OFOnce(&onceControl, intZeroNumberInit); return (id)intZeroNumber; #ifdef OF_OBJFW_RUNTIME - } else if ((unsigned int)value <= (UINTPTR_MAX >> tagBits)) { - id ret = objc_createTaggedPointer(numberTag, - ((uintptr_t)(unsigned int)value << tagBits) | tagInt); + } else if ((unsigned int)value <= + (UINTPTR_MAX >> OFTaggedPointerNumberTagBits)) { + id ret = [OFTaggedPointerNumber numberWithInt: value]; if (ret != nil) return ret; #endif } - return (id)[[OFNumber of_alloc] initWithInt: value]; + return (id)[[OFConcreteNumber alloc] initWithInt: value]; } - (instancetype)initWithLong: (long)value { if (value == 0) { static OFOnceControl onceControl = OFOnceControlInitValue; OFOnce(&onceControl, longZeroNumberInit); return (id)longZeroNumber; #ifdef OF_OBJFW_RUNTIME - } else if ((unsigned long)value <= (UINTPTR_MAX >> tagBits)) { - id ret = objc_createTaggedPointer(numberTag, - ((uintptr_t)(unsigned long)value << tagBits) | tagLong); + } else if ((unsigned long)value <= + (UINTPTR_MAX >> OFTaggedPointerNumberTagBits)) { + id ret = [OFTaggedPointerNumber numberWithLong: value]; if (ret != nil) return ret; #endif } - return (id)[[OFNumber of_alloc] initWithLong: value]; + return (id)[[OFConcreteNumber alloc] initWithLong: value]; } - (instancetype)initWithLongLong: (long long)value { if (value == 0) { static OFOnceControl onceControl = OFOnceControlInitValue; OFOnce(&onceControl, longLongZeroNumberInit); return (id)longLongZeroNumber; #ifdef OF_OBJFW_RUNTIME - } else if ((unsigned long long)value <= (UINTPTR_MAX >> tagBits)) { - id ret = objc_createTaggedPointer(numberTag, - ((uintptr_t)(unsigned long long)value << tagBits) | - tagLongLong); + } else if ((unsigned long long)value <= + (UINTPTR_MAX >> OFTaggedPointerNumberTagBits)) { + id ret = [OFTaggedPointerNumber numberWithLongLong: value]; if (ret != nil) return ret; #endif } - return (id)[[OFNumber of_alloc] initWithLongLong: value]; + return (id)[[OFConcreteNumber alloc] initWithLongLong: value]; } - (instancetype)initWithUnsignedChar: (unsigned char)value { if (value == 0) { static OFOnceControl onceControl = OFOnceControlInitValue; OFOnce(&onceControl, unsignedCharZeroNumberInit); return (id)unsignedCharZeroNumber; #ifdef OF_OBJFW_RUNTIME - } else if (value <= (UINTPTR_MAX >> tagBits)) { - id ret = objc_createTaggedPointer(numberTag, - ((uintptr_t)value << tagBits) | tagUnsignedChar); + } else if (value <= (UINTPTR_MAX >> OFTaggedPointerNumberTagBits)) { + id ret = [OFTaggedPointerNumber numberWithUnsignedChar: value]; if (ret != nil) return ret; #endif } - return (id)[[OFNumber of_alloc] initWithUnsignedChar: value]; + return (id)[[OFConcreteNumber alloc] initWithUnsignedChar: value]; } - (instancetype)initWithUnsignedShort: (unsigned short)value { if (value == 0) { static OFOnceControl onceControl = OFOnceControlInitValue; OFOnce(&onceControl, unsignedShortZeroNumberInit); return (id)unsignedShortZeroNumber; #ifdef OF_OBJFW_RUNTIME - } else if (value <= (UINTPTR_MAX >> tagBits)) { - id ret = objc_createTaggedPointer(numberTag, - ((uintptr_t)value << tagBits) | tagUnsignedShort); + } else if (value <= (UINTPTR_MAX >> OFTaggedPointerNumberTagBits)) { + id ret = [OFTaggedPointerNumber numberWithUnsignedShort: value]; if (ret != nil) return ret; #endif } - return (id)[[OFNumber of_alloc] initWithUnsignedShort: value]; + return (id)[[OFConcreteNumber alloc] initWithUnsignedShort: value]; } - (instancetype)initWithUnsignedInt: (unsigned int)value { if (value == 0) { static OFOnceControl onceControl = OFOnceControlInitValue; OFOnce(&onceControl, unsignedIntZeroNumberInit); return (id)unsignedIntZeroNumber; #ifdef OF_OBJFW_RUNTIME - } else if (value <= (UINTPTR_MAX >> tagBits)) { - id ret = objc_createTaggedPointer(numberTag, - ((uintptr_t)value << tagBits) | tagUnsignedInt); + } else if (value <= (UINTPTR_MAX >> OFTaggedPointerNumberTagBits)) { + id ret = [OFTaggedPointerNumber numberWithUnsignedInt: value]; if (ret != nil) return ret; #endif } - return (id)[[OFNumber of_alloc] initWithUnsignedInt: value]; + return (id)[[OFConcreteNumber alloc] initWithUnsignedInt: value]; } - (instancetype)initWithUnsignedLong: (unsigned long)value { if (value == 0) { static OFOnceControl onceControl = OFOnceControlInitValue; OFOnce(&onceControl, unsignedLongZeroNumberInit); return (id)unsignedLongZeroNumber; #ifdef OF_OBJFW_RUNTIME - } else if (value <= (UINTPTR_MAX >> tagBits)) { - id ret = objc_createTaggedPointer(numberTag, - ((uintptr_t)value << tagBits) | tagUnsignedLong); + } else if (value <= (UINTPTR_MAX >> OFTaggedPointerNumberTagBits)) { + id ret = [OFTaggedPointerNumber numberWithUnsignedLong: value]; if (ret != nil) return ret; #endif } - return (id)[[OFNumber of_alloc] initWithUnsignedLong: value]; + return (id)[[OFConcreteNumber alloc] initWithUnsignedLong: value]; } - (instancetype)initWithUnsignedLongLong: (unsigned long long)value { if (value == 0) { static OFOnceControl onceControl = OFOnceControlInitValue; OFOnce(&onceControl, unsignedLongLongZeroNumberInit); return (id)unsignedLongLongZeroNumber; #ifdef OF_OBJFW_RUNTIME - } else if (value <= (UINTPTR_MAX >> tagBits)) { - id ret = objc_createTaggedPointer(numberTag, - ((uintptr_t)value << tagBits) | tagUnsignedLongLong); + } else if (value <= (UINTPTR_MAX >> OFTaggedPointerNumberTagBits)) { + id ret = [OFTaggedPointerNumber + numberWithUnsignedLongLong: value]; if (ret != nil) return ret; #endif } - return (id)[[OFNumber of_alloc] initWithUnsignedLongLong: value]; + return (id)[[OFConcreteNumber alloc] initWithUnsignedLongLong: value]; } - (instancetype)initWithFloat: (float)value { if (value == 0) { @@ -360,11 +320,11 @@ static OFOnceControl onceControl = OFOnceControlInitValue; OFOnce(&onceControl, floatZeroNumberInit); return (id)floatZeroNumber; } - return (id)[[OFNumber of_alloc] initWithFloat: value]; + return (id)[[OFConcreteNumber alloc] initWithFloat: value]; } - (instancetype)initWithDouble: (double)value { if (value == 0) { @@ -371,117 +331,28 @@ static OFOnceControl onceControl = OFOnceControlInitValue; OFOnce(&onceControl, doubleZeroNumberInit); return (id)doubleZeroNumber; } - return (id)[[OFNumber of_alloc] initWithDouble: value]; + return (id)[[OFConcreteNumber alloc] initWithDouble: value]; } #ifdef __clang__ # pragma clang diagnostic pop #endif OF_SINGLETON_METHODS @end -@implementation OFNumberSingleton +@implementation OFConcreteNumberSingleton OF_SINGLETON_METHODS @end -#ifdef OF_OBJFW_RUNTIME -@implementation OFTaggedPointerNumber -- (const char *)objCType -{ - uintptr_t value = object_getTaggedPointerValue(self); - - switch (value & tagMask) { - case tagChar: - return @encode(signed char); - case tagShort: - return @encode(short); - case tagInt: - return @encode(int); - case tagLong: - return @encode(long); - case tagLongLong: - return @encode(long long); - case tagUnsignedChar: - return @encode(unsigned char); - case tagUnsignedShort: - return @encode(unsigned short); - case tagUnsignedInt: - return @encode(unsigned int); - case tagUnsignedLong: - return @encode(unsigned long); - case tagUnsignedLongLong: - return @encode(unsigned long long); - default: - @throw [OFInvalidArgumentException exception]; - } -} - -# define RETURN_VALUE \ - uintptr_t value = object_getTaggedPointerValue(self); \ - \ - switch (value & tagMask) { \ - case tagChar: \ - return (signed char)(unsigned char)(value >> tagBits); \ - case tagShort: \ - return (short)(unsigned short)(value >> tagBits); \ - case tagInt: \ - return (int)(unsigned int)(value >> tagBits); \ - case tagLong: \ - return (long)(unsigned long)(value >> tagBits); \ - case tagLongLong: \ - return (long long)(unsigned long long)(value >> tagBits); \ - case tagUnsignedChar: \ - return (unsigned char)(value >> tagBits); \ - case tagUnsignedShort: \ - return (unsigned short)(value >> tagBits); \ - case tagUnsignedInt: \ - return (unsigned int)(value >> tagBits); \ - case tagUnsignedLong: \ - return (unsigned long)(value >> tagBits); \ - case tagUnsignedLongLong: \ - return (unsigned long long)(value >> tagBits); \ - default: \ - @throw [OFInvalidArgumentException exception]; \ - } -- (long long)longLongValue -{ - RETURN_VALUE -} - -- (unsigned long long)unsignedLongLongValue -{ - RETURN_VALUE -} - -- (double)doubleValue -{ - RETURN_VALUE -} -@end -# undef RETURN_VALUE -#endif - @implementation OFNumber + (void)initialize { - if (self != [OFNumber class]) - return; - - object_setClass((id)&placeholder, [OFPlaceholderNumber class]); - -#ifdef OF_OBJFW_RUNTIME - numberTag = - objc_registerTaggedPointerClass([OFTaggedPointerNumber class]); -#endif -} - -+ (instancetype)of_alloc -{ - return [super alloc]; + if (self == [OFNumber class]) + object_setClass((id)&placeholder, [OFPlaceholderNumber class]); } + (instancetype)alloc { if (self == [OFNumber class]) @@ -488,16 +359,10 @@ return (id)&placeholder; return [super alloc]; } -+ (instancetype)valueWithBytes: (const void *)bytes - objCType: (const char *)objCType -{ - OF_UNRECOGNIZED_SELECTOR -} - + (instancetype)valueWithPointer: (const void *)pointer { OF_UNRECOGNIZED_SELECTOR } @@ -589,223 +454,89 @@ + (instancetype)numberWithDouble: (double)value { return [[[self alloc] initWithDouble: value] autorelease]; } -- (instancetype)init -{ - OF_INVALID_INIT_METHOD -} - -- (instancetype)initWithBytes: (const void *)bytes - objCType: (const char *)objCType -{ - OF_INVALID_INIT_METHOD -} - - (instancetype)initWithBool: (bool)value { - self = [super initWithBytes: &value objCType: @encode(bool)]; - - _value.unsigned_ = value; - _typeEncoding = @encode(bool); - - return self; + return [self initWithBytes: &value objCType: @encode(bool)]; } - (instancetype)initWithChar: (signed char)value { - self = [super initWithBytes: &value objCType: @encode(signed char)]; - - _value.signed_ = value; - _typeEncoding = @encode(signed char); - - return self; + return [self initWithBytes: &value objCType: @encode(signed char)]; } - (instancetype)initWithShort: (short)value { - self = [super initWithBytes: &value objCType: @encode(short)]; - - _value.signed_ = value; - _typeEncoding = @encode(short); - - return self; + return [self initWithBytes: &value objCType: @encode(short)]; } - (instancetype)initWithInt: (int)value { - self = [super initWithBytes: &value objCType: @encode(int)]; - - _value.signed_ = value; - _typeEncoding = @encode(int); - - return self; + return [self initWithBytes: &value objCType: @encode(int)]; } - (instancetype)initWithLong: (long)value { - self = [super initWithBytes: &value objCType: @encode(long)]; - - _value.signed_ = value; - _typeEncoding = @encode(long); - - return self; + return [self initWithBytes: &value objCType: @encode(long)]; } - (instancetype)initWithLongLong: (long long)value { - self = [super initWithBytes: &value objCType: @encode(long long)]; - - _value.signed_ = value; - _typeEncoding = @encode(long long); - - return self; + return [self initWithBytes: &value objCType: @encode(long long)]; } - (instancetype)initWithUnsignedChar: (unsigned char)value { - self = [super initWithBytes: &value objCType: @encode(unsigned char)]; - - _value.unsigned_ = value; - _typeEncoding = @encode(unsigned char); - - return self; + return [self initWithBytes: &value objCType: @encode(unsigned char)]; } - (instancetype)initWithUnsignedShort: (unsigned short)value { - self = [super initWithBytes: &value objCType: @encode(unsigned short)]; - - _value.unsigned_ = value; - _typeEncoding = @encode(unsigned short); - - return self; + return [self initWithBytes: &value objCType: @encode(unsigned short)]; } - (instancetype)initWithUnsignedInt: (unsigned int)value { - self = [super initWithBytes: &value objCType: @encode(unsigned int)]; - - _value.unsigned_ = value; - _typeEncoding = @encode(unsigned int); - - return self; + return [self initWithBytes: &value objCType: @encode(unsigned int)]; } - (instancetype)initWithUnsignedLong: (unsigned long)value { - self = [super initWithBytes: &value objCType: @encode(unsigned long)]; - - _value.unsigned_ = value; - _typeEncoding = @encode(unsigned long); - - return self; + return [self initWithBytes: &value objCType: @encode(unsigned long)]; } - (instancetype)initWithUnsignedLongLong: (unsigned long long)value { - self = [super initWithBytes: &value - objCType: @encode(unsigned long long)]; - - _value.unsigned_ = value; - _typeEncoding = @encode(unsigned long long); - - return self; + return [self initWithBytes: &value + objCType: @encode(unsigned long long)]; } - (instancetype)initWithFloat: (float)value { - self = [super initWithBytes: &value objCType: @encode(float)]; - - _value.float_ = value; - _typeEncoding = @encode(float); - - return self; + return [self initWithBytes: &value objCType: @encode(float)]; } - (instancetype)initWithDouble: (double)value { - self = [super initWithBytes: &value objCType: @encode(double)]; - - _value.float_ = value; - _typeEncoding = @encode(double); - - return self; -} - -- (const char *)objCType -{ - return _typeEncoding; -} - -- (void)getValue: (void *)value size: (size_t)size -{ - switch (*self.objCType) { -#define CASE(enc, type, property) \ - case enc: { \ - type tmp = (type)self.property; \ - \ - if (size != sizeof(type)) \ - @throw [OFOutOfRangeException exception]; \ - \ - memcpy(value, &tmp, size); \ - break; \ - } - CASE('B', bool, unsignedLongLongValue) - CASE('c', signed char, longLongValue) - CASE('s', short, longLongValue) - CASE('i', int, longLongValue) - CASE('l', long, longLongValue) - CASE('q', long long, longLongValue) - CASE('C', unsigned char, unsignedLongLongValue) - CASE('S', unsigned short, unsignedLongLongValue) - CASE('I', unsigned int, unsignedLongLongValue) - CASE('L', unsigned long, unsignedLongLongValue) - CASE('Q', unsigned long long, unsignedLongLongValue) - CASE('f', float, doubleValue) - CASE('d', double, doubleValue) -#undef CASE - default: - @throw [OFInvalidFormatException exception]; - } + return [self initWithBytes: &value objCType: @encode(double)]; } - (long long)longLongValue { - if (isFloat(self)) - return _value.float_; - else if (isSigned(self)) - return _value.signed_; - else if (isUnsigned(self)) - return _value.unsigned_; - else - @throw [OFInvalidFormatException exception]; + OF_UNRECOGNIZED_SELECTOR } - (unsigned long long)unsignedLongLongValue { - if (isFloat(self)) - return _value.float_; - else if (isSigned(self)) - return _value.signed_; - else if (isUnsigned(self)) - return _value.unsigned_; - else - @throw [OFInvalidFormatException exception]; + OF_UNRECOGNIZED_SELECTOR } - (double)doubleValue { - if (isFloat(self)) - return _value.float_; - else if (isSigned(self)) - return _value.signed_; - else if (isUnsigned(self)) - return _value.unsigned_; - else - @throw [OFInvalidFormatException exception]; + OF_UNRECOGNIZED_SELECTOR } - (bool)boolValue { return (bool)self.unsignedLongLongValue; @@ -965,11 +696,11 @@ return [self stringValue]; } - (OFString *)stringValue { - if (*self.objCType == 'B') + if (self.objCType[0] == 'B' && self.objCType[1] == '\0') return (self.boolValue ? @"true" : @"false"); if (isFloat(self)) return [OFString stringWithFormat: @"%g", self.doubleValue]; if (isSigned(self)) return [OFString stringWithFormat: @"%lld", self.longLongValue]; @@ -995,11 +726,11 @@ of_JSONRepresentationWithOptions: (OFJSONRepresentationOptions)options depth: (size_t)depth { double doubleValue; - if (*self.objCType == 'B') + if (self.objCType[0] == 'B' && self.objCType[1] == '\0') return (self.boolValue ? @"true" : @"false"); doubleValue = self.doubleValue; if (isinf(doubleValue)) { if (options & OFJSONRepresentationOptionJSON5) { @@ -1016,10 +747,13 @@ - (OFData *)messagePackRepresentation { OFMutableData *data; const char *typeEncoding = self.objCType; + + if (typeEncoding[0] == '\0' || typeEncoding[1] != '\0') + @throw [OFInvalidFormatException exception]; if (*typeEncoding == 'B') { uint8_t type = (self.boolValue ? 0xC3 : 0xC2); data = [OFMutableData dataWithItems: &type count: 1]; } else if (*typeEncoding == 'f') {