ADDED .github/FUNDING.yml Index: .github/FUNDING.yml ================================================================== --- /dev/null +++ .github/FUNDING.yml @@ -0,0 +1,1 @@ +github: Midar Index: .travis.yml ================================================================== --- .travis.yml +++ .travis.yml @@ -287,12 +287,12 @@ - build() { if ! git clean -fxd >/tmp/clean_log 2>&1; then cat /tmp/clean_log; exit 1; fi; - ./autogen.sh; - .travis/build.sh "$@"; + ./autogen.sh || exit 1; + .travis/build.sh "$@" || exit 1; } - if [ "$TRAVIS_OS_NAME" = "linux" -a -z "$config" ]; then build_32_64() { build OBJC="$CC" $@; Index: Makefile ================================================================== --- Makefile +++ Makefile @@ -23,11 +23,11 @@ tarball: docs echo "Generating tarball for version ${PACKAGE_VERSION}..." rm -fr objfw-${PACKAGE_VERSION} objfw-${PACKAGE_VERSION}.tar \ objfw-${PACKAGE_VERSION}.tar.gz fossil tarball --name objfw-${PACKAGE_VERSION} current - \ - --exclude '.cirrus*,.fossil-settings/*,.gitignore,.travis*' | \ + --exclude '.cirrus*,.fossil*,.git*,.travis*' | \ ofarc -ttgz -xq - cp configure config.h.in objfw-${PACKAGE_VERSION}/ ofarc -cq objfw-${PACKAGE_VERSION}.tar \ $$(find objfw-${PACKAGE_VERSION} | sort) rm -fr objfw-${PACKAGE_VERSION} Index: PLATFORMS.md ================================================================== --- PLATFORMS.md +++ PLATFORMS.md @@ -33,11 +33,11 @@ DOS --- - * OS Versions: Windows XP DOS Emulation, DOSBox + * OS Versions: Windows XP DOS Emulation, DOSBox, MS-DOS 6.0, FreeDOS 1.2 * Architectures: x86 * Compilers: DJGPP GCC 4.7.3 (djdev204) * Runtimes: ObjFW Index: README.md ================================================================== --- README.md +++ README.md @@ -186,11 +186,11 @@ Unfortunately, there is no workaround for this other than to upgrade/downgrade Xcode or to build upstream Clang yourself. In particular, Xcode 11 Beta 1 to Beta 3 are known to be affected. While Xcode 11 Beta 4 to Xcode 11.3 work, the bug was unfortunately reintroduced in - Xcode 11.4.1 and a fix is not expected before Xcode 11.6. + Xcode 11.4.1 and was only fixed in Xcode 12 Beta 1. You can get older versions of Xcode [here](https://developer.apple.com/download) by clicking on "More" in the top-right corner. Index: src/OFNumber.h ================================================================== --- src/OFNumber.h +++ src/OFNumber.h @@ -35,131 +35,34 @@ OF_ASSUME_NONNULL_BEGIN /*! @file */ -/*! - * @brief The C type of a number stored in an OFNumber. - */ -typedef enum { - /*! `bool` */ - OF_NUMBER_TYPE_BOOL = 0x01, - /*! `unsigned char` */ - OF_NUMBER_TYPE_UCHAR = 0x02, - /*! `unsigned short` */ - OF_NUMBER_TYPE_USHORT = 0x03, - /*! `unsigned int` */ - OF_NUMBER_TYPE_UINT = 0x04, - /*! `unsigned long` */ - OF_NUMBER_TYPE_ULONG = 0x05, - /*! `unsigned long long` */ - OF_NUMBER_TYPE_ULONGLONG = 0x06, - /*! `size_t` */ - OF_NUMBER_TYPE_SIZE = 0x07, - /*! `uint8_t` */ - OF_NUMBER_TYPE_UINT8 = 0x08, - /*! `uint16_t` */ - OF_NUMBER_TYPE_UINT16 = 0x09, - /*! `uint32_t` */ - OF_NUMBER_TYPE_UINT32 = 0x0A, - /*! `uint64_t` */ - OF_NUMBER_TYPE_UINT64 = 0x0B, - /*! `uintptr_t` */ - OF_NUMBER_TYPE_UINTPTR = 0x0C, - /*! `uintmax_t` */ - OF_NUMBER_TYPE_UINTMAX = 0x0D, - OF_NUMBER_TYPE_SIGNED = 0x10, - /*! `signed char` */ - OF_NUMBER_TYPE_CHAR = OF_NUMBER_TYPE_UCHAR | - OF_NUMBER_TYPE_SIGNED, - /*! `signed short` */ - OF_NUMBER_TYPE_SHORT = OF_NUMBER_TYPE_USHORT | - OF_NUMBER_TYPE_SIGNED, - /*! `signed int` */ - OF_NUMBER_TYPE_INT = OF_NUMBER_TYPE_UINT | - OF_NUMBER_TYPE_SIGNED, - /*! `signed long` */ - OF_NUMBER_TYPE_LONG = OF_NUMBER_TYPE_ULONG | - OF_NUMBER_TYPE_SIGNED, - /*! `signed long long` */ - OF_NUMBER_TYPE_LONGLONG = OF_NUMBER_TYPE_ULONGLONG | - OF_NUMBER_TYPE_SIGNED, - /*! `int8_t` */ - OF_NUMBER_TYPE_INT8 = OF_NUMBER_TYPE_UINT8 | - OF_NUMBER_TYPE_SIGNED, - /*! `int16_t` */ - OF_NUMBER_TYPE_INT16 = OF_NUMBER_TYPE_UINT16 | - OF_NUMBER_TYPE_SIGNED, - /*! `int32_t` */ - OF_NUMBER_TYPE_INT32 = OF_NUMBER_TYPE_UINT32 | - OF_NUMBER_TYPE_SIGNED, - /*! `int64_t` */ - OF_NUMBER_TYPE_INT64 = OF_NUMBER_TYPE_UINT64 | - OF_NUMBER_TYPE_SIGNED, - /*! `ssize_t` */ - OF_NUMBER_TYPE_SSIZE = OF_NUMBER_TYPE_SIZE | - OF_NUMBER_TYPE_SIGNED, - /*! `intmax_t` */ - OF_NUMBER_TYPE_INTMAX = OF_NUMBER_TYPE_UINTMAX | - OF_NUMBER_TYPE_SIGNED, - /*! `ptrdiff_t` */ - OF_NUMBER_TYPE_PTRDIFF = 0x0E | OF_NUMBER_TYPE_SIGNED, - /*! `intptr_t` */ - OF_NUMBER_TYPE_INTPTR = 0x0F | OF_NUMBER_TYPE_SIGNED, - /*! `float` */ - OF_NUMBER_TYPE_FLOAT = 0x20, - /*! `double` */ - OF_NUMBER_TYPE_DOUBLE = 0x40 | OF_NUMBER_TYPE_FLOAT -} of_number_type_t; - /*! * @class OFNumber OFNumber.h ObjFW/OFNumber.h * * @brief Provides a way to store a number in an object. */ +#ifndef OF_NUMBER_M OF_SUBCLASSING_RESTRICTED +#endif @interface OFNumber: OFValue { union of_number_value { - bool bool_; - signed char sChar; - signed short sShort; - signed int sInt; - signed long sLong; - signed long long sLongLong; - unsigned char uChar; - unsigned short uShort; - unsigned int uInt; - unsigned long uLong; - unsigned long long uLongLong; - int8_t int8; - int16_t int16; - int32_t int32; - int64_t int64; - uint8_t uInt8; - uint16_t uInt16; - uint32_t uInt32; - uint64_t uInt64; - size_t size; - ssize_t sSize; - intmax_t intMax; - uintmax_t uIntMax; - ptrdiff_t ptrDiff; - intptr_t intPtr; - uintptr_t uIntPtr; - float float_; - double double_; + double float_; + intmax_t signed_; + uintmax_t unsigned_; } _value; - of_number_type_t _type; + enum of_number_type { + OF_NUMBER_TYPE_FLOAT = 1, + OF_NUMBER_TYPE_SIGNED, + OF_NUMBER_TYPE_UNSIGNED + } _type; + const char *_typeEncoding; } -/*! - * @brief The type of the number. - */ -@property (readonly, nonatomic) of_number_type_t type; - /*! * @brief The OFNumber as a `bool`. */ @property (readonly, nonatomic) bool boolValue; @@ -167,28 +70,28 @@ * @brief The OFNumber as a `signed char`. */ @property (readonly, nonatomic) signed char charValue; /*! - * @brief The OFNumber as a `signed short`. - */ -@property (readonly, nonatomic) signed short shortValue; - -/*! - * @brief The OFNumber as a `signed int`. - */ -@property (readonly, nonatomic) signed int intValue; - -/*! - * @brief The OFNumber as a `signed long`. - */ -@property (readonly, nonatomic) signed long longValue; - -/*! - * @brief The OFNumber as a `signed long long`. - */ -@property (readonly, nonatomic) signed long long longLongValue; + * @brief The OFNumber as a `short`. + */ +@property (readonly, nonatomic) short shortValue; + +/*! + * @brief The OFNumber as an `int`. + */ +@property (readonly, nonatomic) int intValue; + +/*! + * @brief The OFNumber as a `long`. + */ +@property (readonly, nonatomic) long longValue; + +/*! + * @brief The OFNumber as a `long long`. + */ +@property (readonly, nonatomic) long long longLongValue; /*! * @brief The OFNumber as an `unsigned char`. */ @property (readonly, nonatomic) unsigned char unsignedCharValue; @@ -329,40 +232,40 @@ * @return A new autoreleased OFNumber */ + (instancetype)numberWithChar: (signed char)sChar; /*! - * @brief Creates a new OFNumber with the specified `signed short`. - * - * @param sShort A `signed short` which the OFNumber should contain - * @return A new autoreleased OFNumber - */ -+ (instancetype)numberWithShort: (signed short)sShort; - -/*! - * @brief Creates a new OFNumber with the specified `signed int`. - * - * @param sInt A `signed int` which the OFNumber should contain - * @return A new autoreleased OFNumber - */ -+ (instancetype)numberWithInt: (signed int)sInt; - -/*! - * @brief Creates a new OFNumber with the specified `signed long`. - * - * @param sLong A `signed long` which the OFNumber should contain - * @return A new autoreleased OFNumber - */ -+ (instancetype)numberWithLong: (signed long)sLong; - -/*! - * @brief Creates a new OFNumber with the specified `signed long long`. - * - * @param sLongLong A `signed long long` which the OFNumber should contain - * @return A new autoreleased OFNumber - */ -+ (instancetype)numberWithLongLong: (signed long long)sLongLong; + * @brief Creates a new OFNumber with the specified `short`. + * + * @param sShort A `short` which the OFNumber should contain + * @return A new autoreleased OFNumber + */ ++ (instancetype)numberWithShort: (short)sShort; + +/*! + * @brief Creates a new OFNumber with the specified `int`. + * + * @param sInt An `int` which the OFNumber should contain + * @return A new autoreleased OFNumber + */ ++ (instancetype)numberWithInt: (int)sInt; + +/*! + * @brief Creates a new OFNumber with the specified `long`. + * + * @param sLong A `long` which the OFNumber should contain + * @return A new autoreleased OFNumber + */ ++ (instancetype)numberWithLong: (long)sLong; + +/*! + * @brief Creates a new OFNumber with the specified `long long`. + * + * @param sLongLong A `long long` which the OFNumber should contain + * @return A new autoreleased OFNumber + */ ++ (instancetype)numberWithLongLong: (long long)sLongLong; /*! * @brief Creates a new OFNumber with the specified `unsigned char`. * * @param uChar An `unsigned char` which the OFNumber should contain @@ -566,44 +469,41 @@ * @return An initialized OFNumber */ - (instancetype)initWithChar: (signed char)sChar; /*! - * @brief Initializes an already allocated OFNumber with the specified - * `signed short`. - * - * @param sShort A `signed short` which the OFNumber should contain - * @return An initialized OFNumber - */ -- (instancetype)initWithShort: (signed short)sShort; - -/*! - * @brief Initializes an already allocated OFNumber with the specified - * `signed int`. - * - * @param sInt A `signed int` which the OFNumber should contain - * @return An initialized OFNumber - */ -- (instancetype)initWithInt: (signed int)sInt; - -/*! - * @brief Initializes an already allocated OFNumber with the specified - * `signed long`. - * - * @param sLong A `signed long` which the OFNumber should contain - * @return An initialized OFNumber - */ -- (instancetype)initWithLong: (signed long)sLong; - -/*! - * @brief Initializes an already allocated OFNumber with the specified - * `signed long long`. - * - * @param sLongLong A `signed long long` which the OFNumber should contain - * @return An initialized OFNumber - */ -- (instancetype)initWithLongLong: (signed long long)sLongLong; + * @brief Initializes an already allocated OFNumber with the specified `short`. + * + * @param sShort A `short` which the OFNumber should contain + * @return An initialized OFNumber + */ +- (instancetype)initWithShort: (short)sShort; + +/*! + * @brief Initializes an already allocated OFNumber with the specified `int`. + * + * @param sInt An `int` which the OFNumber should contain + * @return An initialized OFNumber + */ +- (instancetype)initWithInt: (int)sInt; + +/*! + * @brief Initializes an already allocated OFNumber with the specified `long`. + * + * @param sLong A `long` which the OFNumber should contain + * @return An initialized OFNumber + */ +- (instancetype)initWithLong: (long)sLong; + +/*! + * @brief Initializes an already allocated OFNumber with the specified + * `long long`. + * + * @param sLongLong A `long long` which the OFNumber should contain + * @return An initialized OFNumber + */ +- (instancetype)initWithLongLong: (long long)sLongLong; /*! * @brief Initializes an already allocated OFNumber with the specified * `unsigned char`. * Index: src/OFNumber.m ================================================================== --- src/OFNumber.m +++ src/OFNumber.m @@ -13,10 +13,12 @@ * 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" @@ -27,79 +29,388 @@ #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 () ++ (instancetype)of_alloc; - (OFString *)of_JSONRepresentationWithOptions: (int)options depth: (size_t)depth; @end + +@interface OFNumberPlaceholder: OFNumber +@end + +@interface OFNumberSingleton: OFNumber +@end + +static struct { + Class isa; +} placeholder; + +static OFNumberSingleton *zeroNumber, *oneNumber, *twoNumber; +static OFNumberSingleton *trueNumber, *falseNumber; + +static void +initZeroNumber(void) +{ + zeroNumber = [[OFNumberSingleton alloc] initWithUnsignedChar: 0]; +} + +static void +initOneNumber(void) +{ + oneNumber = [[OFNumberSingleton alloc] initWithUnsignedChar: 1]; +} + +static void +initTwoNumber(void) +{ + twoNumber = [[OFNumberSingleton alloc] initWithUnsignedChar: 2]; +} + +static void +initTrueNumber(void) +{ + trueNumber = [[OFNumberSingleton alloc] initWithBool: true]; +} + +static void +initFalseNumber(void) +{ + falseNumber = [[OFNumberSingleton alloc] initWithBool: false]; +} + +@implementation OFNumberPlaceholder +- (instancetype)initWithBool: (bool)bool_ +{ + if (bool_) { + static of_once_t once; + of_once(&once, initTrueNumber); + return (id)trueNumber; + } else { + static of_once_t once; + of_once(&once, initFalseNumber); + return (id)falseNumber; + } +} + +- (instancetype)initWithChar: (signed char)sChar +{ + if (sChar >= 0) + return [self initWithUnsignedChar: sChar]; + + return (id)[[OFNumber of_alloc] initWithChar: sChar]; +} + +- (instancetype)initWithShort: (short)sShort +{ + if (sShort >= 0) + return [self initWithUnsignedShort: sShort]; + if (sShort >= SCHAR_MIN) + return [self initWithChar: (signed char)sShort]; + + return (id)[[OFNumber of_alloc] initWithShort: sShort]; +} + +- (instancetype)initWithInt: (int)sInt +{ + if (sInt >= 0) + return [self initWithUnsignedInt: sInt]; + if (sInt >= SHRT_MIN) + return [self initWithShort: (short)sInt]; + + return (id)[[OFNumber of_alloc] initWithInt: sInt]; +} + +- (instancetype)initWithLong: (long)sLong +{ + if (sLong >= 0) + return [self initWithUnsignedLong: sLong]; + if (sLong >= INT_MIN) + return [self initWithShort: (int)sLong]; + + return (id)[[OFNumber of_alloc] initWithLong: sLong]; +} + +- (instancetype)initWithLongLong: (long long)sLongLong +{ + if (sLongLong >= 0) + return [self initWithUnsignedLongLong: sLongLong]; + if (sLongLong >= LONG_MIN) + return [self initWithLong: (long)sLongLong]; + + return (id)[[OFNumber of_alloc] initWithLongLong: sLongLong]; +} + +- (instancetype)initWithUnsignedChar: (unsigned char)uChar +{ + switch (uChar) { + case 0: { + static of_once_t once = OF_ONCE_INIT; + of_once(&once, initZeroNumber); + return (id)zeroNumber; + } + case 1: { + static of_once_t once = OF_ONCE_INIT; + of_once(&once, initOneNumber); + return (id)oneNumber; + } + case 2: { + static of_once_t once = OF_ONCE_INIT; + of_once(&once, initTwoNumber); + return (id)twoNumber; + } + } + + return (id)[[OFNumber of_alloc] initWithUnsignedChar: uChar]; +} + +- (instancetype)initWithUnsignedShort: (unsigned short)uShort +{ + if (uShort <= UCHAR_MAX) + return [self initWithUnsignedChar: (unsigned char)uShort]; + + return (id)[[OFNumber of_alloc] initWithUnsignedShort: uShort]; +} + +- (instancetype)initWithUnsignedInt: (unsigned int)uInt +{ + if (uInt <= USHRT_MAX) + return [self initWithUnsignedShort: (unsigned short)uInt]; + + return (id)[[OFNumber of_alloc] initWithUnsignedInt: uInt]; +} + +- (instancetype)initWithUnsignedLong: (unsigned long)uLong +{ + if (uLong <= UINT_MAX) + return [self initWithUnsignedInt: (unsigned int)uLong]; + + return (id)[[OFNumber of_alloc] initWithUnsignedLong: uLong]; +} + +- (instancetype)initWithUnsignedLongLong: (unsigned long long)uLongLong +{ + if (uLongLong <= ULONG_MAX) + return [self initWithUnsignedLong: (unsigned long)uLongLong]; + + return (id)[[OFNumber of_alloc] initWithUnsignedLongLong: uLongLong]; +} + +- (instancetype)initWithInt8: (int8_t)int8 +{ + if (int8 >= 0) + return [self initWithUInt8: int8]; + + return (id)[[OFNumber of_alloc] initWithInt8: int8]; +} + +- (instancetype)initWithInt16: (int16_t)int16 +{ + if (int16 >= 0) + return [self initWithUInt16: int16]; + if (int16 >= INT8_MIN) + return [self initWithInt8: (int8_t)int16]; + + return (id)[[OFNumber of_alloc] initWithInt16: int16]; +} + +- (instancetype)initWithInt32: (int32_t)int32 +{ + if (int32 >= 0) + return [self initWithUInt32: int32]; + if (int32 >= INT16_MIN) + return [self initWithInt16: (int16_t)int32]; + + return (id)[[OFNumber of_alloc] initWithInt32: int32]; +} + +- (instancetype)initWithInt64: (int64_t)int64 +{ + if (int64 >= 0) + return [self initWithUInt64: int64]; + if (int64 >= INT32_MIN) + return [self initWithInt32: (int32_t)int64]; + + return (id)[[OFNumber of_alloc] initWithInt64: int64]; +} + +- (instancetype)initWithUInt8: (uint8_t)uInt8 +{ + return (id)[[OFNumber of_alloc] initWithUInt8: uInt8]; +} + +- (instancetype)initWithUInt16: (uint16_t)uInt16 +{ + if (uInt16 <= UINT8_MAX) + return [self initWithUInt8: (uint8_t)uInt16]; + + return (id)[[OFNumber of_alloc] initWithUInt16: uInt16]; +} + +- (instancetype)initWithUInt32: (uint32_t)uInt32 +{ + if (uInt32 <= UINT16_MAX) + return [self initWithUInt16: (uint16_t)uInt32]; + + return (id)[[OFNumber of_alloc] initWithUInt32: uInt32]; +} + +- (instancetype)initWithUInt64: (uint64_t)uInt64 +{ + if (uInt64 <= UINT32_MAX) + return [self initWithUInt32: (uint32_t)uInt64]; + + return (id)[[OFNumber of_alloc] initWithUInt64: uInt64]; +} + +- (instancetype)initWithSize: (size_t)size +{ + if (size <= ULONG_MAX) + return [self initWithUnsignedLong: (unsigned long)size]; + + return (id)[[OFNumber of_alloc] initWithSize: size]; +} + +- (instancetype)initWithSSize: (ssize_t)sSize +{ + if (sSize >= 0) + return [self initWithSize: sSize]; + if (sSize <= LONG_MIN) + return [self initWithLong: (long)sSize]; + + return (id)[[OFNumber of_alloc] initWithSSize: sSize]; +} + +- (instancetype)initWithIntMax: (intmax_t)intMax +{ + if (intMax >= 0) + return [self initWithUIntMax: intMax]; + if (intMax <= LLONG_MIN) + return [self initWithLongLong: (long long)intMax]; + + return (id)[[OFNumber of_alloc] initWithIntMax: intMax]; +} + +- (instancetype)initWithUIntMax: (uintmax_t)uIntMax +{ + if (uIntMax <= ULLONG_MAX) + return [self initWithUnsignedLongLong: + (unsigned long long)uIntMax]; + + return (id)[[OFNumber of_alloc] initWithUIntMax: uIntMax]; +} + +#ifdef __clang__ +/* + * This warning should probably not exist at all, as it prevents checking + * whether one type fits into another in a portable way. + */ +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare" +#endif + +- (instancetype)initWithPtrDiff: (ptrdiff_t)ptrDiff +{ + if (ptrDiff >= LLONG_MIN && ptrDiff <= LLONG_MAX) + return [self initWithLongLong: (long long)ptrDiff]; + + return (id)[[OFNumber of_alloc] initWithPtrDiff: ptrDiff]; +} + +- (instancetype)initWithIntPtr: (intptr_t)intPtr +{ + if (intPtr >= 0) + return [self initWithUIntPtr: intPtr]; + if (intPtr >= LLONG_MIN) + return [self initWithLongLong: (long long)intPtr]; + + return (id)[[OFNumber of_alloc] initWithIntPtr: intPtr]; +} + +- (instancetype)initWithUIntPtr: (uintptr_t)uIntPtr +{ + if (uIntPtr <= ULLONG_MAX) + return [self initWithUnsignedLongLong: + (unsigned long long)uIntPtr]; + + return (id)[[OFNumber of_alloc] initWithUIntPtr: uIntPtr]; +} + +#ifdef __clang__ +# pragma clang diagnostic pop +#endif + +- (instancetype)initWithFloat: (float)float_ +{ + if (float_ == (uintmax_t)float_) + return [self initWithUIntMax: (uintmax_t)float_]; + if (float_ == (intmax_t)float_) + return [self initWithIntMax: (intmax_t)float_]; + + return (id)[[OFNumber of_alloc] initWithFloat: float_]; +} + +- (instancetype)initWithDouble: (double)double_ +{ + if (double_ == (uintmax_t)double_) + return [self initWithUIntMax: (uintmax_t)double_]; + if (double_ == (intmax_t)double_) + return [self initWithIntMax: (intmax_t)double_]; + if (double_ == (float)double_) + return [self initWithFloat: (float)double_]; + + return (id)[[OFNumber of_alloc] initWithDouble: double_]; +} + +- (instancetype)initWithSerialization: (OFXMLElement *)element +{ + return (id)[[OFNumber of_alloc] initWithSerialization: element]; +} +@end + +@implementation OFNumberSingleton +- (instancetype)autorelease +{ + return self; +} + +- (instancetype)retain +{ + return self; +} + +- (void)release +{ +} + +- (unsigned int)retainCount +{ + return OF_RETAIN_COUNT_MAX; +} +@end @implementation OFNumber -@synthesize type = _type; ++ (void)initialize +{ + if (self == [OFNumber class]) + placeholder.isa = [OFNumberPlaceholder class]; +} + ++ (instancetype)of_alloc +{ + return [super alloc]; +} + ++ (instancetype)alloc +{ + if (self == [OFNumber class]) + return (id)&placeholder; + + return [super alloc]; +} + (instancetype)numberWithBool: (bool)bool_ { return [[[self alloc] initWithBool: bool_] autorelease]; } @@ -107,26 +418,26 @@ + (instancetype)numberWithChar: (signed char)sChar { return [[[self alloc] initWithChar: sChar] autorelease]; } -+ (instancetype)numberWithShort: (signed short)sShort ++ (instancetype)numberWithShort: (short)sShort { return [[[self alloc] initWithShort: sShort] autorelease]; } -+ (instancetype)numberWithInt: (signed int)sInt ++ (instancetype)numberWithInt: (int)sInt { return [[[self alloc] initWithInt: sInt] autorelease]; } -+ (instancetype)numberWithLong: (signed long)sLong ++ (instancetype)numberWithLong: (long)sLong { return [[[self alloc] initWithLong: sLong] autorelease]; } -+ (instancetype)numberWithLongLong: (signed long long)sLongLong ++ (instancetype)numberWithLongLong: (long long)sLongLong { return [[[self alloc] initWithLongLong: sLongLong] autorelease]; } + (instancetype)numberWithUnsignedChar: (unsigned char)uChar @@ -246,262 +557,288 @@ - (instancetype)initWithBool: (bool)bool_ { self = [super init]; - _value.bool_ = bool_; - _type = OF_NUMBER_TYPE_BOOL; + _value.unsigned_ = bool_; + _type = OF_NUMBER_TYPE_UNSIGNED; + _typeEncoding = @encode(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; + _value.signed_ = sChar; + _type = OF_NUMBER_TYPE_SIGNED; + _typeEncoding = @encode(signed char); + + return self; +} + +- (instancetype)initWithShort: (short)sShort +{ + self = [super init]; + + _value.signed_ = sShort; + _type = OF_NUMBER_TYPE_SIGNED; + _typeEncoding = @encode(short); + + return self; +} + +- (instancetype)initWithInt: (int)sInt +{ + self = [super init]; + + _value.signed_ = sInt; + _type = OF_NUMBER_TYPE_SIGNED; + _typeEncoding = @encode(int); + + return self; +} + +- (instancetype)initWithLong: (long)sLong +{ + self = [super init]; + + _value.signed_ = sLong; + _type = OF_NUMBER_TYPE_SIGNED; + _typeEncoding = @encode(long); + + return self; +} + +- (instancetype)initWithLongLong: (long long)sLongLong +{ + self = [super init]; + + _value.signed_ = sLongLong; + _type = OF_NUMBER_TYPE_SIGNED; + _typeEncoding = @encode(long long); return self; } - (instancetype)initWithUnsignedChar: (unsigned char)uChar { self = [super init]; - _value.uChar = uChar; - _type = OF_NUMBER_TYPE_UCHAR; + _value.unsigned_ = uChar; + _type = OF_NUMBER_TYPE_UNSIGNED; + _typeEncoding = @encode(unsigned long); return self; } - (instancetype)initWithUnsignedShort: (unsigned short)uShort { self = [super init]; - _value.uShort = uShort; - _type = OF_NUMBER_TYPE_USHORT; + _value.unsigned_ = uShort; + _type = OF_NUMBER_TYPE_UNSIGNED; + _typeEncoding = @encode(unsigned short); return self; } - (instancetype)initWithUnsignedInt: (unsigned int)uInt { self = [super init]; - _value.uInt = uInt; - _type = OF_NUMBER_TYPE_UINT; + _value.unsigned_ = uInt; + _type = OF_NUMBER_TYPE_UNSIGNED; + _typeEncoding = @encode(unsigned int); return self; } - (instancetype)initWithUnsignedLong: (unsigned long)uLong { self = [super init]; - _value.uLong = uLong; - _type = OF_NUMBER_TYPE_ULONG; + _value.unsigned_ = uLong; + _type = OF_NUMBER_TYPE_UNSIGNED; + _typeEncoding = @encode(unsigned long); return self; } - (instancetype)initWithUnsignedLongLong: (unsigned long long)uLongLong { self = [super init]; - _value.uLongLong = uLongLong; - _type = OF_NUMBER_TYPE_ULONGLONG; + _value.unsigned_ = uLongLong; + _type = OF_NUMBER_TYPE_UNSIGNED; + _typeEncoding = @encode(unsigned long long); return self; } - (instancetype)initWithInt8: (int8_t)int8 { self = [super init]; - _value.int8 = int8; - _type = OF_NUMBER_TYPE_INT8; + _value.signed_ = int8; + _type = OF_NUMBER_TYPE_SIGNED; + _typeEncoding = @encode(int8_t); return self; } - (instancetype)initWithInt16: (int16_t)int16 { self = [super init]; - _value.int16 = int16; - _type = OF_NUMBER_TYPE_INT16; + _value.signed_ = int16; + _type = OF_NUMBER_TYPE_SIGNED; + _typeEncoding = @encode(int16_t); return self; } - (instancetype)initWithInt32: (int32_t)int32 { self = [super init]; - _value.int32 = int32; - _type = OF_NUMBER_TYPE_INT32; + _value.signed_ = int32; + _type = OF_NUMBER_TYPE_SIGNED; + _typeEncoding = @encode(int32_t); return self; } - (instancetype)initWithInt64: (int64_t)int64 { self = [super init]; - _value.int64 = int64; - _type = OF_NUMBER_TYPE_INT64; + _value.signed_ = int64; + _type = OF_NUMBER_TYPE_SIGNED; + _typeEncoding = @encode(int64_t); return self; } - (instancetype)initWithUInt8: (uint8_t)uInt8 { self = [super init]; - _value.uInt8 = uInt8; - _type = OF_NUMBER_TYPE_UINT8; + _value.unsigned_ = uInt8; + _type = OF_NUMBER_TYPE_UNSIGNED; + _typeEncoding = @encode(uint8_t); return self; } - (instancetype)initWithUInt16: (uint16_t)uInt16 { self = [super init]; - _value.uInt16 = uInt16; - _type = OF_NUMBER_TYPE_UINT16; + _value.unsigned_ = uInt16; + _type = OF_NUMBER_TYPE_UNSIGNED; + _typeEncoding = @encode(uint16_t); return self; } - (instancetype)initWithUInt32: (uint32_t)uInt32 { self = [super init]; - _value.uInt32 = uInt32; - _type = OF_NUMBER_TYPE_UINT32; + _value.unsigned_ = uInt32; + _type = OF_NUMBER_TYPE_UNSIGNED; + _typeEncoding = @encode(uint32_t); return self; } - (instancetype)initWithUInt64: (uint64_t)uInt64 { self = [super init]; - _value.uInt64 = uInt64; - _type = OF_NUMBER_TYPE_UINT64; + _value.unsigned_ = uInt64; + _type = OF_NUMBER_TYPE_UNSIGNED; + _typeEncoding = @encode(uint64_t); return self; } - (instancetype)initWithSize: (size_t)size { self = [super init]; - _value.size = size; - _type = OF_NUMBER_TYPE_SIZE; + _value.unsigned_ = size; + _type = OF_NUMBER_TYPE_UNSIGNED; + _typeEncoding = @encode(size_t); return self; } - (instancetype)initWithSSize: (ssize_t)sSize { self = [super init]; - _value.sSize = sSize; - _type = OF_NUMBER_TYPE_SSIZE; + _value.signed_ = sSize; + _type = OF_NUMBER_TYPE_SIGNED; + _typeEncoding = @encode(ssize_t); return self; } - (instancetype)initWithIntMax: (intmax_t)intMax { self = [super init]; - _value.intMax = intMax; - _type = OF_NUMBER_TYPE_INTMAX; + _value.signed_ = intMax; + _type = OF_NUMBER_TYPE_SIGNED; + _typeEncoding = @encode(intmax_t); return self; } - (instancetype)initWithUIntMax: (uintmax_t)uIntMax { self = [super init]; - _value.uIntMax = uIntMax; - _type = OF_NUMBER_TYPE_UINTMAX; + _value.unsigned_ = uIntMax; + _type = OF_NUMBER_TYPE_UNSIGNED; + _typeEncoding = @encode(uintmax_t); return self; } - (instancetype)initWithPtrDiff: (ptrdiff_t)ptrDiff { self = [super init]; - _value.ptrDiff = ptrDiff; - _type = OF_NUMBER_TYPE_PTRDIFF; + _value.signed_ = ptrDiff; + _type = OF_NUMBER_TYPE_SIGNED; + _typeEncoding = @encode(ptrdiff_t); return self; } - (instancetype)initWithIntPtr: (intptr_t)intPtr { self = [super init]; - _value.intPtr = intPtr; - _type = OF_NUMBER_TYPE_INTPTR; + _value.signed_ = intPtr; + _type = OF_NUMBER_TYPE_SIGNED; + _typeEncoding = @encode(intptr_t); return self; } - (instancetype)initWithUIntPtr: (uintptr_t)uIntPtr { self = [super init]; - _value.uIntPtr = uIntPtr; - _type = OF_NUMBER_TYPE_UINTPTR; + _value.unsigned_ = uIntPtr; + _type = OF_NUMBER_TYPE_UNSIGNED; + _typeEncoding = @encode(uintptr_t); return self; } - (instancetype)initWithFloat: (float)float_ @@ -508,20 +845,22 @@ { self = [super init]; _value.float_ = float_; _type = OF_NUMBER_TYPE_FLOAT; + _typeEncoding = @encode(float); return self; } - (instancetype)initWithDouble: (double)double_ { self = [super init]; - _value.double_ = double_; - _type = OF_NUMBER_TYPE_DOUBLE; + _value.float_ = double_; + _type = OF_NUMBER_TYPE_FLOAT; + _typeEncoding = @encode(double); return self; } - (instancetype)initWithSerialization: (OFXMLElement *)element @@ -536,40 +875,31 @@ ![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; + if ([typeString isEqual: @"bool"]) { + OFString *stringValue = element.stringValue; + if ([stringValue isEqual: @"true"]) + self = [self initWithBool: true]; + else if ([stringValue isEqual: @"false"]) + self = [self initWithBool: false]; else @throw [OFInvalidArgumentException exception]; - } else if ([typeString isEqual: @"unsigned"]) { + } else if ([typeString isEqual: @"float"]) + self = [self initWithDouble: OF_BSWAP_DOUBLE_IF_LE( + OF_INT_TO_DOUBLE_RAW(OF_BSWAP64_IF_LE( + (uint64_t)element.hexadecimalValue)))]; + else if ([typeString isEqual: @"signed"]) + self = [self initWithIntMax: element.doubleValue]; + 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"]) { - _type = OF_NUMBER_TYPE_FLOAT; - _value.float_ = OF_BSWAP_FLOAT_IF_LE( - OF_INT_TO_FLOAT_RAW(OF_BSWAP32_IF_LE( - (uint32_t)element.hexadecimalValue))); - } else if ([typeString isEqual: @"double"]) { - _type = OF_NUMBER_TYPE_DOUBLE; - _value.double_ = OF_BSWAP_DOUBLE_IF_LE( - OF_INT_TO_DOUBLE_RAW(OF_BSWAP64_IF_LE( - (uint64_t)element.hexadecimalValue))); - } else + self = [self initWithUIntMax: element.decimalValue]; + else @throw [OFInvalidArgumentException exception]; objc_autoreleasePoolPop(pool); } @catch (id e) { [self release]; @@ -579,249 +909,57 @@ 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]; - } -} - + return _typeEncoding; +} + +- (void)getValue: (void *)value + size: (size_t)size +{ + switch (*_typeEncoding) { +#define CASE(enc, type, field) \ + case enc: { \ + type tmp = (type)_value.field; \ + \ + if (size != sizeof(type)) \ + @throw [OFOutOfRangeException exception]; \ + \ + memcpy(value, &tmp, size); \ + break; \ + } + CASE('B', bool, unsigned_) + CASE('c', signed char, signed_) + CASE('s', short, signed_) + CASE('i', int, signed_) + CASE('l', long, signed_) + CASE('q', long long, signed_) + CASE('C', unsigned char, unsigned_) + CASE('S', unsigned short, unsigned_) + CASE('I', unsigned int, unsigned_) + CASE('L', unsigned long, unsigned_) + CASE('Q', unsigned long long, unsigned_) + CASE('f', float, float_) + CASE('d', double, float_) +#undef CASE + default: + @throw [OFInvalidFormatException exception]; + } +} + +#define RETURN_AS(t) \ + switch (_type) { \ + case OF_NUMBER_TYPE_FLOAT: \ + return (t)_value.float_; \ + case OF_NUMBER_TYPE_SIGNED: \ + return (t)_value.signed_; \ + case OF_NUMBER_TYPE_UNSIGNED: \ + return (t)_value.unsigned_; \ + default: \ + @throw [OFInvalidFormatException exception]; \ + } - (bool)boolValue { RETURN_AS(bool) } @@ -828,28 +966,28 @@ - (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) +- (short)shortValue +{ + RETURN_AS(short) +} + +- (int)intValue +{ + RETURN_AS(int) +} + +- (long)longValue +{ + RETURN_AS(long) +} + +- (long long)longLongValue +{ + RETURN_AS(long long) } - (unsigned char)unsignedCharValue { RETURN_AS(unsigned char) @@ -957,10 +1095,11 @@ - (double)doubleValue { RETURN_AS(double) } +#undef RETURN_AS - (bool)isEqual: (id)object { OFNumber *number; @@ -970,12 +1109,12 @@ if (![object isKindOfClass: [OFNumber class]]) return false; number = object; - if (_type & OF_NUMBER_TYPE_FLOAT || - number->_type & OF_NUMBER_TYPE_FLOAT) { + 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; @@ -983,12 +1122,12 @@ return false; return (value1 == value2); } - if (_type & OF_NUMBER_TYPE_SIGNED || - number->_type & OF_NUMBER_TYPE_SIGNED) + if (_type == OF_NUMBER_TYPE_SIGNED || + number->_type == OF_NUMBER_TYPE_SIGNED) return (number.intMaxValue == self.intMaxValue); return (number.uIntMaxValue == self.uIntMaxValue); } @@ -999,23 +1138,23 @@ if (![(id)object isKindOfClass: [OFNumber class]]) @throw [OFInvalidArgumentException exception]; number = (OFNumber *)object; - if (_type & OF_NUMBER_TYPE_FLOAT || - number->_type & OF_NUMBER_TYPE_FLOAT) { + 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) { + } 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; @@ -1036,61 +1175,43 @@ } } - (uint32_t)hash { - of_number_type_t type = _type; + enum of_number_type 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) { + if (type == OF_NUMBER_TYPE_FLOAT) { double d; if (isnan(self.doubleValue)) return 0; d = OF_BSWAP_DOUBLE_IF_BE(self.doubleValue); for (uint_fast8_t i = 0; i < sizeof(double); i++) OF_HASH_ADD(hash, ((char *)&d)[i]); - } else if (type & OF_NUMBER_TYPE_SIGNED) { + } 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 { + } else if (type == OF_NUMBER_TYPE_UNSIGNED) { uintmax_t v = self.uIntMaxValue; while (v != 0) { OF_HASH_ADD(hash, v & 0xFF); v >>= 8; } - } + } else + @throw [OFInvalidFormatException exception]; OF_HASH_FINALIZE(hash); return hash; } @@ -1105,63 +1226,20 @@ return [self stringValue]; } - (OFString *)stringValue { - 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]; - } + if (*_typeEncoding == 'B') + return (_value.unsigned_ ? @"true" : @"false"); + if (_type == OF_NUMBER_TYPE_FLOAT) + return [OFString stringWithFormat: @"%g", _value.float_]; + if (_type == OF_NUMBER_TYPE_SIGNED) + return [OFString stringWithFormat: @"%jd", _value.signed_]; + if (_type == OF_NUMBER_TYPE_UNSIGNED) + return [OFString stringWithFormat: @"%ju", _value.unsigned_]; + + @throw [OFInvalidFormatException exception]; } - (OFXMLElement *)XMLElementBySerializing { void *pool = objc_autoreleasePoolPush(); @@ -1169,66 +1247,28 @@ 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: + if (*_typeEncoding == 'B') + [element addAttributeWithName: @"type" + stringValue: @"bool"]; + else if (_type == OF_NUMBER_TYPE_FLOAT) { [element addAttributeWithName: @"type" stringValue: @"float"]; - element.stringValue = [OFString stringWithFormat: @"%08" PRIx32, - OF_BSWAP32_IF_LE(OF_FLOAT_TO_INT_RAW(OF_BSWAP_FLOAT_IF_LE( - _value.float_)))]; - - break; - case OF_NUMBER_TYPE_DOUBLE: - [element addAttributeWithName: @"type" - stringValue: @"double"]; element.stringValue = [OFString stringWithFormat: @"%016" PRIx64, OF_BSWAP64_IF_LE(OF_DOUBLE_TO_INT_RAW(OF_BSWAP_DOUBLE_IF_LE( - _value.double_)))]; - - break; - default: + _value.float_)))]; + } else if (_type == OF_NUMBER_TYPE_SIGNED) + [element addAttributeWithName: @"type" + stringValue: @"signed"]; + else if (_type == OF_NUMBER_TYPE_UNSIGNED) + [element addAttributeWithName: @"type" + stringValue: @"unsigned"]; + else @throw [OFInvalidFormatException exception]; - } [element retain]; objc_autoreleasePoolPop(pool); @@ -1250,12 +1290,12 @@ - (OFString *)of_JSONRepresentationWithOptions: (int)options depth: (size_t)depth { double doubleValue; - if (_type == OF_NUMBER_TYPE_BOOL) - return (_value.bool_ ? @"true" : @"false"); + if (*_typeEncoding == 'B') + return (_value.unsigned_ ? @"true" : @"false"); doubleValue = self.doubleValue; if (isinf(doubleValue)) { if (options & OF_JSON_REPRESENTATION_JSON5) { if (doubleValue > 0) @@ -1271,36 +1311,36 @@ - (OFData *)messagePackRepresentation { OFMutableData *data; - if (_type == OF_NUMBER_TYPE_BOOL) { - uint8_t type = (_value.bool_ ? 0xC3 : 0xC2); + if (*_typeEncoding == 'B') { + uint8_t type = (_value.unsigned_ ? 0xC3 : 0xC2); data = [OFMutableData dataWithItems: &type count: 1]; - } else if (_type == OF_NUMBER_TYPE_FLOAT) { + } else if (*_typeEncoding == 'f') { 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) { + } else if (*_typeEncoding == 'd') { uint8_t type = 0xCB; - double tmp = OF_BSWAP_DOUBLE_IF_LE(_value.double_); + double tmp = OF_BSWAP_DOUBLE_IF_LE(_value.float_); data = [OFMutableData dataWithItemSize: 1 capacity: 9]; [data addItem: &type]; [data addItems: &tmp count: sizeof(tmp)]; - } else if (_type & OF_NUMBER_TYPE_SIGNED) { + } 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); @@ -1345,11 +1385,11 @@ [data addItem: &type]; [data addItems: &tmp count: sizeof(tmp)]; } else @throw [OFOutOfRangeException exception]; - } else { + } else if (_type == OF_NUMBER_TYPE_UNSIGNED) { uintmax_t value = self.uIntMaxValue; if (value <= 127) { uint8_t tmp = ((uint8_t)value & 0x7F); @@ -1394,12 +1434,13 @@ [data addItem: &type]; [data addItems: &tmp count: sizeof(tmp)]; } else @throw [OFOutOfRangeException exception]; - } + } else + @throw [OFInvalidFormatException exception]; [data makeImmutable]; return data; } @end Index: tests/serialization.xml ================================================================== --- tests/serialization.xml +++ tests/serialization.xml @@ -15,12 +15,12 @@ Qu"xbar test - 1234 - 40934a456d5cfaad + 1234 + 40934a456d5cfaad asd 40934a456d5cfaad