]> git.saurik.com Git - apple/cf.git/blobdiff - CFNumber.c
CF-476.10.tar.gz
[apple/cf.git] / CFNumber.c
diff --git a/CFNumber.c b/CFNumber.c
new file mode 100644 (file)
index 0000000..b185dc4
--- /dev/null
@@ -0,0 +1,1115 @@
+/*
+ * 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
+