2 * Copyright (c) 2012 Apple 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@
25 Copyright (c) 1999-2012, Apple Inc. All rights reserved.
26 Responsibility: Ali Ozer
29 #include <CoreFoundation/CFNumber.h>
30 #include "CFInternal.h"
31 #include <CoreFoundation/CFPriv.h>
36 #if DEPLOYMENT_TARGET_WINDOWS
37 #define isnan(A) _isnan(A)
38 #define isinf(A) !_finite(A)
39 #define copysign(A, B) _copysign(A, B)
42 #define __CFAssertIsBoolean(cf) __CFGenericValidateType(cf, __kCFBooleanTypeID)
48 static struct __CFBoolean __kCFBooleanTrue
= {
51 const CFBooleanRef kCFBooleanTrue
= &__kCFBooleanTrue
;
53 static struct __CFBoolean __kCFBooleanFalse
= {
56 const CFBooleanRef kCFBooleanFalse
= &__kCFBooleanFalse
;
58 static CFStringRef
__CFBooleanCopyDescription(CFTypeRef cf
) {
59 CFBooleanRef boolean
= (CFBooleanRef
)cf
;
60 return CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("<CFBoolean %p [%p]>{value = %s}"), cf
, CFGetAllocator(cf
), (boolean
== kCFBooleanTrue
) ? "true" : "false");
63 __private_extern__ CFStringRef
__CFBooleanCopyFormattingDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
64 CFBooleanRef boolean
= (CFBooleanRef
)cf
;
65 return (CFStringRef
)CFRetain((boolean
== kCFBooleanTrue
) ? CFSTR("true") : CFSTR("false"));
68 static CFHashCode
__CFBooleanHash(CFTypeRef cf
) {
69 CFBooleanRef boolean
= (CFBooleanRef
)cf
;
70 return (boolean
== kCFBooleanTrue
) ? _CFHashInt(1) : _CFHashInt(0);
73 static void __CFBooleanDeallocate(CFTypeRef cf
) {
74 CFAssert(false, __kCFLogAssertion
, "Deallocated CFBoolean!");
77 static CFTypeID __kCFBooleanTypeID
= _kCFRuntimeNotATypeID
;
79 static const CFRuntimeClass __CFBooleanClass
= {
84 __CFBooleanDeallocate
,
87 __CFBooleanCopyFormattingDescription
,
88 __CFBooleanCopyDescription
91 __private_extern__
void __CFBooleanInitialize(void) {
92 __kCFBooleanTypeID
= _CFRuntimeRegisterClass(&__CFBooleanClass
);
93 _CFRuntimeSetInstanceTypeID(&__kCFBooleanTrue
, __kCFBooleanTypeID
);
94 __kCFBooleanTrue
._base
._cfisa
= __CFISAForTypeID(__kCFBooleanTypeID
);
95 _CFRuntimeSetInstanceTypeID(&__kCFBooleanFalse
, __kCFBooleanTypeID
);
96 __kCFBooleanFalse
._base
._cfisa
= __CFISAForTypeID(__kCFBooleanTypeID
);
99 CFTypeID
CFBooleanGetTypeID(void) {
100 return __kCFBooleanTypeID
;
103 Boolean
CFBooleanGetValue(CFBooleanRef boolean
) {
104 CF_OBJC_FUNCDISPATCHV(__kCFBooleanTypeID
, Boolean
, (NSNumber
*)boolean
, boolValue
);
105 return (boolean
== kCFBooleanTrue
) ? true : false;
111 #define OLD_CRAP_TOO 0
115 // old implementation, for runtime comparison purposes
122 } __CFNumberValue_old
;
124 struct __CFNumber_old
{ /* Only as many bytes as necessary are allocated */
126 __CFNumberValue_old value
;
129 static Boolean
__CFNumberEqual_old(CFTypeRef cf1
, CFTypeRef cf2
);
130 static CFHashCode
__CFNumberHash_old(CFTypeRef cf
);
131 static CFStringRef
__CFNumberCopyDescription_old(CFTypeRef cf
);
132 __private_extern__ CFStringRef
__CFNumberCopyFormattingDescriptionAsFloat64_old(CFTypeRef cf
);
133 static CFStringRef
__CFNumberCopyFormattingDescription_old(CFTypeRef cf
, CFDictionaryRef formatOptions
);
134 static struct __CFNumber_old
* CFNumberCreate_old(CFAllocatorRef allocator
, CFNumberType type
, const void *valuePtr
);
135 static CFNumberType
CFNumberGetType_old(struct __CFNumber_old
* number
);
136 static CFIndex
CFNumberGetByteSize_old(struct __CFNumber_old
* number
);
137 static Boolean
CFNumberIsFloatType_old(struct __CFNumber_old
* number
);
138 static Boolean
CFNumberGetValue_old(struct __CFNumber_old
* number
, CFNumberType type
, void *valuePtr
);
139 static CFComparisonResult
CFNumberCompare_old(struct __CFNumber_old
* number1
, struct __CFNumber_old
* number2
, void *context
);
144 #define __CFAssertIsNumber(cf) __CFGenericValidateType(cf, __kCFNumberTypeID)
145 #define __CFAssertIsValidNumberType(type) CFAssert2((0 < type && type <= kCFNumberMaxType) || (type == kCFNumberSInt128Type), __kCFLogAssertion, "%s(): bad CFNumber type %d", __PRETTY_FUNCTION__, type);
147 /* The IEEE bit patterns... Also have:
148 0x7f800000 float +Inf
150 0xff800000 float -Inf
152 #define BITSFORDOUBLENAN ((uint64_t)0x7ff8000000000000ULL)
153 #define BITSFORDOUBLEPOSINF ((uint64_t)0x7ff0000000000000ULL)
154 #define BITSFORDOUBLENEGINF ((uint64_t)0xfff0000000000000ULL)
156 #if DEPLOYMENT_TARGET_MACOSX || DEPLOYMENT_TARGET_EMBEDDED || DEPLOYMENT_TARGET_EMBEDDED_MINI || DEPLOYMENT_TARGET_LINUX
157 #define FLOAT_POSITIVE_2_TO_THE_64 0x1.0p+64L
158 #define FLOAT_NEGATIVE_2_TO_THE_127 -0x1.0p+127L
159 #define FLOAT_POSITIVE_2_TO_THE_127 0x1.0p+127L
160 #elif DEPLOYMENT_TARGET_WINDOWS
161 #define FLOAT_POSITIVE_2_TO_THE_64 18446744073709551616.0
162 #define FLOAT_NEGATIVE_2_TO_THE_127 -170141183460469231731687303715884105728.0
163 #define FLOAT_POSITIVE_2_TO_THE_127 170141183460469231731687303715884105728.0
165 #error Unknown or unspecified DEPLOYMENT_TARGET
168 typedef struct { // NOTE WELL: these two fields may switch position someday, do not use '= {high, low}' -style initialization
174 kCFNumberSInt128Type
= 17
177 static uint8_t isNeg128(const CFSInt128Struct
*in
) {
181 static CFComparisonResult
cmp128(const CFSInt128Struct
*in1
, const CFSInt128Struct
*in2
) {
182 if (in1
->high
< in2
->high
) return kCFCompareLessThan
;
183 if (in1
->high
> in2
->high
) return kCFCompareGreaterThan
;
184 if (in1
->low
< in2
->low
) return kCFCompareLessThan
;
185 if (in1
->low
> in2
->low
) return kCFCompareGreaterThan
;
186 return kCFCompareEqualTo
;
189 // allows out to be the same as in1 or in2
190 static void add128(CFSInt128Struct
*out
, CFSInt128Struct
*in1
, CFSInt128Struct
*in2
) {
192 tmp
.low
= in1
->low
+ in2
->low
;
193 tmp
.high
= in1
->high
+ in2
->high
;
194 if (UINT64_MAX
- in1
->low
< in2
->low
) {
200 // allows out to be the same as in
201 static void neg128(CFSInt128Struct
*out
, CFSInt128Struct
*in
) {
202 uint64_t tmplow
= ~in
->low
;
203 out
->low
= tmplow
+ 1;
204 out
->high
= ~in
->high
;
205 if (UINT64_MAX
== tmplow
) {
210 static const CFSInt128Struct powersOf10
[] = {
211 { 0x4B3B4CA85A86C47ALL
, 0x098A224000000000ULL
},
212 { 0x0785EE10D5DA46D9LL
, 0x00F436A000000000ULL
},
213 { 0x00C097CE7BC90715LL
, 0xB34B9F1000000000ULL
},
214 { 0x0013426172C74D82LL
, 0x2B878FE800000000ULL
},
215 { 0x0001ED09BEAD87C0LL
, 0x378D8E6400000000ULL
},
216 { 0x0000314DC6448D93LL
, 0x38C15B0A00000000ULL
},
217 { 0x000004EE2D6D415BLL
, 0x85ACEF8100000000ULL
},
218 { 0x0000007E37BE2022LL
, 0xC0914B2680000000ULL
},
219 { 0x0000000C9F2C9CD0LL
, 0x4674EDEA40000000ULL
},
220 { 0x00000001431E0FAELL
, 0x6D7217CAA0000000ULL
},
221 { 0x00000000204FCE5ELL
, 0x3E25026110000000ULL
},
222 { 0x00000000033B2E3CLL
, 0x9FD0803CE8000000ULL
},
223 { 0x000000000052B7D2LL
, 0xDCC80CD2E4000000ULL
},
224 { 0x0000000000084595LL
, 0x161401484A000000ULL
},
225 { 0x000000000000D3C2LL
, 0x1BCECCEDA1000000ULL
},
226 { 0x000000000000152DLL
, 0x02C7E14AF6800000ULL
},
227 { 0x000000000000021ELL
, 0x19E0C9BAB2400000ULL
},
228 { 0x0000000000000036LL
, 0x35C9ADC5DEA00000ULL
},
229 { 0x0000000000000005LL
, 0x6BC75E2D63100000ULL
},
230 { 0x0000000000000000LL
, 0x8AC7230489E80000ULL
},
231 { 0x0000000000000000LL
, 0x0DE0B6B3A7640000ULL
},
232 { 0x0000000000000000LL
, 0x016345785D8A0000ULL
},
233 { 0x0000000000000000LL
, 0x002386F26FC10000ULL
},
234 { 0x0000000000000000LL
, 0x00038D7EA4C68000ULL
},
235 { 0x0000000000000000LL
, 0x00005AF3107A4000ULL
},
236 { 0x0000000000000000LL
, 0x000009184E72A000ULL
},
237 { 0x0000000000000000LL
, 0x000000E8D4A51000ULL
},
238 { 0x0000000000000000LL
, 0x000000174876E800ULL
},
239 { 0x0000000000000000LL
, 0x00000002540BE400ULL
},
240 { 0x0000000000000000LL
, 0x000000003B9ACA00ULL
},
241 { 0x0000000000000000LL
, 0x0000000005F5E100ULL
},
242 { 0x0000000000000000LL
, 0x0000000000989680ULL
},
243 { 0x0000000000000000LL
, 0x00000000000F4240ULL
},
244 { 0x0000000000000000LL
, 0x00000000000186A0ULL
},
245 { 0x0000000000000000LL
, 0x0000000000002710ULL
},
246 { 0x0000000000000000LL
, 0x00000000000003E8ULL
},
247 { 0x0000000000000000LL
, 0x0000000000000064ULL
},
248 { 0x0000000000000000LL
, 0x000000000000000AULL
},
249 { 0x0000000000000000LL
, 0x0000000000000001ULL
},
252 static const CFSInt128Struct neg_powersOf10
[] = {
253 { 0xB4C4B357A5793B85LL
, 0xF675DDC000000000ULL
},
254 { 0xF87A11EF2A25B926LL
, 0xFF0BC96000000000ULL
},
255 { 0xFF3F68318436F8EALL
, 0x4CB460F000000000ULL
},
256 { 0xFFECBD9E8D38B27DLL
, 0xD478701800000000ULL
},
257 { 0xFFFE12F64152783FLL
, 0xC872719C00000000ULL
},
258 { 0xFFFFCEB239BB726CLL
, 0xC73EA4F600000000ULL
},
259 { 0xFFFFFB11D292BEA4LL
, 0x7A53107F00000000ULL
},
260 { 0xFFFFFF81C841DFDDLL
, 0x3F6EB4D980000000ULL
},
261 { 0xFFFFFFF360D3632FLL
, 0xB98B1215C0000000ULL
},
262 { 0xFFFFFFFEBCE1F051LL
, 0x928DE83560000000ULL
},
263 { 0xFFFFFFFFDFB031A1LL
, 0xC1DAFD9EF0000000ULL
},
264 { 0xFFFFFFFFFCC4D1C3LL
, 0x602F7FC318000000ULL
},
265 { 0xFFFFFFFFFFAD482DLL
, 0x2337F32D1C000000ULL
},
266 { 0xFFFFFFFFFFF7BA6ALL
, 0xE9EBFEB7B6000000ULL
},
267 { 0xFFFFFFFFFFFF2C3DLL
, 0xE43133125F000000ULL
},
268 { 0xFFFFFFFFFFFFEAD2LL
, 0xFD381EB509800000ULL
},
269 { 0xFFFFFFFFFFFFFDE1LL
, 0xE61F36454DC00000ULL
},
270 { 0xFFFFFFFFFFFFFFC9LL
, 0xCA36523A21600000ULL
},
271 { 0xFFFFFFFFFFFFFFFALL
, 0x9438A1D29CF00000ULL
},
272 { 0xFFFFFFFFFFFFFFFFLL
, 0x7538DCFB76180000ULL
},
273 { 0xFFFFFFFFFFFFFFFFLL
, 0xF21F494C589C0000ULL
},
274 { 0xFFFFFFFFFFFFFFFFLL
, 0xFE9CBA87A2760000ULL
},
275 { 0xFFFFFFFFFFFFFFFFLL
, 0xFFDC790D903F0000ULL
},
276 { 0xFFFFFFFFFFFFFFFFLL
, 0xFFFC72815B398000ULL
},
277 { 0xFFFFFFFFFFFFFFFFLL
, 0xFFFFA50CEF85C000ULL
},
278 { 0xFFFFFFFFFFFFFFFFLL
, 0xFFFFF6E7B18D6000ULL
},
279 { 0xFFFFFFFFFFFFFFFFLL
, 0xFFFFFF172B5AF000ULL
},
280 { 0xFFFFFFFFFFFFFFFFLL
, 0xFFFFFFE8B7891800ULL
},
281 { 0xFFFFFFFFFFFFFFFFLL
, 0xFFFFFFFDABF41C00ULL
},
282 { 0xFFFFFFFFFFFFFFFFLL
, 0xFFFFFFFFC4653600ULL
},
283 { 0xFFFFFFFFFFFFFFFFLL
, 0xFFFFFFFFFA0A1F00ULL
},
284 { 0xFFFFFFFFFFFFFFFFLL
, 0xFFFFFFFFFF676980ULL
},
285 { 0xFFFFFFFFFFFFFFFFLL
, 0xFFFFFFFFFFF0BDC0ULL
},
286 { 0xFFFFFFFFFFFFFFFFLL
, 0xFFFFFFFFFFFE7960ULL
},
287 { 0xFFFFFFFFFFFFFFFFLL
, 0xFFFFFFFFFFFFD8F0ULL
},
288 { 0xFFFFFFFFFFFFFFFFLL
, 0xFFFFFFFFFFFFFC18ULL
},
289 { 0xFFFFFFFFFFFFFFFFLL
, 0xFFFFFFFFFFFFFF9CULL
},
290 { 0xFFFFFFFFFFFFFFFFLL
, 0xFFFFFFFFFFFFFFF6ULL
},
291 { 0xFFFFFFFFFFFFFFFFLL
, 0xFFFFFFFFFFFFFFFFULL
},
294 static void emit128(char *buffer
, const CFSInt128Struct
*in
, Boolean forcePlus
) {
295 CFSInt128Struct tmp
= *in
;
296 if (isNeg128(&tmp
)) {
299 } else if (forcePlus
) {
302 Boolean doneOne
= false;
304 for (idx
= 0; idx
< sizeof(powersOf10
) / sizeof(powersOf10
[0]); idx
++) {
306 while (cmp128(&powersOf10
[idx
], &tmp
) <= 0) {
307 add128(&tmp
, &tmp
, (CFSInt128Struct
*)&neg_powersOf10
[idx
]);
310 if (0 != count
|| doneOne
) {
311 *buffer
++ = '0' + count
;
321 static void cvtSInt128ToFloat64(Float64
*out
, const CFSInt128Struct
*in
) {
322 // switching to a positive number results in better accuracy
323 // for negative numbers close to zero, because the multiply
324 // of -1 by 2^64 (scaling the Float64 high) is avoided
325 Boolean wasNeg
= false;
326 CFSInt128Struct tmp
= *in
;
327 if (isNeg128(&tmp
)) {
331 Float64 d
= (Float64
)tmp
.high
* FLOAT_POSITIVE_2_TO_THE_64
+ (Float64
)tmp
.low
;
336 static void cvtFloat64ToSInt128(CFSInt128Struct
*out
, const Float64
*in
) {
339 if (d
< FLOAT_NEGATIVE_2_TO_THE_127
) {
340 i
.high
= 0x8000000000000000LL
;
341 i
.low
= 0x0000000000000000ULL
;
345 if (FLOAT_POSITIVE_2_TO_THE_127
<= d
) {
346 i
.high
= 0x7fffffffffffffffLL
;
347 i
.low
= 0xffffffffffffffffULL
;
351 Float64 t
= floor(d
/ FLOAT_POSITIVE_2_TO_THE_64
);
353 i
.low
= (uint64_t)(d
- t
* FLOAT_POSITIVE_2_TO_THE_64
);
360 struct __CFNumber_old
*__old__
;
363 uint64_t _pad
; // need this space here for the constant objects
364 /* 0 or 8 more bytes allocated here */
367 /* Seven bits in base:
369 Bits 4..0: CFNumber type
372 static struct __CFNumber __kCFNumberNaN
= {
373 INIT_CFRUNTIME_BASE(), 0ULL
375 const CFNumberRef kCFNumberNaN
= &__kCFNumberNaN
;
377 static struct __CFNumber __kCFNumberNegativeInfinity
= {
378 INIT_CFRUNTIME_BASE(), 0ULL
380 const CFNumberRef kCFNumberNegativeInfinity
= &__kCFNumberNegativeInfinity
;
382 static struct __CFNumber __kCFNumberPositiveInfinity
= {
383 INIT_CFRUNTIME_BASE(), 0ULL
385 const CFNumberRef kCFNumberPositiveInfinity
= &__kCFNumberPositiveInfinity
;
387 static const struct {
388 uint16_t canonicalType
:5; // canonical fixed-width type
389 uint16_t floatBit
:1; // is float
390 uint16_t storageBit
:1; // storage size (0: (float ? 4 : 8), 1: (float ? 8 : 16) bits)
391 uint16_t lgByteSize
:3; // base-2 log byte size of public type
393 } __CFNumberTypeTable
[] = {
394 /* 0 */ {0, 0, 0, 0},
396 /* kCFNumberSInt8Type */ {kCFNumberSInt8Type
, 0, 0, 0, 0},
397 /* kCFNumberSInt16Type */ {kCFNumberSInt16Type
, 0, 0, 1, 0},
398 /* kCFNumberSInt32Type */ {kCFNumberSInt32Type
, 0, 0, 2, 0},
399 /* kCFNumberSInt64Type */ {kCFNumberSInt64Type
, 0, 0, 3, 0},
400 /* kCFNumberFloat32Type */ {kCFNumberFloat32Type
, 1, 0, 2, 0},
401 /* kCFNumberFloat64Type */ {kCFNumberFloat64Type
, 1, 1, 3, 0},
403 /* kCFNumberCharType */ {kCFNumberSInt8Type
, 0, 0, 0, 0},
404 /* kCFNumberShortType */ {kCFNumberSInt16Type
, 0, 0, 1, 0},
405 /* kCFNumberIntType */ {kCFNumberSInt32Type
, 0, 0, 2, 0},
407 /* kCFNumberLongType */ {kCFNumberSInt64Type
, 0, 0, 3, 0},
409 /* kCFNumberLongType */ {kCFNumberSInt32Type
, 0, 0, 2, 0},
411 /* kCFNumberLongLongType */ {kCFNumberSInt64Type
, 0, 0, 3, 0},
412 /* kCFNumberFloatType */ {kCFNumberFloat32Type
, 1, 0, 2, 0},
413 /* kCFNumberDoubleType */ {kCFNumberFloat64Type
, 1, 1, 3, 0},
416 /* kCFNumberCFIndexType */ {kCFNumberSInt64Type
, 0, 0, 3, 0},
417 /* kCFNumberNSIntegerType */ {kCFNumberSInt64Type
, 0, 0, 3, 0},
418 /* kCFNumberCGFloatType */ {kCFNumberFloat64Type
, 1, 1, 3, 0},
420 /* kCFNumberCFIndexType */ {kCFNumberSInt32Type
, 0, 0, 2, 0},
421 /* kCFNumberNSIntegerType */ {kCFNumberSInt32Type
, 0, 0, 2, 0},
422 /* kCFNumberCGFloatType */ {kCFNumberFloat32Type
, 1, 0, 2, 0},
425 /* kCFNumberSInt128Type */ {kCFNumberSInt128Type
, 0, 1, 4, 0},
428 #define CF_IS_TAGGED_INT(OBJ) (CF_TAGGED_OBJ_TYPE(OBJ) == kCFTaggedObjectID_Integer)
430 CF_INLINE CFNumberType
__CFNumberGetType(CFNumberRef num
) {
431 if (CF_IS_TAGGED_INT(num
)) {
432 uintptr_t type_bits
= ((uintptr_t)num
>> 6) & 0x3; // top 2 bits of low byte
433 const CFNumberType canonical_types
[4] = {kCFNumberSInt8Type
, kCFNumberSInt16Type
, kCFNumberSInt32Type
, kCFNumberSInt64Type
};
434 return canonical_types
[type_bits
];
436 return __CFBitfieldGetValue(num
->_base
._cfinfo
[CF_INFO_BITS
], 4, 0);
439 #define CVT(SRC_TYPE, DST_TYPE, DST_MIN, DST_MAX) do { \
440 SRC_TYPE sv; memmove(&sv, data, sizeof(SRC_TYPE)); \
441 DST_TYPE dv = (sv < DST_MIN) ? (DST_TYPE)DST_MIN : (DST_TYPE)(((DST_MAX < sv) ? DST_MAX : sv)); \
442 memmove(valuePtr, &dv, sizeof(DST_TYPE)); \
443 SRC_TYPE vv = (SRC_TYPE)dv; return (vv == sv); \
446 #define CVT128ToInt(SRC_TYPE, DST_TYPE, DST_MIN, DST_MAX) do { \
447 SRC_TYPE sv; memmove(&sv, data, sizeof(SRC_TYPE)); \
448 DST_TYPE dv; Boolean noLoss = false; \
449 if (0 < sv.high || (0 == sv.high && (int64_t)DST_MAX < sv.low)) { \
451 } else if (sv.high < -1 || (-1 == sv.high && sv.low < (int64_t)DST_MIN)) { \
454 dv = (DST_TYPE)sv.low; \
457 memmove(valuePtr, &dv, sizeof(DST_TYPE)); \
461 // returns false if the output value is not the same as the number's value, which
462 // can occur due to accuracy loss and the value not being within the target range
463 static Boolean
__CFNumberGetValue(CFNumberRef number
, CFNumberType type
, void *valuePtr
) {
464 type
= __CFNumberTypeTable
[type
].canonicalType
;
465 CFNumberType ntype
= __CFNumberGetType(number
);
466 const void *data
= &(number
->_pad
);
467 intptr_t taggedInteger
;
468 if (CF_IS_TAGGED_INT(number
)) {
469 taggedInteger
= (intptr_t)number
;
470 taggedInteger
= taggedInteger
>> 8;
471 data
= &taggedInteger
;
474 case kCFNumberSInt8Type
:
475 if (__CFNumberTypeTable
[ntype
].floatBit
) {
476 if (0 == __CFNumberTypeTable
[ntype
].storageBit
) {
477 CVT(Float32
, int8_t, INT8_MIN
, INT8_MAX
);
479 CVT(Float64
, int8_t, INT8_MIN
, INT8_MAX
);
482 if (0 == __CFNumberTypeTable
[ntype
].storageBit
) {
483 CVT(int64_t, int8_t, INT8_MIN
, INT8_MAX
);
485 CVT128ToInt(CFSInt128Struct
, int8_t, INT8_MIN
, INT8_MAX
);
489 case kCFNumberSInt16Type
:
490 if (__CFNumberTypeTable
[ntype
].floatBit
) {
491 if (0 == __CFNumberTypeTable
[ntype
].storageBit
) {
492 CVT(Float32
, int16_t, INT16_MIN
, INT16_MAX
);
494 CVT(Float64
, int16_t, INT16_MIN
, INT16_MAX
);
497 if (0 == __CFNumberTypeTable
[ntype
].storageBit
) {
498 CVT(int64_t, int16_t, INT16_MIN
, INT16_MAX
);
500 CVT128ToInt(CFSInt128Struct
, int16_t, INT16_MIN
, INT16_MAX
);
504 case kCFNumberSInt32Type
:
505 if (__CFNumberTypeTable
[ntype
].floatBit
) {
506 if (0 == __CFNumberTypeTable
[ntype
].storageBit
) {
507 CVT(Float32
, int32_t, INT32_MIN
, INT32_MAX
);
509 CVT(Float64
, int32_t, INT32_MIN
, INT32_MAX
);
512 if (0 == __CFNumberTypeTable
[ntype
].storageBit
) {
513 CVT(int64_t, int32_t, INT32_MIN
, INT32_MAX
);
515 CVT128ToInt(CFSInt128Struct
, int32_t, INT32_MIN
, INT32_MAX
);
519 case kCFNumberSInt64Type
:
520 if (__CFNumberTypeTable
[ntype
].floatBit
) {
521 if (0 == __CFNumberTypeTable
[ntype
].storageBit
) {
522 CVT(Float32
, int64_t, INT64_MIN
, INT64_MAX
);
524 CVT(Float64
, int64_t, INT64_MIN
, INT64_MAX
);
527 if (0 == __CFNumberTypeTable
[ntype
].storageBit
) {
528 memmove(valuePtr
, data
, 8);
530 CVT128ToInt(CFSInt128Struct
, int64_t, INT64_MIN
, INT64_MAX
);
534 case kCFNumberSInt128Type
:
535 if (__CFNumberTypeTable
[ntype
].floatBit
) {
536 if (0 == __CFNumberTypeTable
[ntype
].storageBit
) {
538 memmove(&f
, data
, 4);
541 cvtFloat64ToSInt128(&i
, &d
);
542 memmove(valuePtr
, &i
, 16);
544 cvtSInt128ToFloat64(&d2
, &i
);
545 Float32 f2
= (Float32
)d2
;
549 memmove(&d
, data
, 8);
551 cvtFloat64ToSInt128(&i
, &d
);
552 memmove(valuePtr
, &i
, 16);
554 cvtSInt128ToFloat64(&d2
, &i
);
558 if (0 == __CFNumberTypeTable
[ntype
].storageBit
) {
560 memmove(&j
, data
, 8);
563 i
.high
= (j
< 0) ? -1LL : 0LL;
564 memmove(valuePtr
, &i
, 16);
566 memmove(valuePtr
, data
, 16);
570 case kCFNumberFloat32Type
:
571 if (__CFNumberTypeTable
[ntype
].floatBit
) {
572 if (0 == __CFNumberTypeTable
[ntype
].storageBit
) {
573 memmove(valuePtr
, data
, 4);
576 memmove(&d
, data
, 8);
578 uint32_t l
= 0x7fc00000;
579 memmove(valuePtr
, &l
, 4);
581 } else if (isinf(d
)) {
582 uint32_t l
= 0x7f800000;
583 if (d
< 0.0) l
+= 0x80000000UL
;
584 memmove(valuePtr
, &l
, 4);
587 CVT(Float64
, Float32
, -FLT_MAX
, FLT_MAX
);
590 if (0 == __CFNumberTypeTable
[ntype
].storageBit
) {
591 CVT(int64_t, Float32
, -FLT_MAX
, FLT_MAX
);
594 memmove(&i
, data
, 16);
596 cvtSInt128ToFloat64(&d
, &i
);
597 Float32 f
= (Float32
)d
;
598 memmove(valuePtr
, &f
, 4);
601 cvtFloat64ToSInt128(&i2
, &d
);
602 return cmp128(&i2
, &i
) == kCFCompareEqualTo
;
606 case kCFNumberFloat64Type
:
607 if (__CFNumberTypeTable
[ntype
].floatBit
) {
608 if (0 == __CFNumberTypeTable
[ntype
].storageBit
) {
610 memmove(&f
, data
, 4);
612 uint64_t l
= BITSFORDOUBLENAN
;
613 memmove(valuePtr
, &l
, 8);
615 } else if (isinf(f
)) {
616 uint64_t l
= BITSFORDOUBLEPOSINF
;
617 if (f
< 0.0) l
+= 0x8000000000000000ULL
;
618 memmove(valuePtr
, &l
, 8);
621 CVT(Float32
, Float64
, -DBL_MAX
, DBL_MAX
);
623 memmove(valuePtr
, data
, 8);
626 if (0 == __CFNumberTypeTable
[ntype
].storageBit
) {
627 CVT(int64_t, Float64
, -DBL_MAX
, DBL_MAX
);
630 memmove(&i
, data
, 16);
632 cvtSInt128ToFloat64(&d
, &i
);
633 memmove(valuePtr
, &d
, 8);
635 cvtFloat64ToSInt128(&i2
, &d
);
636 return cmp128(&i2
, &i
) == kCFCompareEqualTo
;
644 #define CVT_COMPAT(SRC_TYPE, DST_TYPE, FT) do { \
645 SRC_TYPE sv; memmove(&sv, data, sizeof(SRC_TYPE)); \
646 DST_TYPE dv = (DST_TYPE)(sv); \
647 memmove(valuePtr, &dv, sizeof(DST_TYPE)); \
648 SRC_TYPE vv = (SRC_TYPE)dv; return (FT) || (vv == sv); \
651 #define CVT128ToInt_COMPAT(SRC_TYPE, DST_TYPE) do { \
652 SRC_TYPE sv; memmove(&sv, data, sizeof(SRC_TYPE)); \
653 DST_TYPE dv; dv = (DST_TYPE)sv.low; \
654 memmove(valuePtr, &dv, sizeof(DST_TYPE)); \
655 uint64_t vv = (uint64_t)dv; return (vv == sv.low); \
658 // this has the old cast-style behavior
659 static Boolean
__CFNumberGetValueCompat(CFNumberRef number
, CFNumberType type
, void *valuePtr
) {
660 type
= __CFNumberTypeTable
[type
].canonicalType
;
661 CFNumberType ntype
= __CFNumberGetType(number
);
662 const void *data
= &(number
->_pad
);
663 intptr_t taggedInteger
;
664 if (CF_IS_TAGGED_INT(number
)) {
665 taggedInteger
= (intptr_t)number
;
666 taggedInteger
= taggedInteger
>> 8;
667 data
= &taggedInteger
;
670 case kCFNumberSInt8Type
:
671 if (__CFNumberTypeTable
[ntype
].floatBit
) {
672 if (0 == __CFNumberTypeTable
[ntype
].storageBit
) {
673 CVT_COMPAT(Float32
, int8_t, 0);
675 CVT_COMPAT(Float64
, int8_t, 0);
678 if (0 == __CFNumberTypeTable
[ntype
].storageBit
) {
679 // Leopard's implemenation of this always returned true. We should only return true when the conversion is lossless. However, there are some clients who use CFNumber with small unsigned values disguised as signed values. Since there is no CFNumber API yet for unsigned values, we need to accomodate those clients for now. <rdar://problem/6471866>
680 // This accomodation should be removed if CFNumber ever provides API for unsigned values. <rdar://problem/6473890>
681 int64_t sv
; memmove(&sv
, data
, sizeof(int64_t));
682 int8_t dv
= (int8_t)(sv
);
683 memmove(valuePtr
, &dv
, sizeof(int8_t));
684 int64_t vv
= (int64_t)dv
; return !_CFExecutableLinkedOnOrAfter(CFSystemVersionSnowLeopard
) || ((sv
>> 8LL) == 0LL) || (vv
== sv
);
686 CVT128ToInt_COMPAT(CFSInt128Struct
, int8_t);
690 case kCFNumberSInt16Type
:
691 if (__CFNumberTypeTable
[ntype
].floatBit
) {
692 if (0 == __CFNumberTypeTable
[ntype
].storageBit
) {
693 CVT_COMPAT(Float32
, int16_t, 0);
695 CVT_COMPAT(Float64
, int16_t, 0);
698 if (0 == __CFNumberTypeTable
[ntype
].storageBit
) {
699 // Leopard's implemenation of this always returned true. We should only return true when the conversion is lossless. However, there are some clients who use CFNumber with small unsigned values disguised as signed values. Since there is no CFNumber API yet for unsigned values, we need to accomodate those clients for now. <rdar://problem/6471866>
700 // This accomodation should be removed if CFNumber ever provides API for unsigned values. <rdar://problem/6473890>
701 int64_t sv
; memmove(&sv
, data
, sizeof(int64_t));
702 int16_t dv
= (int16_t)(sv
);
703 memmove(valuePtr
, &dv
, sizeof(int16_t));
704 int64_t vv
= (int64_t)dv
; return !_CFExecutableLinkedOnOrAfter(CFSystemVersionSnowLeopard
) || ((sv
>> 16LL) == 0LL) || (vv
== sv
);
706 CVT128ToInt_COMPAT(CFSInt128Struct
, int16_t);
710 case kCFNumberSInt32Type
:
711 if (__CFNumberTypeTable
[ntype
].floatBit
) {
712 if (0 == __CFNumberTypeTable
[ntype
].storageBit
) {
713 CVT_COMPAT(Float32
, int32_t, 0);
715 CVT_COMPAT(Float64
, int32_t, 0);
718 if (0 == __CFNumberTypeTable
[ntype
].storageBit
) {
719 CVT_COMPAT(int64_t, int32_t, 0);
721 CVT128ToInt_COMPAT(CFSInt128Struct
, int32_t);
725 case kCFNumberSInt64Type
:
726 if (__CFNumberTypeTable
[ntype
].floatBit
) {
727 if (0 == __CFNumberTypeTable
[ntype
].storageBit
) {
728 CVT_COMPAT(Float32
, int64_t, 0);
730 CVT_COMPAT(Float64
, int64_t, 0);
733 if (0 == __CFNumberTypeTable
[ntype
].storageBit
) {
734 CVT_COMPAT(int64_t, int64_t, 0);
736 CVT128ToInt_COMPAT(CFSInt128Struct
, int64_t);
740 case kCFNumberSInt128Type
:
741 if (__CFNumberTypeTable
[ntype
].floatBit
) {
742 if (0 == __CFNumberTypeTable
[ntype
].storageBit
) {
744 memmove(&f
, data
, 4);
747 cvtFloat64ToSInt128(&i
, &d
);
748 memmove(valuePtr
, &i
, 16);
750 cvtSInt128ToFloat64(&d2
, &i
);
751 Float32 f2
= (Float32
)d2
;
755 memmove(&d
, data
, 8);
757 cvtFloat64ToSInt128(&i
, &d
);
758 memmove(valuePtr
, &i
, 16);
760 cvtSInt128ToFloat64(&d2
, &i
);
764 if (0 == __CFNumberTypeTable
[ntype
].storageBit
) {
766 memmove(&j
, data
, 8);
769 i
.high
= (j
< 0) ? -1LL : 0LL;
770 memmove(valuePtr
, &i
, 16);
772 memmove(valuePtr
, data
, 16);
776 case kCFNumberFloat32Type
:
777 if (__CFNumberTypeTable
[ntype
].floatBit
) {
778 if (0 == __CFNumberTypeTable
[ntype
].storageBit
) {
779 memmove(valuePtr
, data
, 4);
781 CVT_COMPAT(Float64
, Float32
, 0);
784 if (0 == __CFNumberTypeTable
[ntype
].storageBit
) {
785 CVT_COMPAT(int64_t, Float32
, 0);
788 memmove(&i
, data
, 16);
790 cvtSInt128ToFloat64(&d
, &i
);
791 Float32 f
= (Float32
)d
;
792 memmove(valuePtr
, &f
, 4);
795 cvtFloat64ToSInt128(&i2
, &d
);
796 return cmp128(&i2
, &i
) == kCFCompareEqualTo
;
800 case kCFNumberFloat64Type
:
801 if (__CFNumberTypeTable
[ntype
].floatBit
) {
802 if (0 == __CFNumberTypeTable
[ntype
].storageBit
) {
803 CVT_COMPAT(Float32
, Float64
, 0);
805 memmove(valuePtr
, data
, 8);
808 if (0 == __CFNumberTypeTable
[ntype
].storageBit
) {
809 CVT_COMPAT(int64_t, Float64
, 0);
812 memmove(&i
, data
, 16);
814 cvtSInt128ToFloat64(&d
, &i
);
815 memmove(valuePtr
, &d
, 8);
817 cvtFloat64ToSInt128(&i2
, &d
);
818 return cmp128(&i2
, &i
) == kCFCompareEqualTo
;
827 static void FAIL(void) {}
830 static CFStringRef
__CFNumberCopyDescription(CFTypeRef cf
) {
831 CFNumberRef number
= (CFNumberRef
)cf
;
832 CFNumberType type
= __CFNumberGetType(number
);
833 CFMutableStringRef mstr
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
834 CFStringAppendFormat(mstr
, NULL
, CFSTR("<CFNumber %p [%p]>{value = "), cf
, CFGetAllocator(cf
));
835 if (__CFNumberTypeTable
[type
].floatBit
) {
837 __CFNumberGetValue(number
, kCFNumberFloat64Type
, &d
);
839 CFStringAppend(mstr
, CFSTR("nan"));
840 } else if (isinf(d
)) {
841 CFStringAppend(mstr
, (0.0 < d
) ? CFSTR("+infinity") : CFSTR("-infinity"));
842 } else if (0.0 == d
) {
843 CFStringAppend(mstr
, (copysign(1.0, d
) < 0.0) ? CFSTR("-0.0") : CFSTR("+0.0"));
845 CFStringAppendFormat(mstr
, NULL
, CFSTR("%+.*f"), (__CFNumberTypeTable
[type
].storageBit
? 20 : 10), d
);
847 const char *typeName
= "unknown float";
849 case kCFNumberFloat32Type
: typeName
= "kCFNumberFloat32Type"; break;
850 case kCFNumberFloat64Type
: typeName
= "kCFNumberFloat64Type"; break;
852 CFStringAppendFormat(mstr
, NULL
, CFSTR(", type = %s}"), typeName
);
855 __CFNumberGetValue(number
, kCFNumberSInt128Type
, &i
);
857 emit128(buffer
, &i
, true);
858 const char *typeName
= "unknown integer";
860 case kCFNumberSInt8Type
: typeName
= "kCFNumberSInt8Type"; break;
861 case kCFNumberSInt16Type
: typeName
= "kCFNumberSInt16Type"; break;
862 case kCFNumberSInt32Type
: typeName
= "kCFNumberSInt32Type"; break;
863 case kCFNumberSInt64Type
: typeName
= "kCFNumberSInt64Type"; break;
864 case kCFNumberSInt128Type
: typeName
= "kCFNumberSInt128Type"; break;
866 CFStringAppendFormat(mstr
, NULL
, CFSTR("%s, type = %s}"), buffer
, typeName
);
869 if (! number
->__old__
) {
871 printf("*** Test skipped in __CFNumberCopyDescription for number %p\n", cf
);
873 CFStringRef test
= __CFNumberCopyDescription_old(number
->__old__
);
874 if (!CFEqual(test
, mstr
)) {
875 CFLog(kCFLogLevelWarning
, CFSTR("*** TEST FAIL in __CFNumberCopyDescription: '%@' '%@'"), test
, mstr
); FAIL();
882 // This function separated out from __CFNumberCopyFormattingDescription() so the plist creation can use it as well.
884 static CFStringRef
__CFNumberCreateFormattingDescriptionAsFloat64(CFAllocatorRef allocator
, CFTypeRef cf
) {
886 CFNumberGetValue((CFNumberRef
)cf
, kCFNumberFloat64Type
, &d
);
888 return (CFStringRef
)CFRetain(CFSTR("nan"));
891 return (CFStringRef
)CFRetain((0.0 < d
) ? CFSTR("+infinity") : CFSTR("-infinity"));
894 return (CFStringRef
)CFRetain(CFSTR("0.0"));
896 // if %g is used here, need to use DBL_DIG + 2 on Mac OS X, but %f needs +1
897 return CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%.*g"), DBL_DIG
+ 2, d
);
900 __private_extern__ CFStringRef
__CFNumberCopyFormattingDescriptionAsFloat64(CFTypeRef cf
) {
901 CFStringRef result
= __CFNumberCreateFormattingDescriptionAsFloat64(kCFAllocatorSystemDefault
, cf
);
903 CFNumberRef number
= (CFNumberRef
)cf
;
904 if (! number
->__old__
) {
905 printf("*** Test skipped in __CFNumberCopyFormattingDescriptionAsFloat64 for number %p\n", cf
);
907 CFStringRef test
= __CFNumberCopyFormattingDescriptionAsFloat64_old(number
->__old__
);
908 if (!CFEqual(test
, result
)) {
909 CFLog(kCFLogLevelWarning
, CFSTR("*** TEST FAIL in __CFNumberCopyFormattingDescriptionAsFloat64: '%@' '%@'"), test
, result
); FAIL();
916 __private_extern__ CFStringRef
__CFNumberCreateFormattingDescription(CFAllocatorRef allocator
, CFTypeRef cf
, CFDictionaryRef formatOptions
) {
917 CFNumberRef number
= (CFNumberRef
)cf
;
918 CFNumberType type
= __CFNumberGetType(number
);
919 if (__CFNumberTypeTable
[type
].floatBit
) {
920 return __CFNumberCreateFormattingDescriptionAsFloat64(allocator
, number
);
923 __CFNumberGetValue(number
, kCFNumberSInt128Type
, &i
);
925 emit128(buffer
, &i
, false);
926 return CFStringCreateWithFormat(allocator
, NULL
, CFSTR("%s"), buffer
);
929 static CFStringRef
__CFNumberCopyFormattingDescription_new(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
930 CFNumberRef number
= (CFNumberRef
)cf
;
931 CFNumberType type
= __CFNumberGetType(number
);
932 if (__CFNumberTypeTable
[type
].floatBit
) {
933 return __CFNumberCopyFormattingDescriptionAsFloat64(number
);
936 __CFNumberGetValue(number
, kCFNumberSInt128Type
, &i
);
938 emit128(buffer
, &i
, false);
939 return CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("%s"), buffer
);
942 __private_extern__ CFStringRef
__CFNumberCopyFormattingDescription(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
943 CFStringRef result
= __CFNumberCopyFormattingDescription_new(cf
, formatOptions
);
945 CFNumberRef number
= (CFNumberRef
)cf
;
946 if (! number
->__old__
) {
947 printf("*** Test skipped in __CFNumberCopyFormattingDescription for number %p\n", cf
);
949 CFStringRef test
= __CFNumberCopyFormattingDescription_old(number
->__old__
, formatOptions
);
950 if (!CFEqual(test
, result
)) {
951 CFLog(kCFLogLevelWarning
, CFSTR("*** TEST FAIL in __CFNumberCopyFormattingDescription: '%@' '%@'"), test
, result
); FAIL();
959 static Boolean
__CFNumberEqual(CFTypeRef cf1
, CFTypeRef cf2
) {
960 Boolean b
= CFNumberCompare((CFNumberRef
)cf1
, (CFNumberRef
)cf2
, 0) == kCFCompareEqualTo
;
962 CFNumberRef number1
= (CFNumberRef
)cf1
;
963 CFNumberRef number2
= (CFNumberRef
)cf2
;
964 if (! number1
->__old__
|| !number2
->__old__
) {
965 printf("*** Test skipped in __CFNumberEqual for numbers %p %p\n", cf1
, cf2
);
967 Boolean b2
= __CFNumberEqual_old(number1
->__old__
, number2
->__old__
);
969 CFLog(kCFLogLevelWarning
, CFSTR("*** TEST FAIL in __CFNumberEqual: '%d' '%d'"), b2
, b
); FAIL();
976 static CFHashCode
__CFNumberHash(CFTypeRef cf
) {
978 CFNumberRef number
= (CFNumberRef
)cf
;
979 switch (__CFNumberGetType(number
)) {
980 case kCFNumberSInt8Type
:
981 case kCFNumberSInt16Type
:
982 case kCFNumberSInt32Type
: {
984 __CFNumberGetValue(number
, kCFNumberSInt32Type
, &i
);
990 __CFNumberGetValue(number
, kCFNumberFloat64Type
, &d
);
991 h
= _CFHashDouble((double)d
);
996 CFNumberRef number1
= (CFNumberRef
)cf
;
997 if (! number1
->__old__
) {
998 printf("*** Test skipped in __CFNumberHash for number %p\n", cf
);
1000 CFHashCode h2
= __CFNumberHash_old(number1
->__old__
);
1002 CFLog(kCFLogLevelWarning
, CFSTR("*** TEST FAIL in __CFNumberHash: '%d' '%d'"), h2
, h
); FAIL();
1009 static CFTypeID __kCFNumberTypeID
= _kCFRuntimeNotATypeID
;
1010 static void *__CFTaggedNumberClass
= 0;
1013 kCFNumberCachingEnabled
= 0,
1014 kCFNumberCachingDisabled
= 1,
1015 kCFNumberCachingFullyDisabled
= 2
1017 static char __CFNumberCaching
= kCFNumberCachingEnabled
;
1019 static const CFRuntimeClass __CFNumberClass
= {
1027 __CFNumberCopyFormattingDescription
,
1028 __CFNumberCopyDescription
1032 __private_extern__
void __CFNumberInitialize(void) {
1033 __kCFNumberTypeID
= _CFRuntimeRegisterClass(&__CFNumberClass
);
1035 _CFRuntimeSetInstanceTypeID(&__kCFNumberNaN
, __kCFNumberTypeID
);
1036 __kCFNumberNaN
._base
._cfisa
= __CFISAForTypeID(__kCFNumberTypeID
);
1037 __CFBitfieldSetValue(__kCFNumberNaN
._base
._cfinfo
[CF_INFO_BITS
], 4, 0, kCFNumberFloat64Type
);
1038 __kCFNumberNaN
._pad
= BITSFORDOUBLENAN
;
1040 _CFRuntimeSetInstanceTypeID(& __kCFNumberNegativeInfinity
, __kCFNumberTypeID
);
1041 __kCFNumberNegativeInfinity
._base
._cfisa
= __CFISAForTypeID(__kCFNumberTypeID
);
1042 __CFBitfieldSetValue(__kCFNumberNegativeInfinity
._base
._cfinfo
[CF_INFO_BITS
], 4, 0, kCFNumberFloat64Type
);
1043 __kCFNumberNegativeInfinity
._pad
= BITSFORDOUBLENEGINF
;
1045 _CFRuntimeSetInstanceTypeID(& __kCFNumberPositiveInfinity
, __kCFNumberTypeID
);
1046 __kCFNumberPositiveInfinity
._base
._cfisa
= __CFISAForTypeID(__kCFNumberTypeID
);
1047 __CFBitfieldSetValue(__kCFNumberPositiveInfinity
._base
._cfinfo
[CF_INFO_BITS
], 4, 0, kCFNumberFloat64Type
);
1048 __kCFNumberPositiveInfinity
._pad
= BITSFORDOUBLEPOSINF
;
1051 const char *caching
= __CFgetenv("CFNumberDisableCache"); // "all" to disable caching and tagging; anything else to disable caching; nothing to leave both enabled
1052 if (caching
) __CFNumberCaching
= (!strcmp(caching
, "all")) ? kCFNumberCachingFullyDisabled
: kCFNumberCachingDisabled
; // initial state above is kCFNumberCachingEnabled
1055 CFTypeID
CFNumberGetTypeID(void) {
1056 return __kCFNumberTypeID
;
1059 #define MinCachedInt (-1)
1060 #define MaxCachedInt (12)
1061 #define NotToBeCached (MinCachedInt - 1)
1062 static CFNumberRef __CFNumberCache
[MaxCachedInt
- MinCachedInt
+ 1] = {NULL
}; // Storing CFNumberRefs for range MinCachedInt..MaxCachedInt
1064 CFNumberRef
CFNumberCreate(CFAllocatorRef allocator
, CFNumberType type
, const void *valuePtr
) {
1065 __CFAssertIsValidNumberType(type
);
1066 //printf("+ [%p] CFNumberCreate(%p, %d, %p)\n", pthread_self(), allocator, type, valuePtr);
1068 if (!allocator
) allocator
= __CFGetDefaultAllocator();
1070 if (__CFTaggedNumberClass
&& _CFAllocatorIsSystemDefault(allocator
) && (__CFNumberCaching
!= kCFNumberCachingFullyDisabled
)) {
1071 switch (__CFNumberTypeTable
[type
].canonicalType
) { // canonicalized client-desired type
1072 case kCFNumberSInt8Type
: {
1073 int8_t value
= *(int8_t *)valuePtr
;
1074 return (CFNumberRef
)((uintptr_t)((intptr_t)value
<< 8) | (0 << 6) | kCFTaggedObjectID_Integer
);
1076 case kCFNumberSInt16Type
: {
1077 int16_t value
= *(int16_t *)valuePtr
;
1078 return (CFNumberRef
)((uintptr_t)((intptr_t)value
<< 8) | (1 << 6) | kCFTaggedObjectID_Integer
);
1080 case kCFNumberSInt32Type
: {
1081 int32_t value
= *(int32_t *)valuePtr
;
1083 // We don't bother allowing the min 24-bit integer -2^23 to also be fast-pathed;
1084 // tell anybody that complains about that to go ... hang.
1085 int32_t limit
= (1L << 23);
1086 if (value
<= -limit
|| limit
<= value
) break;
1088 uintptr_t ptr_val
= ((uintptr_t)((intptr_t)value
<< 8) | (2 << 6) | kCFTaggedObjectID_Integer
);
1089 return (CFNumberRef
)ptr_val
;
1091 case kCFNumberSInt64Type
: {
1092 int64_t value
= *(int64_t *)valuePtr
;
1094 // We don't bother allowing the min 56-bit integer -2^55 to also be fast-pathed;
1095 // tell anybody that complains about that to go ... hang.
1096 int64_t limit
= (1L << 55);
1097 if (value
<= -limit
|| limit
<= value
) break;
1099 // We don't bother allowing the min 24-bit integer -2^23 to also be fast-pathed;
1100 // tell anybody that complains about that to go ... hang.
1101 int64_t limit
= (1L << 23);
1102 if (value
<= -limit
|| limit
<= value
) break;
1104 uintptr_t ptr_val
= ((uintptr_t)((intptr_t)value
<< 8) | (3 << 6) | kCFTaggedObjectID_Integer
);
1105 return (CFNumberRef
)ptr_val
;
1110 // Look for cases where we can return a cached instance.
1111 // We only use cached objects if the allocator is the system
1112 // default allocator, except for the special floating point
1113 // constant objects, where we return the cached object
1114 // regardless of allocator, since that is what has always
1115 // been done (and now must for compatibility).
1116 int64_t valToBeCached
= NotToBeCached
;
1118 if (__CFNumberTypeTable
[type
].floatBit
) {
1119 CFNumberRef cached
= NULL
;
1120 if (0 == __CFNumberTypeTable
[type
].storageBit
) {
1121 Float32 f
= *(Float32
*)valuePtr
;
1122 if (isnan(f
)) cached
= kCFNumberNaN
;
1123 if (isinf(f
)) cached
= (f
< 0.0) ? kCFNumberNegativeInfinity
: kCFNumberPositiveInfinity
;
1125 Float64 d
= *(Float64
*)valuePtr
;
1126 if (isnan(d
)) cached
= kCFNumberNaN
;
1127 if (isinf(d
)) cached
= (d
< 0.0) ? kCFNumberNegativeInfinity
: kCFNumberPositiveInfinity
;
1129 if (cached
) return (CFNumberRef
)CFRetain(cached
);
1130 } else if (_CFAllocatorIsSystemDefault(allocator
) && (__CFNumberCaching
== kCFNumberCachingEnabled
)) {
1131 switch (__CFNumberTypeTable
[type
].canonicalType
) {
1132 case kCFNumberSInt8Type
: {int8_t val
= *(int8_t *)valuePtr
; if (MinCachedInt
<= val
&& val
<= MaxCachedInt
) valToBeCached
= (int64_t)val
; break;}
1133 case kCFNumberSInt16Type
: {int16_t val
= *(int16_t *)valuePtr
; if (MinCachedInt
<= val
&& val
<= MaxCachedInt
) valToBeCached
= (int64_t)val
; break;}
1134 case kCFNumberSInt32Type
: {int32_t val
= *(int32_t *)valuePtr
; if (MinCachedInt
<= val
&& val
<= MaxCachedInt
) valToBeCached
= (int64_t)val
; break;}
1135 case kCFNumberSInt64Type
: {int64_t val
= *(int64_t *)valuePtr
; if (MinCachedInt
<= val
&& val
<= MaxCachedInt
) valToBeCached
= (int64_t)val
; break;}
1137 if (NotToBeCached
!= valToBeCached
) {
1138 CFNumberRef cached
= __CFNumberCache
[valToBeCached
- MinCachedInt
]; // Atomic to access the value in the cache
1139 if (NULL
!= cached
) return (CFNumberRef
)CFRetain(cached
);
1143 CFIndex size
= 8 + ((!__CFNumberTypeTable
[type
].floatBit
&& __CFNumberTypeTable
[type
].storageBit
) ? 8 : 0);
1145 size
+= 2 * sizeof(void *);
1147 CFNumberRef result
= (CFNumberRef
)_CFRuntimeCreateInstance(allocator
, __kCFNumberTypeID
, size
, NULL
);
1148 if (NULL
== result
) {
1151 __CFBitfieldSetValue(((struct __CFNumber
*)result
)->_base
._cfinfo
[CF_INFO_BITS
], 4, 0, (uint8_t)__CFNumberTypeTable
[type
].canonicalType
);
1154 ((struct __CFNumber
*)result
)->__old__
= CFNumberCreate_old(allocator
, type
, valuePtr
);
1155 CFLog(kCFLogLevelWarning
, CFSTR("+++ Create old number '%@'"), __CFNumberCopyDescription_old(result
->__old__
));
1159 // for a value to be cached, we already have the value handy
1160 if (NotToBeCached
!= valToBeCached
) {
1161 memmove((void *)&result
->_pad
, &valToBeCached
, 8);
1162 // Put this in the cache unless the cache is already filled (by another thread). If we do put it in the cache, retain it an extra time for the cache.
1163 // Note that we don't bother freeing this result and returning the cached value if the cache was filled, since cached CFNumbers are not guaranteed unique.
1164 // Barrier assures that the number that is placed in the cache is properly formed.
1165 CFNumberType origType
= __CFNumberGetType(result
);
1166 // Force all cached numbers to have the same type, so that the type does not
1167 // depend on the order and original type in/with which the numbers are created.
1168 // Forcing the type AFTER it was cached would cause a race condition with other
1169 // threads pulling the number object out of the cache and using it.
1170 __CFBitfieldSetValue(((struct __CFNumber
*)result
)->_base
._cfinfo
[CF_INFO_BITS
], 4, 0, (uint8_t)kCFNumberSInt32Type
);
1171 if (OSAtomicCompareAndSwapPtrBarrier(NULL
, (void *)result
, (void *volatile *)&__CFNumberCache
[valToBeCached
- MinCachedInt
])) {
1174 // Did not cache the number object, put original type back.
1175 __CFBitfieldSetValue(((struct __CFNumber
*)result
)->_base
._cfinfo
[CF_INFO_BITS
], 4, 0, (uint8_t)origType
);
1181 switch (__CFNumberTypeTable
[type
].canonicalType
) {
1182 case kCFNumberSInt8Type
: value
= (uint64_t)(int64_t)*(int8_t *)valuePtr
; goto smallVal
;
1183 case kCFNumberSInt16Type
: value
= (uint64_t)(int64_t)*(int16_t *)valuePtr
; goto smallVal
;
1184 case kCFNumberSInt32Type
: value
= (uint64_t)(int64_t)*(int32_t *)valuePtr
; goto smallVal
;
1185 smallVal
: memmove((void *)&result
->_pad
, &value
, 8); break;
1186 case kCFNumberSInt64Type
: memmove((void *)&result
->_pad
, valuePtr
, 8); break;
1187 case kCFNumberSInt128Type
: memmove((void *)&result
->_pad
, valuePtr
, 16); break;
1188 case kCFNumberFloat32Type
: memmove((void *)&result
->_pad
, valuePtr
, 4); break;
1189 case kCFNumberFloat64Type
: memmove((void *)&result
->_pad
, valuePtr
, 8); break;
1191 //printf(" => %p\n", result);
1195 CFNumberType
CFNumberGetType(CFNumberRef number
) {
1196 //printf("+ [%p] CFNumberGetType(%p)\n", pthread_self(), number);
1197 if (CF_IS_TAGGED_INT(number
)) {
1198 return __CFNumberGetType(number
);
1200 CF_OBJC_FUNCDISPATCHV(__kCFNumberTypeID
, CFNumberType
, (NSNumber
*)number
, _cfNumberType
);
1201 __CFAssertIsNumber(number
);
1202 CFNumberType type
= __CFNumberGetType(number
);
1203 if (kCFNumberSInt128Type
== type
) type
= kCFNumberSInt64Type
; // must hide this type, since it is not public
1204 //printf(" => %d\n", type);
1206 if (! number
->__old__
) {
1207 printf("*** Test skipped in CFNumberGetType for number %p\n", number
);
1209 CFNumberType t2
= CFNumberGetType_old(number
->__old__
);
1211 CFLog(kCFLogLevelWarning
, CFSTR("*** TEST FAIL in CFNumberGetType: '%d' '%d'"), t2
, type
); FAIL();
1218 CF_EXPORT CFNumberType
_CFNumberGetType2(CFNumberRef number
) {
1219 __CFAssertIsNumber(number
);
1220 return __CFNumberGetType(number
);
1223 CFIndex
CFNumberGetByteSize(CFNumberRef number
) {
1224 //printf("+ [%p] CFNumberGetByteSize(%p)\n", pthread_self(), number);
1225 __CFAssertIsNumber(number
);
1226 CFIndex r
= 1 << __CFNumberTypeTable
[CFNumberGetType(number
)].lgByteSize
;
1227 //printf(" => %d\n", r);
1229 if (! number
->__old__
) {
1230 printf("*** Test skipped in CFNumberGetByteSize for number %p\n", number
);
1232 CFIndex r2
= CFNumberGetByteSize_old(number
->__old__
);
1234 CFLog(kCFLogLevelWarning
, CFSTR("*** TEST FAIL in CFNumberGetByteSize: '%d' '%d'"), r2
, r
); FAIL();
1241 Boolean
CFNumberIsFloatType(CFNumberRef number
) {
1242 //printf("+ [%p] CFNumberIsFloatType(%p)\n", pthread_self(), number);
1243 __CFAssertIsNumber(number
);
1244 Boolean r
= __CFNumberTypeTable
[CFNumberGetType(number
)].floatBit
;
1245 //printf(" => %d\n", r);
1247 if (! number
->__old__
) {
1248 printf("*** Test skipped in CFNumberIsFloatType for number %p\n", number
);
1250 Boolean r2
= CFNumberIsFloatType_old(number
->__old__
);
1252 CFLog(kCFLogLevelWarning
, CFSTR("*** TEST FAIL in CFNumberIsFloatType: '%d' '%d'"), r2
, r
); FAIL();
1259 Boolean
CFNumberGetValue(CFNumberRef number
, CFNumberType type
, void *valuePtr
) {
1260 //printf("+ [%p] CFNumberGetValue(%p, %d, %p)\n", pthread_self(), number, type, valuePtr);
1261 if (CF_IS_TAGGED_INT(number
)) {
1262 __CFAssertIsValidNumberType(type
);
1263 uint8_t localMemory
[128];
1264 if (!valuePtr
) valuePtr
= localMemory
;
1265 intptr_t taggedInteger
= (intptr_t)number
;
1266 taggedInteger
= taggedInteger
>> 8;
1267 switch (__CFNumberTypeTable
[type
].canonicalType
) { // canonicalized client-desired type
1268 case kCFNumberSInt8Type
:
1270 if (taggedInteger
< INT8_MIN
) {
1271 *(int8_t *)valuePtr
= INT8_MIN
;
1274 if (INT8_MAX
< taggedInteger
) {
1275 *(int8_t *)valuePtr
= INT8_MAX
;
1279 *(int8_t *)valuePtr
= (int8_t)taggedInteger
;
1281 case kCFNumberSInt16Type
:
1283 if (taggedInteger
< INT16_MIN
) {
1284 *(int16_t *)valuePtr
= INT16_MIN
;
1287 if (INT16_MAX
< taggedInteger
) {
1288 *(int16_t *)valuePtr
= INT16_MAX
;
1292 *(int16_t *)valuePtr
= (int16_t)taggedInteger
;
1294 case kCFNumberSInt32Type
:
1295 *(int32_t *)valuePtr
= (int32_t)taggedInteger
;
1298 case kCFNumberSInt64Type
:
1299 *(int64_t *)valuePtr
= (int64_t)taggedInteger
;
1303 Boolean r
= __CFNumberGetValueCompat(number
, type
, valuePtr
);
1306 CF_OBJC_FUNCDISPATCHV(__kCFNumberTypeID
, Boolean
, (NSNumber
*)number
, _getValue
:(void *)valuePtr forType
:(CFNumberType
)__CFNumberTypeTable
[type
].canonicalType
);
1307 __CFAssertIsNumber(number
);
1308 __CFAssertIsValidNumberType(type
);
1309 uint8_t localMemory
[128];
1310 Boolean r
= __CFNumberGetValueCompat(number
, type
, valuePtr
? valuePtr
: localMemory
);
1311 //printf(" => %d\n", r);
1313 if (! number
->__old__
) {
1314 printf("*** Test skipped in CFNumberGetValue for number %p\n", number
);
1316 uint8_t localMemory2
[128];
1317 Boolean r2
= CFNumberGetValue_old(number
->__old__
, type
, localMemory2
);
1319 CFLog(kCFLogLevelWarning
, CFSTR("*** TEST FAIL 1 in CFNumberGetValue: '%d' '%d'"), r2
, r
); FAIL();
1321 if (0 != memcmp(localMemory2
, valuePtr
, CFNumberGetByteSize(number
))) {
1322 CFLog(kCFLogLevelWarning
, CFSTR("*** TEST FAIL 2 in CFNumberGetValue: BYTES NOT SAME")); FAIL();
1329 static CFComparisonResult
CFNumberCompare_new(CFNumberRef number1
, CFNumberRef number2
, void *context
) {
1330 CF_OBJC_FUNCDISPATCHV(__kCFNumberTypeID
, CFComparisonResult
, (NSNumber
*)number1
, compare
:(NSNumber
*)number2
);
1331 CF_OBJC_FUNCDISPATCHV(__kCFNumberTypeID
, CFComparisonResult
, (NSNumber
*)number2
, _reverseCompare
:(NSNumber
*)number1
);
1332 __CFAssertIsNumber(number1
);
1333 __CFAssertIsNumber(number2
);
1335 CFNumberType type1
= __CFNumberGetType(number1
);
1336 CFNumberType type2
= __CFNumberGetType(number2
);
1337 // Both numbers are integers
1338 if (!__CFNumberTypeTable
[type1
].floatBit
&& !__CFNumberTypeTable
[type2
].floatBit
) {
1339 CFSInt128Struct i1
, i2
;
1340 __CFNumberGetValue(number1
, kCFNumberSInt128Type
, &i1
);
1341 __CFNumberGetValue(number2
, kCFNumberSInt128Type
, &i2
);
1342 return cmp128(&i1
, &i2
);
1344 // Both numbers are floats
1345 if (__CFNumberTypeTable
[type1
].floatBit
&& __CFNumberTypeTable
[type2
].floatBit
) {
1347 __CFNumberGetValue(number1
, kCFNumberFloat64Type
, &d1
);
1348 __CFNumberGetValue(number2
, kCFNumberFloat64Type
, &d2
);
1349 double s1
= copysign(1.0, d1
);
1350 double s2
= copysign(1.0, d2
);
1351 if (isnan(d1
) && isnan(d2
)) return kCFCompareEqualTo
;
1352 if (isnan(d1
)) return (s2
< 0.0) ? kCFCompareGreaterThan
: kCFCompareLessThan
;
1353 if (isnan(d2
)) return (s1
< 0.0) ? kCFCompareLessThan
: kCFCompareGreaterThan
;
1354 // at this point, we know we don't have any NaNs
1355 if (s1
< s2
) return kCFCompareLessThan
;
1356 if (s2
< s1
) return kCFCompareGreaterThan
;
1357 // at this point, we know the signs are the same; do not combine these tests
1358 if (d1
< d2
) return kCFCompareLessThan
;
1359 if (d2
< d1
) return kCFCompareGreaterThan
;
1360 return kCFCompareEqualTo
;
1362 // One float, one integer; swap if necessary so number1 is the float
1363 Boolean swapResult
= false;
1364 if (__CFNumberTypeTable
[type2
].floatBit
) {
1365 CFNumberRef tmp
= number1
;
1370 // At large integer values, the precision of double is quite low
1371 // e.g. all values roughly 2^127 +- 2^73 are represented by 1 double, 2^127.
1372 // If we just used double compare, that would make the 2^73 largest 128-bit
1373 // integers look equal, so we have to use integer comparison when possible.
1375 __CFNumberGetValue(number1
, kCFNumberFloat64Type
, &d1
);
1376 // if the double value is really big, cannot be equal to integer
1377 // nan d1 will not compare true here
1378 if (d1
< FLOAT_NEGATIVE_2_TO_THE_127
) {
1379 return !swapResult
? kCFCompareLessThan
: kCFCompareGreaterThan
;
1381 if (FLOAT_POSITIVE_2_TO_THE_127
<= d1
) {
1382 return !swapResult
? kCFCompareGreaterThan
: kCFCompareLessThan
;
1384 CFSInt128Struct i1
, i2
;
1385 __CFNumberGetValue(number1
, kCFNumberSInt128Type
, &i1
);
1386 __CFNumberGetValue(number2
, kCFNumberSInt128Type
, &i2
);
1387 CFComparisonResult res
= cmp128(&i1
, &i2
);
1388 if (kCFCompareEqualTo
!= res
) {
1389 return !swapResult
? res
: -res
;
1391 // now things are equal, but perhaps due to rounding or nan
1393 if (isNeg128(&i2
)) {
1394 return !swapResult
? kCFCompareGreaterThan
: kCFCompareLessThan
;
1396 // nan compares less than positive 0 too
1397 return !swapResult
? kCFCompareLessThan
: kCFCompareGreaterThan
;
1399 // at this point, we know we don't have NaN
1400 double s1
= copysign(1.0, d1
);
1401 double s2
= isNeg128(&i2
) ? -1.0 : 1.0;
1402 if (s1
< s2
) return !swapResult
? kCFCompareLessThan
: kCFCompareGreaterThan
;
1403 if (s2
< s1
) return !swapResult
? kCFCompareGreaterThan
: kCFCompareLessThan
;
1404 // at this point, we know the signs are the same; do not combine these tests
1405 __CFNumberGetValue(number2
, kCFNumberFloat64Type
, &d2
);
1406 if (d1
< d2
) return !swapResult
? kCFCompareLessThan
: kCFCompareGreaterThan
;
1407 if (d2
< d1
) return !swapResult
? kCFCompareGreaterThan
: kCFCompareLessThan
;
1408 return kCFCompareEqualTo
;
1411 CFComparisonResult
CFNumberCompare(CFNumberRef number1
, CFNumberRef number2
, void *context
) {
1412 //printf("+ [%p] CFNumberCompare(%p, %p, %p)\n", pthread_self(), number1, number2, context);
1413 CFComparisonResult r
= CFNumberCompare_new(number1
, number2
, context
);
1414 //printf(" => %d\n", r);
1416 if (! number1
->__old__
|| !number2
->__old__
) {
1417 printf("*** Test skipped in CFNumberCompare for numbers %p %p\n", number1
, number2
);
1419 CFComparisonResult r2
= CFNumberCompare_old(number1
->__old__
, number2
->__old__
, context
);
1421 CFLog(kCFLogLevelWarning
, CFSTR("*** TEST FAIL in CFNumberCompare: '%d' '%d'"), r2
, r
); FAIL();
1430 static const unsigned char __CFNumberCanonicalType
[kCFNumberMaxType
+ 1] = {
1431 0, kCFNumberSInt8Type
, kCFNumberSInt16Type
, kCFNumberSInt32Type
, kCFNumberSInt64Type
, kCFNumberFloat32Type
, kCFNumberFloat64Type
,
1432 kCFNumberSInt8Type
, kCFNumberSInt16Type
, kCFNumberSInt32Type
, kCFNumberSInt32Type
, kCFNumberSInt64Type
, kCFNumberFloat32Type
, kCFNumberFloat64Type
,
1433 kCFNumberSInt32Type
, kCFNumberSInt32Type
, kCFNumberFloat32Type
1436 static const unsigned char __CFNumberStorageType
[kCFNumberMaxType
+ 1] = {
1437 0, kCFNumberSInt32Type
, kCFNumberSInt32Type
, kCFNumberSInt32Type
, kCFNumberSInt64Type
, kCFNumberFloat32Type
, kCFNumberFloat64Type
,
1438 kCFNumberSInt32Type
, kCFNumberSInt32Type
, kCFNumberSInt32Type
, kCFNumberSInt32Type
, kCFNumberSInt64Type
, kCFNumberFloat32Type
, kCFNumberFloat64Type
,
1439 kCFNumberSInt32Type
, kCFNumberSInt32Type
, kCFNumberFloat32Type
1444 // Returns the type that is used to store the specified type
1445 static CFNumberType
__CFNumberGetStorageTypeForType_old(CFNumberType type
) {
1446 return __CFNumberStorageType
[type
];
1449 // Returns the canonical type used to represent the specified type
1450 static CFNumberType
__CFNumberGetCanonicalTypeForType_old(CFNumberType type
) {
1451 return __CFNumberCanonicalType
[type
];
1454 // Extracts and returns the type out of the CFNumber
1455 static CFNumberType
__CFNumberGetType_old(struct __CFNumber_old
* num
) {
1456 return __CFBitfieldGetValue(num
->_base
._cfinfo
[CF_INFO_BITS
], 4, 0);
1459 // Returns true if the argument type is float or double
1460 static Boolean
__CFNumberTypeIsFloat_old(CFNumberType type
) {
1461 return (type
== kCFNumberFloat64Type
) || (type
== kCFNumberFloat32Type
) || (type
== kCFNumberDoubleType
) || (type
== kCFNumberFloatType
);
1464 // Returns the number of bytes necessary to store the specified type
1465 // Needs to handle all canonical types
1466 static CFIndex
__CFNumberSizeOfType_old(CFNumberType type
) {
1468 case kCFNumberSInt8Type
: return sizeof(int8_t);
1469 case kCFNumberSInt16Type
: return sizeof(int16_t);
1470 case kCFNumberSInt32Type
: return sizeof(SInt32
);
1471 case kCFNumberSInt64Type
: return sizeof(int64_t);
1472 case kCFNumberFloat32Type
: return sizeof(Float32
);
1473 case kCFNumberFloat64Type
: return sizeof(Float64
);
1474 default: printf("*** WARNING: 0 size from __CFNumberSizeOfType_old \n"); return 0;
1478 // Copies an external value of a given type into the appropriate slot in the union (does no type conversion)
1479 // Needs to handle all canonical types
1480 #define SET_VALUE(valueUnion, type, valuePtr) \
1482 case kCFNumberSInt8Type: (valueUnion)->valSInt32 = *(int8_t *)(valuePtr); break; \
1483 case kCFNumberSInt16Type: (valueUnion)->valSInt32 = *(int16_t *)(valuePtr); break; \
1484 case kCFNumberSInt32Type: (valueUnion)->valSInt32 = *(SInt32 *)(valuePtr); break; \
1485 case kCFNumberSInt64Type: (valueUnion)->valSInt64 = *(int64_t *)(valuePtr); break; \
1486 case kCFNumberFloat32Type: (valueUnion)->valFloat32 = *(Float32 *)(valuePtr); break; \
1487 case kCFNumberFloat64Type: (valueUnion)->valFloat64 = *(Float64 *)(valuePtr); break; \
1488 default: printf("*** WARNING: default case in SET_VALUE \n"); break; \
1491 // Casts the specified value into the specified type and copies it into the provided memory
1492 // Needs to handle all canonical types
1493 #define GET_VALUE(value, type, resultPtr) \
1495 case kCFNumberSInt8Type: *(int8_t *)(resultPtr) = (int8_t)value; break; \
1496 case kCFNumberSInt16Type: *(int16_t *)(resultPtr) = (int16_t)value; break; \
1497 case kCFNumberSInt32Type: *(SInt32 *)(resultPtr) = (SInt32)value; break; \
1498 case kCFNumberSInt64Type: *(int64_t *)(resultPtr) = (int64_t)value; break; \
1499 case kCFNumberFloat32Type: *(Float32 *)(resultPtr) = (Float32)value; break; \
1500 case kCFNumberFloat64Type: *(Float64 *)(resultPtr) = (Float64)value; break; \
1501 default: printf("*** WARNING: default case in GET_VALUE \n"); break; \
1504 // Extracts the stored type out of the union and copies it in the desired type into the provided memory
1505 // Needs to handle all storage types
1506 static void __CFNumberGetValue_old(const __CFNumberValue_old
*value
, CFNumberType numberType
, CFNumberType typeToGet
, void *valuePtr
) {
1507 switch (numberType
) {
1508 case kCFNumberSInt32Type
: GET_VALUE(value
->valSInt32
, typeToGet
, valuePtr
); break;
1509 case kCFNumberSInt64Type
: GET_VALUE(value
->valSInt64
, typeToGet
, valuePtr
); break;
1510 case kCFNumberFloat32Type
: GET_VALUE(value
->valFloat32
, typeToGet
, valuePtr
); break;
1511 case kCFNumberFloat64Type
: GET_VALUE(value
->valFloat64
, typeToGet
, valuePtr
); break;
1512 default: printf("*** WARNING: default case in __CFNumberGetValue_old \n"); break; \
1516 // Sees if two value union structs have the same value (will do type conversion)
1517 static Boolean
__CFNumberEqualValue_old(const __CFNumberValue_old
*value1
, CFNumberType type1
, const __CFNumberValue_old
*value2
, CFNumberType type2
) {
1518 if (__CFNumberTypeIsFloat_old(type1
) || __CFNumberTypeIsFloat_old(type2
)) {
1520 __CFNumberGetValue_old(value1
, type1
, kCFNumberFloat64Type
, &d1
);
1521 __CFNumberGetValue_old(value2
, type2
, kCFNumberFloat64Type
, &d2
);
1522 if (isnan(d1
) && isnan(d2
)) return true; // Not mathematically sound, but required
1526 __CFNumberGetValue_old(value1
, type1
, kCFNumberSInt64Type
, &i1
);
1527 __CFNumberGetValue_old(value2
, type2
, kCFNumberSInt64Type
, &i2
);
1532 static Boolean
__CFNumberEqual_old(CFTypeRef cf1
, CFTypeRef cf2
) {
1533 struct __CFNumber_old
* number1
= (struct __CFNumber_old
*)cf1
;
1534 struct __CFNumber_old
* number2
= (struct __CFNumber_old
*)cf2
;
1535 return __CFNumberEqualValue_old(&(number1
->value
), __CFNumberGetType_old(number1
), &(number2
->value
), __CFNumberGetType_old(number2
));
1538 static CFHashCode
__CFNumberHash_old(CFTypeRef cf
) {
1539 struct __CFNumber_old
* number
= (struct __CFNumber_old
*)cf
;
1540 switch (__CFNumberGetType_old((struct __CFNumber_old
*)cf
)) {
1541 case kCFNumberSInt32Type
: return _CFHashInt(number
->value
.valSInt32
);
1542 case kCFNumberSInt64Type
: return _CFHashDouble((double)(number
->value
.valSInt64
));
1543 case kCFNumberFloat32Type
: return _CFHashDouble((double)(number
->value
.valFloat32
));
1544 case kCFNumberFloat64Type
: return _CFHashDouble((double)(number
->value
.valFloat64
));
1545 default: printf("*** WARNING default case in __CFNumberHash_old\n");
1550 #define BUFFER_SIZE 100
1551 #define emitChar(ch) \
1552 {if (buf - stackBuf == BUFFER_SIZE) {CFStringAppendCharacters(mstr, stackBuf, BUFFER_SIZE); buf = stackBuf;} *buf++ = ch;}
1554 static void __CFNumberEmitInt64_old(CFMutableStringRef mstr
, int64_t value
, int32_t width
, UniChar pad
, bool explicitPlus
) {
1555 UniChar stackBuf
[BUFFER_SIZE
], *buf
= stackBuf
;
1556 uint64_t uvalue
, factor
, tmp
;
1560 neg
= (value
< 0) ? true : false;
1561 uvalue
= (neg
) ? -value
: value
;
1562 if (neg
|| explicitPlus
) width
--;
1571 for (w
= 0; w
< width
; w
++) emitChar(pad
);
1574 } else if (explicitPlus
) {
1577 while (0 < factor
) {
1578 UniChar ch
= '0' + (UniChar
)(uvalue
/ factor
);
1583 if (buf
> stackBuf
) CFStringAppendCharacters(mstr
, stackBuf
, buf
- stackBuf
);
1586 static CFStringRef
__CFNumberCopyDescription_old(CFTypeRef cf
) {
1587 struct __CFNumber_old
* number
= (struct __CFNumber_old
*)cf
;
1588 CFMutableStringRef mstr
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
1589 CFStringAppendFormat(mstr
, NULL
, CFSTR("<CFNumber %p [%p]>{value = "), cf
, CFGetAllocator(cf
));
1590 switch (__CFNumberGetType_old(number
)) {
1591 case kCFNumberSInt32Type
:
1592 __CFNumberEmitInt64_old(mstr
, number
->value
.valSInt32
, 0, ' ', true);
1593 CFStringAppendFormat(mstr
, NULL
, CFSTR(", type = kCFNumberSInt32Type}"));
1595 case kCFNumberSInt64Type
:
1596 __CFNumberEmitInt64_old(mstr
, number
->value
.valSInt64
, 0, ' ', true);
1597 CFStringAppendFormat(mstr
, NULL
, CFSTR(", type = kCFNumberSInt64Type}"));
1599 case kCFNumberFloat32Type
:
1600 // debugging formatting is intentionally more verbose and explicit about the value of the number
1601 if (isnan(number
->value
.valFloat32
)) {
1602 CFStringAppend(mstr
, CFSTR("nan"));
1603 } else if (isinf(number
->value
.valFloat32
)) {
1604 CFStringAppend(mstr
, (0.0f
< number
->value
.valFloat32
) ? CFSTR("+infinity") : CFSTR("-infinity"));
1605 } else if (0.0f
== number
->value
.valFloat32
) {
1606 CFStringAppend(mstr
, (copysign(1.0, number
->value
.valFloat32
) < 0.0) ? CFSTR("-0.0") : CFSTR("+0.0"));
1608 CFStringAppendFormat(mstr
, NULL
, CFSTR("%+.10f"), number
->value
.valFloat32
);
1610 CFStringAppend(mstr
, CFSTR(", type = kCFNumberFloat32Type}"));
1612 case kCFNumberFloat64Type
:
1613 // debugging formatting is intentionally more verbose and explicit about the value of the number
1614 if (isnan(number
->value
.valFloat64
)) {
1615 CFStringAppend(mstr
, CFSTR("nan"));
1616 } else if (isinf(number
->value
.valFloat64
)) {
1617 CFStringAppend(mstr
, (0.0 < number
->value
.valFloat64
) ? CFSTR("+infinity") : CFSTR("-infinity"));
1618 } else if (0.0 == number
->value
.valFloat64
) {
1619 CFStringAppend(mstr
, (copysign(1.0, number
->value
.valFloat64
) < 0.0) ? CFSTR("-0.0") : CFSTR("+0.0"));
1621 CFStringAppendFormat(mstr
, NULL
, CFSTR("%+.20f"), number
->value
.valFloat64
);
1623 CFStringAppend(mstr
, CFSTR(", type = kCFNumberFloat64Type}"));
1632 // This function separated out from __CFNumberCopyFormattingDescription() so the plist creation can use it as well.
1634 __private_extern__ CFStringRef
__CFNumberCopyFormattingDescriptionAsFloat64_old(CFTypeRef cf
) {
1636 CFNumberGetValue_old((struct __CFNumber_old
*)cf
, kCFNumberFloat64Type
, &d
);
1638 return (CFStringRef
)CFRetain(CFSTR("nan"));
1641 return (CFStringRef
)CFRetain((0.0 < d
) ? CFSTR("+infinity") : CFSTR("-infinity"));
1644 return (CFStringRef
)CFRetain(CFSTR("0.0"));
1646 // if %g is used here, need to use DBL_DIG + 2 on Mac OS X, but %f needs +1
1647 return CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("%.*g"), DBL_DIG
+ 2, d
);
1650 static CFStringRef
__CFNumberCopyFormattingDescription_old(CFTypeRef cf
, CFDictionaryRef formatOptions
) {
1651 struct __CFNumber_old
* number
= (struct __CFNumber_old
*)cf
;
1652 CFMutableStringRef mstr
;
1654 switch (__CFNumberGetType_old(number
)) {
1655 case kCFNumberSInt32Type
:
1656 case kCFNumberSInt64Type
:
1657 value
= (__CFNumberGetType_old(number
) == kCFNumberSInt32Type
) ? number
->value
.valSInt32
: number
->value
.valSInt64
;
1658 mstr
= CFStringCreateMutable(kCFAllocatorSystemDefault
, 0);
1659 __CFNumberEmitInt64_old(mstr
, value
, 0, ' ', false);
1661 case kCFNumberFloat32Type
:
1662 if (isnan(number
->value
.valFloat32
)) {
1663 return (CFStringRef
)CFRetain(CFSTR("nan"));
1665 if (isinf(number
->value
.valFloat32
)) {
1666 return (CFStringRef
)CFRetain((0.0f
< number
->value
.valFloat32
) ? CFSTR("+infinity") : CFSTR("-infinity"));
1668 if (0.0f
== number
->value
.valFloat32
) {
1669 return (CFStringRef
)CFRetain(CFSTR("0.0"));
1671 // if %g is used here, need to use FLT_DIG + 2 on Mac OS X, but %f needs +1
1672 return CFStringCreateWithFormat(kCFAllocatorSystemDefault
, NULL
, CFSTR("%.*g"), FLT_DIG
+ 2, number
->value
.valFloat32
);
1673 case kCFNumberFloat64Type
:
1674 return __CFNumberCopyFormattingDescriptionAsFloat64_old(number
);
1683 static struct __CFNumber_old
* CFNumberCreate_old(CFAllocatorRef allocator
, CFNumberType type
, const void *valuePtr
) {
1684 struct __CFNumber_old
* num
;
1685 CFNumberType equivType
, storageType
;
1688 CFSInt128Struct
*s
= valuePtr
;
1689 s
->high
= (int64_t)s
->low
;
1690 type
= kCFNumberSInt64Type
;
1694 equivType
= __CFNumberGetCanonicalTypeForType_old(type
);
1696 storageType
= __CFNumberGetStorageTypeForType_old(type
);
1698 num
= (struct __CFNumber_old
*)_CFRuntimeCreateInstance(allocator
, __kCFNumberTypeID
, __CFNumberSizeOfType_old(storageType
), NULL
);
1702 SET_VALUE((__CFNumberValue_old
*)&(num
->value
), equivType
, valuePtr
);
1703 __CFBitfieldSetValue(((struct __CFNumber_old
*)num
)->_base
._cfinfo
[CF_INFO_BITS
], 6, 0, (uint8_t)storageType
);
1705 if (__CFNumberGetType_old(num
) == 0) printf("*** ERROR: new number %p type is 0 (%d)\n", num
, storageType
);
1709 static CFNumberType
CFNumberGetType_old(struct __CFNumber_old
* number
) {
1711 return __CFNumberGetType_old(number
);
1714 static CFIndex
CFNumberGetByteSize_old(struct __CFNumber_old
* number
) {
1715 return __CFNumberSizeOfType_old(CFNumberGetType_old(number
));
1718 static Boolean
CFNumberIsFloatType_old(struct __CFNumber_old
* number
) {
1719 return __CFNumberTypeIsFloat_old(CFNumberGetType_old(number
));
1722 static Boolean
CFNumberGetValue_old(struct __CFNumber_old
* number
, CFNumberType type
, void *valuePtr
) {
1723 uint8_t localMemory
[sizeof(__CFNumberValue_old
)];
1724 __CFNumberValue_old localValue
;
1725 CFNumberType numType
;
1726 CFNumberType storageTypeForType
;
1728 if (type
== 17) type
= kCFNumberSInt64Type
;
1730 storageTypeForType
= __CFNumberGetStorageTypeForType_old(type
);
1731 type
= __CFNumberGetCanonicalTypeForType_old(type
);
1732 if (!valuePtr
) valuePtr
= &localMemory
;
1734 numType
= __CFNumberGetType_old(number
);
1735 __CFNumberGetValue_old((__CFNumberValue_old
*)&(number
->value
), numType
, type
, valuePtr
);
1737 // If the types match, then we're fine!
1738 if (numType
== storageTypeForType
) return true;
1740 // Test to see if the returned value is intact...
1741 SET_VALUE(&localValue
, type
, valuePtr
);
1742 return __CFNumberEqualValue_old(&localValue
, storageTypeForType
, &(number
->value
), numType
);
1745 static CFComparisonResult
CFNumberCompare_old(struct __CFNumber_old
* number1
, struct __CFNumber_old
* number2
, void *context
) {
1746 CFNumberType type1
, type2
;
1749 type1
= __CFNumberGetType_old(number1
);
1750 type2
= __CFNumberGetType_old(number2
);
1752 if (__CFNumberTypeIsFloat_old(type1
) || __CFNumberTypeIsFloat_old(type2
)) {
1755 __CFNumberGetValue_old(&(number1
->value
), type1
, kCFNumberFloat64Type
, &d1
);
1756 __CFNumberGetValue_old(&(number2
->value
), type2
, kCFNumberFloat64Type
, &d2
);
1757 s1
= copysign(1.0, d1
);
1758 s2
= copysign(1.0, d2
);
1759 if (isnan(d1
) && isnan(d2
)) return kCFCompareEqualTo
;
1760 if (isnan(d1
)) return (s2
< 0.0) ? kCFCompareGreaterThan
: kCFCompareLessThan
;
1761 if (isnan(d2
)) return (s1
< 0.0) ? kCFCompareLessThan
: kCFCompareGreaterThan
;
1762 // at this point, we know we don't have any NaNs
1763 if (s1
< s2
) return kCFCompareLessThan
;
1764 if (s2
< s1
) return kCFCompareGreaterThan
;
1765 // at this point, we know the signs are the same; do not combine these tests
1766 if (d1
< d2
) return kCFCompareLessThan
;
1767 if (d2
< d1
) return kCFCompareGreaterThan
;
1768 return kCFCompareEqualTo
;
1771 __CFNumberGetValue_old(&(number1
->value
), type1
, kCFNumberSInt64Type
, &i1
);
1772 __CFNumberGetValue_old(&(number2
->value
), type2
, kCFNumberSInt64Type
, &i2
);
1773 return (i1
> i2
) ? kCFCompareGreaterThan
: ((i1
< i2
) ? kCFCompareLessThan
: kCFCompareEqualTo
);
1780 #undef __CFAssertIsBoolean
1781 #undef __CFAssertIsNumber
1782 #undef __CFAssertIsValidNumberType
1783 #undef BITSFORDOUBLENAN
1784 #undef BITSFORDOUBLEPOSINF
1785 #undef BITSFORDOUBLENEGINF
1788 #undef NotToBeCached