]> git.saurik.com Git - apple/cf.git/blobdiff - Collections.subproj/CFStorage.c
CF-476.10.tar.gz
[apple/cf.git] / Collections.subproj / CFStorage.c
diff --git a/Collections.subproj/CFStorage.c b/Collections.subproj/CFStorage.c
deleted file mode 100644 (file)
index 35b4b6e..0000000
+++ /dev/null
@@ -1,659 +0,0 @@
-/*
- * Copyright (c) 2005 Apple Computer, 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@
- */
-/*     CFStorage.c
-       Copyright 1999-2002, Apple, Inc. All rights reserved.
-       Responsibility: Ali Ozer
-*/
-
-/*
-2-3 tree storing arbitrary sized values.
-??? Currently elementSize cannot be greater than storage->maxLeafCapacity, which is less than or equal to __CFStorageMaxLeafCapacity
-*/
-
-#include "CFStorage.h"
-#include "CFInternal.h"
-
-#if defined(__MACH__)
-#include <mach/mach.h>
-#else
-enum {
-    vm_page_size = 4096
-};
-#endif
-
-enum {
-    __CFStorageMaxLeafCapacity = 65536
-};
-
-#define COPYMEM(src,dst,n) CF_WRITE_BARRIER_MEMMOVE((dst), (src), (n))
-#define PAGE_LIMIT ((CFIndex)vm_page_size / 2)
-
-CF_INLINE int roundToPage(int num) {
-    return (num + vm_page_size - 1) & ~(vm_page_size - 1);
-}
-
-typedef struct __CFStorageNode {
-    CFIndex numBytes;  /* Number of actual bytes in this node and all its children */
-    bool isLeaf;
-    union {
-        struct {
-            CFIndex capacityInBytes;   // capacityInBytes is capacity of memory; this is either 0, or >= numBytes
-            uint8_t *memory;
-        } leaf;
-        struct {
-            struct __CFStorageNode *child[3];
-        } notLeaf;
-    } info;
-} CFStorageNode;
-
-struct __CFStorage {
-    CFRuntimeBase base;
-    CFIndex valueSize;
-    CFRange cachedRange;       // In terms of values, not bytes
-    CFStorageNode *cachedNode; // If cachedRange is valid, then either this or
-    uint8_t *cachedNodeMemory; //    this should be non-NULL
-    CFIndex maxLeafCapacity;   // In terms of bytes
-    CFStorageNode rootNode;
-    CFOptionFlags nodeHint;    // auto_memory_type_t, AUTO_MEMORY_SCANNED or AUTO_MEMORY_UNSCANNED.
-};
-
-/* Allocates the memory and initializes the capacity in a leaf. __CFStorageAllocLeafNodeMemory() is the entry point; __CFStorageAllocLeafNodeMemoryAux is called if actual reallocation is needed.
-*/
-static void __CFStorageAllocLeafNodeMemoryAux(CFAllocatorRef allocator, CFStorageRef storage, CFStorageNode *node, CFIndex cap) {
-    CF_WRITE_BARRIER_ASSIGN(allocator, node->info.leaf.memory, _CFAllocatorReallocateGC(allocator, node->info.leaf.memory, cap, storage->nodeHint));   // This will free... ??? Use allocator
-    if (__CFOASafe) __CFSetLastAllocationEventName(node->info.leaf.memory, "CFStorage (node bytes)");
-    node->info.leaf.capacityInBytes = cap;
-}
-
-CF_INLINE void __CFStorageAllocLeafNodeMemory(CFAllocatorRef allocator, CFStorageRef storage, CFStorageNode *node, CFIndex cap, bool compact) {
-    if (cap > PAGE_LIMIT) {
-        cap = roundToPage(cap);
-       if (cap > storage->maxLeafCapacity) cap = storage->maxLeafCapacity;
-    } else {
-        cap = (((cap + 63) / 64) * 64);
-    }
-    if (compact ? (cap != node->info.leaf.capacityInBytes) : (cap > node->info.leaf.capacityInBytes)) __CFStorageAllocLeafNodeMemoryAux(allocator, storage, node, cap);
-}
-
-/* Sets the cache to point at the specified node or memory. loc and len are in terms of values, not bytes. To clear the cache set these two to 0.
-   At least one of node or memory should be non-NULL. memory is consulted first when using the cache.
-*/
-CF_INLINE void __CFStorageSetCache(CFStorageRef storage, CFStorageNode *node, uint8_t *memory, CFIndex loc, CFIndex len) {
-    CFAllocatorRef allocator = __CFGetAllocator(storage);
-    storage->cachedRange.location = loc;
-    storage->cachedRange.length = len;
-    CF_WRITE_BARRIER_BASE_ASSIGN(allocator, storage, storage->cachedNode, node);
-    CF_WRITE_BARRIER_BASE_ASSIGN(allocator, storage, storage->cachedNodeMemory, memory);
-}
-
-/* Gets the location for the specified absolute loc from the cached info; call only after verifying that the cache is OK to use.
-   Note that we assume if !storage->cachedNodeMemory, then storage->cachedNode must be non-NULL.
-   However, it is possible to have storage->cachedNodeMemory without storage->cachedNode.  We check the memory before node.
-*/
-CF_INLINE uint8_t *__CFStorageGetFromCache(CFStorageRef storage, CFIndex loc) {
-    if (!storage->cachedNodeMemory && !(storage->cachedNodeMemory = storage->cachedNode->info.leaf.memory)) {
-        CFAllocatorRef allocator = CFGetAllocator(storage);
-        __CFStorageAllocLeafNodeMemory(allocator, storage, storage->cachedNode, storage->cachedNode->numBytes, false);
-        CF_WRITE_BARRIER_BASE_ASSIGN(allocator, storage, storage->cachedNodeMemory, storage->cachedNode->info.leaf.memory);
-    }
-    return storage->cachedNodeMemory + (loc - storage->cachedRange.location) * storage->valueSize;
-}
-
-/* Returns the number of the child containing the desired value and the relative index of the value in that child.
-   forInsertion = true means that we are looking for the child in which to insert; this changes the behavior when the index is at the end of a child
-   relativeByteNum (not optional, for performance reasons) returns the relative byte number of the specified byte in the child.
-   Don't call with leaf nodes!
-*/
-CF_INLINE void __CFStorageFindChild(CFStorageNode *node, CFIndex byteNum, bool forInsertion, CFIndex *childNum, CFIndex *relativeByteNum) {
-    if (forInsertion) byteNum--;       /* If for insertion, we do <= checks, not <, so this accomplishes the same thing */
-    if (byteNum < node->info.notLeaf.child[0]->numBytes) *childNum = 0;
-    else {
-        byteNum -= node->info.notLeaf.child[0]->numBytes;
-        if (byteNum < node->info.notLeaf.child[1]->numBytes) *childNum = 1;
-        else {
-            byteNum -= node->info.notLeaf.child[1]->numBytes;
-            *childNum = 2;
-        }
-    }
-    if (forInsertion) byteNum++;
-    *relativeByteNum = byteNum;
-}
-
-/* Finds the location where the specified byte is stored. If validConsecutiveByteRange is not NULL, returns
-   the range of bytes that are consecutive with this one.
-   !!! Assumes the byteNum is within the range of this node.
-*/
-static void *__CFStorageFindByte(CFStorageRef storage, CFStorageNode *node, CFIndex byteNum, CFRange *validConsecutiveByteRange) {
-    if (node->isLeaf) {
-        if (validConsecutiveByteRange) *validConsecutiveByteRange = CFRangeMake(0, node->numBytes);
-        __CFStorageAllocLeafNodeMemory(CFGetAllocator(storage), storage, node, node->numBytes, false);
-        return node->info.leaf.memory + byteNum; 
-    } else {
-        void *result;
-        CFIndex childNum;
-        CFIndex relativeByteNum;
-        __CFStorageFindChild(node, byteNum, false, &childNum, &relativeByteNum);
-        result = __CFStorageFindByte(storage, node->info.notLeaf.child[childNum], relativeByteNum, validConsecutiveByteRange);
-        if (validConsecutiveByteRange) {
-            if (childNum > 0) validConsecutiveByteRange->location += node->info.notLeaf.child[0]->numBytes;
-            if (childNum > 1) validConsecutiveByteRange->location += node->info.notLeaf.child[1]->numBytes;
-        }
-        return result;
-    }
-}
-
-/* Guts of CFStorageGetValueAtIndex(); note that validConsecutiveValueRange is not optional.
-   Consults and updates cache.
-*/
-CF_INLINE void *__CFStorageGetValueAtIndex(CFStorageRef storage, CFIndex idx, CFRange *validConsecutiveValueRange) {
-    uint8_t *result;
-    if (idx < storage->cachedRange.location + storage->cachedRange.length && idx >= storage->cachedRange.location) {
-        result = __CFStorageGetFromCache(storage, idx);
-    } else {
-        CFRange range;
-        result = __CFStorageFindByte(storage, &storage->rootNode, idx * storage->valueSize, &range);
-        __CFStorageSetCache(storage, NULL, result - (idx * storage->valueSize - range.location), range.location / storage->valueSize, range.length / storage->valueSize);
-    }
-    *validConsecutiveValueRange = storage->cachedRange;
-    return result;
-}
-
-static CFStorageNode *__CFStorageCreateNode(CFAllocatorRef allocator, bool isLeaf, CFIndex numBytes) {
-    CFStorageNode *newNode = _CFAllocatorAllocateGC(allocator, sizeof(CFStorageNode), 0);
-    if (__CFOASafe) __CFSetLastAllocationEventName(newNode, "CFStorage (node)");
-    newNode->isLeaf = isLeaf;
-    newNode->numBytes = numBytes;
-    if (isLeaf) {
-        newNode->info.leaf.capacityInBytes = 0;
-        newNode->info.leaf.memory = NULL;
-    } else {
-        newNode->info.notLeaf.child[0] = newNode->info.notLeaf.child[1] = newNode->info.notLeaf.child[2] = NULL;
-    }
-    return newNode;
-}
-
-static void __CFStorageNodeDealloc(CFAllocatorRef allocator, CFStorageNode *node, bool freeNodeItself) {
-    if (node->isLeaf) {
-        _CFAllocatorDeallocateGC(allocator, node->info.leaf.memory);
-    } else {
-        int cnt;
-        for (cnt = 0; cnt < 3; cnt++) if (node->info.notLeaf.child[cnt]) __CFStorageNodeDealloc(allocator, node->info.notLeaf.child[cnt], true);
-    }
-    if (freeNodeItself) _CFAllocatorDeallocateGC(allocator, node);
-}
-
-static CFIndex __CFStorageGetNumChildren(CFStorageNode *node) {
-    if (!node || node->isLeaf) return 0;
-    if (node->info.notLeaf.child[2]) return 3;
-    if (node->info.notLeaf.child[1]) return 2;
-    if (node->info.notLeaf.child[0]) return 1;
-    return 0;
-}
-
-/* The boolean compact indicates whether leaf nodes that get smaller should be realloced.
-*/
-static void __CFStorageDelete(CFAllocatorRef allocator, CFStorageRef storage, CFStorageNode *node, CFRange range, bool compact) {
-    if (node->isLeaf) {
-       node->numBytes -= range.length;
-        // If this node had memory allocated, readjust the bytes...
-       if (node->info.leaf.memory) {
-            COPYMEM(node->info.leaf.memory + range.location + range.length, node->info.leaf.memory + range.location, node->numBytes - range.location);
-           if (compact) __CFStorageAllocLeafNodeMemory(allocator, storage, node, node->numBytes, true);
-       }
-   } else {
-        bool childrenAreLeaves = node->info.notLeaf.child[0]->isLeaf;
-       node->numBytes -= range.length;
-       while (range.length > 0) {
-            CFRange rangeToDelete;
-            CFIndex relativeByteNum;
-            CFIndex childNum;
-            __CFStorageFindChild(node, range.location + range.length, true, &childNum, &relativeByteNum);
-            if (range.length > relativeByteNum) {
-                rangeToDelete.length = relativeByteNum;
-                rangeToDelete.location = 0;
-            } else {
-                rangeToDelete.length = range.length;
-                rangeToDelete.location = relativeByteNum - range.length;
-            }
-            __CFStorageDelete(allocator, storage, node->info.notLeaf.child[childNum], rangeToDelete, compact);
-            if (node->info.notLeaf.child[childNum]->numBytes == 0) {           // Delete empty node and compact
-                int cnt;
-                _CFAllocatorDeallocateGC(allocator, node->info.notLeaf.child[childNum]);
-                for (cnt = childNum; cnt < 2; cnt++) {
-                    CF_WRITE_BARRIER_ASSIGN(allocator, node->info.notLeaf.child[cnt], node->info.notLeaf.child[cnt+1]);
-                }
-                node->info.notLeaf.child[2] = NULL;
-            }
-           range.length -= rangeToDelete.length;
-       }
-        // At this point the remaining children are packed
-        if (childrenAreLeaves) {
-            // Children are leaves; if their total bytes is smaller than a leaf's worth, collapse into one...
-            if (node->numBytes > 0 && node->numBytes <= storage->maxLeafCapacity) {
-                __CFStorageAllocLeafNodeMemory(allocator, storage, node->info.notLeaf.child[0], node->numBytes, false);
-                if (node->info.notLeaf.child[1] && node->info.notLeaf.child[1]->numBytes) {
-                    COPYMEM(node->info.notLeaf.child[1]->info.leaf.memory, node->info.notLeaf.child[0]->info.leaf.memory + node->info.notLeaf.child[0]->numBytes, node->info.notLeaf.child[1]->numBytes);
-                    if (node->info.notLeaf.child[2] && node->info.notLeaf.child[2]->numBytes) {
-                        COPYMEM(node->info.notLeaf.child[2]->info.leaf.memory, node->info.notLeaf.child[0]->info.leaf.memory + node->info.notLeaf.child[0]->numBytes + node->info.notLeaf.child[1]->numBytes, node->info.notLeaf.child[2]->numBytes);
-                        __CFStorageNodeDealloc(allocator, node->info.notLeaf.child[2], true);
-                        node->info.notLeaf.child[2] = NULL;
-                    }
-                    __CFStorageNodeDealloc(allocator, node->info.notLeaf.child[1], true);
-                    node->info.notLeaf.child[1] = NULL;
-                }
-                node->info.notLeaf.child[0]->numBytes = node->numBytes;
-            }
-        } else {
-            // Children are not leaves; combine their children to assure each node has 2 or 3 children...
-           // (Could try to bypass all this by noting up above whether the number of grandchildren changed...)
-            CFStorageNode *gChildren[9];
-            CFIndex cCnt, gCnt, cnt;
-            CFIndex totalG = 0;        // Total number of grandchildren
-            for (cCnt = 0; cCnt < 3; cCnt++) {
-                CFStorageNode *child = node->info.notLeaf.child[cCnt];
-                if (child) {
-                   for (gCnt = 0; gCnt < 3; gCnt++) if (child->info.notLeaf.child[gCnt]) {
-                        gChildren[totalG++] = child->info.notLeaf.child[gCnt];
-                        child->info.notLeaf.child[gCnt] = NULL;
-                    }
-                   child->numBytes = 0;
-               }
-            }
-            gCnt = 0;  // Total number of grandchildren placed
-           for (cCnt = 0; cCnt < 3; cCnt++) {
-                // These tables indicate how many children each child should have, given the total number of grandchildren (last child gets remainder)
-                static const unsigned char forChild0[10] = {0, 1, 2, 3, 2, 3, 3, 3, 3, 3};
-                static const unsigned char forChild1[10] = {0, 0, 0, 0, 2, 2, 3, 2, 3, 3};
-               // sCnt is the number of grandchildren to be placed into child cCnt
-               // Depending on child number, pick the right number
-                CFIndex sCnt = (cCnt == 0) ? forChild0[totalG] : ((cCnt == 1) ? forChild1[totalG] : totalG);
-               // Assure we have that many grandchildren...
-               if (sCnt > totalG - gCnt) sCnt = totalG - gCnt;
-                if (sCnt) {
-                    if (!node->info.notLeaf.child[cCnt]) {
-                        CFStorageNode *newNode = __CFStorageCreateNode(allocator, false, 0);
-                        CF_WRITE_BARRIER_ASSIGN(allocator, node->info.notLeaf.child[cCnt], newNode);
-                    }
-                    for (cnt = 0; cnt < sCnt; cnt++) {
-                        node->info.notLeaf.child[cCnt]->numBytes += gChildren[gCnt]->numBytes;
-                        CF_WRITE_BARRIER_ASSIGN(allocator, node->info.notLeaf.child[cCnt]->info.notLeaf.child[cnt], gChildren[gCnt++]);
-                    }
-                } else {
-                    if (node->info.notLeaf.child[cCnt]) {
-                        _CFAllocatorDeallocateGC(allocator, node->info.notLeaf.child[cCnt]);
-                        node->info.notLeaf.child[cCnt] = NULL;
-                    }
-                }
-           }
-        }
-    }
-}
-
-
-/* Returns NULL or additional node to come after this node
-   Assumption: size is never > storage->maxLeafCapacity
-*/
-static CFStorageNode *__CFStorageInsert(CFAllocatorRef allocator, CFStorageRef storage, CFStorageNode *node, CFIndex byteNum, CFIndex size, CFIndex absoluteByteNum) {
-    if (node->isLeaf) {
-        if (size + node->numBytes > storage->maxLeafCapacity) {        // Need to create more child nodes
-            if (byteNum == node->numBytes) {   // Inserting at end; easy...
-                CFStorageNode *newNode = __CFStorageCreateNode(allocator, true, size);
-                __CFStorageSetCache(storage, newNode, NULL, absoluteByteNum / storage->valueSize, size / storage->valueSize);
-                return newNode;
-            } else if (byteNum == 0) { // Inserting at front; also easy, but we need to swap node and newNode
-                CFStorageNode *newNode = __CFStorageCreateNode(allocator, true, 0);
-                CF_WRITE_BARRIER_MEMMOVE(newNode, node, sizeof(CFStorageNode));
-                node->isLeaf = true;
-                node->numBytes = size;
-                node->info.leaf.capacityInBytes = 0;
-                node->info.leaf.memory = NULL;
-                __CFStorageSetCache(storage, node, NULL, absoluteByteNum / storage->valueSize, size / storage->valueSize);
-                return newNode;
-            } else if (byteNum + size <= storage->maxLeafCapacity) {   // Inserting at middle; inserted region will fit into existing child
-                // Create new node to hold the overflow
-                CFStorageNode *newNode = __CFStorageCreateNode(allocator, true, node->numBytes - byteNum);
-                if (node->info.leaf.memory) {  // We allocate memory lazily...
-                    __CFStorageAllocLeafNodeMemory(allocator, storage, newNode, node->numBytes - byteNum, false);
-                    COPYMEM(node->info.leaf.memory + byteNum, newNode->info.leaf.memory, node->numBytes - byteNum);
-                    __CFStorageAllocLeafNodeMemory(allocator, storage, node, byteNum + size, false);
-                }
-                node->numBytes = byteNum + size;
-                __CFStorageSetCache(storage, node, node->info.leaf.memory, (absoluteByteNum - byteNum) / storage->valueSize, node->numBytes / storage->valueSize);
-                return newNode;
-            } else {   // Inserting some of new into one node, rest into another; remember that the assumption is size <= storage->maxLeafCapacity
-                CFStorageNode *newNode = __CFStorageCreateNode(allocator, true, node->numBytes + size - storage->maxLeafCapacity);     // New stuff
-                if (node->info.leaf.memory) {  // We allocate memory lazily...
-                    __CFStorageAllocLeafNodeMemory(allocator, storage, newNode, node->numBytes + size - storage->maxLeafCapacity, false);
-                    COPYMEM(node->info.leaf.memory + byteNum, newNode->info.leaf.memory + byteNum + size - storage->maxLeafCapacity, node->numBytes - byteNum);
-                    __CFStorageAllocLeafNodeMemory(allocator, storage, node, storage->maxLeafCapacity, false);
-                }
-                node->numBytes = storage->maxLeafCapacity;
-                __CFStorageSetCache(storage, node, node->info.leaf.memory, (absoluteByteNum - byteNum) / storage->valueSize, node->numBytes / storage->valueSize);
-                //__CFStorageSetCache(storage, NULL, NULL, 0, 0);
-                return newNode;
-            }
-        } else {       // No need to create new nodes!
-            if (node->info.leaf.memory) {
-                __CFStorageAllocLeafNodeMemory(allocator, storage, node, node->numBytes + size, false);
-                COPYMEM(node->info.leaf.memory + byteNum, node->info.leaf.memory + byteNum + size, node->numBytes - byteNum);
-            }
-            node->numBytes += size;
-            __CFStorageSetCache(storage, node, node->info.leaf.memory, (absoluteByteNum - byteNum) / storage->valueSize, node->numBytes / storage->valueSize);
-            return NULL;
-        }
-    } else {
-        CFIndex relativeByteNum;
-        CFIndex childNum;
-        CFStorageNode *newNode;
-        __CFStorageFindChild(node, byteNum, true, &childNum, &relativeByteNum);
-        newNode = __CFStorageInsert(allocator, storage, node->info.notLeaf.child[childNum], relativeByteNum, size, absoluteByteNum);
-        if (newNode) {
-            if (node->info.notLeaf.child[2] == NULL) { // There's an empty slot for the new node, cool
-                if (childNum == 0) CF_WRITE_BARRIER_ASSIGN(allocator, node->info.notLeaf.child[2], node->info.notLeaf.child[1]);       // Make room
-                CF_WRITE_BARRIER_ASSIGN(allocator, node->info.notLeaf.child[childNum + 1], newNode);
-                node->numBytes += size;
-                return NULL;
-            } else {
-                CFStorageNode *anotherNode = __CFStorageCreateNode(allocator, false, 0);       // Create another node
-                if (childNum == 0) {   // Last two children go to new node
-                    CF_WRITE_BARRIER_ASSIGN(allocator, anotherNode->info.notLeaf.child[0], node->info.notLeaf.child[1]);
-                    CF_WRITE_BARRIER_ASSIGN(allocator, anotherNode->info.notLeaf.child[1], node->info.notLeaf.child[2]);
-                    CF_WRITE_BARRIER_ASSIGN(allocator, node->info.notLeaf.child[1], newNode);
-                    node->info.notLeaf.child[2] = NULL;
-                } else if (childNum == 1) {    // Last child goes to new node
-                    CF_WRITE_BARRIER_ASSIGN(allocator, anotherNode->info.notLeaf.child[0], newNode);
-                    CF_WRITE_BARRIER_ASSIGN(allocator, anotherNode->info.notLeaf.child[1], node->info.notLeaf.child[2]);
-                    node->info.notLeaf.child[2] = NULL;
-                } else {       // New node contains the new comers...
-                    CF_WRITE_BARRIER_ASSIGN(allocator, anotherNode->info.notLeaf.child[0], node->info.notLeaf.child[2]);
-                    CF_WRITE_BARRIER_ASSIGN(allocator, anotherNode->info.notLeaf.child[1], newNode);
-                    node->info.notLeaf.child[2] = NULL;
-                }
-                node->numBytes = node->info.notLeaf.child[0]->numBytes + node->info.notLeaf.child[1]->numBytes;
-                anotherNode->numBytes = anotherNode->info.notLeaf.child[0]->numBytes + anotherNode->info.notLeaf.child[1]->numBytes;
-                return anotherNode;
-            }
-        } else {
-            node->numBytes += size;
-        }
-    }
-    return NULL;
-}
-
-CF_INLINE CFIndex __CFStorageGetCount(CFStorageRef storage) {
-    return storage->rootNode.numBytes / storage->valueSize;
-}
-
-static bool __CFStorageEqual(CFTypeRef cf1, CFTypeRef cf2) {
-    CFStorageRef storage1 = (CFStorageRef)cf1;
-    CFStorageRef storage2 = (CFStorageRef)cf2;
-    CFIndex loc, count, valueSize;
-    CFRange range1, range2;
-    uint8_t *ptr1, *ptr2;
-
-    count = __CFStorageGetCount(storage1);
-    if (count != __CFStorageGetCount(storage2)) return false;
-
-    valueSize = __CFStorageGetValueSize(storage1);
-    if (valueSize != __CFStorageGetValueSize(storage2)) return false;
-
-    loc = range1.location = range1.length = range2.location = range2.length = 0;
-    ptr1 = ptr2 = NULL;
-
-    while (loc < count) {
-       CFIndex cntThisTime;
-       if (loc >= range1.location + range1.length) ptr1 = CFStorageGetValueAtIndex(storage1, loc, &range1);
-       if (loc >= range2.location + range2.length) ptr2 = CFStorageGetValueAtIndex(storage2, loc, &range2);
-       cntThisTime = range1.location + range1.length;
-       if (range2.location + range2.length < cntThisTime) cntThisTime = range2.location + range2.length;
-       cntThisTime -= loc;
-       if (memcmp(ptr1, ptr2, valueSize * cntThisTime) != 0) return false;
-       ptr1 += valueSize * cntThisTime;
-       ptr2 += valueSize * cntThisTime;
-       loc += cntThisTime;
-    }
-    return true;
-}
-
-static CFHashCode __CFStorageHash(CFTypeRef cf) {
-    CFStorageRef Storage = (CFStorageRef)cf;
-    return __CFStorageGetCount(Storage);
-}
-
-static void __CFStorageDescribeNode(CFStorageNode *node, CFMutableStringRef str, CFIndex level) {
-    int cnt;
-    for (cnt = 0; cnt < level; cnt++) CFStringAppendCString(str, "  ", CFStringGetSystemEncoding());
-
-    if (node->isLeaf) {
-        CFStringAppendFormat(str, NULL, CFSTR("Leaf %d/%d\n"), node->numBytes, node->info.leaf.capacityInBytes);
-    } else {
-        CFStringAppendFormat(str, NULL, CFSTR("Node %d\n"), node->numBytes);
-        for (cnt = 0; cnt < 3; cnt++) if (node->info.notLeaf.child[cnt]) __CFStorageDescribeNode(node->info.notLeaf.child[cnt], str, level+1);
-    }
-}
-
-static CFIndex __CFStorageGetNodeCapacity(CFStorageNode *node) {
-    if (!node) return 0;
-    if (node->isLeaf) return node->info.leaf.capacityInBytes;
-    return __CFStorageGetNodeCapacity(node->info.notLeaf.child[0]) + __CFStorageGetNodeCapacity(node->info.notLeaf.child[1]) + __CFStorageGetNodeCapacity(node->info.notLeaf.child[2]);
-}
-
-CFIndex __CFStorageGetCapacity(CFStorageRef storage) {
-    return __CFStorageGetNodeCapacity(&storage->rootNode) / storage->valueSize;
-}
-
-CFIndex __CFStorageGetValueSize(CFStorageRef storage) {
-    return storage->valueSize;
-}
-
-static CFStringRef __CFStorageCopyDescription(CFTypeRef cf) {
-    CFStorageRef storage = (CFStorageRef)cf;
-    CFMutableStringRef result;
-    CFAllocatorRef allocator = CFGetAllocator(storage);
-    result = CFStringCreateMutable(allocator, 0);
-    CFStringAppendFormat(result, NULL, CFSTR("<CFStorage %p [%p]>[count = %u, capacity = %u]\n"), storage, allocator, __CFStorageGetCount(storage), __CFStorageGetCapacity(storage));
-    __CFStorageDescribeNode(&storage->rootNode, result, 0);
-    return result;
-}
-
-static void __CFStorageDeallocate(CFTypeRef cf) {
-    CFStorageRef storage = (CFStorageRef)cf;
-    CFAllocatorRef allocator = CFGetAllocator(storage);
-    if (CF_IS_COLLECTABLE_ALLOCATOR(allocator)) return; // XXX_PCB GC will take care of us.
-    __CFStorageNodeDealloc(allocator, &storage->rootNode, false);
-}
-
-static CFTypeID __kCFStorageTypeID = _kCFRuntimeNotATypeID;
-
-static const CFRuntimeClass __CFStorageClass = {
-    _kCFRuntimeScannedObject,
-    "CFStorage",
-    NULL,      // init
-    NULL,      // copy
-    __CFStorageDeallocate,
-    (void *)__CFStorageEqual,
-    __CFStorageHash,
-    NULL,      // 
-    __CFStorageCopyDescription
-};
-
-__private_extern__ void __CFStorageInitialize(void) {
-    __kCFStorageTypeID = _CFRuntimeRegisterClass(&__CFStorageClass);
-}
-
-/*** Public API ***/
-
-CFStorageRef CFStorageCreate(CFAllocatorRef allocator, CFIndex valueSize) {
-    CFStorageRef storage;
-    CFIndex size = sizeof(struct __CFStorage) - sizeof(CFRuntimeBase);
-    storage = (CFStorageRef)_CFRuntimeCreateInstance(allocator, __kCFStorageTypeID, size, NULL);
-    if (NULL == storage) {
-       return NULL;
-    }
-    storage->valueSize = valueSize;
-    storage->cachedRange.location = 0;
-    storage->cachedRange.length = 0;
-    storage->cachedNode = NULL;
-    storage->cachedNodeMemory = NULL;
-    storage->maxLeafCapacity = __CFStorageMaxLeafCapacity;
-    if (valueSize && ((storage->maxLeafCapacity % valueSize) != 0)) {  
-        storage->maxLeafCapacity = (storage->maxLeafCapacity / valueSize) * valueSize; // Make it fit perfectly (3406853)
-    }
-    memset(&(storage->rootNode), 0, sizeof(CFStorageNode));
-    storage->rootNode.isLeaf = true;
-    storage->nodeHint = AUTO_MEMORY_SCANNED;
-    if (__CFOASafe) __CFSetLastAllocationEventName(storage, "CFStorage");
-    return storage;    
-}
-
-CFTypeID CFStorageGetTypeID(void) {
-    return __kCFStorageTypeID;
-}
-
-CFIndex CFStorageGetCount(CFStorageRef storage) {
-    return __CFStorageGetCount(storage);
-}
-
-/* Returns pointer to the specified value
-   index and validConsecutiveValueRange are in terms of values
-*/
-void *CFStorageGetValueAtIndex(CFStorageRef storage, CFIndex idx, CFRange *validConsecutiveValueRange) {
-    CFRange range;
-    return __CFStorageGetValueAtIndex(storage, idx, validConsecutiveValueRange ? validConsecutiveValueRange : &range);
-}
-
-/* Makes space for range.length values at location range.location
-   This function deepens the tree if necessary...
-*/
-void CFStorageInsertValues(CFStorageRef storage, CFRange range) {
-    CFIndex numBytesToInsert = range.length * storage->valueSize;
-    CFIndex byteNum = range.location * storage->valueSize;
-    while (numBytesToInsert > 0) {
-        CFStorageNode *newNode;
-        CFAllocatorRef allocator = CFGetAllocator(storage);
-        CFIndex insertThisTime = numBytesToInsert;
-        if (insertThisTime > storage->maxLeafCapacity) {
-            insertThisTime = (storage->maxLeafCapacity / storage->valueSize) * storage->valueSize;
-        }
-        newNode = __CFStorageInsert(allocator, storage, &storage->rootNode, byteNum, insertThisTime, byteNum);
-        if (newNode) {
-            CFStorageNode *tempRootNode = __CFStorageCreateNode(allocator, false, 0);  // Will copy the (static) rootNode over to this
-            CF_WRITE_BARRIER_MEMMOVE(tempRootNode, &storage->rootNode, sizeof(CFStorageNode));
-            storage->rootNode.isLeaf = false;
-            CF_WRITE_BARRIER_BASE_ASSIGN(allocator, storage, storage->rootNode.info.notLeaf.child[0], tempRootNode);
-            CF_WRITE_BARRIER_BASE_ASSIGN(allocator, storage, storage->rootNode.info.notLeaf.child[1], newNode);
-            storage->rootNode.info.notLeaf.child[2] = NULL;
-            storage->rootNode.numBytes = tempRootNode->numBytes + newNode->numBytes;
-            if (storage->cachedNode == &(storage->rootNode))
-                CF_WRITE_BARRIER_BASE_ASSIGN(allocator, storage, storage->cachedNode, tempRootNode);   // The cache should follow the node
-        }
-        numBytesToInsert -= insertThisTime;
-        byteNum += insertThisTime;
-    }
-}
-
-/* Deletes the values in the specified range
-   This function gets rid of levels if necessary...
-*/
-void CFStorageDeleteValues(CFStorageRef storage, CFRange range) {
-    CFAllocatorRef allocator = CFGetAllocator(storage);
-    range.location *= storage->valueSize;
-    range.length *= storage->valueSize;
-    __CFStorageDelete(allocator, storage, &storage->rootNode, range, true);
-    while (__CFStorageGetNumChildren(&storage->rootNode) == 1) {
-        CFStorageNode *child = storage->rootNode.info.notLeaf.child[0];        // The single child
-        CF_WRITE_BARRIER_MEMMOVE(&storage->rootNode, child, sizeof(CFStorageNode));
-        _CFAllocatorDeallocateGC(allocator, child);
-    }
-    if (__CFStorageGetNumChildren(&storage->rootNode) == 0 && !storage->rootNode.isLeaf) {
-       storage->rootNode.isLeaf = true;
-       storage->rootNode.info.leaf.capacityInBytes = 0;
-       storage->rootNode.info.leaf.memory = NULL;
-    }
-    // ??? Need to update the cache
-    storage->cachedRange = CFRangeMake(0, 0);
-}
-
-void CFStorageGetValues(CFStorageRef storage, CFRange range, void *values) {
-    while (range.length > 0) {
-        CFRange leafRange;
-        void *storagePtr = __CFStorageGetValueAtIndex(storage, range.location, &leafRange);
-        CFIndex cntThisTime = range.length;
-        if (cntThisTime > leafRange.length - (range.location - leafRange.location)) cntThisTime = leafRange.length - (range.location - leafRange.location);
-        COPYMEM(storagePtr, values, cntThisTime * storage->valueSize);
-               ((uint8_t *)values) += cntThisTime * storage->valueSize;
-        range.location += cntThisTime;
-        range.length -= cntThisTime;
-    }
-}
-
-void CFStorageApplyFunction(CFStorageRef storage, CFRange range, CFStorageApplierFunction applier, void *context) {
-    while (0 < range.length) {
-        CFRange leafRange;
-        const void *storagePtr;
-        CFIndex idx, cnt;
-        storagePtr = CFStorageGetValueAtIndex(storage, range.location, &leafRange);
-        cnt = __CFMin(range.length, leafRange.location + leafRange.length - range.location);
-        for (idx = 0; idx < cnt; idx++) {
-            applier(storagePtr, context);
-            storagePtr = (const char *)storagePtr + storage->valueSize;
-        }
-        range.length -= cnt;
-        range.location += cnt;
-    }
-}
-
-void CFStorageReplaceValues(CFStorageRef storage, CFRange range, const void *values) {
-    while (range.length > 0) {
-        CFRange leafRange;
-        void *storagePtr = __CFStorageGetValueAtIndex(storage, range.location, &leafRange);
-        CFIndex cntThisTime = range.length;
-        if (cntThisTime > leafRange.length - (range.location - leafRange.location)) cntThisTime = leafRange.length - (range.location - leafRange.location);
-        COPYMEM(values, storagePtr, cntThisTime * storage->valueSize);
-       ((const uint8_t *)values) += cntThisTime * storage->valueSize;
-        range.location += cntThisTime;
-        range.length -= cntThisTime;
-    }
-}
-
-/* Used by CFArray.c */
-
-static void __CFStorageNodeSetLayoutType(CFStorageNode *node, auto_zone_t *zone, auto_memory_type_t type) {
-    if (node->isLeaf) {
-        auto_zone_set_layout_type(zone, node->info.leaf.memory, type);
-    } else {
-        CFStorageNode **children = node->info.notLeaf.child;
-        if (children[0]) __CFStorageNodeSetLayoutType(children[0], zone, type);
-        if (children[1]) __CFStorageNodeSetLayoutType(children[1], zone, type);
-        if (children[2]) __CFStorageNodeSetLayoutType(children[2], zone, type);
-    }
-}
-
-__private_extern__ void _CFStorageSetWeak(CFStorageRef storage) {
-    storage->nodeHint = AUTO_MEMORY_UNSCANNED;
-    __CFStorageNodeSetLayoutType(&storage->rootNode, __CFCollectableZone, storage->nodeHint);
-}
-
-#undef COPYMEM
-#undef PAGE_LIMIT
-