2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 Copyright 1999-2002, Apple, Inc. All rights reserved.
25 Responsibility: Ali Ozer
28 #include <CoreFoundation/CFNumber.h>
29 #include "CFInternal.h"
30 #include "CFUtilitiesPriv.h"
33 #if defined(__WIN32__) && !defined(__MINGW32__) && !defined(__CYGWIN__)
35 #define isinf !_finite
40 #define __CFAssertIsBoolean(cf) __CFGenericValidateType(cf, __kCFBooleanTypeID)
41 #define __CFAssertIsNumber(cf) __CFGenericValidateType(cf, __kCFNumberTypeID)
42 #define __CFAssertIsValidNumberType(type) CFAssert2((type > 0 && type <= kCFNumberMaxType && __CFNumberCanonicalType[type]), __kCFLogAssertion, "%s(): bad CFNumber type %d", __PRETTY_FUNCTION__, type);
43 #define __CFInvalidNumberStorageType(type) CFAssert2(true, __kCFLogAssertion, "%s(): bad CFNumber storage type %d", __PRETTY_FUNCTION__, type);
45 /* The IEEE bit patterns... Also have:
50 #define BITSFORDOUBLENAN ((uint64_t)0x7ff8000000000000ULL)
51 #define BITSFORDOUBLEPOSINF ((uint64_t)0x7ff0000000000000ULL)
52 #define BITSFORDOUBLENEGINF ((uint64_t)0xfff0000000000000ULL)
58 static struct __CFBoolean __kCFBooleanTrue
= {
59 INIT_CFRUNTIME_BASE(NULL
, 0, 0x0080)
61 const CFBooleanRef kCFBooleanTrue
= &__kCFBooleanTrue
;
63 static struct __CFBoolean __kCFBooleanFalse
= {
64 INIT_CFRUNTIME_BASE(NULL
, 0, 0x0080)
66 const CFBooleanRef kCFBooleanFalse
= &__kCFBooleanFalse
;
68 static CFStringRef
__CFBooleanCopyDescription(CFTypeRef cf
) {
69 CFBooleanRef boolean
= (CFBooleanRef
)cf
;
70 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("<CFBoolean %p [%p]>{value = %s}"), cf
, CFGetAllocator(cf
), (boolean
== kCFBooleanTrue
) ? "true" : "false");
73 static CFStringRef
__CFBooleanCopyFormattingDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
74 CFBooleanRef boolean
= (CFBooleanRef
)cf
;
75 return CFRetain((boolean
== kCFBooleanTrue
) ? CFSTR("true") : CFSTR("false"));
78 static void __CFBooleanDeallocate(CFTypeRef cf
) {
79 CFAssert(false, __kCFLogAssertion
, "Deallocated CFBoolean!");
82 static CFTypeID __kCFBooleanTypeID
= _kCFRuntimeNotATypeID
;
84 static const CFRuntimeClass __CFBooleanClass
= {
89 __CFBooleanDeallocate
,
92 __CFBooleanCopyFormattingDescription
,
93 __CFBooleanCopyDescription
96 __private_extern__
void __CFBooleanInitialize(void) {
97 __kCFBooleanTypeID
= _CFRuntimeRegisterClass(&__CFBooleanClass
);
98 _CFRuntimeSetInstanceTypeID(&__kCFBooleanTrue
, __kCFBooleanTypeID
);
99 __kCFBooleanTrue
._base
._isa
= __CFISAForTypeID(__kCFBooleanTypeID
);
100 _CFRuntimeSetInstanceTypeID(&__kCFBooleanFalse
, __kCFBooleanTypeID
);
101 __kCFBooleanFalse
._base
._isa
= __CFISAForTypeID(__kCFBooleanTypeID
);
104 CFTypeID
CFBooleanGetTypeID(void) {
105 return __kCFBooleanTypeID
;
108 Boolean
CFBooleanGetValue(CFBooleanRef boolean
) {
109 CF_OBJC_FUNCDISPATCH0(__kCFBooleanTypeID
, Boolean
, boolean
, "boolValue");
110 return (boolean
== kCFBooleanTrue
) ? true : false;
123 struct __CFNumber
{ /* Only as many bytes as necessary are allocated */
125 __CFNumberValue value
;
128 static struct __CFNumber __kCFNumberNaN
= {
129 INIT_CFRUNTIME_BASE(NULL
, 0, 0x0080), {0}
131 const CFNumberRef kCFNumberNaN
= &__kCFNumberNaN
;
133 static struct __CFNumber __kCFNumberNegativeInfinity
= {
134 INIT_CFRUNTIME_BASE(NULL
, 0, 0x0080), {0}
136 const CFNumberRef kCFNumberNegativeInfinity
= &__kCFNumberNegativeInfinity
;
138 static struct __CFNumber __kCFNumberPositiveInfinity
= {
139 INIT_CFRUNTIME_BASE(NULL
, 0, 0x0080), {0}
141 const CFNumberRef kCFNumberPositiveInfinity
= &__kCFNumberPositiveInfinity
;
144 /* Seven bits in base:
145 Bits 4..0: CFNumber type
146 Bit 6: is unsigned number
150 /* ??? 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.
153 /* 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.
155 static const unsigned char __CFNumberCanonicalType
[kCFNumberMaxType
+ 1] = {
156 0, kCFNumberSInt8Type
, kCFNumberSInt16Type
, kCFNumberSInt32Type
, kCFNumberSInt64Type
, kCFNumberFloat32Type
, kCFNumberFloat64Type
,
157 kCFNumberSInt8Type
, kCFNumberSInt16Type
, kCFNumberSInt32Type
, kCFNumberSInt32Type
, kCFNumberSInt64Type
, kCFNumberFloat32Type
, kCFNumberFloat64Type
,
161 /* This table determines what storage format is used for any given type.
162 !!! These are the only types that can occur in the types field of a CFNumber.
163 !!! If the number or kind of types returned by this array changes, also need to fix NSNumber and NSCFNumber.
165 static const unsigned char __CFNumberStorageType
[kCFNumberMaxType
+ 1] = {
166 0, kCFNumberSInt32Type
, kCFNumberSInt32Type
, kCFNumberSInt32Type
, kCFNumberSInt64Type
, kCFNumberFloat32Type
, kCFNumberFloat64Type
,
167 kCFNumberSInt32Type
, kCFNumberSInt32Type
, kCFNumberSInt32Type
, kCFNumberSInt32Type
, kCFNumberSInt64Type
, kCFNumberFloat32Type
, kCFNumberFloat64Type
,
171 // Returns the type that is used to store the specified type
172 CF_INLINE CFNumberType
__CFNumberGetStorageTypeForType(CFNumberType type
) {
173 return __CFNumberStorageType
[type
];
176 // Returns the canonical type used to represent the specified type
177 CF_INLINE CFNumberType
__CFNumberGetCanonicalTypeForType(CFNumberType type
) {
178 return __CFNumberCanonicalType
[type
];
181 // Extracts and returns the type out of the CFNumber
182 CF_INLINE CFNumberType
__CFNumberGetType(CFNumberRef num
) {
183 return __CFBitfieldGetValue(num
->_base
._info
, 4, 0);
186 // Returns true if the argument type is float or double
187 CF_INLINE Boolean
__CFNumberTypeIsFloat(CFNumberType type
) {
188 return (type
== kCFNumberFloat64Type
) || (type
== kCFNumberFloat32Type
) || (type
== kCFNumberDoubleType
) || (type
== kCFNumberFloatType
);
191 // Returns the number of bytes necessary to store the specified type
192 // Needs to handle all canonical types
193 CF_INLINE CFIndex
__CFNumberSizeOfType(CFNumberType type
) {
195 case kCFNumberSInt8Type
: return sizeof(int8_t);
196 case kCFNumberSInt16Type
: return sizeof(int16_t);
197 case kCFNumberSInt32Type
: return sizeof(SInt32
);
198 case kCFNumberSInt64Type
: return sizeof(int64_t);
199 case kCFNumberFloat32Type
: return sizeof(Float32
);
200 case kCFNumberFloat64Type
: return sizeof(Float64
);
205 // Copies an external value of a given type into the appropriate slot in the union (does no type conversion)
206 // Needs to handle all canonical types
207 #define SET_VALUE(valueUnion, type, valuePtr) \
209 case kCFNumberSInt8Type: (valueUnion)->valSInt32 = *(int8_t *)(valuePtr); break; \
210 case kCFNumberSInt16Type: (valueUnion)->valSInt32 = *(int16_t *)(valuePtr); break; \
211 case kCFNumberSInt32Type: (valueUnion)->valSInt32 = *(SInt32 *)(valuePtr); break; \
212 case kCFNumberSInt64Type: (valueUnion)->valSInt64 = *(int64_t *)(valuePtr); break; \
213 case kCFNumberFloat32Type: (valueUnion)->valFloat32 = *(Float32 *)(valuePtr); break; \
214 case kCFNumberFloat64Type: (valueUnion)->valFloat64 = *(Float64 *)(valuePtr); break; \
218 // Casts the specified value into the specified type and copies it into the provided memory
219 // Needs to handle all canonical types
220 #define GET_VALUE(value, type, resultPtr) \
222 case kCFNumberSInt8Type: *(int8_t *)(resultPtr) = (int8_t)value; break; \
223 case kCFNumberSInt16Type: *(int16_t *)(resultPtr) = (int16_t)value; break; \
224 case kCFNumberSInt32Type: *(SInt32 *)(resultPtr) = (SInt32)value; break; \
225 case kCFNumberSInt64Type: *(int64_t *)(resultPtr) = (int64_t)value; break; \
226 case kCFNumberFloat32Type: *(Float32 *)(resultPtr) = (Float32)value; break; \
227 case kCFNumberFloat64Type: *(Float64 *)(resultPtr) = (Float64)value; break; \
231 // Extracts the stored type out of the union and copies it in the desired type into the provided memory
232 // Needs to handle all storage types
233 CF_INLINE
void __CFNumberGetValue(const __CFNumberValue
*value
, CFNumberType numberType
, CFNumberType typeToGet
, void *valuePtr
) {
234 switch (numberType
) {
235 case kCFNumberSInt32Type
: GET_VALUE(value
->valSInt32
, typeToGet
, valuePtr
); break;
236 case kCFNumberSInt64Type
: GET_VALUE(value
->valSInt64
, typeToGet
, valuePtr
); break;
237 case kCFNumberFloat32Type
: GET_VALUE(value
->valFloat32
, typeToGet
, valuePtr
); break;
238 case kCFNumberFloat64Type
: GET_VALUE(value
->valFloat64
, typeToGet
, valuePtr
); break;
243 // Sees if two value union structs have the same value (will do type conversion)
244 static Boolean
__CFNumberEqualValue(const __CFNumberValue
*value1
, CFNumberType type1
, const __CFNumberValue
*value2
, CFNumberType type2
) {
245 if (__CFNumberTypeIsFloat(type1
) || __CFNumberTypeIsFloat(type2
)) {
247 __CFNumberGetValue(value1
, type1
, kCFNumberFloat64Type
, &d1
);
248 __CFNumberGetValue(value2
, type2
, kCFNumberFloat64Type
, &d2
);
249 if (_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar
)) {
250 if (isnan(d1
) && isnan(d2
)) return true; // Not mathematically sound, but required
255 __CFNumberGetValue(value1
, type1
, kCFNumberSInt64Type
, &i1
);
256 __CFNumberGetValue(value2
, type2
, kCFNumberSInt64Type
, &i2
);
261 static Boolean
__CFNumberEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
262 CFNumberRef number1
= (CFNumberRef
)cf1
;
263 CFNumberRef number2
= (CFNumberRef
)cf2
;
264 return __CFNumberEqualValue(&(number1
->value
), __CFNumberGetType(number1
), &(number2
->value
), __CFNumberGetType(number2
));
267 static CFHashCode
__CFNumberHash(CFTypeRef cf
) {
268 CFNumberRef number
= (CFNumberRef
)cf
;
269 switch (__CFNumberGetType(cf
)) {
270 case kCFNumberSInt32Type
: return _CFHashInt(number
->value
.valSInt32
);
271 case kCFNumberSInt64Type
: return _CFHashDouble((double)(number
->value
.valSInt64
));
272 case kCFNumberFloat32Type
: return _CFHashDouble((double)(number
->value
.valFloat32
));
273 case kCFNumberFloat64Type
: return _CFHashDouble((double)(number
->value
.valFloat64
));
275 __CFInvalidNumberStorageType(__CFNumberGetType(cf
));
281 #define emitChar(ch) \
282 {if (buf - stackBuf == bufSize) {CFStringAppendCharacters(mstr, stackBuf, bufSize); buf = stackBuf;} *buf++ = ch;}
284 static void __CFNumberEmitInt64(CFMutableStringRef mstr
, int64_t value
, int32_t width
, UniChar pad
, bool explicitPlus
) {
285 UniChar stackBuf
[bufSize
], *buf
= stackBuf
;
286 uint64_t uvalue
, factor
, tmp
;
290 neg
= (value
< 0) ? true : false;
291 uvalue
= (neg
) ? -value
: value
;
292 if (neg
|| explicitPlus
) width
--;
301 for (w
= 0; w
< width
; w
++) emitChar(pad
);
304 } else if (explicitPlus
) {
308 UniChar ch
= '0' + (uvalue
/ factor
);
313 if (buf
> stackBuf
) CFStringAppendCharacters(mstr
, stackBuf
, buf
- stackBuf
);
316 static CFStringRef
__CFNumberCopyDescription(CFTypeRef cf
) {
317 CFNumberRef number
= (CFNumberRef
)cf
;
318 CFMutableStringRef mstr
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
319 CFStringAppendFormat(mstr
, NULL
, CFSTR("<CFNumber %p [%p]>{value = "), cf
, CFGetAllocator(cf
));
320 switch (__CFNumberGetType(number
)) {
321 case kCFNumberSInt32Type
:
322 __CFNumberEmitInt64(mstr
, number
->value
.valSInt32
, 0, ' ', true);
323 CFStringAppendFormat(mstr
, NULL
, CFSTR(", type = kCFNumberSInt32Type}"));
325 case kCFNumberSInt64Type
:
326 __CFNumberEmitInt64(mstr
, number
->value
.valSInt64
, 0, ' ', true);
327 CFStringAppendFormat(mstr
, NULL
, CFSTR(", type = kCFNumberSInt64Type}"));
329 case kCFNumberFloat32Type
:
330 // debugging formatting is intentionally more verbose and explicit about the value of the number
331 if (isnan(number
->value
.valFloat32
)) {
332 CFStringAppend(mstr
, CFSTR("nan"));
333 } else if (isinf(number
->value
.valFloat32
)) {
334 CFStringAppend(mstr
, (0.0f
< number
->value
.valFloat32
) ? CFSTR("+infinity") : CFSTR("-infinity"));
335 } else if (0.0f
== number
->value
.valFloat32
) {
336 CFStringAppend(mstr
, (copysign(1.0, number
->value
.valFloat32
) < 0.0) ? CFSTR("-0.0") : CFSTR("+0.0"));
338 CFStringAppendFormat(mstr
, NULL
, CFSTR("%+.10f"), number
->value
.valFloat32
);
340 CFStringAppend(mstr
, CFSTR(", type = kCFNumberFloat32Type}"));
342 case kCFNumberFloat64Type
:
343 // debugging formatting is intentionally more verbose and explicit about the value of the number
344 if (isnan(number
->value
.valFloat64
)) {
345 CFStringAppend(mstr
, CFSTR("nan"));
346 } else if (isinf(number
->value
.valFloat64
)) {
347 CFStringAppend(mstr
, (0.0 < number
->value
.valFloat64
) ? CFSTR("+infinity") : CFSTR("-infinity"));
348 } else if (0.0 == number
->value
.valFloat64
) {
349 CFStringAppend(mstr
, (copysign(1.0, number
->value
.valFloat64
) < 0.0) ? CFSTR("-0.0") : CFSTR("+0.0"));
351 CFStringAppendFormat(mstr
, NULL
, CFSTR("%+.20f"), number
->value
.valFloat64
);
353 CFStringAppend(mstr
, CFSTR(", type = kCFNumberFloat64Type}"));
356 __CFInvalidNumberStorageType(__CFNumberGetType(number
));
363 // This function separated out from __CFNumberCopyFormattingDescription() so the plist creation can use it as well.
365 __private_extern__ CFStringRef
__CFNumberCopyFormattingDescriptionAsFloat64(CFTypeRef cf
) {
367 CFNumberGetValue(cf
, kCFNumberFloat64Type
, &d
);
368 if (_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar
)) {
370 return CFRetain(CFSTR("nan"));
373 return CFRetain((0.0 < d
) ? CFSTR("+infinity") : CFSTR("-infinity"));
376 return CFRetain(CFSTR("0.0"));
378 // if %g is used here, need to use DBL_DIG + 2 on Mac OS X, but %f needs +1
379 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%.*g"), DBL_DIG
+ 2, d
);
381 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%lf"), d
);
384 static CFStringRef
__CFNumberCopyFormattingDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
385 CFNumberRef number
= (CFNumberRef
)cf
;
386 CFMutableStringRef mstr
;
388 switch (__CFNumberGetType(number
)) {
389 case kCFNumberSInt32Type
:
390 case kCFNumberSInt64Type
:
391 value
= (__CFNumberGetType(number
) == kCFNumberSInt32Type
) ? number
->value
.valSInt32
: number
->value
.valSInt64
;
392 mstr
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
393 __CFNumberEmitInt64(mstr
, value
, 0, ' ', false);
395 case kCFNumberFloat32Type
:
396 if (_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar
)) {
397 if (isnan(number
->value
.valFloat32
)) {
398 return CFRetain(CFSTR("nan"));
400 if (isinf(number
->value
.valFloat32
)) {
401 return CFRetain((0.0f
< number
->value
.valFloat32
) ? CFSTR("+infinity") : CFSTR("-infinity"));
403 if (0.0f
== number
->value
.valFloat32
) {
404 return CFRetain(CFSTR("0.0"));
406 // if %g is used here, need to use FLT_DIG + 2 on Mac OS X, but %f needs +1
407 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%.*g"), FLT_DIG
+ 2, number
->value
.valFloat32
);
409 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%f"), number
->value
.valFloat32
);
411 case kCFNumberFloat64Type
:
412 return __CFNumberCopyFormattingDescriptionAsFloat64(number
);
415 __CFInvalidNumberStorageType(__CFNumberGetType(number
));
420 static CFTypeID __kCFNumberTypeID
= _kCFRuntimeNotATypeID
;
422 static const CFRuntimeClass __CFNumberClass
= {
430 __CFNumberCopyFormattingDescription
,
431 __CFNumberCopyDescription
434 __private_extern__
void __CFNumberInitialize(void) {
435 uint64_t dnan
= BITSFORDOUBLENAN
;
436 uint64_t negInf
= BITSFORDOUBLENEGINF
;
437 uint64_t posInf
= BITSFORDOUBLEPOSINF
;
439 __kCFNumberTypeID
= _CFRuntimeRegisterClass(&__CFNumberClass
);
441 _CFRuntimeSetInstanceTypeID(&__kCFNumberNaN
, __kCFNumberTypeID
);
442 __kCFNumberNaN
._base
._isa
= __CFISAForTypeID(__kCFNumberTypeID
);
443 __CFBitfieldSetValue(__kCFNumberNaN
._base
._info
, 4, 0, kCFNumberFloat64Type
);
444 __kCFNumberNaN
.value
.valFloat64
= *(double *)&dnan
;
446 _CFRuntimeSetInstanceTypeID(& __kCFNumberNegativeInfinity
, __kCFNumberTypeID
);
447 __kCFNumberNegativeInfinity
._base
._isa
= __CFISAForTypeID(__kCFNumberTypeID
);
448 __CFBitfieldSetValue(__kCFNumberNegativeInfinity
._base
._info
, 4, 0, kCFNumberFloat64Type
);
449 __kCFNumberNegativeInfinity
.value
.valFloat64
= *(double *)&negInf
;
451 _CFRuntimeSetInstanceTypeID(& __kCFNumberPositiveInfinity
, __kCFNumberTypeID
);
452 __kCFNumberPositiveInfinity
._base
._isa
= __CFISAForTypeID(__kCFNumberTypeID
);
453 __CFBitfieldSetValue(__kCFNumberPositiveInfinity
._base
._info
, 4, 0, kCFNumberFloat64Type
);
454 __kCFNumberPositiveInfinity
.value
.valFloat64
= *(double *)&posInf
;
457 Boolean
_CFNumberIsU(CFNumberRef num
) {
458 return __CFBitfieldGetValue(__kCFNumberPositiveInfinity
._base
._info
, 6, 6);
461 void _CFNumberSetU(CFNumberRef num
, Boolean unsign
) {
462 __CFBitfieldSetValue(__kCFNumberPositiveInfinity
._base
._info
, 6, 6, (unsign
? 1 : 0));
465 CFTypeID
CFNumberGetTypeID(void) {
466 return __kCFNumberTypeID
;
469 #define MinCachedInt (-1)
470 #define MaxCachedInt (12)
471 #define NotToBeCached (MinCachedInt - 1)
472 static CFNumberRef _CFNumberCache
[MaxCachedInt
- MinCachedInt
+ 1] = {NULL
}; // Storing CFNumberRefs for SInt32 range MinCachedInt..MaxCachedInt
473 static CFSpinLock_t _CFNumberCacheLock
= 0;
475 CFNumberRef
CFNumberCreate(CFAllocatorRef allocator
, CFNumberType type
, const void *valuePtr
) {
477 CFNumberType equivType
, storageType
;
478 int32_t valToBeCached
= NotToBeCached
;
480 equivType
= __CFNumberGetCanonicalTypeForType(type
);
482 // Take care of some special cases; in some cases we will return here without actually creating a new CFNumber
484 case kCFNumberFloat32Type
: {
485 Float32 val
= *(Float32
*)(valuePtr
);
486 if (isnan(val
)) return CFRetain(kCFNumberNaN
);
487 if (isinf(val
)) return CFRetain((val
< 0.0) ? kCFNumberNegativeInfinity
: kCFNumberPositiveInfinity
);
490 case kCFNumberFloat64Type
: {
491 Float64 val
= *(Float64
*)(valuePtr
);
492 if (isnan(val
)) return CFRetain(kCFNumberNaN
);
493 if (isinf(val
)) return CFRetain((val
< 0.0) ? kCFNumberNegativeInfinity
: kCFNumberPositiveInfinity
);
498 case kCFNumberSInt64Type
: {SInt64 val
= *(SInt64
*)(valuePtr
); if (val
>= MinCachedInt
&& val
<= MaxCachedInt
) valToBeCached
= val
; break;}
499 case kCFNumberSInt32Type
: {SInt32 val
= *(SInt32
*)(valuePtr
); if (val
>= MinCachedInt
&& val
<= MaxCachedInt
) valToBeCached
= val
; break;}
500 case kCFNumberSInt16Type
: {SInt16 val
= *(SInt16
*)(valuePtr
); if (val
>= MinCachedInt
&& val
<= MaxCachedInt
) valToBeCached
= val
; break;}
501 case kCFNumberSInt8Type
: {SInt8 val
= *(SInt8
*)(valuePtr
); if (val
>= MinCachedInt
&& val
<= MaxCachedInt
) valToBeCached
= val
; break;}
504 if (valToBeCached
!= NotToBeCached
) { // Even if not yet cached, this will assure that we cache it after the number is created
505 __CFSpinLock(&_CFNumberCacheLock
);
506 CFNumberRef result
= _CFNumberCache
[valToBeCached
- MinCachedInt
];
507 __CFSpinUnlock(&_CFNumberCacheLock
);
508 if (result
) return CFRetain(result
);
509 // 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
510 valuePtr
= &valToBeCached
;
511 type
= kCFNumberSInt32Type
;
512 equivType
= __CFNumberGetCanonicalTypeForType(type
);
518 storageType
= __CFNumberGetStorageTypeForType(type
);
520 num
= (CFNumberRef
)_CFRuntimeCreateInstance(allocator
, __kCFNumberTypeID
, __CFNumberSizeOfType(storageType
), NULL
);
524 SET_VALUE((__CFNumberValue
*)&(num
->value
), equivType
, valuePtr
);
525 __CFBitfieldSetValue(((struct __CFNumber
*)num
)->_base
._info
, 6, 0, storageType
);
527 // If this was a number worth caching, cache it
528 if (valToBeCached
!= NotToBeCached
) {
529 int slot
= valToBeCached
- MinCachedInt
;
530 __CFSpinLock(&_CFNumberCacheLock
);
531 if (_CFNumberCache
[slot
] == NULL
) _CFNumberCache
[slot
] = num
;
532 __CFSpinUnlock(&_CFNumberCacheLock
);
533 if (_CFNumberCache
[slot
] == num
) CFRetain(num
); // Extra retain for the cached number
538 CFNumberType
CFNumberGetType(CFNumberRef number
) {
539 CF_OBJC_FUNCDISPATCH0(__kCFNumberTypeID
, CFNumberType
, number
, "_cfNumberType");
541 __CFAssertIsNumber(number
);
542 return __CFNumberGetType(number
);
545 CFIndex
CFNumberGetByteSize(CFNumberRef number
) {
546 __CFAssertIsNumber(number
);
547 return __CFNumberSizeOfType(CFNumberGetType(number
));
550 Boolean
CFNumberIsFloatType(CFNumberRef number
) {
551 __CFAssertIsNumber(number
);
552 return __CFNumberTypeIsFloat(CFNumberGetType(number
));
555 Boolean
CFNumberGetValue(CFNumberRef number
, CFNumberType type
, void *valuePtr
) {
556 uint8_t localMemory
[sizeof(__CFNumberValue
)];
557 __CFNumberValue localValue
;
558 CFNumberType numType
;
559 CFNumberType storageTypeForType
;
561 CF_OBJC_FUNCDISPATCH2(__kCFNumberTypeID
, Boolean
, number
, "_getValue:forType:", valuePtr
, __CFNumberGetCanonicalTypeForType(type
));
563 __CFAssertIsNumber(number
);
564 __CFAssertIsValidNumberType(type
);
566 storageTypeForType
= __CFNumberGetStorageTypeForType(type
);
567 type
= __CFNumberGetCanonicalTypeForType(type
);
568 if (!valuePtr
) valuePtr
= &localMemory
;
570 numType
= __CFNumberGetType(number
);
571 __CFNumberGetValue((__CFNumberValue
*)&(number
->value
), numType
, type
, valuePtr
);
573 // If the types match, then we're fine!
574 if (numType
== storageTypeForType
) return true;
576 // Test to see if the returned value is intact...
577 SET_VALUE(&localValue
, type
, valuePtr
);
578 return __CFNumberEqualValue(&localValue
, storageTypeForType
, &(number
->value
), numType
);
581 CFComparisonResult
CFNumberCompare(CFNumberRef number1
, CFNumberRef number2
, void *context
) {
582 CFNumberType type1
, type2
;
584 CF_OBJC_FUNCDISPATCH1(__kCFNumberTypeID
, CFComparisonResult
, number1
, "compare:", number2
);
585 CF_OBJC_FUNCDISPATCH1(__kCFNumberTypeID
, CFComparisonResult
, number2
, "_reverseCompare:", number1
);
587 __CFAssertIsNumber(number1
);
588 __CFAssertIsNumber(number2
);
590 type1
= __CFNumberGetType(number1
);
591 type2
= __CFNumberGetType(number2
);
593 if (__CFNumberTypeIsFloat(type1
) || __CFNumberTypeIsFloat(type2
)) {
596 __CFNumberGetValue(&(number1
->value
), type1
, kCFNumberFloat64Type
, &d1
);
597 __CFNumberGetValue(&(number2
->value
), type2
, kCFNumberFloat64Type
, &d2
);
598 s1
= copysign(1.0, d1
);
599 s2
= copysign(1.0, d2
);
600 if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar
)) {
601 return (d1
> d2
) ? kCFCompareGreaterThan
: ((d1
< d2
) ? kCFCompareLessThan
: kCFCompareEqualTo
);
603 if (isnan(d1
) && isnan(d2
)) return kCFCompareEqualTo
;
604 if (isnan(d1
)) return (s2
< 0.0) ? kCFCompareGreaterThan
: kCFCompareLessThan
;
605 if (isnan(d2
)) return (s1
< 0.0) ? kCFCompareLessThan
: kCFCompareGreaterThan
;
606 // at this point, we know we don't have any NaNs
607 if (s1
< s2
) return kCFCompareLessThan
;
608 if (s2
< s1
) return kCFCompareGreaterThan
;
609 // at this point, we know the signs are the same; do not combine these tests
610 if (d1
< d2
) return kCFCompareLessThan
;
611 if (d2
< d1
) return kCFCompareGreaterThan
;
612 return kCFCompareEqualTo
;
615 __CFNumberGetValue(&(number1
->value
), type1
, kCFNumberSInt64Type
, &i1
);
616 __CFNumberGetValue(&(number2
->value
), type2
, kCFNumberSInt64Type
, &i2
);
617 return (i1
> i2
) ? kCFCompareGreaterThan
: ((i1
< i2
) ? kCFCompareLessThan
: kCFCompareEqualTo
);