/* * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in * compliance with the License. Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this * file. * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. * * @APPLE_LICENSE_HEADER_END@ */ /* CFNumber.c Copyright 1999-2002, Apple, Inc. All rights reserved. Responsibility: Ali Ozer */ #include #include "CFInternal.h" #include "CFUtilitiesPriv.h" #include #include #if defined(__WIN32__) && !defined(__MINGW32__) && !defined(__CYGWIN__) #define isnan _isnan #define isinf !_finite #endif /* Various assertions */ #define __CFAssertIsBoolean(cf) __CFGenericValidateType(cf, __kCFBooleanTypeID) #define __CFAssertIsNumber(cf) __CFGenericValidateType(cf, __kCFNumberTypeID) #define __CFAssertIsValidNumberType(type) CFAssert2((type > 0 && type <= kCFNumberMaxType && __CFNumberCanonicalType[type]), __kCFLogAssertion, "%s(): bad CFNumber type %d", __PRETTY_FUNCTION__, type); #define __CFInvalidNumberStorageType(type) CFAssert2(true, __kCFLogAssertion, "%s(): bad CFNumber storage type %d", __PRETTY_FUNCTION__, type); /* The IEEE bit patterns... Also have: 0x7f800000 float +Inf 0x7fc00000 float NaN 0xff800000 float -Inf */ #define BITSFORDOUBLENAN ((uint64_t)0x7ff8000000000000ULL) #define BITSFORDOUBLEPOSINF ((uint64_t)0x7ff0000000000000ULL) #define BITSFORDOUBLENEGINF ((uint64_t)0xfff0000000000000ULL) struct __CFBoolean { CFRuntimeBase _base; }; static struct __CFBoolean __kCFBooleanTrue = { INIT_CFRUNTIME_BASE(NULL, 0, 0x0080) }; const CFBooleanRef kCFBooleanTrue = &__kCFBooleanTrue; static struct __CFBoolean __kCFBooleanFalse = { INIT_CFRUNTIME_BASE(NULL, 0, 0x0080) }; const CFBooleanRef kCFBooleanFalse = &__kCFBooleanFalse; static CFStringRef __CFBooleanCopyDescription(CFTypeRef cf) { CFBooleanRef boolean = (CFBooleanRef)cf; return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("{value = %s}"), cf, CFGetAllocator(cf), (boolean == kCFBooleanTrue) ? "true" : "false"); } static CFStringRef __CFBooleanCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { CFBooleanRef boolean = (CFBooleanRef)cf; return CFRetain((boolean == kCFBooleanTrue) ? CFSTR("true") : CFSTR("false")); } static void __CFBooleanDeallocate(CFTypeRef cf) { CFAssert(false, __kCFLogAssertion, "Deallocated CFBoolean!"); } static CFTypeID __kCFBooleanTypeID = _kCFRuntimeNotATypeID; static const CFRuntimeClass __CFBooleanClass = { 0, "CFBoolean", NULL, // init NULL, // copy __CFBooleanDeallocate, NULL, NULL, __CFBooleanCopyFormattingDescription, __CFBooleanCopyDescription }; __private_extern__ void __CFBooleanInitialize(void) { __kCFBooleanTypeID = _CFRuntimeRegisterClass(&__CFBooleanClass); _CFRuntimeSetInstanceTypeID(&__kCFBooleanTrue, __kCFBooleanTypeID); __kCFBooleanTrue._base._isa = __CFISAForTypeID(__kCFBooleanTypeID); _CFRuntimeSetInstanceTypeID(&__kCFBooleanFalse, __kCFBooleanTypeID); __kCFBooleanFalse._base._isa = __CFISAForTypeID(__kCFBooleanTypeID); } CFTypeID CFBooleanGetTypeID(void) { return __kCFBooleanTypeID; } Boolean CFBooleanGetValue(CFBooleanRef boolean) { CF_OBJC_FUNCDISPATCH0(__kCFBooleanTypeID, Boolean, boolean, "boolValue"); return (boolean == kCFBooleanTrue) ? true : false; } /*** CFNumber ***/ typedef union { SInt32 valSInt32; int64_t valSInt64; Float32 valFloat32; Float64 valFloat64; } __CFNumberValue; struct __CFNumber { /* Only as many bytes as necessary are allocated */ CFRuntimeBase _base; __CFNumberValue value; }; static struct __CFNumber __kCFNumberNaN = { INIT_CFRUNTIME_BASE(NULL, 0, 0x0080), {0} }; const CFNumberRef kCFNumberNaN = &__kCFNumberNaN; static struct __CFNumber __kCFNumberNegativeInfinity = { INIT_CFRUNTIME_BASE(NULL, 0, 0x0080), {0} }; const CFNumberRef kCFNumberNegativeInfinity = &__kCFNumberNegativeInfinity; static struct __CFNumber __kCFNumberPositiveInfinity = { INIT_CFRUNTIME_BASE(NULL, 0, 0x0080), {0} }; const CFNumberRef kCFNumberPositiveInfinity = &__kCFNumberPositiveInfinity; /* Seven bits in base: Bits 4..0: CFNumber type Bit 6: is unsigned number */ /* ??? These tables should be changed on different architectures, depending on the actual sizes of basic C types such as int, long, float; also size of CFIndex. We can probably compute these tables at runtime. */ /* Canonical types are the types that the implementation knows how to deal with. There should be one for each type that is distinct; so this table basically is a type equivalence table. All functions that take a type from the outside world should call __CFNumberGetCanonicalTypeForType() before doing anything with it. */ static const unsigned char __CFNumberCanonicalType[kCFNumberMaxType + 1] = { 0, kCFNumberSInt8Type, kCFNumberSInt16Type, kCFNumberSInt32Type, kCFNumberSInt64Type, kCFNumberFloat32Type, kCFNumberFloat64Type, kCFNumberSInt8Type, kCFNumberSInt16Type, kCFNumberSInt32Type, kCFNumberSInt32Type, kCFNumberSInt64Type, kCFNumberFloat32Type, kCFNumberFloat64Type, kCFNumberSInt32Type }; /* This table determines what storage format is used for any given type. !!! These are the only types that can occur in the types field of a CFNumber. !!! If the number or kind of types returned by this array changes, also need to fix NSNumber and NSCFNumber. */ static const unsigned char __CFNumberStorageType[kCFNumberMaxType + 1] = { 0, kCFNumberSInt32Type, kCFNumberSInt32Type, kCFNumberSInt32Type, kCFNumberSInt64Type, kCFNumberFloat32Type, kCFNumberFloat64Type, kCFNumberSInt32Type, kCFNumberSInt32Type, kCFNumberSInt32Type, kCFNumberSInt32Type, kCFNumberSInt64Type, kCFNumberFloat32Type, kCFNumberFloat64Type, kCFNumberSInt32Type }; // Returns the type that is used to store the specified type CF_INLINE CFNumberType __CFNumberGetStorageTypeForType(CFNumberType type) { return __CFNumberStorageType[type]; } // Returns the canonical type used to represent the specified type CF_INLINE CFNumberType __CFNumberGetCanonicalTypeForType(CFNumberType type) { return __CFNumberCanonicalType[type]; } // Extracts and returns the type out of the CFNumber CF_INLINE CFNumberType __CFNumberGetType(CFNumberRef num) { return __CFBitfieldGetValue(num->_base._info, 4, 0); } // Returns true if the argument type is float or double CF_INLINE Boolean __CFNumberTypeIsFloat(CFNumberType type) { return (type == kCFNumberFloat64Type) || (type == kCFNumberFloat32Type) || (type == kCFNumberDoubleType) || (type == kCFNumberFloatType); } // Returns the number of bytes necessary to store the specified type // Needs to handle all canonical types CF_INLINE CFIndex __CFNumberSizeOfType(CFNumberType type) { switch (type) { case kCFNumberSInt8Type: return sizeof(int8_t); case kCFNumberSInt16Type: return sizeof(int16_t); case kCFNumberSInt32Type: return sizeof(SInt32); case kCFNumberSInt64Type: return sizeof(int64_t); case kCFNumberFloat32Type: return sizeof(Float32); case kCFNumberFloat64Type: return sizeof(Float64); default: return 0; } } // Copies an external value of a given type into the appropriate slot in the union (does no type conversion) // Needs to handle all canonical types #define SET_VALUE(valueUnion, type, valuePtr) \ switch (type) { \ case kCFNumberSInt8Type: (valueUnion)->valSInt32 = *(int8_t *)(valuePtr); break; \ case kCFNumberSInt16Type: (valueUnion)->valSInt32 = *(int16_t *)(valuePtr); break; \ case kCFNumberSInt32Type: (valueUnion)->valSInt32 = *(SInt32 *)(valuePtr); break; \ case kCFNumberSInt64Type: (valueUnion)->valSInt64 = *(int64_t *)(valuePtr); break; \ case kCFNumberFloat32Type: (valueUnion)->valFloat32 = *(Float32 *)(valuePtr); break; \ case kCFNumberFloat64Type: (valueUnion)->valFloat64 = *(Float64 *)(valuePtr); break; \ default: break; \ } // Casts the specified value into the specified type and copies it into the provided memory // Needs to handle all canonical types #define GET_VALUE(value, type, resultPtr) \ switch (type) { \ case kCFNumberSInt8Type: *(int8_t *)(resultPtr) = (int8_t)value; break; \ case kCFNumberSInt16Type: *(int16_t *)(resultPtr) = (int16_t)value; break; \ case kCFNumberSInt32Type: *(SInt32 *)(resultPtr) = (SInt32)value; break; \ case kCFNumberSInt64Type: *(int64_t *)(resultPtr) = (int64_t)value; break; \ case kCFNumberFloat32Type: *(Float32 *)(resultPtr) = (Float32)value; break; \ case kCFNumberFloat64Type: *(Float64 *)(resultPtr) = (Float64)value; break; \ default: break; \ } // Extracts the stored type out of the union and copies it in the desired type into the provided memory // Needs to handle all storage types CF_INLINE void __CFNumberGetValue(const __CFNumberValue *value, CFNumberType numberType, CFNumberType typeToGet, void *valuePtr) { switch (numberType) { case kCFNumberSInt32Type: GET_VALUE(value->valSInt32, typeToGet, valuePtr); break; case kCFNumberSInt64Type: GET_VALUE(value->valSInt64, typeToGet, valuePtr); break; case kCFNumberFloat32Type: GET_VALUE(value->valFloat32, typeToGet, valuePtr); break; case kCFNumberFloat64Type: GET_VALUE(value->valFloat64, typeToGet, valuePtr); break; default: break; \ } } // Sees if two value union structs have the same value (will do type conversion) static Boolean __CFNumberEqualValue(const __CFNumberValue *value1, CFNumberType type1, const __CFNumberValue *value2, CFNumberType type2) { if (__CFNumberTypeIsFloat(type1) || __CFNumberTypeIsFloat(type2)) { Float64 d1, d2; __CFNumberGetValue(value1, type1, kCFNumberFloat64Type, &d1); __CFNumberGetValue(value2, type2, kCFNumberFloat64Type, &d2); if (_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) { if (isnan(d1) && isnan(d2)) return true; // Not mathematically sound, but required } return d1 == d2; } else { int64_t i1, i2; __CFNumberGetValue(value1, type1, kCFNumberSInt64Type, &i1); __CFNumberGetValue(value2, type2, kCFNumberSInt64Type, &i2); return i1 == i2; } } static Boolean __CFNumberEqual(CFTypeRef cf1, CFTypeRef cf2) { CFNumberRef number1 = (CFNumberRef)cf1; CFNumberRef number2 = (CFNumberRef)cf2; return __CFNumberEqualValue(&(number1->value), __CFNumberGetType(number1), &(number2->value), __CFNumberGetType(number2)); } static CFHashCode __CFNumberHash(CFTypeRef cf) { CFNumberRef number = (CFNumberRef)cf; switch (__CFNumberGetType(cf)) { case kCFNumberSInt32Type: return _CFHashInt(number->value.valSInt32); case kCFNumberSInt64Type: return _CFHashDouble((double)(number->value.valSInt64)); case kCFNumberFloat32Type: return _CFHashDouble((double)(number->value.valFloat32)); case kCFNumberFloat64Type: return _CFHashDouble((double)(number->value.valFloat64)); default: __CFInvalidNumberStorageType(__CFNumberGetType(cf)); return 0; } } #define bufSize 100 #define emitChar(ch) \ {if (buf - stackBuf == bufSize) {CFStringAppendCharacters(mstr, stackBuf, bufSize); buf = stackBuf;} *buf++ = ch;} static void __CFNumberEmitInt64(CFMutableStringRef mstr, int64_t value, int32_t width, UniChar pad, bool explicitPlus) { UniChar stackBuf[bufSize], *buf = stackBuf; uint64_t uvalue, factor, tmp; int32_t w; bool neg; neg = (value < 0) ? true : false; uvalue = (neg) ? -value : value; if (neg || explicitPlus) width--; width--; factor = 1; tmp = uvalue; while (9 < tmp) { width--; factor *= 10; tmp /= 10; } for (w = 0; w < width; w++) emitChar(pad); if (neg) { emitChar('-'); } else if (explicitPlus) { emitChar('+'); } while (0 < factor) { UniChar ch = '0' + (uvalue / factor); uvalue %= factor; emitChar(ch); factor /= 10; } if (buf > stackBuf) CFStringAppendCharacters(mstr, stackBuf, buf - stackBuf); } static CFStringRef __CFNumberCopyDescription(CFTypeRef cf) { CFNumberRef number = (CFNumberRef)cf; CFMutableStringRef mstr = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); CFStringAppendFormat(mstr, NULL, CFSTR("{value = "), cf, CFGetAllocator(cf)); switch (__CFNumberGetType(number)) { case kCFNumberSInt32Type: __CFNumberEmitInt64(mstr, number->value.valSInt32, 0, ' ', true); CFStringAppendFormat(mstr, NULL, CFSTR(", type = kCFNumberSInt32Type}")); break; case kCFNumberSInt64Type: __CFNumberEmitInt64(mstr, number->value.valSInt64, 0, ' ', true); CFStringAppendFormat(mstr, NULL, CFSTR(", type = kCFNumberSInt64Type}")); break; case kCFNumberFloat32Type: // debugging formatting is intentionally more verbose and explicit about the value of the number if (isnan(number->value.valFloat32)) { CFStringAppend(mstr, CFSTR("nan")); } else if (isinf(number->value.valFloat32)) { CFStringAppend(mstr, (0.0f < number->value.valFloat32) ? CFSTR("+infinity") : CFSTR("-infinity")); } else if (0.0f == number->value.valFloat32) { CFStringAppend(mstr, (copysign(1.0, number->value.valFloat32) < 0.0) ? CFSTR("-0.0") : CFSTR("+0.0")); } else { CFStringAppendFormat(mstr, NULL, CFSTR("%+.10f"), number->value.valFloat32); } CFStringAppend(mstr, CFSTR(", type = kCFNumberFloat32Type}")); break; case kCFNumberFloat64Type: // debugging formatting is intentionally more verbose and explicit about the value of the number if (isnan(number->value.valFloat64)) { CFStringAppend(mstr, CFSTR("nan")); } else if (isinf(number->value.valFloat64)) { CFStringAppend(mstr, (0.0 < number->value.valFloat64) ? CFSTR("+infinity") : CFSTR("-infinity")); } else if (0.0 == number->value.valFloat64) { CFStringAppend(mstr, (copysign(1.0, number->value.valFloat64) < 0.0) ? CFSTR("-0.0") : CFSTR("+0.0")); } else { CFStringAppendFormat(mstr, NULL, CFSTR("%+.20f"), number->value.valFloat64); } CFStringAppend(mstr, CFSTR(", type = kCFNumberFloat64Type}")); break; default: __CFInvalidNumberStorageType(__CFNumberGetType(number)); CFRelease(mstr); return NULL; } return mstr; } // This function separated out from __CFNumberCopyFormattingDescription() so the plist creation can use it as well. __private_extern__ CFStringRef __CFNumberCopyFormattingDescriptionAsFloat64(CFTypeRef cf) { double d; CFNumberGetValue(cf, kCFNumberFloat64Type, &d); if (_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) { if (isnan(d)) { return CFRetain(CFSTR("nan")); } if (isinf(d)) { return CFRetain((0.0 < d) ? CFSTR("+infinity") : CFSTR("-infinity")); } if (0.0 == d) { return CFRetain(CFSTR("0.0")); } // if %g is used here, need to use DBL_DIG + 2 on Mac OS X, but %f needs +1 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%.*g"), DBL_DIG + 2, d); } return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%lf"), d); } static CFStringRef __CFNumberCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) { CFNumberRef number = (CFNumberRef)cf; CFMutableStringRef mstr; int64_t value; switch (__CFNumberGetType(number)) { case kCFNumberSInt32Type: case kCFNumberSInt64Type: value = (__CFNumberGetType(number) == kCFNumberSInt32Type) ? number->value.valSInt32 : number->value.valSInt64; mstr = CFStringCreateMutable(kCFAllocatorSystemDefault, 0); __CFNumberEmitInt64(mstr, value, 0, ' ', false); return mstr; case kCFNumberFloat32Type: if (_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) { if (isnan(number->value.valFloat32)) { return CFRetain(CFSTR("nan")); } if (isinf(number->value.valFloat32)) { return CFRetain((0.0f < number->value.valFloat32) ? CFSTR("+infinity") : CFSTR("-infinity")); } if (0.0f == number->value.valFloat32) { return CFRetain(CFSTR("0.0")); } // if %g is used here, need to use FLT_DIG + 2 on Mac OS X, but %f needs +1 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%.*g"), FLT_DIG + 2, number->value.valFloat32); } return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%f"), number->value.valFloat32); break; case kCFNumberFloat64Type: return __CFNumberCopyFormattingDescriptionAsFloat64(number); break; default: __CFInvalidNumberStorageType(__CFNumberGetType(number)); return NULL; } } static CFTypeID __kCFNumberTypeID = _kCFRuntimeNotATypeID; static const CFRuntimeClass __CFNumberClass = { 0, "CFNumber", NULL, // init NULL, // copy NULL, __CFNumberEqual, __CFNumberHash, __CFNumberCopyFormattingDescription, __CFNumberCopyDescription }; __private_extern__ void __CFNumberInitialize(void) { uint64_t dnan = BITSFORDOUBLENAN; uint64_t negInf = BITSFORDOUBLENEGINF; uint64_t posInf = BITSFORDOUBLEPOSINF; __kCFNumberTypeID = _CFRuntimeRegisterClass(&__CFNumberClass); _CFRuntimeSetInstanceTypeID(&__kCFNumberNaN, __kCFNumberTypeID); __kCFNumberNaN._base._isa = __CFISAForTypeID(__kCFNumberTypeID); __CFBitfieldSetValue(__kCFNumberNaN._base._info, 4, 0, kCFNumberFloat64Type); __kCFNumberNaN.value.valFloat64 = *(double *)&dnan; _CFRuntimeSetInstanceTypeID(& __kCFNumberNegativeInfinity, __kCFNumberTypeID); __kCFNumberNegativeInfinity._base._isa = __CFISAForTypeID(__kCFNumberTypeID); __CFBitfieldSetValue(__kCFNumberNegativeInfinity._base._info, 4, 0, kCFNumberFloat64Type); __kCFNumberNegativeInfinity.value.valFloat64 = *(double *)&negInf; _CFRuntimeSetInstanceTypeID(& __kCFNumberPositiveInfinity, __kCFNumberTypeID); __kCFNumberPositiveInfinity._base._isa = __CFISAForTypeID(__kCFNumberTypeID); __CFBitfieldSetValue(__kCFNumberPositiveInfinity._base._info, 4, 0, kCFNumberFloat64Type); __kCFNumberPositiveInfinity.value.valFloat64 = *(double *)&posInf; } Boolean _CFNumberIsU(CFNumberRef num) { return __CFBitfieldGetValue(__kCFNumberPositiveInfinity._base._info, 6, 6); } void _CFNumberSetU(CFNumberRef num, Boolean unsign) { __CFBitfieldSetValue(__kCFNumberPositiveInfinity._base._info, 6, 6, (unsign ? 1 : 0)); } CFTypeID CFNumberGetTypeID(void) { return __kCFNumberTypeID; } #define MinCachedInt (-1) #define MaxCachedInt (12) #define NotToBeCached (MinCachedInt - 1) static CFNumberRef _CFNumberCache[MaxCachedInt - MinCachedInt + 1] = {NULL}; // Storing CFNumberRefs for SInt32 range MinCachedInt..MaxCachedInt static CFSpinLock_t _CFNumberCacheLock = 0; CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType type, const void *valuePtr) { CFNumberRef num; CFNumberType equivType, storageType; int32_t valToBeCached = NotToBeCached; equivType = __CFNumberGetCanonicalTypeForType(type); // Take care of some special cases; in some cases we will return here without actually creating a new CFNumber switch (equivType) { case kCFNumberFloat32Type: { Float32 val = *(Float32 *)(valuePtr); if (isnan(val)) return CFRetain(kCFNumberNaN); if (isinf(val)) return CFRetain((val < 0.0) ? kCFNumberNegativeInfinity : kCFNumberPositiveInfinity); break; } case kCFNumberFloat64Type: { Float64 val = *(Float64 *)(valuePtr); if (isnan(val)) return CFRetain(kCFNumberNaN); if (isinf(val)) return CFRetain((val < 0.0) ? kCFNumberNegativeInfinity : kCFNumberPositiveInfinity); break; } default: { switch (equivType) { case kCFNumberSInt64Type: {SInt64 val = *(SInt64 *)(valuePtr); if (val >= MinCachedInt && val <= MaxCachedInt) valToBeCached = val; break;} case kCFNumberSInt32Type: {SInt32 val = *(SInt32 *)(valuePtr); if (val >= MinCachedInt && val <= MaxCachedInt) valToBeCached = val; break;} case kCFNumberSInt16Type: {SInt16 val = *(SInt16 *)(valuePtr); if (val >= MinCachedInt && val <= MaxCachedInt) valToBeCached = val; break;} case kCFNumberSInt8Type: {SInt8 val = *(SInt8 *)(valuePtr); if (val >= MinCachedInt && val <= MaxCachedInt) valToBeCached = val; break;} default:; } if (valToBeCached != NotToBeCached) { // Even if not yet cached, this will assure that we cache it after the number is created __CFSpinLock(&_CFNumberCacheLock); CFNumberRef result = _CFNumberCache[valToBeCached - MinCachedInt]; __CFSpinUnlock(&_CFNumberCacheLock); if (result) return CFRetain(result); // Turns out it's a number we want do cache, but don't have cached yet; so let's normalize it so we're only caching 32-bit int valuePtr = &valToBeCached; type = kCFNumberSInt32Type; equivType = __CFNumberGetCanonicalTypeForType(type); } break; } } storageType = __CFNumberGetStorageTypeForType(type); num = (CFNumberRef)_CFRuntimeCreateInstance(allocator, __kCFNumberTypeID, __CFNumberSizeOfType(storageType), NULL); if (NULL == num) { return NULL; } SET_VALUE((__CFNumberValue *)&(num->value), equivType, valuePtr); __CFBitfieldSetValue(((struct __CFNumber *)num)->_base._info, 6, 0, storageType); // If this was a number worth caching, cache it if (valToBeCached != NotToBeCached) { int slot = valToBeCached - MinCachedInt; __CFSpinLock(&_CFNumberCacheLock); if (_CFNumberCache[slot] == NULL) _CFNumberCache[slot] = num; __CFSpinUnlock(&_CFNumberCacheLock); if (_CFNumberCache[slot] == num) CFRetain(num); // Extra retain for the cached number } return num; } CFNumberType CFNumberGetType(CFNumberRef number) { CF_OBJC_FUNCDISPATCH0(__kCFNumberTypeID, CFNumberType, number, "_cfNumberType"); __CFAssertIsNumber(number); return __CFNumberGetType(number); } CFIndex CFNumberGetByteSize(CFNumberRef number) { __CFAssertIsNumber(number); return __CFNumberSizeOfType(CFNumberGetType(number)); } Boolean CFNumberIsFloatType(CFNumberRef number) { __CFAssertIsNumber(number); return __CFNumberTypeIsFloat(CFNumberGetType(number)); } Boolean CFNumberGetValue(CFNumberRef number, CFNumberType type, void *valuePtr) { uint8_t localMemory[sizeof(__CFNumberValue)]; __CFNumberValue localValue; CFNumberType numType; CFNumberType storageTypeForType; CF_OBJC_FUNCDISPATCH2(__kCFNumberTypeID, Boolean, number, "_getValue:forType:", valuePtr, __CFNumberGetCanonicalTypeForType(type)); __CFAssertIsNumber(number); __CFAssertIsValidNumberType(type); storageTypeForType = __CFNumberGetStorageTypeForType(type); type = __CFNumberGetCanonicalTypeForType(type); if (!valuePtr) valuePtr = &localMemory; numType = __CFNumberGetType(number); __CFNumberGetValue((__CFNumberValue *)&(number->value), numType, type, valuePtr); // If the types match, then we're fine! if (numType == storageTypeForType) return true; // Test to see if the returned value is intact... SET_VALUE(&localValue, type, valuePtr); return __CFNumberEqualValue(&localValue, storageTypeForType, &(number->value), numType); } CFComparisonResult CFNumberCompare(CFNumberRef number1, CFNumberRef number2, void *context) { CFNumberType type1, type2; CF_OBJC_FUNCDISPATCH1(__kCFNumberTypeID, CFComparisonResult, number1, "compare:", number2); CF_OBJC_FUNCDISPATCH1(__kCFNumberTypeID, CFComparisonResult, number2, "_reverseCompare:", number1); __CFAssertIsNumber(number1); __CFAssertIsNumber(number2); type1 = __CFNumberGetType(number1); type2 = __CFNumberGetType(number2); if (__CFNumberTypeIsFloat(type1) || __CFNumberTypeIsFloat(type2)) { Float64 d1, d2; double s1, s2; __CFNumberGetValue(&(number1->value), type1, kCFNumberFloat64Type, &d1); __CFNumberGetValue(&(number2->value), type2, kCFNumberFloat64Type, &d2); s1 = copysign(1.0, d1); s2 = copysign(1.0, d2); if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) { return (d1 > d2) ? kCFCompareGreaterThan : ((d1 < d2) ? kCFCompareLessThan : kCFCompareEqualTo); } if (isnan(d1) && isnan(d2)) return kCFCompareEqualTo; if (isnan(d1)) return (s2 < 0.0) ? kCFCompareGreaterThan : kCFCompareLessThan; if (isnan(d2)) return (s1 < 0.0) ? kCFCompareLessThan : kCFCompareGreaterThan; // at this point, we know we don't have any NaNs if (s1 < s2) return kCFCompareLessThan; if (s2 < s1) return kCFCompareGreaterThan; // at this point, we know the signs are the same; do not combine these tests if (d1 < d2) return kCFCompareLessThan; if (d2 < d1) return kCFCompareGreaterThan; return kCFCompareEqualTo; } else { int64_t i1, i2; __CFNumberGetValue(&(number1->value), type1, kCFNumberSInt64Type, &i1); __CFNumberGetValue(&(number2->value), type2, kCFNumberSInt64Type, &i2); return (i1 > i2) ? kCFCompareGreaterThan : ((i1 < i2) ? kCFCompareLessThan : kCFCompareEqualTo); } }