2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 Copyright 1999-2002, Apple, Inc. All rights reserved.
27 Responsibility: Ali Ozer
30 #include <CoreFoundation/CFNumber.h>
31 #include "CFInternal.h"
32 #include "CFUtilities.h"
35 #if defined(__WIN32__)
37 #define isinf !_finite
42 #define __CFAssertIsBoolean(cf) __CFGenericValidateType(cf, __kCFBooleanTypeID)
43 #define __CFAssertIsNumber(cf) __CFGenericValidateType(cf, __kCFNumberTypeID)
44 #define __CFAssertIsValidNumberType(type) CFAssert2((type > 0 && type <= kCFNumberMaxType && __CFNumberCanonicalType[type]), __kCFLogAssertion, "%s(): bad CFNumber type %d", __PRETTY_FUNCTION__, type);
45 #define __CFInvalidNumberStorageType(type) CFAssert2(true, __kCFLogAssertion, "%s(): bad CFNumber storage type %d", __PRETTY_FUNCTION__, type);
47 /* The IEEE bit patterns... Also have:
52 #define BITSFORDOUBLENAN ((uint64_t)0x7ff8000000000000ULL)
53 #define BITSFORDOUBLEPOSINF ((uint64_t)0x7ff0000000000000ULL)
54 #define BITSFORDOUBLENEGINF ((uint64_t)0xfff0000000000000ULL)
60 static struct __CFBoolean __kCFBooleanTrue
= {
61 INIT_CFRUNTIME_BASE(NULL
, 0, 0x0080)
63 const CFBooleanRef kCFBooleanTrue
= &__kCFBooleanTrue
;
65 static struct __CFBoolean __kCFBooleanFalse
= {
66 INIT_CFRUNTIME_BASE(NULL
, 0, 0x0080)
68 const CFBooleanRef kCFBooleanFalse
= &__kCFBooleanFalse
;
70 static CFStringRef
__CFBooleanCopyDescription(CFTypeRef cf
) {
71 CFBooleanRef boolean
= (CFBooleanRef
)cf
;
72 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("<CFBoolean %p [%p]>{value = %s}"), cf
, CFGetAllocator(cf
), (boolean
== kCFBooleanTrue
) ? "true" : "false");
75 static CFStringRef
__CFBooleanCopyFormattingDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
76 CFBooleanRef boolean
= (CFBooleanRef
)cf
;
77 return CFRetain((boolean
== kCFBooleanTrue
) ? CFSTR("true") : CFSTR("false"));
80 static void __CFBooleanDeallocate(CFTypeRef cf
) {
81 CFAssert(false, __kCFLogAssertion
, "Deallocated CFBoolean!");
84 static CFTypeID __kCFBooleanTypeID
= _kCFRuntimeNotATypeID
;
86 static const CFRuntimeClass __CFBooleanClass
= {
91 __CFBooleanDeallocate
,
94 __CFBooleanCopyFormattingDescription
,
95 __CFBooleanCopyDescription
98 __private_extern__
void __CFBooleanInitialize(void) {
99 __kCFBooleanTypeID
= _CFRuntimeRegisterClass(&__CFBooleanClass
);
100 _CFRuntimeSetInstanceTypeID(&__kCFBooleanTrue
, __kCFBooleanTypeID
);
101 __kCFBooleanTrue
._base
._isa
= __CFISAForTypeID(__kCFBooleanTypeID
);
102 _CFRuntimeSetInstanceTypeID(&__kCFBooleanFalse
, __kCFBooleanTypeID
);
103 __kCFBooleanFalse
._base
._isa
= __CFISAForTypeID(__kCFBooleanTypeID
);
106 CFTypeID
CFBooleanGetTypeID(void) {
107 return __kCFBooleanTypeID
;
110 Boolean
CFBooleanGetValue(CFBooleanRef boolean
) {
111 CF_OBJC_FUNCDISPATCH0(__kCFBooleanTypeID
, Boolean
, boolean
, "boolValue");
112 return (boolean
== kCFBooleanTrue
) ? true : false;
125 struct __CFNumber
{ /* Only as many bytes as necessary are allocated */
127 __CFNumberValue value
;
130 static struct __CFNumber __kCFNumberNaN
= {
131 INIT_CFRUNTIME_BASE(NULL
, 0, 0x0080), {0}
133 const CFNumberRef kCFNumberNaN
= &__kCFNumberNaN
;
135 static struct __CFNumber __kCFNumberNegativeInfinity
= {
136 INIT_CFRUNTIME_BASE(NULL
, 0, 0x0080), {0}
138 const CFNumberRef kCFNumberNegativeInfinity
= &__kCFNumberNegativeInfinity
;
140 static struct __CFNumber __kCFNumberPositiveInfinity
= {
141 INIT_CFRUNTIME_BASE(NULL
, 0, 0x0080), {0}
143 const CFNumberRef kCFNumberPositiveInfinity
= &__kCFNumberPositiveInfinity
;
146 /* Eight bits in base:
147 Bits 6..0: type (bits 4..0 is CFNumberType)
150 __kCFNumberIsPositiveInfinity
= (0x20 | kCFNumberFloat64Type
),
151 __kCFNumberIsNegativeInfinity
= (0x40 | kCFNumberFloat64Type
),
152 __kCFNumberIsNaN
= (0x60 | kCFNumberFloat64Type
)
156 /* ??? 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.
159 /* 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.
161 static const unsigned char __CFNumberCanonicalType
[kCFNumberMaxType
+ 1] = {
162 0, kCFNumberSInt8Type
, kCFNumberSInt16Type
, kCFNumberSInt32Type
, kCFNumberSInt64Type
, kCFNumberFloat32Type
, kCFNumberFloat64Type
,
163 kCFNumberSInt8Type
, kCFNumberSInt16Type
, kCFNumberSInt32Type
, kCFNumberSInt32Type
, kCFNumberSInt64Type
, kCFNumberFloat32Type
, kCFNumberFloat64Type
,
167 /* This table determines what storage format is used for any given type.
168 !!! These are the only types that can occur in the types field of a CFNumber.
169 !!! If the number or kind of types returned by this array changes, also need to fix NSNumber and NSCFNumber.
171 static const unsigned char __CFNumberStorageType
[kCFNumberMaxType
+ 1] = {
172 0, kCFNumberSInt32Type
, kCFNumberSInt32Type
, kCFNumberSInt32Type
, kCFNumberSInt64Type
, kCFNumberFloat32Type
, kCFNumberFloat64Type
,
173 kCFNumberSInt32Type
, kCFNumberSInt32Type
, kCFNumberSInt32Type
, kCFNumberSInt32Type
, kCFNumberSInt64Type
, kCFNumberFloat32Type
, kCFNumberFloat64Type
,
177 // Returns the type that is used to store the specified type
178 CF_INLINE CFNumberType
__CFNumberGetStorageTypeForType(CFNumberType type
) {
179 return __CFNumberStorageType
[type
];
182 // Returns the canonical type used to represent the specified type
183 CF_INLINE CFNumberType
__CFNumberGetCanonicalTypeForType(CFNumberType type
) {
184 return __CFNumberCanonicalType
[type
];
187 // Extracts and returns the type out of the CFNumber
188 CF_INLINE CFNumberType
__CFNumberGetType(CFNumberRef num
) {
189 return __CFBitfieldGetValue(num
->_base
._info
, 4, 0);
192 // Returns true if the argument type is float or double
193 CF_INLINE Boolean
__CFNumberTypeIsFloat(CFNumberType type
) {
194 return (type
== kCFNumberFloat64Type
) || (type
== kCFNumberFloat32Type
) || (type
== kCFNumberDoubleType
) || (type
== kCFNumberFloatType
);
197 // Returns the number of bytes necessary to store the specified type
198 // Needs to handle all canonical types
199 CF_INLINE CFIndex
__CFNumberSizeOfType(CFNumberType type
) {
201 case kCFNumberSInt8Type
: return sizeof(int8_t);
202 case kCFNumberSInt16Type
: return sizeof(int16_t);
203 case kCFNumberSInt32Type
: return sizeof(SInt32
);
204 case kCFNumberSInt64Type
: return sizeof(int64_t);
205 case kCFNumberFloat32Type
: return sizeof(Float32
);
206 case kCFNumberFloat64Type
: return sizeof(Float64
);
211 // Copies an external value of a given type into the appropriate slot in the union (does no type conversion)
212 // Needs to handle all canonical types
213 #define SET_VALUE(valueUnion, type, valuePtr) \
215 case kCFNumberSInt8Type: (valueUnion)->valSInt32 = *(int8_t *)(valuePtr); break; \
216 case kCFNumberSInt16Type: (valueUnion)->valSInt32 = *(int16_t *)(valuePtr); break; \
217 case kCFNumberSInt32Type: (valueUnion)->valSInt32 = *(SInt32 *)(valuePtr); break; \
218 case kCFNumberSInt64Type: (valueUnion)->valSInt64 = *(int64_t *)(valuePtr); break; \
219 case kCFNumberFloat32Type: (valueUnion)->valFloat32 = *(Float32 *)(valuePtr); break; \
220 case kCFNumberFloat64Type: (valueUnion)->valFloat64 = *(Float64 *)(valuePtr); break; \
224 // Casts the specified value into the specified type and copies it into the provided memory
225 // Needs to handle all canonical types
226 #define GET_VALUE(value, type, resultPtr) \
228 case kCFNumberSInt8Type: *(int8_t *)(valuePtr) = (int8_t)value; break; \
229 case kCFNumberSInt16Type: *(int16_t *)(valuePtr) = (int16_t)value; break; \
230 case kCFNumberSInt32Type: *(SInt32 *)(valuePtr) = (SInt32)value; break; \
231 case kCFNumberSInt64Type: *(int64_t *)(valuePtr) = (int64_t)value; break; \
232 case kCFNumberFloat32Type: *(Float32 *)(valuePtr) = (Float32)value; break; \
233 case kCFNumberFloat64Type: *(Float64 *)(valuePtr) = (Float64)value; break; \
237 // Extracts the stored type out of the union and copies it in the desired type into the provided memory
238 // Needs to handle all storage types
239 CF_INLINE
void __CFNumberGetValue(const __CFNumberValue
*value
, CFNumberType numberType
, CFNumberType typeToGet
, void *valuePtr
) {
240 switch (numberType
) {
241 case kCFNumberSInt32Type
: GET_VALUE(value
->valSInt32
, typeToGet
, resultPtr
); break;
242 case kCFNumberSInt64Type
: GET_VALUE(value
->valSInt64
, typeToGet
, resultPtr
); break;
243 case kCFNumberFloat32Type
: GET_VALUE(value
->valFloat32
, typeToGet
, resultPtr
); break;
244 case kCFNumberFloat64Type
: GET_VALUE(value
->valFloat64
, typeToGet
, resultPtr
); break;
249 // Sees if two value union structs have the same value (will do type conversion)
250 static Boolean
__CFNumberEqualValue(const __CFNumberValue
*value1
, CFNumberType type1
, const __CFNumberValue
*value2
, CFNumberType type2
) {
251 if (__CFNumberTypeIsFloat(type1
) || __CFNumberTypeIsFloat(type2
)) {
253 __CFNumberGetValue(value1
, type1
, kCFNumberFloat64Type
, &d1
);
254 __CFNumberGetValue(value2
, type2
, kCFNumberFloat64Type
, &d2
);
255 if (_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar
)) {
256 if (isnan(d1
) && isnan(d2
)) return true; // Not mathematically sound, but required
261 __CFNumberGetValue(value1
, type1
, kCFNumberSInt64Type
, &i1
);
262 __CFNumberGetValue(value2
, type2
, kCFNumberSInt64Type
, &i2
);
267 static Boolean
__CFNumberEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
268 CFNumberRef number1
= (CFNumberRef
)cf1
;
269 CFNumberRef number2
= (CFNumberRef
)cf2
;
270 return __CFNumberEqualValue(&(number1
->value
), __CFNumberGetType(number1
), &(number2
->value
), __CFNumberGetType(number2
));
273 static CFHashCode
__CFNumberHash(CFTypeRef cf
) {
274 CFNumberRef number
= (CFNumberRef
)cf
;
275 switch (__CFNumberGetType(cf
)) {
276 case kCFNumberSInt32Type
: return _CFHashInt(number
->value
.valSInt32
);
277 case kCFNumberSInt64Type
: return _CFHashDouble((double)(number
->value
.valSInt64
));
278 case kCFNumberFloat32Type
: return _CFHashDouble((double)(number
->value
.valFloat32
));
279 case kCFNumberFloat64Type
: return _CFHashDouble((double)(number
->value
.valFloat64
));
281 __CFInvalidNumberStorageType(__CFNumberGetType(cf
));
287 #define emitChar(ch) \
288 {if (buf - stackBuf == bufSize) {CFStringAppendCharacters(mstr, stackBuf, bufSize); buf = stackBuf;} *buf++ = ch;}
290 static void __CFNumberEmitInt64(CFMutableStringRef mstr
, int64_t value
, int32_t width
, UniChar pad
, bool explicitPlus
) {
291 UniChar stackBuf
[bufSize
], *buf
= stackBuf
;
292 uint64_t uvalue
, factor
, tmp
;
296 neg
= (value
< 0) ? true : false;
297 uvalue
= (neg
) ? -value
: value
;
298 if (neg
|| explicitPlus
) width
--;
307 for (w
= 0; w
< width
; w
++) emitChar(pad
);
310 } else if (explicitPlus
) {
314 UniChar ch
= '0' + (uvalue
/ factor
);
319 if (buf
> stackBuf
) CFStringAppendCharacters(mstr
, stackBuf
, buf
- stackBuf
);
322 static CFStringRef
__CFNumberCopyDescription(CFTypeRef cf
) {
323 CFNumberRef number
= (CFNumberRef
)cf
;
324 CFMutableStringRef mstr
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
325 CFStringAppendFormat(mstr
, NULL
, CFSTR("<CFNumber %p [%p]>{value = "), cf
, CFGetAllocator(cf
));
326 switch (__CFNumberGetType(number
)) {
327 case kCFNumberSInt32Type
:
328 __CFNumberEmitInt64(mstr
, number
->value
.valSInt32
, 0, ' ', true);
329 CFStringAppendFormat(mstr
, NULL
, CFSTR(", type = kCFNumberSInt32Type}"));
331 case kCFNumberSInt64Type
:
332 __CFNumberEmitInt64(mstr
, number
->value
.valSInt64
, 0, ' ', true);
333 CFStringAppendFormat(mstr
, NULL
, CFSTR(", type = kCFNumberSInt64Type}"));
335 case kCFNumberFloat32Type
:
336 // debugging formatting is intentionally more verbose and explicit about the value of the number
337 if (isnan(number
->value
.valFloat32
)) {
338 CFStringAppend(mstr
, CFSTR("nan"));
339 } else if (isinf(number
->value
.valFloat32
)) {
340 CFStringAppend(mstr
, (0.0f
< number
->value
.valFloat32
) ? CFSTR("+infinity") : CFSTR("-infinity"));
341 } else if (0.0f
== number
->value
.valFloat32
) {
342 CFStringAppend(mstr
, (copysign(1.0, number
->value
.valFloat32
) < 0.0) ? CFSTR("-0.0") : CFSTR("+0.0"));
344 CFStringAppendFormat(mstr
, NULL
, CFSTR("%+.10f"), number
->value
.valFloat32
);
346 CFStringAppend(mstr
, CFSTR(", type = kCFNumberFloat32Type}"));
348 case kCFNumberFloat64Type
:
349 // debugging formatting is intentionally more verbose and explicit about the value of the number
350 if (isnan(number
->value
.valFloat64
)) {
351 CFStringAppend(mstr
, CFSTR("nan"));
352 } else if (isinf(number
->value
.valFloat64
)) {
353 CFStringAppend(mstr
, (0.0 < number
->value
.valFloat64
) ? CFSTR("+infinity") : CFSTR("-infinity"));
354 } else if (0.0 == number
->value
.valFloat64
) {
355 CFStringAppend(mstr
, (copysign(1.0, number
->value
.valFloat64
) < 0.0) ? CFSTR("-0.0") : CFSTR("+0.0"));
357 CFStringAppendFormat(mstr
, NULL
, CFSTR("%+.20f"), number
->value
.valFloat64
);
359 CFStringAppend(mstr
, CFSTR(", type = kCFNumberFloat64Type}"));
362 __CFInvalidNumberStorageType(__CFNumberGetType(number
));
369 // This function separated out from __CFNumberCopyFormattingDescription() so the plist creation can use it as well.
371 __private_extern__ CFStringRef
__CFNumberCopyFormattingDescriptionAsFloat64(CFTypeRef cf
) {
373 CFNumberGetValue(cf
, kCFNumberFloat64Type
, &d
);
374 if (_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar
)) {
376 return CFRetain(CFSTR("nan"));
379 return CFRetain((0.0 < d
) ? CFSTR("+infinity") : CFSTR("-infinity"));
382 return CFRetain(CFSTR("0.0"));
384 // if %g is used here, need to use DBL_DIG + 2 on Mac OS X, but %f needs +1
385 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%.*g"), DBL_DIG
+ 2, d
);
387 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%lf"), d
);
390 static CFStringRef
__CFNumberCopyFormattingDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
391 CFNumberRef number
= (CFNumberRef
)cf
;
392 CFMutableStringRef mstr
;
394 switch (__CFNumberGetType(number
)) {
395 case kCFNumberSInt32Type
:
396 case kCFNumberSInt64Type
:
397 value
= (__CFNumberGetType(number
) == kCFNumberSInt32Type
) ? number
->value
.valSInt32
: number
->value
.valSInt64
;
398 mstr
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
399 __CFNumberEmitInt64(mstr
, value
, 0, ' ', false);
401 case kCFNumberFloat32Type
:
402 if (_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar
)) {
403 if (isnan(number
->value
.valFloat32
)) {
404 return CFRetain(CFSTR("nan"));
406 if (isinf(number
->value
.valFloat32
)) {
407 return CFRetain((0.0f
< number
->value
.valFloat32
) ? CFSTR("+infinity") : CFSTR("-infinity"));
409 if (0.0f
== number
->value
.valFloat32
) {
410 return CFRetain(CFSTR("0.0"));
412 // if %g is used here, need to use FLT_DIG + 2 on Mac OS X, but %f needs +1
413 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%.*g"), FLT_DIG
+ 2, number
->value
.valFloat32
);
415 return CFStringCreateWithFormat(kCFAllocatorDefault
, NULL
, CFSTR("%f"), number
->value
.valFloat32
);
417 case kCFNumberFloat64Type
:
418 return __CFNumberCopyFormattingDescriptionAsFloat64(number
);
421 __CFInvalidNumberStorageType(__CFNumberGetType(number
));
426 static CFTypeID __kCFNumberTypeID
= _kCFRuntimeNotATypeID
;
428 static const CFRuntimeClass __CFNumberClass
= {
436 __CFNumberCopyFormattingDescription
,
437 __CFNumberCopyDescription
440 __private_extern__
void __CFNumberInitialize(void) {
441 uint64_t dnan
= BITSFORDOUBLENAN
;
442 uint64_t negInf
= BITSFORDOUBLENEGINF
;
443 uint64_t posInf
= BITSFORDOUBLEPOSINF
;
445 __kCFNumberTypeID
= _CFRuntimeRegisterClass(&__CFNumberClass
);
447 _CFRuntimeSetInstanceTypeID(&__kCFNumberNaN
, __kCFNumberTypeID
);
448 __kCFNumberNaN
._base
._isa
= __CFISAForTypeID(__kCFNumberTypeID
);
449 __CFBitfieldSetValue(__kCFNumberNaN
._base
._info
, 6, 0, __kCFNumberIsNaN
);
450 __kCFNumberNaN
.value
.valFloat64
= *(double *)&dnan
;
452 _CFRuntimeSetInstanceTypeID(& __kCFNumberNegativeInfinity
, __kCFNumberTypeID
);
453 __kCFNumberNegativeInfinity
._base
._isa
= __CFISAForTypeID(__kCFNumberTypeID
);
454 __CFBitfieldSetValue(__kCFNumberNegativeInfinity
._base
._info
, 6, 0, __kCFNumberIsNegativeInfinity
);
455 __kCFNumberNegativeInfinity
.value
.valFloat64
= *(double *)&negInf
;
457 _CFRuntimeSetInstanceTypeID(& __kCFNumberPositiveInfinity
, __kCFNumberTypeID
);
458 __kCFNumberPositiveInfinity
._base
._isa
= __CFISAForTypeID(__kCFNumberTypeID
);
459 __CFBitfieldSetValue(__kCFNumberPositiveInfinity
._base
._info
, 6, 0, __kCFNumberIsPositiveInfinity
);
460 __kCFNumberPositiveInfinity
.value
.valFloat64
= *(double *)&posInf
;
463 CFTypeID
CFNumberGetTypeID(void) {
464 return __kCFNumberTypeID
;
467 CFNumberRef
CFNumberCreate(CFAllocatorRef allocator
, CFNumberType type
, const void *valuePtr
) {
469 CFNumberType equivType
, storageType
;
471 if ((type
== kCFNumberFloat32Type
) || (type
== kCFNumberFloatType
)) {
472 Float32 val
= *(Float32
*)(valuePtr
);
473 if (isnan(val
)) return CFRetain(kCFNumberNaN
);
474 if (isinf(val
)) return CFRetain((val
< 0.0) ? kCFNumberNegativeInfinity
: kCFNumberPositiveInfinity
);
475 } else if ((type
== kCFNumberFloat64Type
) || (type
== kCFNumberDoubleType
)) {
476 Float64 val
= *(Float64
*)(valuePtr
);
477 if (isnan(val
)) return CFRetain(kCFNumberNaN
);
478 if (isinf(val
)) return CFRetain((val
< 0.0) ? kCFNumberNegativeInfinity
: kCFNumberPositiveInfinity
);
481 equivType
= __CFNumberGetCanonicalTypeForType(type
);
482 storageType
= __CFNumberGetStorageTypeForType(type
);
484 num
= (CFNumberRef
)_CFRuntimeCreateInstance(allocator
, __kCFNumberTypeID
, __CFNumberSizeOfType(storageType
), NULL
);
488 SET_VALUE((__CFNumberValue
*)&(num
->value
), equivType
, valuePtr
);
489 __CFBitfieldSetValue(((struct __CFNumber
*)num
)->_base
._info
, 6, 0, storageType
);
493 CFNumberType
CFNumberGetType(CFNumberRef number
) {
494 CF_OBJC_FUNCDISPATCH0(__kCFNumberTypeID
, CFNumberType
, number
, "_cfNumberType");
496 __CFAssertIsNumber(number
);
497 return __CFNumberGetType(number
);
500 CFIndex
CFNumberGetByteSize(CFNumberRef number
) {
501 __CFAssertIsNumber(number
);
502 return __CFNumberSizeOfType(CFNumberGetType(number
));
505 Boolean
CFNumberIsFloatType(CFNumberRef number
) {
506 __CFAssertIsNumber(number
);
507 return __CFNumberTypeIsFloat(CFNumberGetType(number
));
510 Boolean
CFNumberGetValue(CFNumberRef number
, CFNumberType type
, void *valuePtr
) {
511 uint8_t localMemory
[sizeof(__CFNumberValue
)];
512 __CFNumberValue localValue
;
513 CFNumberType numType
;
514 CFNumberType storageTypeForType
;
516 CF_OBJC_FUNCDISPATCH2(__kCFNumberTypeID
, Boolean
, number
, "_getValue:forType:", valuePtr
, __CFNumberGetCanonicalTypeForType(type
));
518 __CFAssertIsNumber(number
);
519 __CFAssertIsValidNumberType(type
);
521 storageTypeForType
= __CFNumberGetStorageTypeForType(type
);
522 type
= __CFNumberGetCanonicalTypeForType(type
);
523 if (!valuePtr
) valuePtr
= &localMemory
;
525 numType
= __CFNumberGetType(number
);
526 __CFNumberGetValue((__CFNumberValue
*)&(number
->value
), numType
, type
, valuePtr
);
528 // If the types match, then we're fine!
529 if (numType
== storageTypeForType
) return true;
531 // Test to see if the returned value is intact...
532 SET_VALUE(&localValue
, type
, valuePtr
);
533 return __CFNumberEqualValue(&localValue
, storageTypeForType
, &(number
->value
), numType
);
536 CFComparisonResult
CFNumberCompare(CFNumberRef number1
, CFNumberRef number2
, void *context
) {
537 CFNumberType type1
, type2
;
539 CF_OBJC_FUNCDISPATCH1(__kCFNumberTypeID
, CFComparisonResult
, number1
, "compare:", number2
);
540 CF_OBJC_FUNCDISPATCH1(__kCFNumberTypeID
, CFComparisonResult
, number2
, "_reverseCompare:", number1
);
542 __CFAssertIsNumber(number1
);
543 __CFAssertIsNumber(number2
);
545 type1
= __CFNumberGetType(number1
);
546 type2
= __CFNumberGetType(number2
);
548 if (__CFNumberTypeIsFloat(type1
) || __CFNumberTypeIsFloat(type2
)) {
551 __CFNumberGetValue(&(number1
->value
), type1
, kCFNumberFloat64Type
, &d1
);
552 __CFNumberGetValue(&(number2
->value
), type2
, kCFNumberFloat64Type
, &d2
);
553 s1
= copysign(1.0, d1
);
554 s2
= copysign(1.0, d2
);
555 if (!_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar
)) {
556 return (d1
> d2
) ? kCFCompareGreaterThan
: ((d1
< d2
) ? kCFCompareLessThan
: kCFCompareEqualTo
);
558 if (isnan(d1
) && isnan(d2
)) return kCFCompareEqualTo
;
559 if (isnan(d1
)) return (s2
< 0.0) ? kCFCompareGreaterThan
: kCFCompareLessThan
;
560 if (isnan(d2
)) return (s1
< 0.0) ? kCFCompareLessThan
: kCFCompareGreaterThan
;
561 // at this point, we know we don't have any NaNs
562 if (s1
< s2
) return kCFCompareLessThan
;
563 if (s2
< s1
) return kCFCompareGreaterThan
;
564 // at this point, we know the signs are the same; do not combine these tests
565 if (d1
< d2
) return kCFCompareLessThan
;
566 if (d2
< d1
) return kCFCompareGreaterThan
;
567 return kCFCompareEqualTo
;
570 __CFNumberGetValue(&(number1
->value
), type1
, kCFNumberSInt64Type
, &i1
);
571 __CFNumberGetValue(&(number2
->value
), type2
, kCFNumberSInt64Type
, &i2
);
572 return (i1
> i2
) ? kCFCompareGreaterThan
: ((i1
< i2
) ? kCFCompareLessThan
: kCFCompareEqualTo
);