+/*
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/* CFNumber.c
+ Copyright 1999-2002, Apple, Inc. All rights reserved.
+ Responsibility: Ali Ozer
+*/
+
+#include <CoreFoundation/CFNumber.h>
+#include "CFInternal.h"
+#include "CFPriv.h"
+#include <math.h>
+#include <float.h>
+
+#define __CFAssertIsBoolean(cf) __CFGenericValidateType(cf, __kCFBooleanTypeID)
+
+struct __CFBoolean {
+ CFRuntimeBase _base;
+};
+
+static struct __CFBoolean __kCFBooleanTrue = {
+ INIT_CFRUNTIME_BASE()
+};
+const CFBooleanRef kCFBooleanTrue = &__kCFBooleanTrue;
+
+static struct __CFBoolean __kCFBooleanFalse = {
+ INIT_CFRUNTIME_BASE()
+};
+const CFBooleanRef kCFBooleanFalse = &__kCFBooleanFalse;
+
+static CFStringRef __CFBooleanCopyDescription(CFTypeRef cf) {
+ CFBooleanRef boolean = (CFBooleanRef)cf;
+ return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("<CFBoolean %p [%p]>{value = %s}"), cf, CFGetAllocator(cf), (boolean == kCFBooleanTrue) ? "true" : "false");
+}
+
+static CFStringRef __CFBooleanCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
+ CFBooleanRef boolean = (CFBooleanRef)cf;
+ return (CFStringRef)CFRetain((boolean == kCFBooleanTrue) ? CFSTR("true") : CFSTR("false"));
+}
+
+static void __CFBooleanDeallocate(CFTypeRef cf) {
+ CFAssert(false, __kCFLogAssertion, "Deallocated CFBoolean!");
+}
+
+static CFTypeID __kCFBooleanTypeID = _kCFRuntimeNotATypeID;
+
+static const CFRuntimeClass __CFBooleanClass = {
+ 0,
+ "CFBoolean",
+ NULL, // init
+ NULL, // copy
+ __CFBooleanDeallocate,
+ NULL,
+ NULL,
+ __CFBooleanCopyFormattingDescription,
+ __CFBooleanCopyDescription
+};
+
+__private_extern__ void __CFBooleanInitialize(void) {
+ __kCFBooleanTypeID = _CFRuntimeRegisterClass(&__CFBooleanClass);
+ _CFRuntimeSetInstanceTypeID(&__kCFBooleanTrue, __kCFBooleanTypeID);
+ __kCFBooleanTrue._base._cfisa = __CFISAForTypeID(__kCFBooleanTypeID);
+ _CFRuntimeSetInstanceTypeID(&__kCFBooleanFalse, __kCFBooleanTypeID);
+ __kCFBooleanFalse._base._cfisa = __CFISAForTypeID(__kCFBooleanTypeID);
+}
+
+CFTypeID CFBooleanGetTypeID(void) {
+ return __kCFBooleanTypeID;
+}
+
+Boolean CFBooleanGetValue(CFBooleanRef boolean) {
+ CF_OBJC_FUNCDISPATCH0(__kCFBooleanTypeID, Boolean, boolean, "boolValue");
+ return (boolean == kCFBooleanTrue) ? true : false;
+}
+
+
+/*** CFNumber ***/
+
+#define __CFAssertIsNumber(cf) __CFGenericValidateType(cf, __kCFNumberTypeID)
+#define __CFAssertIsValidNumberType(type) CFAssert2((0 < type && type <= kCFNumberMaxType) || (type == kCFNumberSInt128Type), __kCFLogAssertion, "%s(): bad CFNumber type %d", __PRETTY_FUNCTION__, type);
+
+/* The IEEE bit patterns... Also have:
+0x7f800000 float +Inf
+0x7fc00000 float NaN
+0xff800000 float -Inf
+*/
+#define BITSFORDOUBLENAN ((uint64_t)0x7ff8000000000000ULL)
+#define BITSFORDOUBLEPOSINF ((uint64_t)0x7ff0000000000000ULL)
+#define BITSFORDOUBLENEGINF ((uint64_t)0xfff0000000000000ULL)
+
+#if DEPLOYMENT_TARGET_MACOSX
+#define FLOAT_POSITIVE_2_TO_THE_64 0x1.0p+64L
+#define FLOAT_NEGATIVE_2_TO_THE_127 -0x1.0p+127L
+#define FLOAT_POSITIVE_2_TO_THE_127 0x1.0p+127L
+#endif
+
+typedef struct { // NOTE WELL: these two fields may switch position someday, do not use '= {high, low}' -style initialization
+ int64_t high;
+ uint64_t low;
+} CFSInt128Struct;
+
+enum {
+ kCFNumberSInt128Type = 17
+};
+
+static uint8_t isNeg128(const CFSInt128Struct *in) {
+ return in->high < 0;
+}
+
+static CFComparisonResult cmp128(const CFSInt128Struct *in1, const CFSInt128Struct *in2) {
+ if (in1->high < in2->high) return kCFCompareLessThan;
+ if (in1->high > in2->high) return kCFCompareGreaterThan;
+ if (in1->low < in2->low) return kCFCompareLessThan;
+ if (in1->low > in2->low) return kCFCompareGreaterThan;
+ return kCFCompareEqualTo;
+}
+
+// allows out to be the same as in1 or in2
+static void add128(CFSInt128Struct *out, CFSInt128Struct *in1, CFSInt128Struct *in2) {
+ CFSInt128Struct tmp;
+ tmp.low = in1->low + in2->low;
+ tmp.high = in1->high + in2->high;
+ if (UINT64_MAX - in1->low < in2->low) {
+ tmp.high++;
+ }
+ *out = tmp;
+}
+
+// allows out to be the same as in
+static void neg128(CFSInt128Struct *out, CFSInt128Struct *in) {
+ uint64_t tmplow = ~in->low;
+ out->low = tmplow + 1;
+ out->high = ~in->high;
+ if (UINT64_MAX == tmplow) {
+ out->high++;
+ }
+}
+
+static const CFSInt128Struct powersOf10[] = {
+ { 0x4B3B4CA85A86C47ALL, 0x098A224000000000ULL },
+ { 0x0785EE10D5DA46D9LL, 0x00F436A000000000ULL },
+ { 0x00C097CE7BC90715LL, 0xB34B9F1000000000ULL },
+ { 0x0013426172C74D82LL, 0x2B878FE800000000ULL },
+ { 0x0001ED09BEAD87C0LL, 0x378D8E6400000000ULL },
+ { 0x0000314DC6448D93LL, 0x38C15B0A00000000ULL },
+ { 0x000004EE2D6D415BLL, 0x85ACEF8100000000ULL },
+ { 0x0000007E37BE2022LL, 0xC0914B2680000000ULL },
+ { 0x0000000C9F2C9CD0LL, 0x4674EDEA40000000ULL },
+ { 0x00000001431E0FAELL, 0x6D7217CAA0000000ULL },
+ { 0x00000000204FCE5ELL, 0x3E25026110000000ULL },
+ { 0x00000000033B2E3CLL, 0x9FD0803CE8000000ULL },
+ { 0x000000000052B7D2LL, 0xDCC80CD2E4000000ULL },
+ { 0x0000000000084595LL, 0x161401484A000000ULL },
+ { 0x000000000000D3C2LL, 0x1BCECCEDA1000000ULL },
+ { 0x000000000000152DLL, 0x02C7E14AF6800000ULL },
+ { 0x000000000000021ELL, 0x19E0C9BAB2400000ULL },
+ { 0x0000000000000036LL, 0x35C9ADC5DEA00000ULL },
+ { 0x0000000000000005LL, 0x6BC75E2D63100000ULL },
+ { 0x0000000000000000LL, 0x8AC7230489E80000ULL },
+ { 0x0000000000000000LL, 0x0DE0B6B3A7640000ULL },
+ { 0x0000000000000000LL, 0x016345785D8A0000ULL },
+ { 0x0000000000000000LL, 0x002386F26FC10000ULL },
+ { 0x0000000000000000LL, 0x00038D7EA4C68000ULL },
+ { 0x0000000000000000LL, 0x00005AF3107A4000ULL },
+ { 0x0000000000000000LL, 0x000009184E72A000ULL },
+ { 0x0000000000000000LL, 0x000000E8D4A51000ULL },
+ { 0x0000000000000000LL, 0x000000174876E800ULL },
+ { 0x0000000000000000LL, 0x00000002540BE400ULL },
+ { 0x0000000000000000LL, 0x000000003B9ACA00ULL },
+ { 0x0000000000000000LL, 0x0000000005F5E100ULL },
+ { 0x0000000000000000LL, 0x0000000000989680ULL },
+ { 0x0000000000000000LL, 0x00000000000F4240ULL },
+ { 0x0000000000000000LL, 0x00000000000186A0ULL },
+ { 0x0000000000000000LL, 0x0000000000002710ULL },
+ { 0x0000000000000000LL, 0x00000000000003E8ULL },
+ { 0x0000000000000000LL, 0x0000000000000064ULL },
+ { 0x0000000000000000LL, 0x000000000000000AULL },
+ { 0x0000000000000000LL, 0x0000000000000001ULL },
+};
+
+static const CFSInt128Struct neg_powersOf10[] = {
+ { 0xB4C4B357A5793B85LL, 0xF675DDC000000000ULL },
+ { 0xF87A11EF2A25B926LL, 0xFF0BC96000000000ULL },
+ { 0xFF3F68318436F8EALL, 0x4CB460F000000000ULL },
+ { 0xFFECBD9E8D38B27DLL, 0xD478701800000000ULL },
+ { 0xFFFE12F64152783FLL, 0xC872719C00000000ULL },
+ { 0xFFFFCEB239BB726CLL, 0xC73EA4F600000000ULL },
+ { 0xFFFFFB11D292BEA4LL, 0x7A53107F00000000ULL },
+ { 0xFFFFFF81C841DFDDLL, 0x3F6EB4D980000000ULL },
+ { 0xFFFFFFF360D3632FLL, 0xB98B1215C0000000ULL },
+ { 0xFFFFFFFEBCE1F051LL, 0x928DE83560000000ULL },
+ { 0xFFFFFFFFDFB031A1LL, 0xC1DAFD9EF0000000ULL },
+ { 0xFFFFFFFFFCC4D1C3LL, 0x602F7FC318000000ULL },
+ { 0xFFFFFFFFFFAD482DLL, 0x2337F32D1C000000ULL },
+ { 0xFFFFFFFFFFF7BA6ALL, 0xE9EBFEB7B6000000ULL },
+ { 0xFFFFFFFFFFFF2C3DLL, 0xE43133125F000000ULL },
+ { 0xFFFFFFFFFFFFEAD2LL, 0xFD381EB509800000ULL },
+ { 0xFFFFFFFFFFFFFDE1LL, 0xE61F36454DC00000ULL },
+ { 0xFFFFFFFFFFFFFFC9LL, 0xCA36523A21600000ULL },
+ { 0xFFFFFFFFFFFFFFFALL, 0x9438A1D29CF00000ULL },
+ { 0xFFFFFFFFFFFFFFFFLL, 0x7538DCFB76180000ULL },
+ { 0xFFFFFFFFFFFFFFFFLL, 0xF21F494C589C0000ULL },
+ { 0xFFFFFFFFFFFFFFFFLL, 0xFE9CBA87A2760000ULL },
+ { 0xFFFFFFFFFFFFFFFFLL, 0xFFDC790D903F0000ULL },
+ { 0xFFFFFFFFFFFFFFFFLL, 0xFFFC72815B398000ULL },
+ { 0xFFFFFFFFFFFFFFFFLL, 0xFFFFA50CEF85C000ULL },
+ { 0xFFFFFFFFFFFFFFFFLL, 0xFFFFF6E7B18D6000ULL },
+ { 0xFFFFFFFFFFFFFFFFLL, 0xFFFFFF172B5AF000ULL },
+ { 0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFE8B7891800ULL },
+ { 0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFDABF41C00ULL },
+ { 0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFC4653600ULL },
+ { 0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFFA0A1F00ULL },
+ { 0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFFF676980ULL },
+ { 0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFFFF0BDC0ULL },
+ { 0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFFFFE7960ULL },
+ { 0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFFFFFD8F0ULL },
+ { 0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFFFFFFC18ULL },
+ { 0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFFFFFFF9CULL },
+ { 0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFFFFFFFF6ULL },
+ { 0xFFFFFFFFFFFFFFFFLL, 0xFFFFFFFFFFFFFFFFULL },
+};
+
+static void emit128(char *buffer, const CFSInt128Struct *in, Boolean forcePlus) {
+ CFSInt128Struct tmp = *in;
+ if (isNeg128(&tmp)) {
+ neg128(&tmp, &tmp);
+ *buffer++ = '-';
+ } else if (forcePlus) {
+ *buffer++ = '+';
+ }
+ Boolean doneOne = false;
+ int idx;
+ for (idx = 0; idx < sizeof(powersOf10) / sizeof(powersOf10[0]); idx++) {
+ int count = 0;
+ while (cmp128(&powersOf10[idx], &tmp) <= 0) {
+ add128(&tmp, &tmp, (CFSInt128Struct *)&neg_powersOf10[idx]);
+ count++;
+ }
+ if (0 != count || doneOne) {
+ *buffer++ = '0' + count;
+ doneOne = true;
+ }
+ }
+ if (!doneOne) {
+ *buffer++ = '0';
+ }
+ *buffer = '\0';
+}
+
+static void cvtSInt128ToFloat64(Float64 *out, const CFSInt128Struct *in) {
+ // switching to a positive number results in better accuracy
+ // for negative numbers close to zero, because the multiply
+ // of -1 by 2^64 (scaling the Float64 high) is avoided
+ Boolean wasNeg = false;
+ CFSInt128Struct tmp = *in;
+ if (isNeg128(&tmp)) {
+ neg128(&tmp, &tmp);
+ wasNeg = true;
+ }
+ Float64 d = (Float64)tmp.high * FLOAT_POSITIVE_2_TO_THE_64 + (Float64)tmp.low;
+ if (wasNeg) d = -d;
+ *out = d;
+}
+
+static void cvtFloat64ToSInt128(CFSInt128Struct *out, const Float64 *in) {
+ CFSInt128Struct i;
+ Float64 d = *in;
+ if (d < FLOAT_NEGATIVE_2_TO_THE_127) {
+ i.high = 0x8000000000000000LL;
+ i.low = 0x0000000000000000ULL;
+ *out = i;
+ return;
+ }
+ if (FLOAT_POSITIVE_2_TO_THE_127<= d) {
+ i.high = 0x7fffffffffffffffLL;
+ i.low = 0xffffffffffffffffULL;
+ *out = i;
+ return;
+ }
+ Float64 t = floor(d / FLOAT_POSITIVE_2_TO_THE_64);
+ i.high = (int64_t)t;
+ i.low = (uint64_t)(d - t * FLOAT_POSITIVE_2_TO_THE_64);
+ *out = i;
+}
+
+struct __CFNumber {
+ CFRuntimeBase _base;
+ uint64_t _pad; // need this space here for the constant objects
+ /* 0 or 8 more bytes allocated here */
+};
+
+/* Seven bits in base:
+ Bits 6..5: unused
+ Bits 4..0: CFNumber type
+*/
+
+static struct __CFNumber __kCFNumberNaN = {
+ INIT_CFRUNTIME_BASE(), 0ULL
+};
+const CFNumberRef kCFNumberNaN = &__kCFNumberNaN;
+
+static struct __CFNumber __kCFNumberNegativeInfinity = {
+ INIT_CFRUNTIME_BASE(), 0ULL
+};
+const CFNumberRef kCFNumberNegativeInfinity = &__kCFNumberNegativeInfinity;
+
+static struct __CFNumber __kCFNumberPositiveInfinity = {
+ INIT_CFRUNTIME_BASE(), 0ULL
+};
+const CFNumberRef kCFNumberPositiveInfinity = &__kCFNumberPositiveInfinity;
+
+static const struct {
+ uint16_t canonicalType:5; // canonical fixed-width type
+ uint16_t floatBit:1; // is float
+ uint16_t storageBit:1; // storage size (0: (float ? 4 : 8), 1: (float ? 8 : 16) bits)
+ uint16_t lgByteSize:3; // base-2 log byte size of public type
+ uint16_t unused:6;
+} __CFNumberTypeTable[] = {
+ /* 0 */ {0, 0, 0, 0},
+
+ /* kCFNumberSInt8Type */ {kCFNumberSInt8Type, 0, 0, 0, 0},
+ /* kCFNumberSInt16Type */ {kCFNumberSInt16Type, 0, 0, 1, 0},
+ /* kCFNumberSInt32Type */ {kCFNumberSInt32Type, 0, 0, 2, 0},
+ /* kCFNumberSInt64Type */ {kCFNumberSInt64Type, 0, 0, 3, 0},
+ /* kCFNumberFloat32Type */ {kCFNumberFloat32Type, 1, 0, 2, 0},
+ /* kCFNumberFloat64Type */ {kCFNumberFloat64Type, 1, 1, 3, 0},
+
+ /* kCFNumberCharType */ {kCFNumberSInt8Type, 0, 0, 0, 0},
+ /* kCFNumberShortType */ {kCFNumberSInt16Type, 0, 0, 1, 0},
+ /* kCFNumberIntType */ {kCFNumberSInt32Type, 0, 0, 2, 0},
+#if __LP64__
+ /* kCFNumberLongType */ {kCFNumberSInt64Type, 0, 0, 3, 0},
+#else
+ /* kCFNumberLongType */ {kCFNumberSInt32Type, 0, 0, 2, 0},
+#endif
+ /* kCFNumberLongLongType */ {kCFNumberSInt64Type, 0, 0, 3, 0},
+ /* kCFNumberFloatType */ {kCFNumberFloat32Type, 1, 0, 2, 0},
+ /* kCFNumberDoubleType */ {kCFNumberFloat64Type, 1, 1, 3, 0},
+
+#if __LP64__
+ /* kCFNumberCFIndexType */ {kCFNumberSInt64Type, 0, 0, 3, 0},
+ /* kCFNumberNSIntegerType */ {kCFNumberSInt64Type, 0, 0, 3, 0},
+ /* kCFNumberCGFloatType */ {kCFNumberFloat64Type, 1, 1, 3, 0},
+#else
+ /* kCFNumberCFIndexType */ {kCFNumberSInt32Type, 0, 0, 2, 0},
+ /* kCFNumberNSIntegerType */ {kCFNumberSInt32Type, 0, 0, 2, 0},
+ /* kCFNumberCGFloatType */ {kCFNumberFloat32Type, 1, 0, 2, 0},
+#endif
+
+ /* kCFNumberSInt128Type */ {kCFNumberSInt128Type, 0, 1, 4, 0},
+};
+
+CF_INLINE CFNumberType __CFNumberGetType(CFNumberRef num) {
+ return __CFBitfieldGetValue(num->_base._cfinfo[CF_INFO_BITS], 4, 0);
+}
+
+#define CVT(SRC_TYPE, DST_TYPE, DST_MIN, DST_MAX) do { \
+ SRC_TYPE sv; memmove(&sv, data, sizeof(SRC_TYPE)); \
+ DST_TYPE dv = (sv < DST_MIN) ? (DST_TYPE)DST_MIN : (DST_TYPE)(((DST_MAX < sv) ? DST_MAX : sv)); \
+ memmove(valuePtr, &dv, sizeof(DST_TYPE)); \
+ SRC_TYPE vv = (SRC_TYPE)dv; return (vv == sv); \
+ } while (0)
+
+#define CVT128ToInt(SRC_TYPE, DST_TYPE, DST_MIN, DST_MAX) do { \
+ SRC_TYPE sv; memmove(&sv, data, sizeof(SRC_TYPE)); \
+ DST_TYPE dv; Boolean noLoss = false; \
+ if (0 < sv.high || (0 == sv.high && (int64_t)DST_MAX < sv.low)) { \
+ dv = DST_MAX; \
+ } else if (sv.high < -1 || (-1 == sv.high && sv.low < (int64_t)DST_MIN)) { \
+ dv = DST_MIN; \
+ } else { \
+ dv = (DST_TYPE)sv.low; \
+ noLoss = true; \
+ } \
+ memmove(valuePtr, &dv, sizeof(DST_TYPE)); \
+ return noLoss; \
+ } while (0)
+
+// returns false if the output value is not the same as the number's value, which
+// can occur due to accuracy loss and the value not being within the target range
+static Boolean __CFNumberGetValue(CFNumberRef number, CFNumberType type, void *valuePtr) {
+ type = __CFNumberTypeTable[type].canonicalType;
+ CFNumberType ntype = __CFNumberGetType(number);
+ const void *data = &(number->_pad);
+ switch (type) {
+ case kCFNumberSInt8Type:
+ if (__CFNumberTypeTable[ntype].floatBit) {
+ if (0 == __CFNumberTypeTable[ntype].storageBit) {
+ CVT(Float32, int8_t, INT8_MIN, INT8_MAX);
+ } else {
+ CVT(Float64, int8_t, INT8_MIN, INT8_MAX);
+ }
+ } else {
+ if (0 == __CFNumberTypeTable[ntype].storageBit) {
+ CVT(int64_t, int8_t, INT8_MIN, INT8_MAX);
+ } else {
+ CVT128ToInt(CFSInt128Struct, int8_t, INT8_MIN, INT8_MAX);
+ }
+ }
+ return true;
+ case kCFNumberSInt16Type:
+ if (__CFNumberTypeTable[ntype].floatBit) {
+ if (0 == __CFNumberTypeTable[ntype].storageBit) {
+ CVT(Float32, int16_t, INT16_MIN, INT16_MAX);
+ } else {
+ CVT(Float64, int16_t, INT16_MIN, INT16_MAX);
+ }
+ } else {
+ if (0 == __CFNumberTypeTable[ntype].storageBit) {
+ CVT(int64_t, int16_t, INT16_MIN, INT16_MAX);
+ } else {
+ CVT128ToInt(CFSInt128Struct, int16_t, INT16_MIN, INT16_MAX);
+ }
+ }
+ return true;
+ case kCFNumberSInt32Type:
+ if (__CFNumberTypeTable[ntype].floatBit) {
+ if (0 == __CFNumberTypeTable[ntype].storageBit) {
+ CVT(Float32, int32_t, INT32_MIN, INT32_MAX);
+ } else {
+ CVT(Float64, int32_t, INT32_MIN, INT32_MAX);
+ }
+ } else {
+ if (0 == __CFNumberTypeTable[ntype].storageBit) {
+ CVT(int64_t, int32_t, INT32_MIN, INT32_MAX);
+ } else {
+ CVT128ToInt(CFSInt128Struct, int32_t, INT32_MIN, INT32_MAX);
+ }
+ }
+ return true;
+ case kCFNumberSInt64Type:
+ if (__CFNumberTypeTable[ntype].floatBit) {
+ if (0 == __CFNumberTypeTable[ntype].storageBit) {
+ CVT(Float32, int64_t, INT64_MIN, INT64_MAX);
+ } else {
+ CVT(Float64, int64_t, INT64_MIN, INT64_MAX);
+ }
+ } else {
+ if (0 == __CFNumberTypeTable[ntype].storageBit) {
+ memmove(valuePtr, data, 8);
+ } else {
+ CVT128ToInt(CFSInt128Struct, int64_t, INT64_MIN, INT64_MAX);
+ }
+ }
+ return true;
+ case kCFNumberSInt128Type:
+ if (__CFNumberTypeTable[ntype].floatBit) {
+ if (0 == __CFNumberTypeTable[ntype].storageBit) {
+ Float32 f;
+ memmove(&f, data, 4);
+ Float64 d = f;
+ CFSInt128Struct i;
+ cvtFloat64ToSInt128(&i, &d);
+ memmove(valuePtr, &i, 16);
+ Float64 d2;
+ cvtSInt128ToFloat64(&d2, &i);
+ Float32 f2 = (Float32)d2;
+ return (f2 == f);
+ } else {
+ Float64 d;
+ memmove(&d, data, 8);
+ CFSInt128Struct i;
+ cvtFloat64ToSInt128(&i, &d);
+ memmove(valuePtr, &i, 16);
+ Float64 d2;
+ cvtSInt128ToFloat64(&d2, &i);
+ return (d2 == d);
+ }
+ } else {
+ if (0 == __CFNumberTypeTable[ntype].storageBit) {
+ int64_t j;
+ memmove(&j, data, 8);
+ CFSInt128Struct i;
+ i.low = j;
+ i.high = (j < 0) ? -1LL : 0LL;
+ memmove(valuePtr, &i, 16);
+ } else {
+ memmove(valuePtr, data, 16);
+ }
+ }
+ return true;
+ case kCFNumberFloat32Type:
+ if (__CFNumberTypeTable[ntype].floatBit) {
+ if (0 == __CFNumberTypeTable[ntype].storageBit) {
+ memmove(valuePtr, data, 4);
+ } else {
+ double d;
+ memmove(&d, data, 8);
+ if (isnan(d)) {
+ uint32_t l = 0x7fc00000;
+ memmove(valuePtr, &l, 4);
+ return true;
+ } else if (isinf(d)) {
+ uint32_t l = 0x7f800000;
+ if (d < 0.0) l += 0x80000000UL;
+ memmove(valuePtr, &l, 4);
+ return true;
+ }
+ CVT(Float64, Float32, -FLT_MAX, FLT_MAX);
+ }
+ } else {
+ if (0 == __CFNumberTypeTable[ntype].storageBit) {
+ CVT(int64_t, Float32, -FLT_MAX, FLT_MAX);
+ } else {
+ CFSInt128Struct i;
+ memmove(&i, data, 16);
+ Float64 d;
+ cvtSInt128ToFloat64(&d, &i);
+ Float32 f = (Float32)d;
+ memmove(valuePtr, &f, 4);
+ d = f;
+ CFSInt128Struct i2;
+ cvtFloat64ToSInt128(&i2, &d);
+ return cmp128(&i2, &i) == kCFCompareEqualTo;
+ }
+ }
+ return true;
+ case kCFNumberFloat64Type:
+ if (__CFNumberTypeTable[ntype].floatBit) {
+ if (0 == __CFNumberTypeTable[ntype].storageBit) {
+ float f;
+ memmove(&f, data, 4);
+ if (isnan(f)) {
+ uint64_t l = BITSFORDOUBLENAN;
+ memmove(valuePtr, &l, 8);
+ return true;
+ } else if (isinf(f)) {
+ uint64_t l = BITSFORDOUBLEPOSINF;
+ if (f < 0.0) l += 0x8000000000000000ULL;
+ memmove(valuePtr, &l, 8);
+ return true;
+ }
+ CVT(Float32, Float64, -DBL_MAX, DBL_MAX);
+ } else {
+ memmove(valuePtr, data, 8);
+ }
+ } else {
+ if (0 == __CFNumberTypeTable[ntype].storageBit) {
+ CVT(int64_t, Float64, -DBL_MAX, DBL_MAX);
+ } else {
+ CFSInt128Struct i;
+ memmove(&i, data, 16);
+ Float64 d;
+ cvtSInt128ToFloat64(&d, &i);
+ memmove(valuePtr, &d, 8);
+ CFSInt128Struct i2;
+ cvtFloat64ToSInt128(&i2, &d);
+ return cmp128(&i2, &i) == kCFCompareEqualTo;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+#define CVT_COMPAT(SRC_TYPE, DST_TYPE, FT) do { \
+ SRC_TYPE sv; memmove(&sv, data, sizeof(SRC_TYPE)); \
+ DST_TYPE dv = (DST_TYPE)(sv); \
+ memmove(valuePtr, &dv, sizeof(DST_TYPE)); \
+ SRC_TYPE vv = (SRC_TYPE)dv; return (FT) || (vv == sv); \
+ } while (0)
+
+#define CVT128ToInt_COMPAT(SRC_TYPE, DST_TYPE) do { \
+ SRC_TYPE sv; memmove(&sv, data, sizeof(SRC_TYPE)); \
+ DST_TYPE dv; dv = (DST_TYPE)sv.low; \
+ memmove(valuePtr, &dv, sizeof(DST_TYPE)); \
+ uint64_t vv = (uint64_t)dv; return (vv == sv.low); \
+ } while (0)
+
+// this has the old cast-style behavior
+static Boolean __CFNumberGetValueCompat(CFNumberRef number, CFNumberType type, void *valuePtr) {
+ type = __CFNumberTypeTable[type].canonicalType;
+ CFNumberType ntype = __CFNumberGetType(number);
+ const void *data = &(number->_pad);
+ switch (type) {
+ case kCFNumberSInt8Type:
+ if (__CFNumberTypeTable[ntype].floatBit) {
+ if (0 == __CFNumberTypeTable[ntype].storageBit) {
+ CVT_COMPAT(Float32, int8_t, 0);
+ } else {
+ CVT_COMPAT(Float64, int8_t, 0);
+ }
+ } else {
+ if (0 == __CFNumberTypeTable[ntype].storageBit) {
+ CVT_COMPAT(int64_t, int8_t, 1);
+ } else {
+ CVT128ToInt_COMPAT(CFSInt128Struct, int8_t);
+ }
+ }
+ return true;
+ case kCFNumberSInt16Type:
+ if (__CFNumberTypeTable[ntype].floatBit) {
+ if (0 == __CFNumberTypeTable[ntype].storageBit) {
+ CVT_COMPAT(Float32, int16_t, 0);
+ } else {
+ CVT_COMPAT(Float64, int16_t, 0);
+ }
+ } else {
+ if (0 == __CFNumberTypeTable[ntype].storageBit) {
+ CVT_COMPAT(int64_t, int16_t, 1);
+ } else {
+ CVT128ToInt_COMPAT(CFSInt128Struct, int16_t);
+ }
+ }
+ return true;
+ case kCFNumberSInt32Type:
+ if (__CFNumberTypeTable[ntype].floatBit) {
+ if (0 == __CFNumberTypeTable[ntype].storageBit) {
+ CVT_COMPAT(Float32, int32_t, 0);
+ } else {
+ CVT_COMPAT(Float64, int32_t, 0);
+ }
+ } else {
+ if (0 == __CFNumberTypeTable[ntype].storageBit) {
+ CVT_COMPAT(int64_t, int32_t, 0);
+ } else {
+ CVT128ToInt_COMPAT(CFSInt128Struct, int32_t);
+ }
+ }
+ return true;
+ case kCFNumberSInt64Type:
+ if (__CFNumberTypeTable[ntype].floatBit) {
+ if (0 == __CFNumberTypeTable[ntype].storageBit) {
+ CVT_COMPAT(Float32, int64_t, 0);
+ } else {
+ CVT_COMPAT(Float64, int64_t, 0);
+ }
+ } else {
+ if (0 == __CFNumberTypeTable[ntype].storageBit) {
+ CVT_COMPAT(int64_t, int64_t, 0);
+ } else {
+ CVT128ToInt_COMPAT(CFSInt128Struct, int64_t);
+ }
+ }
+ return true;
+ case kCFNumberSInt128Type:
+ if (__CFNumberTypeTable[ntype].floatBit) {
+ if (0 == __CFNumberTypeTable[ntype].storageBit) {
+ Float32 f;
+ memmove(&f, data, 4);
+ Float64 d = f;
+ CFSInt128Struct i;
+ cvtFloat64ToSInt128(&i, &d);
+ memmove(valuePtr, &i, 16);
+ Float64 d2;
+ cvtSInt128ToFloat64(&d2, &i);
+ Float32 f2 = (Float32)d2;
+ return (f2 == f);
+ } else {
+ Float64 d;
+ memmove(&d, data, 8);
+ CFSInt128Struct i;
+ cvtFloat64ToSInt128(&i, &d);
+ memmove(valuePtr, &i, 16);
+ Float64 d2;
+ cvtSInt128ToFloat64(&d2, &i);
+ return (d2 == d);
+ }
+ } else {
+ if (0 == __CFNumberTypeTable[ntype].storageBit) {
+ int64_t j;
+ memmove(&j, data, 8);
+ CFSInt128Struct i;
+ i.low = j;
+ i.high = (j < 0) ? -1LL : 0LL;
+ memmove(valuePtr, &i, 16);
+ } else {
+ memmove(valuePtr, data, 16);
+ }
+ }
+ return true;
+ case kCFNumberFloat32Type:
+ if (__CFNumberTypeTable[ntype].floatBit) {
+ if (0 == __CFNumberTypeTable[ntype].storageBit) {
+ memmove(valuePtr, data, 4);
+ } else {
+ CVT_COMPAT(Float64, Float32, 0);
+ }
+ } else {
+ if (0 == __CFNumberTypeTable[ntype].storageBit) {
+ CVT_COMPAT(int64_t, Float32, 0);
+ } else {
+ CFSInt128Struct i;
+ memmove(&i, data, 16);
+ Float64 d;
+ cvtSInt128ToFloat64(&d, &i);
+ Float32 f = (Float32)d;
+ memmove(valuePtr, &f, 4);
+ d = f;
+ CFSInt128Struct i2;
+ cvtFloat64ToSInt128(&i2, &d);
+ return cmp128(&i2, &i) == kCFCompareEqualTo;
+ }
+ }
+ return true;
+ case kCFNumberFloat64Type:
+ if (__CFNumberTypeTable[ntype].floatBit) {
+ if (0 == __CFNumberTypeTable[ntype].storageBit) {
+ CVT_COMPAT(Float32, Float64, 0);
+ } else {
+ memmove(valuePtr, data, 8);
+ }
+ } else {
+ if (0 == __CFNumberTypeTable[ntype].storageBit) {
+ CVT_COMPAT(int64_t, Float64, 0);
+ } else {
+ CFSInt128Struct i;
+ memmove(&i, data, 16);
+ Float64 d;
+ cvtSInt128ToFloat64(&d, &i);
+ memmove(valuePtr, &d, 8);
+ CFSInt128Struct i2;
+ cvtFloat64ToSInt128(&i2, &d);
+ return cmp128(&i2, &i) == kCFCompareEqualTo;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+static CFStringRef __CFNumberCopyDescription(CFTypeRef cf) {
+ CFNumberRef number = (CFNumberRef)cf;
+ CFNumberType type = __CFNumberGetType(number);
+ CFMutableStringRef mstr = CFStringCreateMutable(kCFAllocatorSystemDefault, 0);
+ CFStringAppendFormat(mstr, NULL, CFSTR("<CFNumber %p [%p]>{value = "), cf, CFGetAllocator(cf));
+ if (__CFNumberTypeTable[type].floatBit) {
+ Float64 d;
+ __CFNumberGetValue(number, kCFNumberFloat64Type, &d);
+ if (isnan(d)) {
+ CFStringAppend(mstr, CFSTR("nan"));
+ } else if (isinf(d)) {
+ CFStringAppend(mstr, (0.0 < d) ? CFSTR("+infinity") : CFSTR("-infinity"));
+ } else if (0.0 == d) {
+ CFStringAppend(mstr, (copysign(1.0, d) < 0.0) ? CFSTR("-0.0") : CFSTR("+0.0"));
+ } else {
+ CFStringAppendFormat(mstr, NULL, CFSTR("%+.*f"), (__CFNumberTypeTable[type].storageBit ? 20 : 10), d);
+ }
+ const char *typeName = "unknown float";
+ switch (type) {
+ case kCFNumberFloat32Type: typeName = "kCFNumberFloat32Type"; break;
+ case kCFNumberFloat64Type: typeName = "kCFNumberFloat64Type"; break;
+ }
+ CFStringAppendFormat(mstr, NULL, CFSTR(", type = %s}"), typeName);
+ } else {
+ CFSInt128Struct i;
+ __CFNumberGetValue(number, kCFNumberSInt128Type, &i);
+ char buffer[128];
+ emit128(buffer, &i, true);
+ const char *typeName = "unknown integer";
+ switch (type) {
+ case kCFNumberSInt8Type: typeName = "kCFNumberSInt8Type"; break;
+ case kCFNumberSInt16Type: typeName = "kCFNumberSInt16Type"; break;
+ case kCFNumberSInt32Type: typeName = "kCFNumberSInt32Type"; break;
+ case kCFNumberSInt64Type: typeName = "kCFNumberSInt64Type"; break;
+ case kCFNumberSInt128Type: typeName = "kCFNumberSInt128Type"; break;
+ }
+ CFStringAppendFormat(mstr, NULL, CFSTR("%s, type = %s}"), buffer, typeName);
+ }
+ return mstr;
+}
+
+// This function separated out from __CFNumberCopyFormattingDescription() so the plist creation can use it as well.
+
+static CFStringRef __CFNumberCopyFormattingDescriptionAsFloat64_new(CFTypeRef cf) {
+ Float64 d;
+ CFNumberGetValue((CFNumberRef)cf, kCFNumberFloat64Type, &d);
+ if (isnan(d)) {
+ return (CFStringRef)CFRetain(CFSTR("nan"));
+ }
+ if (isinf(d)) {
+ return (CFStringRef)CFRetain((0.0 < d) ? CFSTR("+infinity") : CFSTR("-infinity"));
+ }
+ if (0.0 == d) {
+ return (CFStringRef)CFRetain(CFSTR("0.0"));
+ }
+ // if %g is used here, need to use DBL_DIG + 2 on Mac OS X, but %f needs +1
+ return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%.*g"), DBL_DIG + 2, d);
+}
+
+__private_extern__ CFStringRef __CFNumberCopyFormattingDescriptionAsFloat64(CFTypeRef cf) {
+ CFStringRef result = __CFNumberCopyFormattingDescriptionAsFloat64_new(cf);
+ return result;
+}
+
+static CFStringRef __CFNumberCopyFormattingDescription_new(CFTypeRef cf, CFDictionaryRef formatOptions) {
+ CFNumberRef number = (CFNumberRef)cf;
+ CFNumberType type = __CFNumberGetType(number);
+ if (__CFNumberTypeTable[type].floatBit) {
+ return __CFNumberCopyFormattingDescriptionAsFloat64(number);
+ }
+ CFSInt128Struct i;
+ __CFNumberGetValue(number, kCFNumberSInt128Type, &i);
+ char buffer[128];
+ emit128(buffer, &i, false);
+ return CFStringCreateWithFormat(kCFAllocatorSystemDefault, NULL, CFSTR("%s"), buffer);
+}
+
+static CFStringRef __CFNumberCopyFormattingDescription(CFTypeRef cf, CFDictionaryRef formatOptions) {
+ CFStringRef result = __CFNumberCopyFormattingDescription_new(cf, formatOptions);
+ return result;
+}
+
+
+static Boolean __CFNumberEqual(CFTypeRef cf1, CFTypeRef cf2) {
+ Boolean b = CFNumberCompare((CFNumberRef)cf1, (CFNumberRef)cf2, 0) == kCFCompareEqualTo;
+ return b;
+}
+
+static CFHashCode __CFNumberHash(CFTypeRef cf) {
+ CFHashCode h;
+ CFNumberRef number = (CFNumberRef)cf;
+ switch (__CFNumberGetType(number)) {
+ case kCFNumberSInt8Type:
+ case kCFNumberSInt16Type:
+ case kCFNumberSInt32Type: {
+ SInt32 i;
+ __CFNumberGetValue(number, kCFNumberSInt32Type, &i);
+ h = _CFHashInt(i);
+ break;
+ }
+ default: {
+ Float64 d;
+ __CFNumberGetValue(number, kCFNumberFloat64Type, &d);
+ h = _CFHashDouble((double)d);
+ break;
+ }
+ }
+ return h;
+}
+
+static CFTypeID __kCFNumberTypeID = _kCFRuntimeNotATypeID;
+
+static const CFRuntimeClass __CFNumberClass = {
+ 0,
+ "CFNumber",
+ NULL, // init
+ NULL, // copy
+ NULL,
+ __CFNumberEqual,
+ __CFNumberHash,
+ __CFNumberCopyFormattingDescription,
+ __CFNumberCopyDescription
+};
+
+__private_extern__ void __CFNumberInitialize(void) {
+ __kCFNumberTypeID = _CFRuntimeRegisterClass(&__CFNumberClass);
+
+ _CFRuntimeSetInstanceTypeID(&__kCFNumberNaN, __kCFNumberTypeID);
+ __kCFNumberNaN._base._cfisa = __CFISAForTypeID(__kCFNumberTypeID);
+ __CFBitfieldSetValue(__kCFNumberNaN._base._cfinfo[CF_INFO_BITS], 4, 0, kCFNumberFloat64Type);
+ __kCFNumberNaN._pad = BITSFORDOUBLENAN;
+
+ _CFRuntimeSetInstanceTypeID(& __kCFNumberNegativeInfinity, __kCFNumberTypeID);
+ __kCFNumberNegativeInfinity._base._cfisa = __CFISAForTypeID(__kCFNumberTypeID);
+ __CFBitfieldSetValue(__kCFNumberNegativeInfinity._base._cfinfo[CF_INFO_BITS], 4, 0, kCFNumberFloat64Type);
+ __kCFNumberNegativeInfinity._pad = BITSFORDOUBLENEGINF;
+
+ _CFRuntimeSetInstanceTypeID(& __kCFNumberPositiveInfinity, __kCFNumberTypeID);
+ __kCFNumberPositiveInfinity._base._cfisa = __CFISAForTypeID(__kCFNumberTypeID);
+ __CFBitfieldSetValue(__kCFNumberPositiveInfinity._base._cfinfo[CF_INFO_BITS], 4, 0, kCFNumberFloat64Type);
+ __kCFNumberPositiveInfinity._pad = BITSFORDOUBLEPOSINF;
+}
+
+CFTypeID CFNumberGetTypeID(void) {
+ return __kCFNumberTypeID;
+}
+
+#define MinCachedInt (-1)
+#define MaxCachedInt (12)
+#define NotToBeCached (MinCachedInt - 1)
+static CFNumberRef __CFNumberCache[MaxCachedInt - MinCachedInt + 1] = {NULL}; // Storing CFNumberRefs for range MinCachedInt..MaxCachedInt
+
+CFNumberRef CFNumberCreate(CFAllocatorRef allocator, CFNumberType type, const void *valuePtr) {
+ __CFAssertIsValidNumberType(type);
+//printf("+ [%p] CFNumberCreate(%p, %d, %p)\n", pthread_self(), allocator, type, valuePtr);
+
+ // Look for cases where we can return a cached instance.
+ // We only use cached objects if the allocator is the system
+ // default allocator, except for the special floating point
+ // constant objects, where we return the cached object
+ // regardless of allocator, since that is what has always
+ // been done (and now must for compatibility).
+ if (!allocator) allocator = __CFGetDefaultAllocator();
+ int64_t valToBeCached = NotToBeCached;
+
+ if (__CFNumberTypeTable[type].floatBit) {
+ CFNumberRef cached = NULL;
+ if (0 == __CFNumberTypeTable[type].storageBit) {
+ Float32 f = *(Float32 *)valuePtr;
+ if (isnan(f)) cached = kCFNumberNaN;
+ if (isinf(f)) cached = (f < 0.0) ? kCFNumberNegativeInfinity : kCFNumberPositiveInfinity;
+ } else {
+ Float64 d = *(Float64 *)valuePtr;
+ if (isnan(d)) cached = kCFNumberNaN;
+ if (isinf(d)) cached = (d < 0.0) ? kCFNumberNegativeInfinity : kCFNumberPositiveInfinity;
+ }
+ if (cached) return (CFNumberRef)CFRetain(cached);
+ } else if (kCFAllocatorSystemDefault == allocator) {
+ switch (__CFNumberTypeTable[type].canonicalType) {
+ case kCFNumberSInt8Type: {int8_t val = *(int8_t *)valuePtr; if (MinCachedInt <= val && val <= MaxCachedInt) valToBeCached = (int64_t)val; break;}
+ case kCFNumberSInt16Type: {int16_t val = *(int16_t *)valuePtr; if (MinCachedInt <= val && val <= MaxCachedInt) valToBeCached = (int64_t)val; break;}
+ case kCFNumberSInt32Type: {int32_t val = *(int32_t *)valuePtr; if (MinCachedInt <= val && val <= MaxCachedInt) valToBeCached = (int64_t)val; break;}
+ case kCFNumberSInt64Type: {int64_t val = *(int64_t *)valuePtr; if (MinCachedInt <= val && val <= MaxCachedInt) valToBeCached = (int64_t)val; break;}
+ }
+ if (NotToBeCached != valToBeCached) {
+ CFNumberRef cached = __CFNumberCache[valToBeCached - MinCachedInt]; // Atomic to access the value in the cache
+ if (NULL != cached) return (CFNumberRef)CFRetain(cached);
+ }
+ }
+
+ CFIndex size = 8 + ((!__CFNumberTypeTable[type].floatBit && __CFNumberTypeTable[type].storageBit) ? 8 : 0);
+ CFNumberRef result = (CFNumberRef)_CFRuntimeCreateInstance(allocator, __kCFNumberTypeID, size, NULL);
+ if (NULL == result) {
+ return NULL;
+ }
+ __CFBitfieldSetValue(((struct __CFNumber *)result)->_base._cfinfo[CF_INFO_BITS], 4, 0, (uint8_t)__CFNumberTypeTable[type].canonicalType);
+
+
+ // for a value to be cached, we already have the value handy
+ if (NotToBeCached != valToBeCached) {
+ memmove((void *)&result->_pad, &valToBeCached, 8);
+ // 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.
+ // 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.
+ // Barrier assures that the number that is placed in the cache is properly formed.
+ CFNumberType origType = __CFNumberGetType(result);
+ // Force all cached numbers to have the same type, so that the type does not
+ // depend on the order and original type in/with which the numbers are created.
+ // Forcing the type AFTER it was cached would cause a race condition with other
+ // threads pulling the number object out of the cache and using it.
+ __CFBitfieldSetValue(((struct __CFNumber *)result)->_base._cfinfo[CF_INFO_BITS], 4, 0, (uint8_t)kCFNumberSInt32Type);
+ if (OSAtomicCompareAndSwapPtrBarrier(NULL, (void *)result, (void *volatile *)&__CFNumberCache[valToBeCached - MinCachedInt])) {
+ CFRetain(result);
+ } else {
+ // Did not cache the number object, put original type back.
+ __CFBitfieldSetValue(((struct __CFNumber *)result)->_base._cfinfo[CF_INFO_BITS], 4, 0, (uint8_t)origType);
+ }
+ return result;
+ }
+
+ uint64_t value;
+ switch (__CFNumberTypeTable[type].canonicalType) {
+ case kCFNumberSInt8Type: value = (uint64_t)(int64_t)*(int8_t *)valuePtr; goto smallVal;
+ case kCFNumberSInt16Type: value = (uint64_t)(int64_t)*(int16_t *)valuePtr; goto smallVal;
+ case kCFNumberSInt32Type: value = (uint64_t)(int64_t)*(int32_t *)valuePtr; goto smallVal;
+ smallVal: memmove((void *)&result->_pad, &value, 8); break;
+ case kCFNumberSInt64Type: memmove((void *)&result->_pad, valuePtr, 8); break;
+ case kCFNumberSInt128Type: memmove((void *)&result->_pad, valuePtr, 16); break;
+ case kCFNumberFloat32Type: memmove((void *)&result->_pad, valuePtr, 4); break;
+ case kCFNumberFloat64Type: memmove((void *)&result->_pad, valuePtr, 8); break;
+ }
+//printf(" => %p\n", result);
+ return result;
+}
+
+CFNumberType CFNumberGetType(CFNumberRef number) {
+//printf("+ [%p] CFNumberGetType(%p)\n", pthread_self(), number);
+ CF_OBJC_FUNCDISPATCH0(__kCFNumberTypeID, CFNumberType, number, "_cfNumberType");
+ __CFAssertIsNumber(number);
+ CFNumberType type = __CFNumberGetType(number);
+ if (kCFNumberSInt128Type == type) type = kCFNumberSInt64Type; // must hide this type, since it is not public
+//printf(" => %d\n", type);
+ return type;
+}
+
+CFNumberType _CFNumberGetType2(CFNumberRef number) {
+ __CFAssertIsNumber(number);
+ return __CFNumberGetType(number);
+}
+
+CFIndex CFNumberGetByteSize(CFNumberRef number) {
+//printf("+ [%p] CFNumberGetByteSize(%p)\n", pthread_self(), number);
+ __CFAssertIsNumber(number);
+ CFIndex r = 1 << __CFNumberTypeTable[CFNumberGetType(number)].lgByteSize;
+//printf(" => %d\n", r);
+ return r;
+}
+
+Boolean CFNumberIsFloatType(CFNumberRef number) {
+//printf("+ [%p] CFNumberIsFloatType(%p)\n", pthread_self(), number);
+ __CFAssertIsNumber(number);
+ Boolean r = __CFNumberTypeTable[CFNumberGetType(number)].floatBit;
+//printf(" => %d\n", r);
+ return r;
+}
+
+Boolean CFNumberGetValue(CFNumberRef number, CFNumberType type, void *valuePtr) {
+//printf("+ [%p] CFNumberGetValue(%p, %d, %p)\n", pthread_self(), number, type, valuePtr);
+ CF_OBJC_FUNCDISPATCH2(__kCFNumberTypeID, Boolean, number, "_getValue:forType:", valuePtr, __CFNumberTypeTable[type].canonicalType);
+ __CFAssertIsNumber(number);
+ __CFAssertIsValidNumberType(type);
+ uint8_t localMemory[128];
+ Boolean r = __CFNumberGetValueCompat(number, type, valuePtr ? valuePtr : localMemory);
+//printf(" => %d\n", r);
+ return r;
+}
+
+static CFComparisonResult CFNumberCompare_new(CFNumberRef number1, CFNumberRef number2, void *context) {
+ CF_OBJC_FUNCDISPATCH1(__kCFNumberTypeID, CFComparisonResult, number1, "compare:", number2);
+ CF_OBJC_FUNCDISPATCH1(__kCFNumberTypeID, CFComparisonResult, number2, "_reverseCompare:", number1);
+ __CFAssertIsNumber(number1);
+ __CFAssertIsNumber(number2);
+
+ CFNumberType type1 = __CFNumberGetType(number1);
+ CFNumberType type2 = __CFNumberGetType(number2);
+ // Both numbers are integers
+ if (!__CFNumberTypeTable[type1].floatBit && !__CFNumberTypeTable[type2].floatBit) {
+ CFSInt128Struct i1, i2;
+ __CFNumberGetValue(number1, kCFNumberSInt128Type, &i1);
+ __CFNumberGetValue(number2, kCFNumberSInt128Type, &i2);
+ return cmp128(&i1, &i2);
+ }
+ // Both numbers are floats
+ if (__CFNumberTypeTable[type1].floatBit && __CFNumberTypeTable[type2].floatBit) {
+ Float64 d1, d2;
+ __CFNumberGetValue(number1, kCFNumberFloat64Type, &d1);
+ __CFNumberGetValue(number2, kCFNumberFloat64Type, &d2);
+ double s1 = copysign(1.0, d1);
+ double s2 = copysign(1.0, d2);
+ if (isnan(d1) && isnan(d2)) return kCFCompareEqualTo;
+ if (isnan(d1)) return (s2 < 0.0) ? kCFCompareGreaterThan : kCFCompareLessThan;
+ if (isnan(d2)) return (s1 < 0.0) ? kCFCompareLessThan : kCFCompareGreaterThan;
+ // at this point, we know we don't have any NaNs
+ if (s1 < s2) return kCFCompareLessThan;
+ if (s2 < s1) return kCFCompareGreaterThan;
+ // at this point, we know the signs are the same; do not combine these tests
+ if (d1 < d2) return kCFCompareLessThan;
+ if (d2 < d1) return kCFCompareGreaterThan;
+ return kCFCompareEqualTo;
+ }
+ // One float, one integer; swap if necessary so number1 is the float
+ Boolean swapResult = false;
+ if (__CFNumberTypeTable[type2].floatBit) {
+ CFNumberRef tmp = number1;
+ number1 = number2;
+ number2 = tmp;
+ swapResult = true;
+ }
+ // At large integer values, the precision of double is quite low
+ // e.g. all values roughly 2^127 +- 2^73 are represented by 1 double, 2^127.
+ // If we just used double compare, that would make the 2^73 largest 128-bit
+ // integers look equal, so we have to use integer comparison when possible.
+ Float64 d1, d2;
+ __CFNumberGetValue(number1, kCFNumberFloat64Type, &d1);
+ // if the double value is really big, cannot be equal to integer
+ // nan d1 will not compare true here
+ if (d1 < FLOAT_NEGATIVE_2_TO_THE_127) {
+ return !swapResult ? kCFCompareLessThan : kCFCompareGreaterThan;
+ }
+ if (FLOAT_POSITIVE_2_TO_THE_127 <= d1) {
+ return !swapResult ? kCFCompareGreaterThan : kCFCompareLessThan;
+ }
+ CFSInt128Struct i1, i2;
+ __CFNumberGetValue(number1, kCFNumberSInt128Type, &i1);
+ __CFNumberGetValue(number2, kCFNumberSInt128Type, &i2);
+ CFComparisonResult res = cmp128(&i1, &i2);
+ if (kCFCompareEqualTo != res) {
+ return !swapResult ? res : -res;
+ }
+ // now things are equal, but perhaps due to rounding or nan
+ if (isnan(d1)) {
+ if (isNeg128(&i2)) {
+ return !swapResult ? kCFCompareGreaterThan : kCFCompareLessThan;
+ }
+ // nan compares less than positive 0 too
+ return !swapResult ? kCFCompareLessThan : kCFCompareGreaterThan;
+ }
+ // at this point, we know we don't have NaN
+ double s1 = copysign(1.0, d1);
+ double s2 = isNeg128(&i2) ? -1.0 : 1.0;
+ if (s1 < s2) return !swapResult ? kCFCompareLessThan : kCFCompareGreaterThan;
+ if (s2 < s1) return !swapResult ? kCFCompareGreaterThan : kCFCompareLessThan;
+ // at this point, we know the signs are the same; do not combine these tests
+ __CFNumberGetValue(number2, kCFNumberFloat64Type, &d2);
+ if (d1 < d2) return !swapResult ? kCFCompareLessThan : kCFCompareGreaterThan;
+ if (d2 < d1) return !swapResult ? kCFCompareGreaterThan : kCFCompareLessThan;
+ return kCFCompareEqualTo;
+}
+
+CFComparisonResult CFNumberCompare(CFNumberRef number1, CFNumberRef number2, void *context) {
+//printf("+ [%p] CFNumberCompare(%p, %p, %p)\n", pthread_self(), number1, number2, context);
+ CFComparisonResult r = CFNumberCompare_new(number1, number2, context);
+//printf(" => %d\n", r);
+ return r;
+}
+
+#undef __CFAssertIsBoolean
+#undef __CFAssertIsNumber
+#undef __CFAssertIsValidNumberType
+#undef BITSFORDOUBLENAN
+#undef BITSFORDOUBLEPOSINF
+#undef BITSFORDOUBLENEGINF
+#undef MinCachedInt
+#undef MaxCachedInt
+#undef NotToBeCached
+