]> git.saurik.com Git - apple/cf.git/blob - NumberDate.subproj/CFNumber.c
CF-368.tar.gz
[apple/cf.git] / NumberDate.subproj / CFNumber.c
1 /*
2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /* CFNumber.c
24 Copyright 1999-2002, Apple, Inc. All rights reserved.
25 Responsibility: Ali Ozer
26 */
27
28 #include <CoreFoundation/CFNumber.h>
29 #include "CFInternal.h"
30 #include "CFUtilitiesPriv.h"
31 #include <math.h>
32 #include <float.h>
33 #if defined(__WIN32__) && !defined(__MINGW32__) && !defined(__CYGWIN__)
34 #define isnan _isnan
35 #define isinf !_finite
36 #endif
37
38 /* Various assertions
39 */
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);
44
45 /* The IEEE bit patterns... Also have:
46 0x7f800000 float +Inf
47 0x7fc00000 float NaN
48 0xff800000 float -Inf
49 */
50 #define BITSFORDOUBLENAN ((uint64_t)0x7ff8000000000000ULL)
51 #define BITSFORDOUBLEPOSINF ((uint64_t)0x7ff0000000000000ULL)
52 #define BITSFORDOUBLENEGINF ((uint64_t)0xfff0000000000000ULL)
53
54 struct __CFBoolean {
55 CFRuntimeBase _base;
56 };
57
58 static struct __CFBoolean __kCFBooleanTrue = {
59 INIT_CFRUNTIME_BASE(NULL, 0, 0x0080)
60 };
61 const CFBooleanRef kCFBooleanTrue = &__kCFBooleanTrue;
62
63 static struct __CFBoolean __kCFBooleanFalse = {
64 INIT_CFRUNTIME_BASE(NULL, 0, 0x0080)
65 };
66 const CFBooleanRef kCFBooleanFalse = &__kCFBooleanFalse;
67
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");
71 }
72
73 static CFStringRef __CFBooleanCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
74 CFBooleanRef boolean = (CFBooleanRef)cf;
75 return CFRetain((boolean == kCFBooleanTrue) ? CFSTR("true") : CFSTR("false"));
76 }
77
78 static void __CFBooleanDeallocate(CFTypeRef cf) {
79 CFAssert(false, __kCFLogAssertion, "Deallocated CFBoolean!");
80 }
81
82 static CFTypeID __kCFBooleanTypeID = _kCFRuntimeNotATypeID;
83
84 static const CFRuntimeClass __CFBooleanClass = {
85 0,
86 "CFBoolean",
87 NULL, // init
88 NULL, // copy
89 __CFBooleanDeallocate,
90 NULL,
91 NULL,
92 __CFBooleanCopyFormattingDescription,
93 __CFBooleanCopyDescription
94 };
95
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);
102 }
103
104 CFTypeID CFBooleanGetTypeID(void) {
105 return __kCFBooleanTypeID;
106 }
107
108 Boolean CFBooleanGetValue(CFBooleanRef boolean) {
109 CF_OBJC_FUNCDISPATCH0(__kCFBooleanTypeID, Boolean, boolean, "boolValue");
110 return (boolean == kCFBooleanTrue) ? true : false;
111 }
112
113
114 /*** CFNumber ***/
115
116 typedef union {
117 SInt32 valSInt32;
118 int64_t valSInt64;
119 Float32 valFloat32;
120 Float64 valFloat64;
121 } __CFNumberValue;
122
123 struct __CFNumber { /* Only as many bytes as necessary are allocated */
124 CFRuntimeBase _base;
125 __CFNumberValue value;
126 };
127
128 static struct __CFNumber __kCFNumberNaN = {
129 INIT_CFRUNTIME_BASE(NULL, 0, 0x0080), {0}
130 };
131 const CFNumberRef kCFNumberNaN = &__kCFNumberNaN;
132
133 static struct __CFNumber __kCFNumberNegativeInfinity = {
134 INIT_CFRUNTIME_BASE(NULL, 0, 0x0080), {0}
135 };
136 const CFNumberRef kCFNumberNegativeInfinity = &__kCFNumberNegativeInfinity;
137
138 static struct __CFNumber __kCFNumberPositiveInfinity = {
139 INIT_CFRUNTIME_BASE(NULL, 0, 0x0080), {0}
140 };
141 const CFNumberRef kCFNumberPositiveInfinity = &__kCFNumberPositiveInfinity;
142
143
144 /* Seven bits in base:
145 Bits 4..0: CFNumber type
146 Bit 6: is unsigned number
147 */
148
149
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.
151 */
152
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.
154 */
155 static const unsigned char __CFNumberCanonicalType[kCFNumberMaxType + 1] = {
156 0, kCFNumberSInt8Type, kCFNumberSInt16Type, kCFNumberSInt32Type, kCFNumberSInt64Type, kCFNumberFloat32Type, kCFNumberFloat64Type,
157 kCFNumberSInt8Type, kCFNumberSInt16Type, kCFNumberSInt32Type, kCFNumberSInt32Type, kCFNumberSInt64Type, kCFNumberFloat32Type, kCFNumberFloat64Type,
158 kCFNumberSInt32Type
159 };
160
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.
164 */
165 static const unsigned char __CFNumberStorageType[kCFNumberMaxType + 1] = {
166 0, kCFNumberSInt32Type, kCFNumberSInt32Type, kCFNumberSInt32Type, kCFNumberSInt64Type, kCFNumberFloat32Type, kCFNumberFloat64Type,
167 kCFNumberSInt32Type, kCFNumberSInt32Type, kCFNumberSInt32Type, kCFNumberSInt32Type, kCFNumberSInt64Type, kCFNumberFloat32Type, kCFNumberFloat64Type,
168 kCFNumberSInt32Type
169 };
170
171 // Returns the type that is used to store the specified type
172 CF_INLINE CFNumberType __CFNumberGetStorageTypeForType(CFNumberType type) {
173 return __CFNumberStorageType[type];
174 }
175
176 // Returns the canonical type used to represent the specified type
177 CF_INLINE CFNumberType __CFNumberGetCanonicalTypeForType(CFNumberType type) {
178 return __CFNumberCanonicalType[type];
179 }
180
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);
184 }
185
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);
189 }
190
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) {
194 switch (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);
201 default: return 0;
202 }
203 }
204
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) \
208 switch (type) { \
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; \
215 default: break; \
216 }
217
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) \
221 switch (type) { \
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; \
228 default: break; \
229 }
230
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;
239 default: break; \
240 }
241 }
242
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)) {
246 Float64 d1, d2;
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
251 }
252 return d1 == d2;
253 } else {
254 int64_t i1, i2;
255 __CFNumberGetValue(value1, type1, kCFNumberSInt64Type, &i1);
256 __CFNumberGetValue(value2, type2, kCFNumberSInt64Type, &i2);
257 return i1 == i2;
258 }
259 }
260
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));
265 }
266
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));
274 default:
275 __CFInvalidNumberStorageType(__CFNumberGetType(cf));
276 return 0;
277 }
278 }
279
280 #define bufSize 100
281 #define emitChar(ch) \
282 {if (buf - stackBuf == bufSize) {CFStringAppendCharacters(mstr, stackBuf, bufSize); buf = stackBuf;} *buf++ = ch;}
283
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;
287 int32_t w;
288 bool neg;
289
290 neg = (value < 0) ? true : false;
291 uvalue = (neg) ? -value : value;
292 if (neg || explicitPlus) width--;
293 width--;
294 factor = 1;
295 tmp = uvalue;
296 while (9 < tmp) {
297 width--;
298 factor *= 10;
299 tmp /= 10;
300 }
301 for (w = 0; w < width; w++) emitChar(pad);
302 if (neg) {
303 emitChar('-');
304 } else if (explicitPlus) {
305 emitChar('+');
306 }
307 while (0 < factor) {
308 UniChar ch = '0' + (uvalue / factor);
309 uvalue %= factor;
310 emitChar(ch);
311 factor /= 10;
312 }
313 if (buf > stackBuf) CFStringAppendCharacters(mstr, stackBuf, buf - stackBuf);
314 }
315
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}"));
324 break;
325 case kCFNumberSInt64Type:
326 __CFNumberEmitInt64(mstr, number->value.valSInt64, 0, ' ', true);
327 CFStringAppendFormat(mstr, NULL, CFSTR(", type = kCFNumberSInt64Type}"));
328 break;
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"));
337 } else {
338 CFStringAppendFormat(mstr, NULL, CFSTR("%+.10f"), number->value.valFloat32);
339 }
340 CFStringAppend(mstr, CFSTR(", type = kCFNumberFloat32Type}"));
341 break;
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"));
350 } else {
351 CFStringAppendFormat(mstr, NULL, CFSTR("%+.20f"), number->value.valFloat64);
352 }
353 CFStringAppend(mstr, CFSTR(", type = kCFNumberFloat64Type}"));
354 break;
355 default:
356 __CFInvalidNumberStorageType(__CFNumberGetType(number));
357 CFRelease(mstr);
358 return NULL;
359 }
360 return mstr;
361 }
362
363 // This function separated out from __CFNumberCopyFormattingDescription() so the plist creation can use it as well.
364
365 __private_extern__ CFStringRef __CFNumberCopyFormattingDescriptionAsFloat64(CFTypeRef cf) {
366 double d;
367 CFNumberGetValue(cf, kCFNumberFloat64Type, &d);
368 if (_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) {
369 if (isnan(d)) {
370 return CFRetain(CFSTR("nan"));
371 }
372 if (isinf(d)) {
373 return CFRetain((0.0 < d) ? CFSTR("+infinity") : CFSTR("-infinity"));
374 }
375 if (0.0 == d) {
376 return CFRetain(CFSTR("0.0"));
377 }
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);
380 }
381 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%lf"), d);
382 }
383
384 static CFStringRef __CFNumberCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
385 CFNumberRef number = (CFNumberRef)cf;
386 CFMutableStringRef mstr;
387 int64_t value;
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);
394 return mstr;
395 case kCFNumberFloat32Type:
396 if (_CFExecutableLinkedOnOrAfter(CFSystemVersionJaguar)) {
397 if (isnan(number->value.valFloat32)) {
398 return CFRetain(CFSTR("nan"));
399 }
400 if (isinf(number->value.valFloat32)) {
401 return CFRetain((0.0f < number->value.valFloat32) ? CFSTR("+infinity") : CFSTR("-infinity"));
402 }
403 if (0.0f == number->value.valFloat32) {
404 return CFRetain(CFSTR("0.0"));
405 }
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);
408 }
409 return CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%f"), number->value.valFloat32);
410 break;
411 case kCFNumberFloat64Type:
412 return __CFNumberCopyFormattingDescriptionAsFloat64(number);
413 break;
414 default:
415 __CFInvalidNumberStorageType(__CFNumberGetType(number));
416 return NULL;
417 }
418 }
419
420 static CFTypeID __kCFNumberTypeID = _kCFRuntimeNotATypeID;
421
422 static const CFRuntimeClass __CFNumberClass = {
423 0,
424 "CFNumber",
425 NULL, // init
426 NULL, // copy
427 NULL,
428 __CFNumberEqual,
429 __CFNumberHash,
430 __CFNumberCopyFormattingDescription,
431 __CFNumberCopyDescription
432 };
433
434 __private_extern__ void __CFNumberInitialize(void) {
435 uint64_t dnan = BITSFORDOUBLENAN;
436 uint64_t negInf = BITSFORDOUBLENEGINF;
437 uint64_t posInf = BITSFORDOUBLEPOSINF;
438
439 __kCFNumberTypeID = _CFRuntimeRegisterClass(&__CFNumberClass);
440
441 _CFRuntimeSetInstanceTypeID(&__kCFNumberNaN, __kCFNumberTypeID);
442 __kCFNumberNaN._base._isa = __CFISAForTypeID(__kCFNumberTypeID);
443 __CFBitfieldSetValue(__kCFNumberNaN._base._info, 4, 0, kCFNumberFloat64Type);
444 __kCFNumberNaN.value.valFloat64 = *(double *)&dnan;
445
446 _CFRuntimeSetInstanceTypeID(& __kCFNumberNegativeInfinity, __kCFNumberTypeID);
447 __kCFNumberNegativeInfinity._base._isa = __CFISAForTypeID(__kCFNumberTypeID);
448 __CFBitfieldSetValue(__kCFNumberNegativeInfinity._base._info, 4, 0, kCFNumberFloat64Type);
449 __kCFNumberNegativeInfinity.value.valFloat64 = *(double *)&negInf;
450
451 _CFRuntimeSetInstanceTypeID(& __kCFNumberPositiveInfinity, __kCFNumberTypeID);
452 __kCFNumberPositiveInfinity._base._isa = __CFISAForTypeID(__kCFNumberTypeID);
453 __CFBitfieldSetValue(__kCFNumberPositiveInfinity._base._info, 4, 0, kCFNumberFloat64Type);
454 __kCFNumberPositiveInfinity.value.valFloat64 = *(double *)&posInf;
455 }
456
457 Boolean _CFNumberIsU(CFNumberRef num) {
458 return __CFBitfieldGetValue(__kCFNumberPositiveInfinity._base._info, 6, 6);
459 }
460
461 void _CFNumberSetU(CFNumberRef num, Boolean unsign) {
462 __CFBitfieldSetValue(__kCFNumberPositiveInfinity._base._info, 6, 6, (unsign ? 1 : 0));
463 }
464
465 CFTypeID CFNumberGetTypeID(void) {
466 return __kCFNumberTypeID;
467 }
468
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;
474
475 CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType type, const void *valuePtr) {
476 CFNumberRef num;
477 CFNumberType equivType, storageType;
478 int32_t valToBeCached = NotToBeCached;
479
480 equivType = __CFNumberGetCanonicalTypeForType(type);
481
482 // Take care of some special cases; in some cases we will return here without actually creating a new CFNumber
483 switch (equivType) {
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);
488 break;
489 }
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);
494 break;
495 }
496 default: {
497 switch (equivType) {
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;}
502 default:;
503 }
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);
513 }
514 break;
515 }
516 }
517
518 storageType = __CFNumberGetStorageTypeForType(type);
519
520 num = (CFNumberRef)_CFRuntimeCreateInstance(allocator, __kCFNumberTypeID, __CFNumberSizeOfType(storageType), NULL);
521 if (NULL == num) {
522 return NULL;
523 }
524 SET_VALUE((__CFNumberValue *)&(num->value), equivType, valuePtr);
525 __CFBitfieldSetValue(((struct __CFNumber *)num)->_base._info, 6, 0, storageType);
526
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
534 }
535 return num;
536 }
537
538 CFNumberType CFNumberGetType(CFNumberRef number) {
539 CF_OBJC_FUNCDISPATCH0(__kCFNumberTypeID, CFNumberType, number, "_cfNumberType");
540
541 __CFAssertIsNumber(number);
542 return __CFNumberGetType(number);
543 }
544
545 CFIndex CFNumberGetByteSize(CFNumberRef number) {
546 __CFAssertIsNumber(number);
547 return __CFNumberSizeOfType(CFNumberGetType(number));
548 }
549
550 Boolean CFNumberIsFloatType(CFNumberRef number) {
551 __CFAssertIsNumber(number);
552 return __CFNumberTypeIsFloat(CFNumberGetType(number));
553 }
554
555 Boolean CFNumberGetValue(CFNumberRef number, CFNumberType type, void *valuePtr) {
556 uint8_t localMemory[sizeof(__CFNumberValue)];
557 __CFNumberValue localValue;
558 CFNumberType numType;
559 CFNumberType storageTypeForType;
560
561 CF_OBJC_FUNCDISPATCH2(__kCFNumberTypeID, Boolean, number, "_getValue:forType:", valuePtr, __CFNumberGetCanonicalTypeForType(type));
562
563 __CFAssertIsNumber(number);
564 __CFAssertIsValidNumberType(type);
565
566 storageTypeForType = __CFNumberGetStorageTypeForType(type);
567 type = __CFNumberGetCanonicalTypeForType(type);
568 if (!valuePtr) valuePtr = &localMemory;
569
570 numType = __CFNumberGetType(number);
571 __CFNumberGetValue((__CFNumberValue *)&(number->value), numType, type, valuePtr);
572
573 // If the types match, then we're fine!
574 if (numType == storageTypeForType) return true;
575
576 // Test to see if the returned value is intact...
577 SET_VALUE(&localValue, type, valuePtr);
578 return __CFNumberEqualValue(&localValue, storageTypeForType, &(number->value), numType);
579 }
580
581 CFComparisonResult CFNumberCompare(CFNumberRef number1, CFNumberRef number2, void *context) {
582 CFNumberType type1, type2;
583
584 CF_OBJC_FUNCDISPATCH1(__kCFNumberTypeID, CFComparisonResult, number1, "compare:", number2);
585 CF_OBJC_FUNCDISPATCH1(__kCFNumberTypeID, CFComparisonResult, number2, "_reverseCompare:", number1);
586
587 __CFAssertIsNumber(number1);
588 __CFAssertIsNumber(number2);
589
590 type1 = __CFNumberGetType(number1);
591 type2 = __CFNumberGetType(number2);
592
593 if (__CFNumberTypeIsFloat(type1) || __CFNumberTypeIsFloat(type2)) {
594 Float64 d1, d2;
595 double s1, s2;
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);
602 }
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;
613 } else {
614 int64_t i1, i2;
615 __CFNumberGetValue(&(number1->value), type1, kCFNumberSInt64Type, &i1);
616 __CFNumberGetValue(&(number2->value), type2, kCFNumberSInt64Type, &i2);
617 return (i1 > i2) ? kCFCompareGreaterThan : ((i1 < i2) ? kCFCompareLessThan : kCFCompareEqualTo);
618 }
619 }
620