/* * Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, * 2018 * Jonathan Schleifer <js@heap.zone> * * All rights reserved. * * This file is part of ObjFW. It may be distributed under the terms of the * Q Public License 1.0, which can be found in the file LICENSE.QPL included in * the packaging of this file. * * Alternatively, it may be distributed under the terms of the GNU General * 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. */ #include "config.h" #include <math.h> #import "OFNumber.h" #import "OFString.h" #import "OFXMLElement.h" #import "OFXMLAttribute.h" #import "OFData.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFOutOfRangeException.h" #define RETURN_AS(t) \ switch (_type) { \ case OF_NUMBER_TYPE_BOOL: \ return (t)_value.bool_; \ case OF_NUMBER_TYPE_CHAR: \ return (t)_value.sChar; \ case OF_NUMBER_TYPE_SHORT: \ return (t)_value.sShort; \ case OF_NUMBER_TYPE_INT: \ return (t)_value.sInt; \ case OF_NUMBER_TYPE_LONG: \ return (t)_value.sLong; \ case OF_NUMBER_TYPE_LONGLONG: \ return (t)_value.sLongLong; \ case OF_NUMBER_TYPE_UCHAR: \ return (t)_value.uChar; \ case OF_NUMBER_TYPE_USHORT: \ return (t)_value.uShort; \ case OF_NUMBER_TYPE_UINT: \ return (t)_value.uInt; \ case OF_NUMBER_TYPE_ULONG: \ return (t)_value.uLong; \ case OF_NUMBER_TYPE_ULONGLONG: \ return (t)_value.uLongLong; \ case OF_NUMBER_TYPE_INT8: \ return (t)_value.int8; \ case OF_NUMBER_TYPE_INT16: \ return (t)_value.int16; \ case OF_NUMBER_TYPE_INT32: \ return (t)_value.int32; \ case OF_NUMBER_TYPE_INT64: \ return (t)_value.int64; \ case OF_NUMBER_TYPE_UINT8: \ return (t)_value.uInt8; \ case OF_NUMBER_TYPE_UINT16: \ return (t)_value.uInt16; \ case OF_NUMBER_TYPE_UINT32: \ return (t)_value.uInt32; \ case OF_NUMBER_TYPE_UINT64: \ return (t)_value.uInt64; \ case OF_NUMBER_TYPE_SIZE: \ return (t)_value.size; \ case OF_NUMBER_TYPE_SSIZE: \ return (t)_value.sSize; \ case OF_NUMBER_TYPE_INTMAX: \ return (t)_value.intMax; \ case OF_NUMBER_TYPE_UINTMAX: \ return (t)_value.uIntMax; \ case OF_NUMBER_TYPE_PTRDIFF: \ return (t)_value.ptrDiff; \ case OF_NUMBER_TYPE_INTPTR: \ return (t)_value.intPtr; \ case OF_NUMBER_TYPE_UINTPTR: \ return (t)_value.uIntPtr; \ case OF_NUMBER_TYPE_FLOAT: \ return (t)_value.float_; \ case OF_NUMBER_TYPE_DOUBLE: \ return (t)_value.double_; \ default: \ @throw [OFInvalidFormatException exception]; \ } @interface OFNumber () - (OFString *)of_JSONRepresentationWithOptions: (int)options depth: (size_t)depth; @end @implementation OFNumber @synthesize type = _type; + (instancetype)numberWithBool: (bool)bool_ { return [[[self alloc] initWithBool: bool_] autorelease]; } + (instancetype)numberWithChar: (signed char)sChar { return [[[self alloc] initWithChar: sChar] autorelease]; } + (instancetype)numberWithShort: (signed short)sShort { return [[[self alloc] initWithShort: sShort] autorelease]; } + (instancetype)numberWithInt: (signed int)sInt { return [[[self alloc] initWithInt: sInt] autorelease]; } + (instancetype)numberWithLong: (signed long)sLong { return [[[self alloc] initWithLong: sLong] autorelease]; } + (instancetype)numberWithLongLong: (signed long long)sLongLong { return [[[self alloc] initWithLongLong: sLongLong] autorelease]; } + (instancetype)numberWithUnsignedChar: (unsigned char)uChar { return [[[self alloc] initWithUnsignedChar: uChar] autorelease]; } + (instancetype)numberWithUnsignedShort: (unsigned short)uShort { return [[[self alloc] initWithUnsignedShort: uShort] autorelease]; } + (instancetype)numberWithUnsignedInt: (unsigned int)uInt { return [[[self alloc] initWithUnsignedInt: uInt] autorelease]; } + (instancetype)numberWithUnsignedLong: (unsigned long)uLong { return [[[self alloc] initWithUnsignedLong: uLong] autorelease]; } + (instancetype)numberWithUnsignedLongLong: (unsigned long long)uLongLong { return [[[self alloc] initWithUnsignedLongLong: uLongLong] autorelease]; } + (instancetype)numberWithInt8: (int8_t)int8 { return [[[self alloc] initWithInt8: int8] autorelease]; } + (instancetype)numberWithInt16: (int16_t)int16 { return [[[self alloc] initWithInt16: int16] autorelease]; } + (instancetype)numberWithInt32: (int32_t)int32 { return [[[self alloc] initWithInt32: int32] autorelease]; } + (instancetype)numberWithInt64: (int64_t)int64 { return [[[self alloc] initWithInt64: int64] autorelease]; } + (instancetype)numberWithUInt8: (uint8_t)uInt8 { return [[[self alloc] initWithUInt8: uInt8] autorelease]; } + (instancetype)numberWithUInt16: (uint16_t)uInt16 { return [[[self alloc] initWithUInt16: uInt16] autorelease]; } + (instancetype)numberWithUInt32: (uint32_t)uInt32 { return [[[self alloc] initWithUInt32: uInt32] autorelease]; } + (instancetype)numberWithUInt64: (uint64_t)uInt64 { return [[[self alloc] initWithUInt64: uInt64] autorelease]; } + (instancetype)numberWithSize: (size_t)size { return [[[self alloc] initWithSize: size] autorelease]; } + (instancetype)numberWithSSize: (ssize_t)sSize { return [[[self alloc] initWithSSize: sSize] autorelease]; } + (instancetype)numberWithIntMax: (intmax_t)intMax { return [[[self alloc] initWithIntMax: intMax] autorelease]; } + (instancetype)numberWithUIntMax: (uintmax_t)uIntMax { return [[[self alloc] initWithUIntMax: uIntMax] autorelease]; } + (instancetype)numberWithPtrDiff: (ptrdiff_t)ptrDiff { return [[[self alloc] initWithPtrDiff: ptrDiff] autorelease]; } + (instancetype)numberWithIntPtr: (intptr_t)intPtr { return [[[self alloc] initWithIntPtr: intPtr] autorelease]; } + (instancetype)numberWithUIntPtr: (uintptr_t)uIntPtr { return [[[self alloc] initWithUIntPtr: uIntPtr] autorelease]; } + (instancetype)numberWithFloat: (float)float_ { return [[[self alloc] initWithFloat: float_] autorelease]; } + (instancetype)numberWithDouble: (double)double_ { return [[[self alloc] initWithDouble: double_] autorelease]; } - (instancetype)init { OF_INVALID_INIT_METHOD } - (instancetype)initWithBool: (bool)bool_ { self = [super init]; _value.bool_ = bool_; _type = OF_NUMBER_TYPE_BOOL; return self; } - (instancetype)initWithChar: (signed char)sChar { self = [super init]; _value.sChar = sChar; _type = OF_NUMBER_TYPE_CHAR; return self; } - (instancetype)initWithShort: (signed short)sShort { self = [super init]; _value.sShort = sShort; _type = OF_NUMBER_TYPE_SHORT; return self; } - (instancetype)initWithInt: (signed int)sInt { self = [super init]; _value.sInt = sInt; _type = OF_NUMBER_TYPE_INT; return self; } - (instancetype)initWithLong: (signed long)sLong { self = [super init]; _value.sLong = sLong; _type = OF_NUMBER_TYPE_LONG; return self; } - (instancetype)initWithLongLong: (signed long long)sLongLong { self = [super init]; _value.sLongLong = sLongLong; _type = OF_NUMBER_TYPE_LONGLONG; return self; } - (instancetype)initWithUnsignedChar: (unsigned char)uChar { self = [super init]; _value.uChar = uChar; _type = OF_NUMBER_TYPE_UCHAR; return self; } - (instancetype)initWithUnsignedShort: (unsigned short)uShort { self = [super init]; _value.uShort = uShort; _type = OF_NUMBER_TYPE_USHORT; return self; } - (instancetype)initWithUnsignedInt: (unsigned int)uInt { self = [super init]; _value.uInt = uInt; _type = OF_NUMBER_TYPE_UINT; return self; } - (instancetype)initWithUnsignedLong: (unsigned long)uLong { self = [super init]; _value.uLong = uLong; _type = OF_NUMBER_TYPE_ULONG; return self; } - (instancetype)initWithUnsignedLongLong: (unsigned long long)uLongLong { self = [super init]; _value.uLongLong = uLongLong; _type = OF_NUMBER_TYPE_ULONGLONG; return self; } - (instancetype)initWithInt8: (int8_t)int8 { self = [super init]; _value.int8 = int8; _type = OF_NUMBER_TYPE_INT8; return self; } - (instancetype)initWithInt16: (int16_t)int16 { self = [super init]; _value.int16 = int16; _type = OF_NUMBER_TYPE_INT16; return self; } - (instancetype)initWithInt32: (int32_t)int32 { self = [super init]; _value.int32 = int32; _type = OF_NUMBER_TYPE_INT32; return self; } - (instancetype)initWithInt64: (int64_t)int64 { self = [super init]; _value.int64 = int64; _type = OF_NUMBER_TYPE_INT64; return self; } - (instancetype)initWithUInt8: (uint8_t)uInt8 { self = [super init]; _value.uInt8 = uInt8; _type = OF_NUMBER_TYPE_UINT8; return self; } - (instancetype)initWithUInt16: (uint16_t)uInt16 { self = [super init]; _value.uInt16 = uInt16; _type = OF_NUMBER_TYPE_UINT16; return self; } - (instancetype)initWithUInt32: (uint32_t)uInt32 { self = [super init]; _value.uInt32 = uInt32; _type = OF_NUMBER_TYPE_UINT32; return self; } - (instancetype)initWithUInt64: (uint64_t)uInt64 { self = [super init]; _value.uInt64 = uInt64; _type = OF_NUMBER_TYPE_UINT64; return self; } - (instancetype)initWithSize: (size_t)size { self = [super init]; _value.size = size; _type = OF_NUMBER_TYPE_SIZE; return self; } - (instancetype)initWithSSize: (ssize_t)sSize { self = [super init]; _value.sSize = sSize; _type = OF_NUMBER_TYPE_SSIZE; return self; } - (instancetype)initWithIntMax: (intmax_t)intMax { self = [super init]; _value.intMax = intMax; _type = OF_NUMBER_TYPE_INTMAX; return self; } - (instancetype)initWithUIntMax: (uintmax_t)uIntMax { self = [super init]; _value.uIntMax = uIntMax; _type = OF_NUMBER_TYPE_UINTMAX; return self; } - (instancetype)initWithPtrDiff: (ptrdiff_t)ptrDiff { self = [super init]; _value.ptrDiff = ptrDiff; _type = OF_NUMBER_TYPE_PTRDIFF; return self; } - (instancetype)initWithIntPtr: (intptr_t)intPtr { self = [super init]; _value.intPtr = intPtr; _type = OF_NUMBER_TYPE_INTPTR; return self; } - (instancetype)initWithUIntPtr: (uintptr_t)uIntPtr { self = [super init]; _value.uIntPtr = uIntPtr; _type = OF_NUMBER_TYPE_UINTPTR; return self; } - (instancetype)initWithFloat: (float)float_ { self = [super init]; _value.float_ = float_; _type = OF_NUMBER_TYPE_FLOAT; return self; } - (instancetype)initWithDouble: (double)double_ { self = [super init]; _value.double_ = double_; _type = OF_NUMBER_TYPE_DOUBLE; return self; } - (instancetype)initWithSerialization: (OFXMLElement *)element { self = [super init]; @try { void *pool = objc_autoreleasePoolPush(); OFString *typeString; if (![[element name] isEqual: [self className]] || ![[element namespace] isEqual: OF_SERIALIZATION_NS]) @throw [OFInvalidArgumentException exception]; typeString = [[element attributeForName: @"type"] stringValue]; if ([typeString isEqual: @"boolean"]) { _type = OF_NUMBER_TYPE_BOOL; if ([[element stringValue] isEqual: @"true"]) _value.bool_ = true; else if ([[element stringValue] isEqual: @"false"]) _value.bool_ = false; else @throw [OFInvalidArgumentException exception]; } else if ([typeString isEqual: @"unsigned"]) { /* * FIXME: This will fail if the value is bigger than * INTMAX_MAX! */ _type = OF_NUMBER_TYPE_UINTMAX; _value.uIntMax = [element decimalValue]; } else if ([typeString isEqual: @"signed"]) { _type = OF_NUMBER_TYPE_INTMAX; _value.intMax = [element decimalValue]; } else if ([typeString isEqual: @"float"]) { union { float f; uint32_t u; } f; f.u = OF_BSWAP32_IF_LE( (uint32_t)[element hexadecimalValue]); _type = OF_NUMBER_TYPE_FLOAT; _value.float_ = OF_BSWAP_FLOAT_IF_LE(f.f); } else if ([typeString isEqual: @"double"]) { union { double d; uint64_t u; } d; d.u = OF_BSWAP64_IF_LE( (uint64_t)[element hexadecimalValue]); _type = OF_NUMBER_TYPE_DOUBLE; _value.double_ = OF_BSWAP_DOUBLE_IF_LE(d.d); } else @throw [OFInvalidArgumentException exception]; objc_autoreleasePoolPop(pool); } @catch (id e) { [self release]; @throw e; } return self; } - (const char *)objCType { switch (_type) { case OF_NUMBER_TYPE_BOOL: return @encode(bool); case OF_NUMBER_TYPE_CHAR: return @encode(signed char); case OF_NUMBER_TYPE_SHORT: return @encode(signed short); case OF_NUMBER_TYPE_INT: return @encode(signed int); case OF_NUMBER_TYPE_LONG: return @encode(signed long); case OF_NUMBER_TYPE_LONGLONG: return @encode(signed long long); case OF_NUMBER_TYPE_UCHAR: return @encode(unsigned char); case OF_NUMBER_TYPE_USHORT: return @encode(unsigned short); case OF_NUMBER_TYPE_UINT: return @encode(unsigned int); case OF_NUMBER_TYPE_ULONG: return @encode(unsigned long); case OF_NUMBER_TYPE_ULONGLONG: return @encode(unsigned long long); case OF_NUMBER_TYPE_INT8: return @encode(int8_t); case OF_NUMBER_TYPE_INT16: return @encode(int16_t); case OF_NUMBER_TYPE_INT32: return @encode(int32_t); case OF_NUMBER_TYPE_INT64: return @encode(int64_t); case OF_NUMBER_TYPE_UINT8: return @encode(uint8_t); case OF_NUMBER_TYPE_UINT16: return @encode(uint16_t); case OF_NUMBER_TYPE_UINT32: return @encode(uint32_t); case OF_NUMBER_TYPE_UINT64: return @encode(uint64_t); case OF_NUMBER_TYPE_SIZE: return @encode(size_t); case OF_NUMBER_TYPE_SSIZE: return @encode(ssize_t); case OF_NUMBER_TYPE_INTMAX: return @encode(intmax_t); case OF_NUMBER_TYPE_UINTMAX: return @encode(uintmax_t); case OF_NUMBER_TYPE_PTRDIFF: return @encode(ptrdiff_t); case OF_NUMBER_TYPE_INTPTR: return @encode(intptr_t); case OF_NUMBER_TYPE_UINTPTR: return @encode(uintptr_t); case OF_NUMBER_TYPE_FLOAT: return @encode(float); case OF_NUMBER_TYPE_DOUBLE: return @encode(double); default: @throw [OFInvalidFormatException exception]; } } - (void)getValue: (void *)value size: (size_t)size { switch (_type) { case OF_NUMBER_TYPE_BOOL: if (size != sizeof(bool)) @throw [OFOutOfRangeException exception]; memcpy(value, &_value.bool_, sizeof(bool)); break; case OF_NUMBER_TYPE_CHAR: if (size != sizeof(signed char)) @throw [OFOutOfRangeException exception]; memcpy(value, &_value.sChar, sizeof(signed char)); break; case OF_NUMBER_TYPE_SHORT: if (size != sizeof(signed short)) @throw [OFOutOfRangeException exception]; memcpy(value, &_value.sShort, sizeof(signed short)); break; case OF_NUMBER_TYPE_INT: if (size != sizeof(signed int)) @throw [OFOutOfRangeException exception]; memcpy(value, &_value.sInt, sizeof(signed int)); break; case OF_NUMBER_TYPE_LONG: if (size != sizeof(signed long)) @throw [OFOutOfRangeException exception]; memcpy(value, &_value.sLong, sizeof(signed long)); break; case OF_NUMBER_TYPE_LONGLONG: if (size != sizeof(signed long long)) @throw [OFOutOfRangeException exception]; memcpy(value, &_value.sLongLong, sizeof(signed long long)); break; case OF_NUMBER_TYPE_UCHAR: if (size != sizeof(unsigned char)) @throw [OFOutOfRangeException exception]; memcpy(value, &_value.uChar, sizeof(unsigned char)); break; case OF_NUMBER_TYPE_USHORT: if (size != sizeof(unsigned short)) @throw [OFOutOfRangeException exception]; memcpy(value, &_value.uShort, sizeof(unsigned short)); break; case OF_NUMBER_TYPE_UINT: if (size != sizeof(unsigned int)) @throw [OFOutOfRangeException exception]; memcpy(value, &_value.uInt, sizeof(unsigned int)); break; case OF_NUMBER_TYPE_ULONG: if (size != sizeof(unsigned long)) @throw [OFOutOfRangeException exception]; memcpy(value, &_value.uLong, sizeof(unsigned long)); break; case OF_NUMBER_TYPE_ULONGLONG: if (size != sizeof(unsigned long long)) @throw [OFOutOfRangeException exception]; memcpy(value, &_value.uLongLong, sizeof(unsigned long long)); break; case OF_NUMBER_TYPE_INT8: if (size != sizeof(int8_t)) @throw [OFOutOfRangeException exception]; memcpy(value, &_value.int8, sizeof(int8_t)); break; case OF_NUMBER_TYPE_INT16: if (size != sizeof(int16_t)) @throw [OFOutOfRangeException exception]; memcpy(value, &_value.int16, sizeof(int16_t)); break; case OF_NUMBER_TYPE_INT32: if (size != sizeof(int32_t)) @throw [OFOutOfRangeException exception]; memcpy(value, &_value.int32, sizeof(int32_t)); break; case OF_NUMBER_TYPE_INT64: if (size != sizeof(int64_t)) @throw [OFOutOfRangeException exception]; memcpy(value, &_value.int64, sizeof(int64_t)); break; case OF_NUMBER_TYPE_UINT8: if (size != sizeof(uint8_t)) @throw [OFOutOfRangeException exception]; memcpy(value, &_value.uInt8, sizeof(uint8_t)); break; case OF_NUMBER_TYPE_UINT16: if (size != sizeof(uint16_t)) @throw [OFOutOfRangeException exception]; memcpy(value, &_value.uInt16, sizeof(uint16_t)); break; case OF_NUMBER_TYPE_UINT32: if (size != sizeof(uint32_t)) @throw [OFOutOfRangeException exception]; memcpy(value, &_value.uInt32, sizeof(uint32_t)); break; case OF_NUMBER_TYPE_UINT64: if (size != sizeof(uint64_t)) @throw [OFOutOfRangeException exception]; memcpy(value, &_value.uInt64, sizeof(uint64_t)); break; case OF_NUMBER_TYPE_SIZE: if (size != sizeof(size_t)) @throw [OFOutOfRangeException exception]; memcpy(value, &_value.size, sizeof(size_t)); break; case OF_NUMBER_TYPE_SSIZE: if (size != sizeof(ssize_t)) @throw [OFOutOfRangeException exception]; memcpy(value, &_value.sSize, sizeof(ssize_t)); break; case OF_NUMBER_TYPE_INTMAX: if (size != sizeof(intmax_t)) @throw [OFOutOfRangeException exception]; memcpy(value, &_value.intMax, sizeof(intmax_t)); break; case OF_NUMBER_TYPE_UINTMAX: if (size != sizeof(uintmax_t)) @throw [OFOutOfRangeException exception]; memcpy(value, &_value.uIntMax, sizeof(uintmax_t)); break; case OF_NUMBER_TYPE_PTRDIFF: if (size != sizeof(ptrdiff_t)) @throw [OFOutOfRangeException exception]; memcpy(value, &_value.ptrDiff, sizeof(ptrdiff_t)); break; case OF_NUMBER_TYPE_INTPTR: if (size != sizeof(intptr_t)) @throw [OFOutOfRangeException exception]; memcpy(value, &_value.intPtr, sizeof(intptr_t)); break; case OF_NUMBER_TYPE_UINTPTR: if (size != sizeof(uintptr_t)) @throw [OFOutOfRangeException exception]; memcpy(value, &_value.uIntPtr, sizeof(uintptr_t)); break; case OF_NUMBER_TYPE_FLOAT: if (size != sizeof(float)) @throw [OFOutOfRangeException exception]; memcpy(value, &_value.float_, sizeof(float)); break; case OF_NUMBER_TYPE_DOUBLE: if (size != sizeof(double)) @throw [OFOutOfRangeException exception]; memcpy(value, &_value.double_, sizeof(double)); break; default: @throw [OFInvalidFormatException exception]; } } - (bool)boolValue { RETURN_AS(bool) } - (signed char)charValue { RETURN_AS(signed char) } - (signed short)shortValue { RETURN_AS(signed short) } - (signed int)intValue { RETURN_AS(signed int) } - (signed long)longValue { RETURN_AS(signed long) } - (signed long long)longLongValue { RETURN_AS(signed long long) } - (unsigned char)unsignedCharValue { RETURN_AS(unsigned char) } - (unsigned short)unsignedShortValue { RETURN_AS(unsigned short) } - (unsigned int)unsignedIntValue { RETURN_AS(unsigned int) } - (unsigned long)unsignedLongValue { RETURN_AS(unsigned long) } - (unsigned long long)unsignedLongLongValue { RETURN_AS(unsigned long long) } - (int8_t)int8Value { RETURN_AS(int8_t) } - (int16_t)int16Value { RETURN_AS(int16_t) } - (int32_t)int32Value { RETURN_AS(int32_t) } - (int64_t)int64Value { RETURN_AS(int64_t) } - (uint8_t)uInt8Value { RETURN_AS(uint8_t) } - (uint16_t)uInt16Value { RETURN_AS(uint16_t) } - (uint32_t)uInt32Value { RETURN_AS(uint32_t) } - (uint64_t)uInt64Value { RETURN_AS(uint64_t) } - (size_t)sizeValue { RETURN_AS(size_t) } - (ssize_t)sSizeValue { RETURN_AS(ssize_t) } - (intmax_t)intMaxValue { RETURN_AS(intmax_t) } - (uintmax_t)uIntMaxValue { RETURN_AS(uintmax_t) } - (ptrdiff_t)ptrDiffValue { RETURN_AS(ptrdiff_t) } - (intptr_t)intPtrValue { RETURN_AS(intptr_t) } - (uintptr_t)uIntPtrValue { RETURN_AS(uintptr_t) } - (float)floatValue { RETURN_AS(float) } - (double)doubleValue { RETURN_AS(double) } - (bool)isEqual: (id)object { OFNumber *number; if (object == self) return true; if (![object isKindOfClass: [OFNumber class]]) return false; number = object; if (_type & OF_NUMBER_TYPE_FLOAT || number->_type & OF_NUMBER_TYPE_FLOAT) { double value1 = [number doubleValue]; double value2 = [self doubleValue]; if (isnan(value1) && isnan(value2)) return true; if (isnan(value1) || isnan(value2)) return false; return (value1 == value2); } if (_type & OF_NUMBER_TYPE_SIGNED || number->_type & OF_NUMBER_TYPE_SIGNED) return ([number intMaxValue] == [self intMaxValue]); return ([number uIntMaxValue] == [self uIntMaxValue]); } - (of_comparison_result_t)compare: (id <OFComparing>)object { OFNumber *number; if (![(id)object isKindOfClass: [OFNumber class]]) @throw [OFInvalidArgumentException exception]; number = (OFNumber *)object; if (_type & OF_NUMBER_TYPE_FLOAT || number->_type & OF_NUMBER_TYPE_FLOAT) { double double1 = [self doubleValue]; double double2 = [number doubleValue]; if (double1 > double2) return OF_ORDERED_DESCENDING; if (double1 < double2) return OF_ORDERED_ASCENDING; return OF_ORDERED_SAME; } else if (_type & OF_NUMBER_TYPE_SIGNED || number->_type & OF_NUMBER_TYPE_SIGNED) { intmax_t int1 = [self intMaxValue]; intmax_t int2 = [number intMaxValue]; if (int1 > int2) return OF_ORDERED_DESCENDING; if (int1 < int2) return OF_ORDERED_ASCENDING; return OF_ORDERED_SAME; } else { uintmax_t uint1 = [self uIntMaxValue]; uintmax_t uint2 = [number uIntMaxValue]; if (uint1 > uint2) return OF_ORDERED_DESCENDING; if (uint1 < uint2) return OF_ORDERED_ASCENDING; return OF_ORDERED_SAME; } } - (uint32_t)hash { of_number_type_t type = _type; uint32_t hash; /* Do we really need signed to represent this number? */ if (type & OF_NUMBER_TYPE_SIGNED && [self intMaxValue] >= 0) type &= ~OF_NUMBER_TYPE_SIGNED; /* Do we really need floating point to represent this number? */ if (type & OF_NUMBER_TYPE_FLOAT) { double v = [self doubleValue]; if (v < 0) { if (v == [self intMaxValue]) { type &= ~OF_NUMBER_TYPE_FLOAT; type |= OF_NUMBER_TYPE_SIGNED; } } else { if (v == [self uIntMaxValue]) type &= ~OF_NUMBER_TYPE_FLOAT; } } OF_HASH_INIT(hash); if (type & OF_NUMBER_TYPE_FLOAT) { union { double d; uint8_t b[sizeof(double)]; } d; if (isnan([self doubleValue])) return 0; d.d = OF_BSWAP_DOUBLE_IF_BE([self doubleValue]); for (uint_fast8_t i = 0; i < sizeof(double); i++) OF_HASH_ADD(hash, d.b[i]); } else if (type & OF_NUMBER_TYPE_SIGNED) { intmax_t v = [self intMaxValue] * -1; while (v != 0) { OF_HASH_ADD(hash, v & 0xFF); v >>= 8; } OF_HASH_ADD(hash, 1); } else { uintmax_t v = [self uIntMaxValue]; while (v != 0) { OF_HASH_ADD(hash, v & 0xFF); v >>= 8; } } OF_HASH_FINALIZE(hash); return hash; } - (id)copy { return [self retain]; } - (OFString *)description { OFMutableString *ret; switch (_type) { case OF_NUMBER_TYPE_BOOL: return (_value.bool_ ? @"true" : @"false"); case OF_NUMBER_TYPE_UCHAR: case OF_NUMBER_TYPE_USHORT: case OF_NUMBER_TYPE_UINT: case OF_NUMBER_TYPE_ULONG: case OF_NUMBER_TYPE_ULONGLONG: case OF_NUMBER_TYPE_UINT8: case OF_NUMBER_TYPE_UINT16: case OF_NUMBER_TYPE_UINT32: case OF_NUMBER_TYPE_UINT64: case OF_NUMBER_TYPE_SIZE: case OF_NUMBER_TYPE_UINTMAX: case OF_NUMBER_TYPE_UINTPTR: return [OFString stringWithFormat: @"%ju", [self uIntMaxValue]]; case OF_NUMBER_TYPE_CHAR: case OF_NUMBER_TYPE_SHORT: case OF_NUMBER_TYPE_INT: case OF_NUMBER_TYPE_LONG: case OF_NUMBER_TYPE_LONGLONG: case OF_NUMBER_TYPE_INT8: case OF_NUMBER_TYPE_INT16: case OF_NUMBER_TYPE_INT32: case OF_NUMBER_TYPE_INT64: case OF_NUMBER_TYPE_SSIZE: case OF_NUMBER_TYPE_INTMAX: case OF_NUMBER_TYPE_PTRDIFF: case OF_NUMBER_TYPE_INTPTR: return [OFString stringWithFormat: @"%jd", [self intMaxValue]]; case OF_NUMBER_TYPE_FLOAT: ret = [OFMutableString stringWithFormat: @"%g", _value.float_]; if (![ret containsString: @"."]) [ret appendString: @".0"]; [ret makeImmutable]; return ret; case OF_NUMBER_TYPE_DOUBLE: ret = [OFMutableString stringWithFormat: @"%g", _value.double_]; if (![ret containsString: @"."]) [ret appendString: @".0"]; [ret makeImmutable]; return ret; default: @throw [OFInvalidFormatException exception]; } } - (OFXMLElement *)XMLElementBySerializing { void *pool = objc_autoreleasePoolPush(); OFXMLElement *element; element = [OFXMLElement elementWithName: [self className] namespace: OF_SERIALIZATION_NS stringValue: [self description]]; switch (_type) { case OF_NUMBER_TYPE_BOOL: [element addAttributeWithName: @"type" stringValue: @"boolean"]; break; case OF_NUMBER_TYPE_UCHAR: case OF_NUMBER_TYPE_USHORT: case OF_NUMBER_TYPE_UINT: case OF_NUMBER_TYPE_ULONG: case OF_NUMBER_TYPE_ULONGLONG: case OF_NUMBER_TYPE_UINT8: case OF_NUMBER_TYPE_UINT16: case OF_NUMBER_TYPE_UINT32: case OF_NUMBER_TYPE_UINT64: case OF_NUMBER_TYPE_SIZE: case OF_NUMBER_TYPE_UINTMAX: case OF_NUMBER_TYPE_UINTPTR: [element addAttributeWithName: @"type" stringValue: @"unsigned"]; break; case OF_NUMBER_TYPE_CHAR: case OF_NUMBER_TYPE_SHORT: case OF_NUMBER_TYPE_INT: case OF_NUMBER_TYPE_LONG: case OF_NUMBER_TYPE_LONGLONG: case OF_NUMBER_TYPE_INT8: case OF_NUMBER_TYPE_INT16: case OF_NUMBER_TYPE_INT32: case OF_NUMBER_TYPE_INT64: case OF_NUMBER_TYPE_SSIZE: case OF_NUMBER_TYPE_INTMAX: case OF_NUMBER_TYPE_PTRDIFF: case OF_NUMBER_TYPE_INTPTR:; [element addAttributeWithName: @"type" stringValue: @"signed"]; break; case OF_NUMBER_TYPE_FLOAT:; union { float f; uint32_t u; } f; f.f = OF_BSWAP_FLOAT_IF_LE(_value.float_); [element addAttributeWithName: @"type" stringValue: @"float"]; [element setStringValue: [OFString stringWithFormat: @"%08" PRIx32, OF_BSWAP32_IF_LE(f.u)]]; break; case OF_NUMBER_TYPE_DOUBLE:; union { double d; uint64_t u; } d; d.d = OF_BSWAP_DOUBLE_IF_LE(_value.double_); [element addAttributeWithName: @"type" stringValue: @"double"]; [element setStringValue: [OFString stringWithFormat: @"%016" PRIx64, OF_BSWAP64_IF_LE(d.u)]]; break; default: @throw [OFInvalidFormatException exception]; } [element retain]; objc_autoreleasePoolPop(pool); return [element autorelease]; } - (OFString *)JSONRepresentation { return [self of_JSONRepresentationWithOptions: 0 depth: 0]; } - (OFString *)JSONRepresentationWithOptions: (int)options { return [self of_JSONRepresentationWithOptions: options depth: 0]; } - (OFString *)of_JSONRepresentationWithOptions: (int)options depth: (size_t)depth { double doubleValue; if (_type == OF_NUMBER_TYPE_BOOL) return (_value.bool_ ? @"true" : @"false"); doubleValue = [self doubleValue]; if (isinf(doubleValue)) { if (options & OF_JSON_REPRESENTATION_JSON5) { if (doubleValue > 0) return @"Infinity"; else return @"-Infinity"; } else @throw [OFInvalidArgumentException exception]; } return [self description]; } - (OFData *)messagePackRepresentation { OFMutableData *data; if (_type == OF_NUMBER_TYPE_BOOL) { uint8_t type = (_value.bool_ ? 0xC3 : 0xC2); data = [OFMutableData dataWithItems: &type count: 1]; } else if (_type == OF_NUMBER_TYPE_FLOAT) { uint8_t type = 0xCA; float tmp = OF_BSWAP_FLOAT_IF_LE(_value.float_); data = [OFMutableData dataWithItemSize: 1 capacity: 5]; [data addItem: &type]; [data addItems: &tmp count: sizeof(tmp)]; } else if (_type == OF_NUMBER_TYPE_DOUBLE) { uint8_t type = 0xCB; double tmp = OF_BSWAP_DOUBLE_IF_LE(_value.double_); data = [OFMutableData dataWithItemSize: 1 capacity: 9]; [data addItem: &type]; [data addItems: &tmp count: sizeof(tmp)]; } else if (_type & OF_NUMBER_TYPE_SIGNED) { intmax_t value = [self intMaxValue]; if (value >= -32 && value < 0) { uint8_t tmp = 0xE0 | ((uint8_t)(value - 32) & 0x1F); data = [OFMutableData dataWithItems: &tmp count: 1]; } else if (value >= INT8_MIN && value <= INT8_MAX) { uint8_t type = 0xD0; int8_t tmp = (int8_t)value; data = [OFMutableData dataWithItemSize: 1 capacity: 2]; [data addItem: &type]; [data addItem: &tmp]; } else if (value >= INT16_MIN && value <= INT16_MAX) { uint8_t type = 0xD1; int16_t tmp = OF_BSWAP16_IF_LE((int16_t)value); data = [OFMutableData dataWithItemSize: 1 capacity: 3]; [data addItem: &type]; [data addItems: &tmp count: sizeof(tmp)]; } else if (value >= INT32_MIN && value <= INT32_MAX) { uint8_t type = 0xD2; int32_t tmp = OF_BSWAP32_IF_LE((int32_t)value); data = [OFMutableData dataWithItemSize: 1 capacity: 5]; [data addItem: &type]; [data addItems: &tmp count: sizeof(tmp)]; } else if (value >= INT64_MIN && value <= INT64_MAX) { uint8_t type = 0xD3; int64_t tmp = OF_BSWAP64_IF_LE((int64_t)value); data = [OFMutableData dataWithItemSize: 1 capacity: 9]; [data addItem: &type]; [data addItems: &tmp count: sizeof(tmp)]; } else @throw [OFOutOfRangeException exception]; } else { uintmax_t value = [self uIntMaxValue]; if (value <= 127) { uint8_t tmp = ((uint8_t)value & 0x7F); data = [OFMutableData dataWithItems: &tmp count: 1]; } else if (value <= UINT8_MAX) { uint8_t type = 0xCC; uint8_t tmp = (uint8_t)value; data = [OFMutableData dataWithItemSize: 1 capacity: 2]; [data addItem: &type]; [data addItem: &tmp]; } else if (value <= UINT16_MAX) { uint8_t type = 0xCD; uint16_t tmp = OF_BSWAP16_IF_LE((uint16_t)value); data = [OFMutableData dataWithItemSize: 1 capacity: 3]; [data addItem: &type]; [data addItems: &tmp count: sizeof(tmp)]; } else if (value <= UINT32_MAX) { uint8_t type = 0xCE; uint32_t tmp = OF_BSWAP32_IF_LE((uint32_t)value); data = [OFMutableData dataWithItemSize: 1 capacity: 5]; [data addItem: &type]; [data addItems: &tmp count: sizeof(tmp)]; } else if (value <= UINT64_MAX) { uint8_t type = 0xCF; uint64_t tmp = OF_BSWAP64_IF_LE((uint64_t)value); data = [OFMutableData dataWithItemSize: 1 capacity: 9]; [data addItem: &type]; [data addItems: &tmp count: sizeof(tmp)]; } else @throw [OFOutOfRangeException exception]; } [data makeImmutable]; return data; } @end