git.y1.nz

SameBoy

Accurate GB/GBC emulator
download: https://git.y1.nz/archives/sameboy.tar.gz
README | Files | Log | Refs | LICENSE

HexFiend/HFBTree.m

      1 //
      2 //  HFBTree.m
      3 //  BTree
      4 //
      5 //  Created by peter on 2/6/09.
      6 //  Copyright 2009 ridiculous_fish. All rights reserved.
      7 //
      8 
      9 #import "HFBTree.h"
     10 #include <malloc/malloc.h>
     11 
     12 #define FIXUP_LENGTHS 0
     13 
     14 #define BTREE_BRANCH_ORDER 10
     15 #define BTREE_LEAF_ORDER 10
     16 
     17 #define BTREE_ORDER 10
     18 #define BTREE_NODE_MINIMUM_VALUE_COUNT (BTREE_ORDER / 2)
     19 
     20 #define BTREE_LEAF_MINIMUM_VALUE_COUNT (BTREE_LEAF_ORDER / 2)
     21 
     22 #define BAD_INDEX ((ChildIndex_t)(-1))
     23 typedef unsigned int ChildIndex_t;
     24 
     25 /* How deep can our tree get?  128 is huge. */
     26 #define MAX_DEPTH 128
     27 #define BAD_DEPTH ((TreeDepth_t)(-1))
     28 typedef unsigned int TreeDepth_t;
     29 
     30 #define TreeEntry NSObject <HFBTreeEntry>
     31 #define HFBTreeLength(x) [(TreeEntry *)(x) length]
     32 
     33 
     34 @class HFBTreeNode, HFBTreeBranch, HFBTreeLeaf;
     35 
     36 static TreeEntry *btree_search(HFBTree *tree, HFBTreeIndex offset, HFBTreeIndex *outBeginningOffset);
     37 static id btree_insert_returning_retained_value_for_parent(HFBTree *tree, TreeEntry *entry, HFBTreeIndex offset);
     38 static BOOL btree_remove(HFBTree *tree, HFBTreeIndex offset);
     39 static void __attribute__((unused)) btree_recursive_check_integrity(HFBTree *tree, HFBTreeNode *branchOrLeaf, TreeDepth_t depth, HFBTreeNode **linkHelper);
     40 #if FIXUP_LENGTHS
     41 static HFBTreeIndex btree_recursive_fixup_cached_lengths(HFBTree *tree, HFBTreeNode *branchOrLeaf);
     42 #endif
     43 static HFBTreeIndex __attribute__((unused)) btree_recursive_check_integrity_of_cached_lengths(HFBTreeNode *branchOrLeaf);
     44 static BOOL btree_are_cached_lengths_correct(HFBTreeNode *branchOrLeaf, HFBTreeIndex *outLength);
     45 #if FIXUP_LENGTHS
     46 static NSUInteger btree_entry_count(HFBTreeNode *branchOrLeaf);
     47 #endif
     48 static ChildIndex_t count_node_values(HFBTreeNode *node);
     49 static HFBTreeIndex sum_child_lengths(const id *children, const BOOL isLeaf);
     50 static HFBTreeNode *mutable_copy_node(HFBTreeNode *node, TreeDepth_t depth, HFBTreeNode **linkingHelper);
     51 
     52 #if NDEBUG
     53 #define VERIFY_LENGTH(a)
     54 #else
     55 #define VERIFY_LENGTH(a) btree_recursive_check_integrity_of_cached_lengths((a))
     56 #endif
     57 
     58 #define IS_BRANCH(a) [(a) isKindOfClass:[HFBTreeBranch class]]
     59 #define IS_LEAF(a) [(a) isKindOfClass:[HFBTreeLeaf class]]
     60 
     61 #define ASSERT_IS_BRANCH(a) HFASSERT(IS_BRANCH(a))
     62 #define ASSERT_IS_LEAF(a) HFASSERT(IS_LEAF(a))
     63 
     64 #define GET_LENGTH(node, parentIsLeaf) ((parentIsLeaf) ? HFBTreeLength(node) : CHECK_CAST((node), HFBTreeNode)->subtreeLength)
     65 
     66 #define CHECK_CAST(a, b) ({HFASSERT([(a) isKindOfClass:[b class]]); (b *)(a);})
     67 #define CHECK_CAST_OR_NULL(a, b) ({HFASSERT((a == nil) || [(a) isKindOfClass:[b class]]); (b *)(a);})
     68 
     69 #define DEFEAT_INLINE 1
     70 
     71 #if DEFEAT_INLINE
     72 #define FORCE_STATIC_INLINE static
     73 #else
     74 #define FORCE_STATIC_INLINE static __inline__ __attribute__((always_inline))
     75 #endif
     76 
     77 @interface HFBTreeEnumerator : NSEnumerator {
     78     HFBTreeLeaf *currentLeaf;
     79     ChildIndex_t childIndex;
     80 }
     81 
     82 - (instancetype)initWithLeaf:(HFBTreeLeaf *)leaf;
     83 
     84 @end
     85 
     86 @interface HFBTreeNode : NSObject {
     87     @public
     88     NSUInteger rc;
     89     HFBTreeIndex subtreeLength;
     90     HFBTreeNode *left, *right;
     91     id children[BTREE_ORDER];
     92 }
     93 
     94 @end
     95 
     96 @implementation HFBTreeNode
     97 
     98 - (id)retain {
     99     HFAtomicIncrement(&rc, NO);
    100     return self;
    101 }
    102 
    103 - (oneway void)release {
    104     NSUInteger result = HFAtomicDecrement(&rc, NO);
    105     if (result == (NSUInteger)(-1)) {
    106         [self dealloc];
    107     }
    108 }
    109 
    110 - (NSUInteger)retainCount {
    111     return 1 + rc;
    112 }
    113 
    114 - (void)dealloc {
    115     for (ChildIndex_t i=0; i < BTREE_BRANCH_ORDER; i++) {
    116         if (! children[i]) break;
    117         [children[i] release];
    118     }
    119     [super dealloc];
    120 }
    121 
    122 - (NSString *)shortDescription {
    123     return [NSString stringWithFormat:@"<%@: %p (%llu)>", [self class], self, subtreeLength];
    124 }
    125 
    126 @end
    127 
    128 @interface HFBTreeBranch : HFBTreeNode
    129 @end
    130 
    131 @implementation HFBTreeBranch
    132 
    133 - (NSString *)description {
    134     const char *lengthsMatchString = (subtreeLength == sum_child_lengths(children, NO) ? "" : " INCONSISTENT ");
    135     NSMutableString *s = [NSMutableString stringWithFormat:@"<%@: %p (length: %llu%s) (children: %u) (", [self class], self, subtreeLength, lengthsMatchString, count_node_values(self)];
    136     NSUInteger i;
    137     for (i=0; i < BTREE_ORDER; i++) {
    138         if (children[i] == nil) break;
    139         [s appendFormat:@"%s%@", (i == 0 ? "" : ", "), [children[i] shortDescription]];
    140     }
    141     [s appendString:@")>"];
    142     return s;
    143 }
    144 
    145 @end
    146 
    147 @interface HFBTreeLeaf : HFBTreeNode
    148 @end
    149 
    150 @implementation HFBTreeLeaf
    151 
    152 - (NSString *)description {
    153     NSMutableString *s = [NSMutableString stringWithFormat:@"<%@: %p (%u) (", [self class], self, count_node_values(self)];
    154     NSUInteger i;
    155     for (i=0; i < BTREE_ORDER; i++) {
    156         if (children[i] == nil) break;
    157         [s appendFormat:@"%s%@", (i == 0 ? "" : ", "), children[i]];
    158     }
    159     [s appendString:@")>"];
    160     return s;
    161 }
    162 
    163 @end
    164 
    165 @implementation HFBTree
    166 
    167 - (instancetype)init {
    168     self = [super init];
    169     depth = BAD_DEPTH;
    170     root = nil;
    171     return self;
    172 }
    173 
    174 - (void)dealloc {
    175     [root release];
    176     [super dealloc];
    177 }
    178 
    179 #if HFUNIT_TESTS
    180 - (void)checkIntegrityOfCachedLengths {
    181     if (root == nil) {
    182         /* nothing */
    183     }
    184     else {
    185         btree_recursive_check_integrity_of_cached_lengths(root);
    186     }
    187 }
    188 
    189 - (void)checkIntegrityOfBTreeStructure {
    190     if (depth == BAD_DEPTH) {
    191         HFASSERT(root == nil);
    192     }
    193     else {
    194         HFBTreeNode *linkHelper[MAX_DEPTH + 1] = {};
    195         btree_recursive_check_integrity(self, root, depth, linkHelper);
    196     }
    197 }
    198 #endif
    199 
    200 - (HFBTreeIndex)length {
    201     if (root == nil) return 0;
    202     return ((HFBTreeNode *)root)->subtreeLength;
    203 }
    204 
    205 - (void)insertEntry:(id)entryObj atOffset:(HFBTreeIndex)offset {
    206     TreeEntry *entry = (TreeEntry *)entryObj; //avoid a conflicting types warning
    207     HFASSERT(entry);
    208     HFASSERT(offset <= [self length]);
    209     if (! root) {
    210         HFASSERT([self length] == 0);
    211         HFASSERT(depth == BAD_DEPTH);
    212         HFBTreeLeaf *leaf = [[HFBTreeLeaf alloc] init];
    213         leaf->children[0] = [entry retain];
    214         leaf->subtreeLength = HFBTreeLength(entry);
    215         root = leaf;
    216         depth = 0;
    217     }
    218     else {
    219         HFBTreeNode *newParentValue = btree_insert_returning_retained_value_for_parent(self, entry, offset);
    220         if (newParentValue) {
    221             HFBTreeBranch *newRoot = [[HFBTreeBranch alloc] init];
    222             newRoot->children[0] = root; //transfer our retain
    223             newRoot->children[1] = newParentValue; //transfer the retain we got from the function
    224             newRoot->subtreeLength = HFSum(root->subtreeLength, newParentValue->subtreeLength);
    225             root = newRoot;
    226             depth++;
    227             HFASSERT(depth <= MAX_DEPTH);
    228         }
    229 #if FIXUP_LENGTHS
    230         HFBTreeIndex outLength = -1;
    231         if (! btree_are_cached_lengths_correct(root, &outLength)) {
    232             puts("Fixed up length after insertion");
    233             btree_recursive_fixup_cached_lengths(self, root);
    234         }
    235 #endif
    236     }
    237 }
    238 
    239 - (TreeEntry *)entryContainingOffset:(HFBTreeIndex)offset beginningOffset:(HFBTreeIndex *)outBeginningOffset {
    240     HFASSERT(root != nil);
    241     return btree_search(self, offset, outBeginningOffset);
    242 }
    243 
    244 - (void)removeAllEntries {
    245     [root release];
    246     root = nil;
    247     depth = BAD_DEPTH;
    248 }
    249 
    250 - (void)removeEntryAtOffset:(HFBTreeIndex)offset {
    251     HFASSERT(root != nil);
    252 #if FIXUP_LENGTHS
    253     const NSUInteger beforeCount = btree_entry_count(root);
    254 #endif
    255     BOOL deleteRoot = btree_remove(self, offset);
    256     if (deleteRoot) {
    257         HFASSERT(count_node_values(root) <= 1);
    258         id newRoot = [root->children[0] retain]; //may be nil!
    259         [root release];
    260         root = newRoot;
    261         depth--;
    262     }
    263 #if FIXUP_LENGTHS
    264     const NSUInteger afterCount = btree_entry_count(root);
    265     if (beforeCount != afterCount + 1) {
    266         NSLog(@"Bad counts: before %lu, after %lu", beforeCount, afterCount);
    267     }
    268     HFBTreeIndex outLength = -1;
    269     static NSUInteger fixupCount;
    270     if (! btree_are_cached_lengths_correct(root, &outLength)) {
    271         fixupCount++;
    272         printf("Fixed up length after deletion (%lu)\n", (unsigned long)fixupCount);
    273         btree_recursive_fixup_cached_lengths(self, root);
    274     }
    275     else {
    276         //printf("Length post-deletion was OK! (%lu)\n", fixupCount);
    277     }
    278 #endif
    279 }
    280 
    281 - (id)mutableCopyWithZone:(NSZone *)zone {
    282     USE(zone);
    283     HFBTree *result = [[[self class] alloc] init];
    284     result->depth = depth;
    285     HFBTreeNode *linkingHelper[MAX_DEPTH + 1];
    286     bzero(linkingHelper, (1 + depth) * sizeof *linkingHelper);
    287     result->root = mutable_copy_node(root, depth, linkingHelper);
    288     return result;
    289 }
    290 
    291 FORCE_STATIC_INLINE ChildIndex_t count_node_values(HFBTreeNode *node) {
    292     ChildIndex_t count;
    293     for (count=0; count < BTREE_LEAF_ORDER; count++) {
    294         if (node->children[count] == nil) break;
    295     }
    296     return count;
    297 }
    298 
    299 FORCE_STATIC_INLINE HFBTreeIndex sum_child_lengths(const id *children, const BOOL isLeaf) {
    300     HFBTreeIndex result = 0;
    301     for (ChildIndex_t childIndex = 0; childIndex < BTREE_ORDER; childIndex++) {
    302         id child = children[childIndex];
    303         if (! child) break;
    304         HFBTreeIndex childLength = GET_LENGTH(child, isLeaf);
    305         result = HFSum(result, childLength);
    306     }
    307     return result;
    308 }
    309 
    310 FORCE_STATIC_INLINE HFBTreeIndex sum_N_child_lengths(const id *children, ChildIndex_t numChildren, const BOOL isLeaf) {
    311     HFBTreeIndex result = 0;
    312     for (ChildIndex_t childIndex = 0; childIndex < numChildren; childIndex++) {
    313         id child = children[childIndex];
    314         HFASSERT(child != NULL);
    315         HFBTreeIndex childLength = GET_LENGTH(child, isLeaf);
    316         result = HFSum(result, childLength);
    317     }
    318     return result;
    319 }
    320 
    321 FORCE_STATIC_INLINE ChildIndex_t index_containing_offset(HFBTreeNode *node, HFBTreeIndex offset, HFBTreeIndex * restrict outOffset, const BOOL isLeaf) {
    322     ChildIndex_t childIndex;
    323     HFBTreeIndex previousSum = 0;
    324     const id *children = node->children;
    325     for (childIndex = 0; childIndex < BTREE_ORDER; childIndex++) {
    326         HFASSERT(children[childIndex] != nil);
    327         HFBTreeIndex childLength = GET_LENGTH(children[childIndex], isLeaf);
    328         HFBTreeIndex newSum = HFSum(childLength, previousSum);
    329         if (newSum > offset) {
    330             break;
    331         }
    332         previousSum = newSum;
    333     }
    334     *outOffset = previousSum;
    335     return childIndex;
    336 }
    337 
    338 FORCE_STATIC_INLINE id child_containing_offset(HFBTreeNode *node, HFBTreeIndex offset, HFBTreeIndex * restrict outOffset, const BOOL isLeaf) {
    339     return node->children[index_containing_offset(node, offset, outOffset, isLeaf)];
    340 }
    341 
    342 FORCE_STATIC_INLINE ChildIndex_t index_for_child_at_offset(HFBTreeNode *node, HFBTreeIndex offset, const BOOL isLeaf) {
    343     ChildIndex_t childIndex;
    344     HFBTreeIndex previousSum = 0;
    345     id *const children = node->children;
    346     for (childIndex = 0; childIndex < BTREE_ORDER; childIndex++) {
    347         if (previousSum == offset) break;
    348         HFASSERT(children[childIndex] != nil);
    349         HFBTreeIndex childLength = GET_LENGTH(children[childIndex], isLeaf);
    350         previousSum = HFSum(childLength, previousSum);
    351         HFASSERT(previousSum <= offset);
    352     }
    353     HFASSERT(childIndex <= BTREE_ORDER); //note we allow the child index to be one past the end (in which case we are sure to split the node)
    354     HFASSERT(previousSum == offset); //but we still require the offset to be the sum of all the lengths of this node
    355     return childIndex;
    356 }
    357 
    358 FORCE_STATIC_INLINE ChildIndex_t child_index_for_insertion_at_offset(HFBTreeBranch *branch, HFBTreeIndex insertionOffset, HFBTreeIndex *outPriorCombinedOffset) {
    359     ChildIndex_t indexForInsertion;
    360     HFBTreeIndex priorCombinedOffset = 0;
    361     id *const children = branch->children;
    362     for (indexForInsertion = 0; indexForInsertion < BTREE_BRANCH_ORDER; indexForInsertion++) {
    363         if (! children[indexForInsertion]) break;
    364         HFBTreeNode *childNode = CHECK_CAST(children[indexForInsertion], HFBTreeNode);
    365         HFBTreeIndex subtreeLength = childNode->subtreeLength;
    366         HFASSERT(subtreeLength > 0);
    367         HFBTreeIndex newOffset = HFSum(priorCombinedOffset, subtreeLength);
    368         if (newOffset >= insertionOffset) {
    369             break;
    370         }
    371         priorCombinedOffset = newOffset;
    372     }
    373     *outPriorCombinedOffset = priorCombinedOffset;
    374     return indexForInsertion;
    375 }
    376 
    377 FORCE_STATIC_INLINE ChildIndex_t child_index_for_deletion_at_offset(HFBTreeBranch *branch, HFBTreeIndex deletionOffset, HFBTreeIndex *outPriorCombinedOffset) {
    378     ChildIndex_t indexForDeletion;
    379     HFBTreeIndex priorCombinedOffset = 0;
    380     for (indexForDeletion = 0; indexForDeletion < BTREE_BRANCH_ORDER; indexForDeletion++) {
    381         HFASSERT(branch->children[indexForDeletion] != nil);
    382         HFBTreeNode *childNode = CHECK_CAST(branch->children[indexForDeletion], HFBTreeNode);
    383         HFBTreeIndex subtreeLength = childNode->subtreeLength;
    384         HFASSERT(subtreeLength > 0);
    385         HFBTreeIndex newOffset = HFSum(priorCombinedOffset, subtreeLength);
    386         if (newOffset > deletionOffset) {
    387             /* Key difference between insertion and deletion: insertion uses >=, while deletion uses > */
    388             break;
    389         }
    390         priorCombinedOffset = newOffset;
    391     }
    392     *outPriorCombinedOffset = priorCombinedOffset;
    393     return indexForDeletion;
    394 }
    395 
    396 FORCE_STATIC_INLINE void insert_value_into_array(id value, NSUInteger insertionIndex, id *array, NSUInteger arrayCount) {
    397     HFASSERT(insertionIndex <= arrayCount);
    398     HFASSERT(arrayCount > 0);
    399     NSUInteger pushingIndex = arrayCount - 1;
    400     while (pushingIndex > insertionIndex) {
    401         array[pushingIndex] = array[pushingIndex - 1];
    402         pushingIndex--;
    403     }
    404     array[insertionIndex] = [value retain];
    405 }
    406 
    407 
    408 FORCE_STATIC_INLINE void remove_value_from_array(NSUInteger removalIndex, id *array, NSUInteger arrayCount) {
    409     HFASSERT(removalIndex < arrayCount);
    410     HFASSERT(arrayCount > 0);
    411     HFASSERT(array[removalIndex] != nil);
    412     [array[removalIndex] release];
    413     for (NSUInteger pullingIndex = removalIndex + 1; pullingIndex < arrayCount; pullingIndex++) {
    414         array[pullingIndex - 1] = array[pullingIndex];
    415     }
    416     array[arrayCount - 1] = nil;
    417 }
    418 
    419 static void split_array(const restrict id *values, ChildIndex_t valueCount, restrict id *left, restrict id *right, ChildIndex_t leftArraySizeForClearing) {
    420     const ChildIndex_t midPoint = valueCount/2;
    421     ChildIndex_t inputIndex = 0, outputIndex = 0;
    422     while (inputIndex < midPoint) {
    423         left[outputIndex++] = values[inputIndex++];
    424     }
    425     
    426     /* Clear the remainder of our left array.  Right array does not have to be cleared. */
    427     HFASSERT(outputIndex <= leftArraySizeForClearing);
    428     while (outputIndex < leftArraySizeForClearing) {
    429         left[outputIndex++] = nil;
    430     }
    431     
    432     /* Move the second half of our values into the right array */
    433     outputIndex = 0;
    434     while (inputIndex < valueCount) {
    435         right[outputIndex++] = values[inputIndex++];
    436     }
    437 }
    438 
    439 FORCE_STATIC_INLINE HFBTreeNode *add_child_to_node_possibly_creating_split(HFBTreeNode *node, id value, ChildIndex_t insertionLocation, BOOL isLeaf) {
    440     ChildIndex_t childCount = count_node_values(node);
    441     HFASSERT(insertionLocation <= childCount);
    442     if (childCount < BTREE_ORDER) {
    443         /* No need to make a split */
    444         insert_value_into_array(value, insertionLocation, node->children, childCount + 1);
    445         node->subtreeLength = HFSum(node->subtreeLength, GET_LENGTH(value, isLeaf));
    446         return nil;
    447     }
    448     
    449     HFASSERT(node->children[BTREE_ORDER - 1] != nil); /* we require that it be full */
    450     id allEntries[BTREE_ORDER + 1];
    451     memcpy(allEntries, node->children, BTREE_ORDER * sizeof *node->children);
    452     allEntries[BTREE_ORDER] = nil;
    453     
    454     /* insert_value_into_array applies a retain, so allEntries owns a retain on its values */
    455     insert_value_into_array(value, insertionLocation, allEntries, BTREE_ORDER + 1);
    456     HFBTreeNode *newNode = [[[node class] alloc] init];
    457     
    458     /* figure out our total length */
    459     HFBTreeIndex totalLength = HFSum(node->subtreeLength, GET_LENGTH(value, isLeaf));
    460     
    461     /* Distribute half our values to the new leaf */
    462     split_array(allEntries, sizeof allEntries / sizeof *allEntries, node->children, newNode->children, BTREE_ORDER);
    463     
    464     /* figure out how much is in the new array */
    465     HFBTreeIndex newNodeLength = sum_child_lengths(newNode->children, isLeaf);
    466     
    467     /* update our lengths */
    468     HFASSERT(newNodeLength < totalLength);
    469     newNode->subtreeLength = newNodeLength;
    470     node->subtreeLength = totalLength - newNodeLength;
    471     
    472     /* Link it in */
    473     HFBTreeNode *rightNode = node->right;
    474     newNode->right = rightNode;
    475     if (rightNode) rightNode->left = newNode;
    476     newNode->left = node;
    477     node->right = newNode;
    478     return newNode;
    479 }
    480 
    481 FORCE_STATIC_INLINE void add_values_to_array(const id * restrict srcValues, NSUInteger amountToCopy, id * restrict targetValues, NSUInteger amountToPush) {
    482     // a pushed value at index X goes to index X + amountToCopy
    483     NSUInteger pushIndex = amountToPush;
    484     while (pushIndex--) {
    485         targetValues[amountToCopy + pushIndex] = targetValues[pushIndex];
    486     }
    487     for (NSUInteger i = 0; i < amountToCopy; i++) {
    488         targetValues[i] = [srcValues[i] retain];
    489     }
    490 }
    491 
    492 FORCE_STATIC_INLINE void remove_values_from_array(id * restrict array, NSUInteger amountToRemove, NSUInteger totalArrayLength) {
    493     HFASSERT(totalArrayLength >= amountToRemove);
    494     /* Release existing values */
    495     NSUInteger i;
    496     for (i=0; i < amountToRemove; i++) {
    497         [array[i] release];
    498     }
    499     /* Move remaining values */
    500     for (i=amountToRemove; i < totalArrayLength; i++) {
    501         array[i - amountToRemove] = array[i];
    502     }
    503     /* Clear the end */
    504     for (i=totalArrayLength - amountToRemove; i < totalArrayLength; i++) {
    505         array[i] = nil;
    506     }
    507 }
    508 
    509 FORCE_STATIC_INLINE BOOL rebalance_node_by_distributing_to_neighbors(HFBTreeNode *node, ChildIndex_t childCount, BOOL isLeaf, BOOL * restrict modifiedLeftNeighbor, BOOL *restrict modifiedRightNeighbor) {
    510     HFASSERT(childCount < BTREE_NODE_MINIMUM_VALUE_COUNT);
    511     BOOL result = NO;
    512     HFBTreeNode *leftNeighbor = node->left, *rightNeighbor = node->right;
    513     const ChildIndex_t leftSpaceAvailable = (leftNeighbor ? BTREE_ORDER - count_node_values(leftNeighbor) : 0);
    514     const ChildIndex_t rightSpaceAvailable = (rightNeighbor ? BTREE_ORDER - count_node_values(rightNeighbor) : 0);
    515     if (leftSpaceAvailable + rightSpaceAvailable >= childCount) {
    516         /* We have enough space to redistribute.  Try to do it in such a way that both neighbors end up with the same number of items. */
    517         ChildIndex_t itemCountForLeft = 0, itemCountForRight = 0, itemCountRemaining = childCount;
    518         if (leftSpaceAvailable > rightSpaceAvailable) {
    519             ChildIndex_t amountForLeft = MIN(leftSpaceAvailable - rightSpaceAvailable, itemCountRemaining);
    520             itemCountForLeft += amountForLeft;
    521             itemCountRemaining -= amountForLeft;
    522         }
    523         else if (rightSpaceAvailable > leftSpaceAvailable) {
    524             ChildIndex_t amountForRight = MIN(rightSpaceAvailable - leftSpaceAvailable, itemCountRemaining);
    525             itemCountForRight += amountForRight;
    526             itemCountRemaining -= amountForRight;       
    527         }
    528         /* Now distribute the remainder (if any) evenly, preferring the remainder to go left, because it is slightly cheaper to append to the left than prepend to the right */
    529         itemCountForRight += itemCountRemaining / 2;
    530         itemCountForLeft += itemCountRemaining - (itemCountRemaining / 2);
    531         HFASSERT(itemCountForLeft <= leftSpaceAvailable);
    532         HFASSERT(itemCountForRight <= rightSpaceAvailable);
    533         HFASSERT(itemCountForLeft + itemCountForRight == childCount);
    534         
    535         if (itemCountForLeft > 0) {
    536             /* append to the end */
    537             HFBTreeIndex additionalLengthForLeft = sum_N_child_lengths(node->children, itemCountForLeft, isLeaf);
    538             leftNeighbor->subtreeLength = HFSum(leftNeighbor->subtreeLength, additionalLengthForLeft);
    539             add_values_to_array(node->children, itemCountForLeft, leftNeighbor->children + BTREE_ORDER - leftSpaceAvailable, 0);
    540             HFASSERT(leftNeighbor->subtreeLength == sum_child_lengths(leftNeighbor->children, isLeaf));
    541             *modifiedLeftNeighbor = YES;
    542         }
    543         if (itemCountForRight > 0) {
    544             /* append to the beginning */
    545             HFBTreeIndex additionalLengthForRight = sum_N_child_lengths(node->children + itemCountForLeft, itemCountForRight, isLeaf);
    546             rightNeighbor->subtreeLength = HFSum(rightNeighbor->subtreeLength, additionalLengthForRight);
    547             add_values_to_array(node->children + itemCountForLeft, itemCountForRight, rightNeighbor->children, BTREE_ORDER - rightSpaceAvailable);
    548             HFASSERT(rightNeighbor->subtreeLength == sum_child_lengths(rightNeighbor->children, isLeaf));
    549             *modifiedRightNeighbor = YES;
    550         }
    551         /* Remove ourself from the linked list */
    552         if (leftNeighbor) {
    553             leftNeighbor->right = rightNeighbor;
    554         }
    555         if (rightNeighbor) {
    556             rightNeighbor->left = leftNeighbor;
    557         }
    558         /* Even though we've essentially orphaned ourself, we need to force ourselves consistent (by making ourselves empty) because our parent still references us, and we don't want to make our parent inconsistent. */
    559         for (ChildIndex_t childIndex = 0; node->children[childIndex] != nil; childIndex++) {
    560             [node->children[childIndex] release];
    561             node->children[childIndex] = nil;
    562         }
    563         node->subtreeLength = 0;
    564         
    565         result = YES;
    566     }
    567     return result;
    568 }
    569 
    570 
    571 FORCE_STATIC_INLINE BOOL share_children(HFBTreeNode *node, ChildIndex_t childCount, HFBTreeNode *neighbor, BOOL isRightNeighbor, BOOL isLeaf) {
    572     ChildIndex_t neighborCount = count_node_values(neighbor);
    573     ChildIndex_t totalChildren = (childCount + neighborCount);
    574     BOOL result = NO;
    575     if (totalChildren <= 2 * BTREE_LEAF_ORDER && totalChildren >= 2 * BTREE_LEAF_MINIMUM_VALUE_COUNT) {
    576         ChildIndex_t finalMyCount = totalChildren / 2;
    577         ChildIndex_t finalNeighborCount = totalChildren - finalMyCount;
    578         HFASSERT(finalNeighborCount < neighborCount);
    579         HFASSERT(finalMyCount > childCount);
    580         ChildIndex_t amountToTransfer = finalMyCount - childCount;
    581         HFBTreeIndex lengthChange;
    582         if (isRightNeighbor) {
    583             /* Transfer from left end of right neighbor to this right end of this leaf.  This retains the values. */
    584             add_values_to_array(neighbor->children, amountToTransfer, node->children + childCount, 0);
    585             /* Remove from beginning of right neighbor.  This releases them. */
    586             remove_values_from_array(neighbor->children, amountToTransfer, neighborCount);
    587             lengthChange = sum_N_child_lengths(node->children + childCount, amountToTransfer, isLeaf);
    588         }
    589         else {
    590             /* Transfer from right end of left neighbor to left end of this leaf */
    591             add_values_to_array(neighbor->children + neighborCount - amountToTransfer, amountToTransfer, node->children, childCount);
    592             /* Remove from end of left neighbor */
    593             remove_values_from_array(neighbor->children + neighborCount - amountToTransfer, amountToTransfer, amountToTransfer);
    594             lengthChange = sum_N_child_lengths(node->children, amountToTransfer, isLeaf);
    595         }
    596         HFASSERT(lengthChange <= neighbor->subtreeLength);
    597         neighbor->subtreeLength -= lengthChange;
    598         node->subtreeLength = HFSum(node->subtreeLength, lengthChange);
    599         HFASSERT(count_node_values(node) == finalMyCount);
    600         HFASSERT(count_node_values(neighbor) == finalNeighborCount);
    601         result = YES;
    602     }
    603     return result;
    604 }
    605 
    606 static BOOL rebalance_node_by_sharing_with_neighbors(HFBTreeNode *node, ChildIndex_t childCount, BOOL isLeaf, BOOL * restrict modifiedLeftNeighbor, BOOL *restrict modifiedRightNeighbor) {
    607     HFASSERT(childCount < BTREE_LEAF_MINIMUM_VALUE_COUNT);
    608     BOOL result = NO;
    609     HFBTreeNode *leftNeighbor = node->left, *rightNeighbor = node->right;
    610     if (leftNeighbor) {
    611         result = share_children(node, childCount, leftNeighbor, NO, isLeaf);
    612         if (result) *modifiedLeftNeighbor = YES;
    613     }
    614     if (! result && rightNeighbor) {
    615         result = share_children(node, childCount, rightNeighbor, YES, isLeaf);
    616         if (result) *modifiedRightNeighbor = YES;
    617     }
    618     return result;
    619 }
    620 
    621 /* Return YES if this leaf should be removed after rebalancing.  Other nodes are never removed. */
    622 FORCE_STATIC_INLINE BOOL rebalance_node_after_deletion(HFBTreeNode *node, ChildIndex_t childCount, BOOL isLeaf, BOOL * restrict modifiedLeftNeighbor, BOOL *restrict modifiedRightNeighbor) {
    623     HFASSERT(childCount < BTREE_LEAF_MINIMUM_VALUE_COUNT);
    624     /* We may only delete this leaf, and not adjacent leaves.  Thus our rebalancing strategy is:
    625      If the items to the left or right have sufficient space to hold us, then push our values left or right, and delete this node.
    626      Otherwise, steal items from the left until we have the same number of items. */
    627     BOOL deleteNode = NO;
    628     if (rebalance_node_by_distributing_to_neighbors(node, childCount, isLeaf, modifiedLeftNeighbor, modifiedRightNeighbor)) {
    629         deleteNode = YES;
    630         //puts("rebalance_node_by_distributing_to_neighbors");
    631     }
    632     else if (rebalance_node_by_sharing_with_neighbors(node, childCount, isLeaf, modifiedLeftNeighbor, modifiedRightNeighbor)) {
    633         deleteNode = NO;
    634         //puts("rebalance_node_by_sharing_with_neighbors");
    635     }
    636     else {
    637         [NSException raise:NSInternalInconsistencyException format:@"Unable to rebalance after deleting node %@", node];
    638     }
    639     return deleteNode;
    640 }
    641 
    642 
    643 FORCE_STATIC_INLINE BOOL remove_value_from_node_with_possible_rebalance(HFBTreeNode *node, ChildIndex_t childIndex, BOOL isRootNode, BOOL isLeaf, BOOL * restrict modifiedLeftNeighbor, BOOL *restrict modifiedRightNeighbor) {
    644     HFASSERT(childIndex < BTREE_ORDER);
    645     HFASSERT(node != nil);
    646     HFASSERT(node->children[childIndex] != nil);
    647     HFBTreeIndex entryLength = GET_LENGTH(node->children[childIndex], isLeaf);
    648     HFASSERT(entryLength <= node->subtreeLength);
    649     node->subtreeLength -= entryLength;
    650     BOOL deleteInputNode = NO;
    651     
    652 #if ! NDEBUG
    653     const id savedChild = node->children[childIndex];
    654     NSUInteger childMultiplicity = 0;
    655     NSUInteger v;
    656     for (v = 0; v < BTREE_ORDER; v++) {
    657         if (node->children[v] == savedChild) childMultiplicity++;
    658         if (node->children[v] == nil) break;
    659     }
    660     
    661 #endif
    662     
    663     /* Figure out how many children we have; start at one more than childIndex since we know that childIndex is a valid index */
    664     ChildIndex_t childCount;
    665     for (childCount = childIndex + 1; childCount < BTREE_ORDER; childCount++) {
    666         if (! node->children[childCount]) break;
    667     }
    668     
    669     /* Remove our value at childIndex; this sends it a release message */
    670     remove_value_from_array(childIndex, node->children, childCount);
    671     HFASSERT(childCount > 0);
    672     childCount--;
    673     
    674 #if ! NDEBUG
    675     for (v = 0; v < childCount; v++) {
    676         if (node->children[v] == savedChild) childMultiplicity--;
    677     }
    678     HFASSERT(childMultiplicity == 1);
    679 #endif
    680 
    681     if (childCount < BTREE_LEAF_MINIMUM_VALUE_COUNT && ! isRootNode) {
    682         /* We have too few items; try to rebalance (this will always be possible except from the root node) */
    683         deleteInputNode = rebalance_node_after_deletion(node, childCount, isLeaf, modifiedLeftNeighbor, modifiedRightNeighbor);
    684     }
    685     else {
    686         //NSLog(@"Deletion from %@ with %u remaining, %s root node, so no need to rebalance\n", node, childCount, isRootNode ? "is" : "is not");
    687     }
    688     
    689     return deleteInputNode;
    690 }
    691 
    692 FORCE_STATIC_INLINE void update_node_having_changed_size_of_child(HFBTreeNode *node, BOOL isLeaf) {
    693     HFBTreeIndex newLength = sum_child_lengths(node->children, isLeaf);
    694     /* This should only be called if the length actually changes - so assert as such */
    695     /* I no longer think the above line is true.  It's possible that we can delete a node, and then after a rebalance, we can become the same size we were before. */
    696     //HFASSERT(node->subtreeLength != newLength);
    697     node->subtreeLength = newLength;
    698 }
    699 
    700 struct SubtreeInfo_t {
    701     HFBTreeBranch *branch;
    702     ChildIndex_t childIndex; //childIndex is the index of the child of branch, not branch's index in its parent
    703 };
    704 
    705 static HFBTreeLeaf *btree_descend(HFBTree *tree, struct SubtreeInfo_t *outDescentInfo, HFBTreeIndex *insertionOffset, BOOL isForDelete) {
    706     TreeDepth_t maxDepth = tree->depth;
    707     HFASSERT(maxDepth != BAD_DEPTH && maxDepth <= MAX_DEPTH);
    708     id currentBranchOrLeaf = tree->root;
    709     HFBTreeIndex offsetForSubtree = *insertionOffset;
    710     for (TreeDepth_t currentDepth = 0; currentDepth < maxDepth; currentDepth++) {
    711         ASSERT_IS_BRANCH(currentBranchOrLeaf);
    712         HFBTreeBranch *currentBranch = currentBranchOrLeaf;
    713         HFBTreeIndex priorCombinedOffset = (HFBTreeIndex)-1;
    714         ChildIndex_t nextChildIndex = (isForDelete ? child_index_for_deletion_at_offset : child_index_for_insertion_at_offset)(currentBranch, offsetForSubtree, &priorCombinedOffset);
    715         outDescentInfo[currentDepth].branch = currentBranch;
    716         outDescentInfo[currentDepth].childIndex = nextChildIndex;
    717         offsetForSubtree -= priorCombinedOffset;
    718         currentBranchOrLeaf = currentBranch->children[nextChildIndex];
    719         if (isForDelete) {
    720             HFBTreeNode *node = currentBranchOrLeaf;
    721             HFASSERT(node->subtreeLength > offsetForSubtree);
    722         }
    723     }
    724     ASSERT_IS_LEAF(currentBranchOrLeaf);
    725     *insertionOffset = offsetForSubtree;
    726     return currentBranchOrLeaf;
    727 }
    728 
    729 struct LeafInfo_t {
    730     HFBTreeLeaf *leaf;
    731     ChildIndex_t entryIndex;
    732     HFBTreeIndex offsetOfEntryInTree;
    733 };
    734 
    735 static struct LeafInfo_t btree_find_leaf(HFBTree *tree, HFBTreeIndex offset) {
    736     TreeDepth_t depth = tree->depth;
    737     HFBTreeNode *currentNode = tree->root;
    738     HFBTreeIndex remainingOffset = offset;
    739     while (depth--) {
    740         HFBTreeIndex beginningOffsetOfNode;
    741         currentNode = child_containing_offset(currentNode, remainingOffset, &beginningOffsetOfNode, NO);
    742         HFASSERT(beginningOffsetOfNode <= remainingOffset);
    743         remainingOffset = remainingOffset - beginningOffsetOfNode;
    744     }
    745     ASSERT_IS_LEAF(currentNode);
    746     HFBTreeIndex startOffsetOfEntry;
    747     ChildIndex_t entryIndex = index_containing_offset(currentNode, remainingOffset, &startOffsetOfEntry, YES);
    748     /* The offset of this entry is the requested offset minus the difference between its starting offset within the leaf and the requested offset within the leaf */
    749     HFASSERT(remainingOffset >= startOffsetOfEntry);
    750     HFBTreeIndex offsetIntoEntry = remainingOffset - startOffsetOfEntry;
    751     HFASSERT(offset >= offsetIntoEntry);
    752     HFBTreeIndex beginningOffset = offset - offsetIntoEntry;
    753     return (struct LeafInfo_t){.leaf = CHECK_CAST(currentNode, HFBTreeLeaf), .entryIndex = entryIndex, .offsetOfEntryInTree = beginningOffset};
    754 }
    755 
    756 static TreeEntry *btree_search(HFBTree *tree, HFBTreeIndex offset, HFBTreeIndex *outBeginningOffset) {
    757     struct LeafInfo_t leafInfo = btree_find_leaf(tree, offset);
    758     *outBeginningOffset = leafInfo.offsetOfEntryInTree;
    759     return leafInfo.leaf->children[leafInfo.entryIndex];
    760 }
    761 
    762 static id btree_insert_returning_retained_value_for_parent(HFBTree *tree, TreeEntry *entry, HFBTreeIndex insertionOffset) {
    763     struct SubtreeInfo_t descentInfo[MAX_DEPTH];
    764 #if ! NDEBUG
    765     memset(descentInfo, -1, sizeof descentInfo);
    766 #endif
    767     HFBTreeIndex subtreeOffset = insertionOffset;
    768     HFBTreeLeaf *leaf = btree_descend(tree, descentInfo, &subtreeOffset, NO);
    769     ASSERT_IS_LEAF(leaf);
    770     
    771     ChildIndex_t insertionLocation = index_for_child_at_offset(leaf, subtreeOffset, YES);
    772     HFBTreeNode *retainedValueToInsertIntoParentBranch = add_child_to_node_possibly_creating_split(leaf, entry, insertionLocation, YES);
    773     
    774     /* Walk up */
    775     TreeDepth_t depth = tree->depth;
    776     HFASSERT(depth != BAD_DEPTH);
    777     HFBTreeIndex entryLength = HFBTreeLength(entry);
    778     while (depth--) {
    779         HFBTreeBranch *branch = descentInfo[depth].branch;
    780         branch->subtreeLength = HFSum(branch->subtreeLength, entryLength);
    781         ChildIndex_t childIndex = descentInfo[depth].childIndex;
    782         if (retainedValueToInsertIntoParentBranch) {
    783             HFASSERT(branch->subtreeLength > retainedValueToInsertIntoParentBranch->subtreeLength);
    784             /* Since we copied some stuff out from under ourselves, subtract its length */
    785             branch->subtreeLength -= retainedValueToInsertIntoParentBranch->subtreeLength;
    786             HFBTreeNode *newRetainedValueToInsertIntoParentBranch = add_child_to_node_possibly_creating_split(branch, retainedValueToInsertIntoParentBranch, childIndex + 1, NO);
    787             [retainedValueToInsertIntoParentBranch release];
    788             retainedValueToInsertIntoParentBranch = newRetainedValueToInsertIntoParentBranch;
    789         }
    790     }
    791     return retainedValueToInsertIntoParentBranch;
    792 }
    793 
    794 static BOOL btree_remove(HFBTree *tree, HFBTreeIndex deletionOffset) {
    795     struct SubtreeInfo_t descentInfo[MAX_DEPTH];
    796 #if ! NDEBUG
    797     memset(descentInfo, -1, sizeof descentInfo);
    798 #endif
    799     HFBTreeIndex subtreeOffset = deletionOffset;
    800     HFBTreeLeaf *leaf = btree_descend(tree, descentInfo, &subtreeOffset, YES);
    801     ASSERT_IS_LEAF(leaf);
    802     
    803     HFBTreeIndex previousOffsetSum = 0;
    804     ChildIndex_t childIndex;
    805     for (childIndex = 0; childIndex < BTREE_LEAF_ORDER; childIndex++) {
    806         if (previousOffsetSum == subtreeOffset) break;
    807         TreeEntry *entry = leaf->children[childIndex];
    808         HFASSERT(entry != nil); //if it were nil, then the offset is too large
    809         HFBTreeIndex childLength = HFBTreeLength(entry);
    810         previousOffsetSum = HFSum(childLength, previousOffsetSum);
    811     }
    812     HFASSERT(childIndex < BTREE_LEAF_ORDER);
    813     HFASSERT(previousOffsetSum == subtreeOffset);
    814         
    815     TreeDepth_t depth = tree->depth;
    816     HFASSERT(depth != BAD_DEPTH);
    817     BOOL modifiedLeft = NO, modifiedRight = NO;
    818     BOOL deleteNode = remove_value_from_node_with_possible_rebalance(leaf, childIndex, depth==0/*isRootNode*/, YES, &modifiedLeft, &modifiedRight);
    819     HFASSERT(btree_are_cached_lengths_correct(leaf, NULL));
    820     while (depth--) {
    821         HFBTreeBranch *branch = descentInfo[depth].branch;
    822         ChildIndex_t branchChildIndex = descentInfo[depth].childIndex;
    823         BOOL leftNeighborNeedsUpdating = modifiedLeft && branchChildIndex == 0; //if our child tweaked its left neighbor, and its left neighbor is not also a child of us, we need to inform its parent (which is our left neighbor)
    824         BOOL rightNeighborNeedsUpdating = modifiedRight && (branchChildIndex + 1 == BTREE_BRANCH_ORDER || branch->children[branchChildIndex + 1] == NULL); //same goes for right
    825         if (leftNeighborNeedsUpdating) {
    826             HFASSERT(branch->left != NULL);
    827 //            NSLog(@"Updating lefty %p", branch->left);
    828             update_node_having_changed_size_of_child(branch->left, NO);
    829         }
    830 #if ! NDEBUG
    831         if (branch->left) HFASSERT(btree_are_cached_lengths_correct(branch->left, NULL));
    832 #endif        
    833         if (rightNeighborNeedsUpdating) {
    834             HFASSERT(branch->right != NULL);
    835 //            NSLog(@"Updating righty %p", branch->right);
    836             update_node_having_changed_size_of_child(branch->right, NO);
    837         }
    838 #if ! NDEBUG
    839         if (branch->right) HFASSERT(btree_are_cached_lengths_correct(branch->right, NULL));
    840 #endif        
    841         update_node_having_changed_size_of_child(branch, NO);
    842         modifiedLeft = NO;
    843         modifiedRight = NO;
    844         if (deleteNode) {
    845             deleteNode = remove_value_from_node_with_possible_rebalance(branch, branchChildIndex, depth==0/*isRootNode*/, NO, &modifiedLeft, &modifiedRight);
    846         }
    847         else {
    848         //    update_node_having_changed_size_of_child(branch, NO);
    849             // no need to delete parent nodes, so leave deleteNode as NO
    850         }
    851         /* Our parent may have to modify its left or right neighbor if we had to modify our left or right neighbor or if one of our children modified a neighbor that is not also a child of us. */
    852         modifiedLeft = modifiedLeft || leftNeighborNeedsUpdating;
    853         modifiedRight = modifiedRight || rightNeighborNeedsUpdating;
    854     }
    855     
    856     if (! deleteNode) {
    857         /* Delete the root if it has one node and a depth of at least 1, or zero nodes and a depth of 0  */
    858         deleteNode = (tree->depth >= 1 && tree->root->children[1] == nil) || (tree->depth == 0 && tree->root->children[0] == nil);
    859     }
    860     return deleteNode;
    861 }
    862 
    863 /* linkingHelper stores the last seen node for each depth.  */
    864 static HFBTreeNode *mutable_copy_node(HFBTreeNode *node, TreeDepth_t depth, HFBTreeNode **linkingHelper) {
    865     if (node == nil) return nil;
    866     HFASSERT(depth != BAD_DEPTH);
    867     Class class = (depth == 0 ? [HFBTreeLeaf class] : [HFBTreeBranch class]);
    868     HFBTreeNode *result = [[class alloc] init];
    869     result->subtreeLength = node->subtreeLength;
    870     
    871     /* Link us in */
    872     HFBTreeNode *leftNeighbor = linkingHelper[0];
    873     if (leftNeighbor != nil) {
    874         leftNeighbor->right = result;
    875         result->left = leftNeighbor;
    876     }
    877     
    878     /* Leave us for our future right neighbor to find */
    879     linkingHelper[0] = (void *)result;
    880     
    881     HFBTreeIndex index;
    882     for (index = 0; index < BTREE_ORDER; index++) {
    883         id child = node->children[index];
    884         if (! node->children[index]) break;
    885         if (depth > 0) {
    886             result->children[index] = mutable_copy_node(child, depth - 1, linkingHelper + 1);
    887         }
    888         else {
    889             result->children[index] = [(TreeEntry *)child retain];
    890         }
    891     }
    892     return result;
    893 }
    894 
    895 __attribute__((unused))
    896 static BOOL non_nulls_are_grouped_at_start(const id *ptr, NSUInteger count) {
    897     BOOL hasSeenNull = NO;
    898     for (NSUInteger i=0; i < count; i++) {
    899         BOOL ptrIsNull = (ptr[i] == nil);
    900         hasSeenNull = hasSeenNull || ptrIsNull;
    901         if (hasSeenNull && ! ptrIsNull) {
    902             return NO;
    903         }
    904     }
    905     return YES;
    906 }
    907 
    908 
    909 static void btree_recursive_check_integrity(HFBTree *tree, HFBTreeNode *branchOrLeaf, TreeDepth_t depth, HFBTreeNode **linkHelper) {
    910     HFASSERT(linkHelper[0] == branchOrLeaf->left);
    911     if (linkHelper[0]) HFASSERT(linkHelper[0]->right == branchOrLeaf);
    912     linkHelper[0] = branchOrLeaf;
    913     
    914     if (depth == 0) {
    915         HFBTreeLeaf *leaf = CHECK_CAST(branchOrLeaf, HFBTreeLeaf);
    916         HFASSERT(non_nulls_are_grouped_at_start(leaf->children, BTREE_LEAF_ORDER));
    917     }
    918     else {
    919         HFBTreeBranch *branch = CHECK_CAST(branchOrLeaf, HFBTreeBranch);
    920         HFASSERT(non_nulls_are_grouped_at_start(branch->children, BTREE_BRANCH_ORDER));
    921         for (ChildIndex_t i = 0; i < BTREE_BRANCH_ORDER; i++) {
    922             if (! branch->children[i]) break;
    923             btree_recursive_check_integrity(tree, branch->children[i], depth - 1, linkHelper + 1);
    924         }
    925     }
    926     ChildIndex_t childCount = count_node_values(branchOrLeaf);
    927     if (depth < tree->depth) { // only the root may have fewer than BTREE_NODE_MINIMUM_VALUE_COUNT
    928         HFASSERT(childCount >= BTREE_NODE_MINIMUM_VALUE_COUNT);
    929     }
    930     HFASSERT(childCount <= BTREE_ORDER);
    931 }
    932 
    933 static HFBTreeIndex btree_recursive_check_integrity_of_cached_lengths(HFBTreeNode *branchOrLeaf) {
    934     HFBTreeIndex result = 0;
    935     if (IS_LEAF(branchOrLeaf)) {
    936         HFBTreeLeaf *leaf = CHECK_CAST(branchOrLeaf, HFBTreeLeaf);
    937         for (ChildIndex_t i = 0; i < BTREE_LEAF_ORDER; i++) {
    938             if (! leaf->children[i]) break;
    939             result = HFSum(result, HFBTreeLength(leaf->children[i]));
    940         }
    941     }
    942     else {
    943         HFBTreeBranch *branch = CHECK_CAST(branchOrLeaf, HFBTreeBranch);
    944         for (ChildIndex_t i = 0; i < BTREE_BRANCH_ORDER; i++) {
    945             if (branch->children[i]) {
    946                 HFBTreeIndex subtreeLength = btree_recursive_check_integrity_of_cached_lengths(branch->children[i]);
    947                 result = HFSum(result, subtreeLength);
    948             }
    949         }
    950     }
    951     HFASSERT(result == branchOrLeaf->subtreeLength);
    952     return result;
    953 }
    954 
    955 static BOOL btree_are_cached_lengths_correct(HFBTreeNode *branchOrLeaf, HFBTreeIndex *outLength) {
    956     if (! branchOrLeaf) {
    957         if (outLength) *outLength = 0;
    958         return YES;
    959     }
    960     HFBTreeIndex length = 0;
    961     if (IS_LEAF(branchOrLeaf)) {
    962         HFBTreeLeaf *leaf = CHECK_CAST(branchOrLeaf, HFBTreeLeaf);
    963         for (ChildIndex_t i=0; i < BTREE_LEAF_ORDER; i++) {
    964             if (! leaf->children[i]) break;
    965             length = HFSum(length, HFBTreeLength(leaf->children[i]));
    966         }
    967     }
    968     else {
    969         HFBTreeBranch *branch = CHECK_CAST(branchOrLeaf, HFBTreeBranch);
    970         for (ChildIndex_t i=0; i < BTREE_BRANCH_ORDER; i++) {
    971             if (! branch->children[i]) break;
    972             HFBTreeIndex subLength = (HFBTreeIndex)-1;
    973             if (! btree_are_cached_lengths_correct(branch->children[i], &subLength)) {
    974                 return NO;
    975             }
    976             length = HFSum(length, subLength);
    977         }
    978     }
    979     if (outLength) *outLength = length;
    980     return length == branchOrLeaf->subtreeLength;
    981 }
    982 
    983 #if FIXUP_LENGTHS
    984 static NSUInteger btree_entry_count(HFBTreeNode *branchOrLeaf) {
    985     NSUInteger result = 0;
    986     if (branchOrLeaf == nil) {
    987         // do nothing
    988     }
    989     else if (IS_LEAF(branchOrLeaf)) {
    990         HFBTreeLeaf *leaf = CHECK_CAST(branchOrLeaf, HFBTreeLeaf);
    991         for (ChildIndex_t i=0; i < BTREE_LEAF_ORDER; i++) {
    992             if (! leaf->children[i]) break;
    993             result++;
    994         }        
    995     }
    996     else {
    997         HFBTreeBranch *branch = CHECK_CAST(branchOrLeaf, HFBTreeBranch);
    998         for (ChildIndex_t i=0; i < BTREE_LEAF_ORDER; i++) {
    999             if (! branch->children[i]) break;
   1000             result += btree_entry_count(branch->children[i]);
   1001         }
   1002     }
   1003     return result;
   1004 }
   1005 
   1006 static HFBTreeIndex btree_recursive_fixup_cached_lengths(HFBTree *tree, HFBTreeNode *branchOrLeaf) {
   1007     HFBTreeIndex result = 0;
   1008     if (IS_LEAF(branchOrLeaf)) {
   1009         HFBTreeLeaf *leaf = CHECK_CAST(branchOrLeaf, HFBTreeLeaf);
   1010         for (ChildIndex_t i = 0; i < BTREE_LEAF_ORDER; i++) {
   1011             if (! leaf->children[i]) break;
   1012             result = HFSum(result, HFBTreeLength(leaf->children[i]));
   1013         }
   1014     }
   1015     else {
   1016         HFBTreeBranch *branch = CHECK_CAST(branchOrLeaf, HFBTreeBranch);
   1017         for (ChildIndex_t i = 0; i < BTREE_BRANCH_ORDER; i++) {
   1018             if (! branch->children[i]) break;
   1019             btree_recursive_fixup_cached_lengths(tree, branch->children[i]);
   1020             result = HFSum(result, CHECK_CAST(branch->children[i], HFBTreeNode)->subtreeLength);
   1021         }
   1022     }
   1023     branchOrLeaf->subtreeLength = result;
   1024     return result;
   1025 }
   1026 #endif
   1027 
   1028 FORCE_STATIC_INLINE void btree_apply_function_to_entries(HFBTree *tree, HFBTreeIndex offset, BOOL (*func)(id, HFBTreeIndex, void *), void *userInfo) {
   1029     struct LeafInfo_t leafInfo = btree_find_leaf(tree, offset);
   1030     HFBTreeLeaf *leaf = leafInfo.leaf;
   1031     ChildIndex_t entryIndex = leafInfo.entryIndex;
   1032     HFBTreeIndex leafOffset = leafInfo.offsetOfEntryInTree;
   1033     BOOL continueApplying = YES;
   1034     while (leaf != NULL) {
   1035         for (; entryIndex < BTREE_LEAF_ORDER; entryIndex++) {
   1036             TreeEntry *entry = leaf->children[entryIndex];
   1037             if (! entry) break;
   1038             continueApplying = func(entry, leafOffset, userInfo);
   1039             if (! continueApplying) break;
   1040             leafOffset = HFSum(leafOffset, HFBTreeLength(entry));
   1041         }
   1042         if (! continueApplying) break;
   1043         leaf = CHECK_CAST_OR_NULL(leaf->right, HFBTreeLeaf);
   1044         entryIndex = 0;
   1045     }
   1046 }
   1047 
   1048 - (NSEnumerator *)entryEnumerator {
   1049     if (! root) return [@[] objectEnumerator];
   1050     HFBTreeLeaf *leaf = btree_find_leaf(self, 0).leaf;
   1051     return [[[HFBTreeEnumerator alloc] initWithLeaf:leaf] autorelease];
   1052 }
   1053 
   1054 
   1055 static BOOL add_to_array(id entry, HFBTreeIndex offset __attribute__((unused)), void *array) {
   1056     [(id)array addObject:entry];
   1057     return YES;
   1058 }
   1059 
   1060 - (NSArray *)allEntries {
   1061     if (! root) return @[];
   1062     NSUInteger treeCapacity = 1;
   1063     unsigned int depthIndex = depth;
   1064     while (depthIndex--) treeCapacity *= BTREE_ORDER;
   1065     NSMutableArray *result = [NSMutableArray arrayWithCapacity: treeCapacity/2]; //assume we're half full
   1066     btree_apply_function_to_entries(self, 0, add_to_array, result);
   1067     return result;
   1068 }
   1069 
   1070 - (void)applyFunction:(BOOL (*)(id entry, HFBTreeIndex offset, void *userInfo))func toEntriesStartingAtOffset:(HFBTreeIndex)offset withUserInfo:(void *)userInfo {
   1071     NSParameterAssert(func != NULL);
   1072     if (! root) return;
   1073     btree_apply_function_to_entries(self, offset, func, userInfo);
   1074 }
   1075 
   1076 @end
   1077 
   1078 
   1079 @implementation HFBTreeEnumerator
   1080 
   1081 - (instancetype)initWithLeaf:(HFBTreeLeaf *)leaf {
   1082     NSParameterAssert(leaf != nil);
   1083     ASSERT_IS_LEAF(leaf);
   1084     currentLeaf = leaf;
   1085     return self;
   1086 }
   1087 
   1088 - (id)nextObject {
   1089     if (! currentLeaf) return nil;
   1090     if (childIndex >= BTREE_LEAF_ORDER || currentLeaf->children[childIndex] == nil) {
   1091         childIndex = 0;
   1092         currentLeaf = CHECK_CAST_OR_NULL(currentLeaf->right, HFBTreeLeaf);
   1093     }
   1094     if (currentLeaf == nil) return nil;
   1095     HFASSERT(currentLeaf->children[childIndex] != nil);
   1096     return currentLeaf->children[childIndex++];
   1097 }
   1098 
   1099 @end

This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.