]> git.saurik.com Git - apple/cf.git/blob - NumberDate.subproj/CFNumber.c
CF-299.tar.gz
[apple/cf.git] / NumberDate.subproj / CFNumber.c
1 /*
2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
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
13 * file.
14 *
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.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /* CFNumber.c
26 Copyright 1999-2002, Apple, Inc. All rights reserved.
27 Responsibility: Ali Ozer
28 */
29
30 #include <CoreFoundation/CFNumber.h>
31 #include "CFInternal.h"
32 #include "CFUtilities.h"
33 #include <math.h>
34 #include <float.h>
35 #if defined(__WIN32__)
36 #define isnan _isnan
37 #define isinf !_finite
38 #endif
39
40 /* Various assertions
41 */
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);
46
47 /* The IEEE bit patterns... Also have:
48 0x7f800000 float +Inf
49 0x7fc00000 float NaN
50 0xff800000 float -Inf
51 */
52 #define BITSFORDOUBLENAN ((uint64_t)0x7ff8000000000000ULL)
53 #define BITSFORDOUBLEPOSINF ((uint64_t)0x7ff0000000000000ULL)
54 #define BITSFORDOUBLENEGINF ((uint64_t)0xfff0000000000000ULL)
55
56 struct __CFBoolean {
57 CFRuntimeBase _base;
58 };
59
60 static struct __CFBoolean __kCFBooleanTrue = {
61 INIT_CFRUNTIME_BASE(NULL, 0, 0x0080)
62 };
63 const CFBooleanRef kCFBooleanTrue = &__kCFBooleanTrue;
64
65 static struct __CFBoolean __kCFBooleanFalse = {
66 INIT_CFRUNTIME_BASE(NULL, 0, 0x0080)
67 };
68 const CFBooleanRef kCFBooleanFalse = &__kCFBooleanFalse;
69
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");
73 }
74
75 static CFStringRef __CFBooleanCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
76 CFBooleanRef boolean = (CFBooleanRef)cf;
77 return CFRetain((boolean == kCFBooleanTrue) ? CFSTR("true") : CFSTR("false"));
78 }
79
80 static void __CFBooleanDeallocate(CFTypeRef cf) {
81 CFAssert(false, __kCFLogAssertion, "Deallocated CFBoolean!");
82 }
83
84 static CFTypeID __kCFBooleanTypeID = _kCFRuntimeNotATypeID;
85
86 static const CFRuntimeClass __CFBooleanClass = {
87 0,
88 "CFBoolean",
89 NULL, // init
90 NULL, // copy
91 __CFBooleanDeallocate,
92 NULL,
93 NULL,
94 __CFBooleanCopyFormattingDescription,
95 __CFBooleanCopyDescription
96 };
97
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);
104 }
105
106 CFTypeID CFBooleanGetTypeID(void) {
107 return __kCFBooleanTypeID;
108 }
109
110 Boolean CFBooleanGetValue(CFBooleanRef boolean) {
111 CF_OBJC_FUNCDISPATCH0(__kCFBooleanTypeID, Boolean, boolean, "boolValue");
112 return (boolean == kCFBooleanTrue) ? true : false;
113 }
114
115
116 /*** CFNumber ***/
117
118 typedef union {
119 SInt32 valSInt32;
120 int64_t valSInt64;
121 Float32 valFloat32;
122 Float64 valFloat64;
123 } __CFNumberValue;
124
125 struct __CFNumber { /* Only as many bytes as necessary are allocated */
126 CFRuntimeBase _base;
127 __CFNumberValue value;
128 };
129
130 static struct __CFNumber __kCFNumberNaN = {
131 INIT_CFRUNTIME_BASE(NULL, 0, 0x0080), {0}
132 };
133 const CFNumberRef kCFNumberNaN = &__kCFNumberNaN;
134
135 static struct __CFNumber __kCFNumberNegativeInfinity = {
136 INIT_CFRUNTIME_BASE(NULL, 0, 0x0080), {0}
137 };
138 const CFNumberRef kCFNumberNegativeInfinity = &__kCFNumberNegativeInfinity;
139
140 static struct __CFNumber __kCFNumberPositiveInfinity = {
141 INIT_CFRUNTIME_BASE(NULL, 0, 0x0080), {0}
142 };
143 const CFNumberRef kCFNumberPositiveInfinity = &__kCFNumberPositiveInfinity;
144
145
146 /* Eight bits in base:
147 Bits 6..0: type (bits 4..0 is CFNumberType)
148 */
149 enum {
150 __kCFNumberIsPositiveInfinity = (0x20 | kCFNumberFloat64Type),
151 __kCFNumberIsNegativeInfinity = (0x40 | kCFNumberFloat64Type),
152 __kCFNumberIsNaN = (0x60 | kCFNumberFloat64Type)
153 };
154
155
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.
157 */
158
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.
160 */
161 static const unsigned char __CFNumberCanonicalType[kCFNumberMaxType + 1] = {
162 0, kCFNumberSInt8Type, kCFNumberSInt16Type, kCFNumberSInt32Type, kCFNumberSInt64Type, kCFNumberFloat32Type, kCFNumberFloat64Type,
163 kCFNumberSInt8Type, kCFNumberSInt16Type, kCFNumberSInt32Type, kCFNumberSInt32Type, kCFNumberSInt64Type, kCFNumberFloat32Type, kCFNumberFloat64Type,
164 kCFNumberSInt32Type
165 };
166
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.
170 */
171 static const unsigned char __CFNumberStorageType[kCFNumberMaxType + 1] = {
172 0, kCFNumberSInt32Type, kCFNumberSInt32Type, kCFNumberSInt32Type, kCFNumberSInt64Type, kCFNumberFloat32Type, kCFNumberFloat64Type,
173 kCFNumberSInt32Type, kCFNumberSInt32Type, kCFNumberSInt32Type, kCFNumberSInt32Type, kCFNumberSInt64Type, kCFNumberFloat32Type, kCFNumberFloat64Type,
174 kCFNumberSInt32Type
175 };
176
177 // Returns the type that is used to store the specified type
178 CF_INLINE CFNumberType __CFNumberGetStorageTypeForType(CFNumberType type) {
179 return __CFNumberStorageType[type];
180 }
181
182 // Returns the canonical type used to represent the specified type
183 CF_INLINE CFNumberType __CFNumberGetCanonicalTypeForType(CFNumberType type) {
184 return __CFNumberCanonicalType[type];
185 }
186
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);
190 }
191
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);
195 }
196
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) {
200 switch (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);
207 default: return 0;
208 }
209 }
210
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) \
214 switch (type) { \
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; \
221 default: break; \
222 }
223
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) \
227 switch (type) { \
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; \
234 default: break; \
235 }
236
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;
245 default: break; \
246 }
247 }
248
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)) {
252 Float64 d1, d2;
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
257 }
258 return d1 == d2;
259 } else {
260 int64_t i1, i2;
261 __CFNumberGetValue(value1, type1, kCFNumberSInt64Type, &i1);
262 __CFNumberGetValue(value2, type2, kCFNumberSInt64Type, &i2);
263 return i1 == i2;
264 }
265 }
266
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));
271 }
272
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));
280 default:
281 __CFInvalidNumberStorageType(__CFNumberGetType(cf));
282 return 0;
283 }
284 }
285
286 #define bufSize 100
287 #define emitChar(ch) \
288 {if (buf - stackBuf == bufSize) {CFStringAppendCharacters(mstr, stackBuf, bufSize); buf = stackBuf;} *buf++ = ch;}
289
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;
293 int32_t w;
294 bool neg;
295
296 neg = (value < 0) ? true : false;
297 uvalue = (neg) ? -value : value;
298 if (neg || explicitPlus) width--;
299 width--;
300 factor = 1;
301 tmp = uvalue;
302 while (9 < tmp) {
303 width--;
304 factor *= 10;
305 tmp /= 10;
306 }
307 for (w = 0; w < width; w++) emitChar(pad);
308 if (neg) {
309 emitChar('-');
310 } else if (explicitPlus) {
311 emitChar('+');
312 }
313 while (0 < factor) {
314 UniChar ch = '0' + (uvalue / factor);
315 uvalue %= factor;
316 emitChar(ch);
317 factor /= 10;
318 }
319 if (buf > stackBuf) CFStringAppendCharacters(mstr, stackBuf, buf - stackBuf);
320 }
321
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}"));
330 break;
331 case kCFNumberSInt64Type:
332 __CFNumberEmitInt64(mstr, number->value.valSInt64, 0, ' ', true);
333 CFStringAppendFormat(mstr, NULL, CFSTR(", type = kCFNumberSInt64Type}"));
334 break;
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"));
343 } else {
344 CFStringAppendFormat(mstr, NULL, CFSTR("%+.10f"), number->value.valFloat32);
345 }
346 CFStringAppend(mstr, CFSTR(", type = kCFNumberFloat32Type}"));
347 break;
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"));
356 } else {
357 CFStringAppendFormat(mstr, NULL, CFSTR("%+.20f"), number->value.valFloat64);
358 }
359 CFStringAppend(mstr, CFSTR(", type = kCFNumberFloat64Type}"));
360 break;
361 default:
362 __CFInvalidNumberStorageType(__CFNumberGetType(number));
363 CFRelease(mstr);
364 return NULL;
365 }
366 return mstr;
367 }
368
369 // This function separated out from __CFNumberCopyFormattingDescription() so the plist creation can use it as well.
370
371 __private_extern__ CFStringRef __CFNumberCopyFormattingDescriptionAsFloat64(CFTypeRef cf) {
372 double d;
373 CFNumberGetValue(cf, kCFNumberFloat64Type, &d);
374 if (_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) {
375 if (isnan(d)) {
376 return CFRetain(CFSTR("nan"));
377 }
378 if (isinf(d)) {
379 return CFRetain((0.0 < d) ? CFSTR("+infinity") : CFSTR("-infinity"));
380 }
381 if (0.0 == d) {
382 return CFRetain(CFSTR("0.0"));
383 }
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);
386 }
387 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%lf"), d);
388 }
389
390 static CFStringRef __CFNumberCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
391 CFNumberRef number = (CFNumberRef)cf;
392 CFMutableStringRef mstr;
393 int64_t value;
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);
400 return mstr;
401 case kCFNumberFloat32Type:
402 if (_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) {
403 if (isnan(number->value.valFloat32)) {
404 return CFRetain(CFSTR("nan"));
405 }
406 if (isinf(number->value.valFloat32)) {
407 return CFRetain((0.0f < number->value.valFloat32) ? CFSTR("+infinity") : CFSTR("-infinity"));
408 }
409 if (0.0f == number->value.valFloat32) {
410 return CFRetain(CFSTR("0.0"));
411 }
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);
414 }
415 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%f"), number->value.valFloat32);
416 break;
417 case kCFNumberFloat64Type:
418 return __CFNumberCopyFormattingDescriptionAsFloat64(number);
419 break;
420 default:
421 __CFInvalidNumberStorageType(__CFNumberGetType(number));
422 return NULL;
423 }
424 }
425
426 static CFTypeID __kCFNumberTypeID = _kCFRuntimeNotATypeID;
427
428 static const CFRuntimeClass __CFNumberClass = {
429 0,
430 "CFNumber",
431 NULL, // init
432 NULL, // copy
433 NULL,
434 __CFNumberEqual,
435 __CFNumberHash,
436 __CFNumberCopyFormattingDescription,
437 __CFNumberCopyDescription
438 };
439
440 __private_extern__ void __CFNumberInitialize(void) {
441 uint64_t dnan = BITSFORDOUBLENAN;
442 uint64_t negInf = BITSFORDOUBLENEGINF;
443 uint64_t posInf = BITSFORDOUBLEPOSINF;
444
445 __kCFNumberTypeID = _CFRuntimeRegisterClass(&__CFNumberClass);
446
447 _CFRuntimeSetInstanceTypeID(&__kCFNumberNaN, __kCFNumberTypeID);
448 __kCFNumberNaN._base._isa = __CFISAForTypeID(__kCFNumberTypeID);
449 __CFBitfieldSetValue(__kCFNumberNaN._base._info, 6, 0, __kCFNumberIsNaN);
450 __kCFNumberNaN.value.valFloat64 = *(double *)&dnan;
451
452 _CFRuntimeSetInstanceTypeID(& __kCFNumberNegativeInfinity, __kCFNumberTypeID);
453 __kCFNumberNegativeInfinity._base._isa = __CFISAForTypeID(__kCFNumberTypeID);
454 __CFBitfieldSetValue(__kCFNumberNegativeInfinity._base._info, 6, 0, __kCFNumberIsNegativeInfinity);
455 __kCFNumberNegativeInfinity.value.valFloat64 = *(double *)&negInf;
456
457 _CFRuntimeSetInstanceTypeID(& __kCFNumberPositiveInfinity, __kCFNumberTypeID);
458 __kCFNumberPositiveInfinity._base._isa = __CFISAForTypeID(__kCFNumberTypeID);
459 __CFBitfieldSetValue(__kCFNumberPositiveInfinity._base._info, 6, 0, __kCFNumberIsPositiveInfinity);
460 __kCFNumberPositiveInfinity.value.valFloat64 = *(double *)&posInf;
461 }
462
463 CFTypeID CFNumberGetTypeID(void) {
464 return __kCFNumberTypeID;
465 }
466
467 CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType type, const void *valuePtr) {
468 CFNumberRef num;
469 CFNumberType equivType, storageType;
470
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);
479 }
480
481 equivType = __CFNumberGetCanonicalTypeForType(type);
482 storageType = __CFNumberGetStorageTypeForType(type);
483
484 num = (CFNumberRef)_CFRuntimeCreateInstance(allocator, __kCFNumberTypeID, __CFNumberSizeOfType(storageType), NULL);
485 if (NULL == num) {
486 return NULL;
487 }
488 SET_VALUE((__CFNumberValue *)&(num->value), equivType, valuePtr);
489 __CFBitfieldSetValue(((struct __CFNumber *)num)->_base._info, 6, 0, storageType);
490 return num;
491 }
492
493 CFNumberType CFNumberGetType(CFNumberRef number) {
494 CF_OBJC_FUNCDISPATCH0(__kCFNumberTypeID, CFNumberType, number, "_cfNumberType");
495
496 __CFAssertIsNumber(number);
497 return __CFNumberGetType(number);
498 }
499
500 CFIndex CFNumberGetByteSize(CFNumberRef number) {
501 __CFAssertIsNumber(number);
502 return __CFNumberSizeOfType(CFNumberGetType(number));
503 }
504
505 Boolean CFNumberIsFloatType(CFNumberRef number) {
506 __CFAssertIsNumber(number);
507 return __CFNumberTypeIsFloat(CFNumberGetType(number));
508 }
509
510 Boolean CFNumberGetValue(CFNumberRef number, CFNumberType type, void *valuePtr) {
511 uint8_t localMemory[sizeof(__CFNumberValue)];
512 __CFNumberValue localValue;
513 CFNumberType numType;
514 CFNumberType storageTypeForType;
515
516 CF_OBJC_FUNCDISPATCH2(__kCFNumberTypeID, Boolean, number, "_getValue:forType:", valuePtr, __CFNumberGetCanonicalTypeForType(type));
517
518 __CFAssertIsNumber(number);
519 __CFAssertIsValidNumberType(type);
520
521 storageTypeForType = __CFNumberGetStorageTypeForType(type);
522 type = __CFNumberGetCanonicalTypeForType(type);
523 if (!valuePtr) valuePtr = &localMemory;
524
525 numType = __CFNumberGetType(number);
526 __CFNumberGetValue((__CFNumberValue *)&(number->value), numType, type, valuePtr);
527
528 // If the types match, then we're fine!
529 if (numType == storageTypeForType) return true;
530
531 // Test to see if the returned value is intact...
532 SET_VALUE(&localValue, type, valuePtr);
533 return __CFNumberEqualValue(&localValue, storageTypeForType, &(number->value), numType);
534 }
535
536 CFComparisonResult CFNumberCompare(CFNumberRef number1, CFNumberRef number2, void *context) {
537 CFNumberType type1, type2;
538
539 CF_OBJC_FUNCDISPATCH1(__kCFNumberTypeID, CFComparisonResult, number1, "compare:", number2);
540 CF_OBJC_FUNCDISPATCH1(__kCFNumberTypeID, CFComparisonResult, number2, "_reverseCompare:", number1);
541
542 __CFAssertIsNumber(number1);
543 __CFAssertIsNumber(number2);
544
545 type1 = __CFNumberGetType(number1);
546 type2 = __CFNumberGetType(number2);
547
548 if (__CFNumberTypeIsFloat(type1) || __CFNumberTypeIsFloat(type2)) {
549 Float64 d1, d2;
550 double s1, s2;
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);
557 }
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;
568 } else {
569 int64_t i1, i2;
570 __CFNumberGetValue(&(number1->value), type1, kCFNumberSInt64Type, &i1);
571 __CFNumberGetValue(&(number2->value), type2, kCFNumberSInt64Type, &i2);
572 return (i1 > i2) ? kCFCompareGreaterThan : ((i1 < i2) ? kCFCompareLessThan : kCFCompareEqualTo);
573 }
574 }
575