begin_node: if (assoc_array_ptr_is_shortcut(cursor)) { /* Descend through a shortcut */
shortcut = assoc_array_ptr_to_shortcut(cursor);
cursor = READ_ONCE(shortcut->next_node); /* Address dependency. */
}
node = assoc_array_ptr_to_node(cursor);
slot = 0;
/* We perform two passes of each node. * *Thefirstpassdoesalltheleavesinthisnode.Thismeanswe *don'tmissanyleavesifthenodeissplitupbyinsertionwhilst *we'reiteratingoverthebranchesrootedhere(wemay,however,see *someleavestwice).
*/
has_meta = 0; for (; slot < ASSOC_ARRAY_FAN_OUT; slot++) {
ptr = READ_ONCE(node->slots[slot]); /* Address dependency. */
has_meta |= (unsignedlong)ptr; if (ptr && assoc_array_ptr_is_leaf(ptr)) { /* We need a barrier between the read of the pointer, *whichissuppliedbytheaboveREAD_ONCE().
*/ /* Invoke the callback */
ret = iterator(assoc_array_ptr_to_leaf(ptr),
iterator_data); if (ret) return ret;
}
}
/* The second pass attends to all the metadata pointers. If we follow *oneofthesewemayfindthatwedon'tcomebackhere,butrathergo *backtoareplacementnodewiththeleavesinadifferentlayout. * *Weareguaranteedtomakeprogress,however,astheslotnumberfor *aparticularportionofthekeyspacecannotchange-andwe *continueatthebackpointer+1.
*/ if (!(has_meta & ASSOC_ARRAY_PTR_META_TYPE)) goto finished_node;
slot = 0;
finished_node: /* Move up to the parent (may need to skip back over a shortcut) */
parent = READ_ONCE(node->back_pointer); /* Address dependency. */
slot = node->parent_slot; if (parent == stop) return0;
struct assoc_array_walk_result { struct { struct assoc_array_node *node; /* Node in which leaf might be found */ int level; int slot;
} terminal_node; struct { struct assoc_array_shortcut *shortcut; int level; int sc_level; unsignedlong sc_segments; unsignedlong dissimilarity;
} wrong_shortcut;
};
/* Use segments from the key for the new leaf to navigate through the *internaltree,skippingthroughnodesandshortcutsthatareon *routetothedestination.Eventuallywe'llcometoaslotthatis *eitheremptyorcontainsaleafatwhichpointwe'vefoundanodein *whichtheleafwe'relookingformightbefoundorintowhichit *shouldbeinserted.
*/
jumped:
segments = ops->get_key_chunk(index_key, level);
pr_devel("segments[%d]: %lx\n", level, segments);
if (assoc_array_ptr_is_shortcut(cursor)) goto follow_shortcut;
if (!assoc_array_ptr_is_meta(ptr)) { /* The node doesn't have a node/shortcut pointer in the slot *correspondingtotheindexkeythatwehavetofollow.
*/
result->terminal_node.node = node;
result->terminal_node.level = level;
result->terminal_node.slot = slot;
pr_devel("<--%s() = terminal_node\n", __func__); return assoc_array_walk_found_terminal_node;
}
if (assoc_array_ptr_is_node(ptr)) { /* There is a pointer to a node in the slot corresponding to *thisindexkeysegment,soweneedtofollowit.
*/
cursor = ptr;
level += ASSOC_ARRAY_LEVEL_STEP; if ((level & ASSOC_ARRAY_KEY_CHUNK_MASK) != 0) goto consider_node; goto jumped;
}
/* There is a shortcut in the slot corresponding to the index key *segment.Wefollowtheshortcutifitspartialindexkeymatches *thisleaf's.Otherwiseweneedtosplittheshortcut.
*/
cursor = ptr;
follow_shortcut:
shortcut = assoc_array_ptr_to_shortcut(cursor);
pr_devel("shortcut to %d\n", shortcut->skip_to_level);
sc_level = level + ASSOC_ARRAY_LEVEL_STEP;
BUG_ON(sc_level > shortcut->skip_to_level);
do { /* Check the leaf against the shortcut's index key a word at a *time,trimmingthefinalword(theshortcutstorestheindex *keycompletelyfromtheroottotheshortcut'starget).
*/ if ((sc_level & ASSOC_ARRAY_KEY_CHUNK_MASK) == 0)
segments = ops->get_key_chunk(index_key, sc_level);
if (assoc_array_walk(array, ops, index_key, &result) !=
assoc_array_walk_found_terminal_node) return NULL;
node = result.terminal_node.node;
/* If the target key is available to us, it's has to be pointed to by *theterminalnode.
*/ for (slot = 0; slot < ASSOC_ARRAY_FAN_OUT; slot++) {
ptr = READ_ONCE(node->slots[slot]); /* Address dependency. */ if (ptr && assoc_array_ptr_is_leaf(ptr)) { /* We need a barrier between the read of the pointer *anddereferencingthepointer-butonlyifweare *actuallygoingtodereferenceit.
*/
leaf = assoc_array_ptr_to_leaf(ptr); if (ops->compare_object(leaf, index_key)) return (void *)leaf;
}
}
/* Move back up to the parent (may need to free a shortcut on
* the way up) */ if (assoc_array_ptr_is_shortcut(parent)) {
shortcut = assoc_array_ptr_to_shortcut(parent);
BUG_ON(shortcut->next_node != cursor);
cursor = parent;
parent = shortcut->back_pointer;
slot = shortcut->parent_slot;
pr_devel("free shortcut\n");
kfree(shortcut); if (!parent) return;
BUG_ON(!assoc_array_ptr_is_node(parent));
}
/* Ascend to next slot in parent node */
pr_devel("ascend to %p[%d]\n", parent, slot);
cursor = parent;
node = assoc_array_ptr_to_node(cursor);
slot++; goto continue_node;
}
/* We arrived at a node which doesn't have an onward node or shortcut *pointerthatwehavetofollow.Thismeansthat(a)theleafwe *wantmustgohere(eitherbyinsertionorreplacement)or(b)we *needtosplitthisnodeandinsertinoneofthefragments.
*/
free_slot = -1;
/* Firstly, we have to check the leaves in this node to see if there's *amatchingoneweshouldreplaceinplace.
*/ for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++) {
ptr = node->slots[i]; if (!ptr) {
free_slot = i; continue;
} if (assoc_array_ptr_is_leaf(ptr) &&
ops->compare_object(assoc_array_ptr_to_leaf(ptr),
index_key)) {
pr_devel("replace in slot %d\n", i);
edit->leaf_p = &node->slots[i];
edit->dead_leaf = node->slots[i];
pr_devel("<--%s() = ok [replace]\n", __func__); returntrue;
}
}
/* If there is a free slot in this node then we can just insert the *leafhere.
*/ if (free_slot >= 0) {
pr_devel("insert in free slot %d\n", free_slot);
edit->leaf_p = &node->slots[free_slot];
edit->adjust_count_on = node;
pr_devel("<--%s() = ok [insert]\n", __func__); returntrue;
}
/* The node has no spare slots - so we're either going to have to split *itorinsertanothernodebeforeit. * *Whatever,we'regoingtoneedatleasttwonewnodes-soallocate *thosenow.Wemayalsoneedanewshortcut,butwedealwiththat *whenweneedit.
*/
new_n0 = kzalloc(sizeof(struct assoc_array_node), GFP_KERNEL); if (!new_n0) returnfalse;
edit->new_meta[0] = assoc_array_node_to_ptr(new_n0);
new_n1 = kzalloc(sizeof(struct assoc_array_node), GFP_KERNEL); if (!new_n1) returnfalse;
edit->new_meta[1] = assoc_array_node_to_ptr(new_n1);
/* We need to find out how similar the leaves are. */
pr_devel("no spare slots\n");
have_meta = false; for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++) {
ptr = node->slots[i]; if (assoc_array_ptr_is_meta(ptr)) {
edit->segment_cache[i] = 0xff;
have_meta = true; continue;
}
base_seg = ops->get_object_key_chunk(
assoc_array_ptr_to_leaf(ptr), level);
base_seg >>= level & ASSOC_ARRAY_KEY_CHUNK_MASK;
edit->segment_cache[i] = base_seg & ASSOC_ARRAY_FAN_MASK;
}
if (have_meta) {
pr_devel("have meta\n"); goto split_node;
}
/* The node contains only leaves */
dissimilarity = 0;
base_seg = edit->segment_cache[0]; for (i = 1; i < ASSOC_ARRAY_FAN_OUT; i++)
dissimilarity |= edit->segment_cache[i] ^ base_seg;
if ((dissimilarity & ASSOC_ARRAY_FAN_MASK) == 0) { /* The old leaves all cluster in the same slot. We will need *toinsertashortcutifthenewnodewantstoclusterwiththem.
*/ if ((edit->segment_cache[ASSOC_ARRAY_FAN_OUT] ^ base_seg) == 0) goto all_leaves_cluster_together;
/* Otherwise all the old leaves cluster in the same slot, but *thenewleafwantstogointoadifferentslot-sowe *createanewnode(n0)toholdthenewleafandapointerto *anewnode(n1)holdingalltheoldleaves. * *Thiscanbedonebyfallingthroughtothenodesplitting *path.
*/
pr_devel("present leaves cluster but not new leaf\n");
}
split_node:
pr_devel("split node\n");
/* We need to split the current node. The node must contain anything *fromasingleleaf(intheoneleafcase,thisleafwillcluster *withthenewleaf)andtherestmeta-pointers,toallleaves,some *ofwhichmaycluster. * *Itwon'tcontainthecaseinwhichallthecurrentleavesplusthe *newleaveswanttoclusterinthesameslot. * *Weneedtoexpelatleasttwoleavesoutofasetconsistingofthe *leavesinthenodeandthenewleaf.Thecurrentmetapointerscan *justbecopiedastheyshouldn'tclusterwithanyoftheleaves. * *Weneedanewnode(n0)toreplacethecurrentoneandanewnodeto *taketheexpellednodes(n1).
*/
edit->set[0].to = assoc_array_node_to_ptr(new_n0);
new_n0->back_pointer = node->back_pointer;
new_n0->parent_slot = node->parent_slot;
new_n1->back_pointer = assoc_array_node_to_ptr(new_n0);
new_n1->parent_slot = -1; /* Need to calculate this */
/* Begin by finding two matching leaves. There have to be at least two *thatmatch-eveniftherearemetapointers-becauseanyleafthat *wouldmatchaslotwithametapointerinitmustbesomewhere *behindthatmetapointerandcannotbehere.Further,givenN *remainingleafslots,wenowhaveN+1leavestogointhem.
*/ for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++) {
slot = edit->segment_cache[i]; if (slot != 0xff) for (j = i + 1; j < ASSOC_ARRAY_FAN_OUT + 1; j++) if (edit->segment_cache[j] == slot) goto found_slot_for_multiple_occupancy;
}
found_slot_for_multiple_occupancy:
pr_devel("same slot: %x %x [%02x]\n", i, j, slot);
BUG_ON(i >= ASSOC_ARRAY_FAN_OUT);
BUG_ON(j >= ASSOC_ARRAY_FAN_OUT + 1);
BUG_ON(slot >= ASSOC_ARRAY_FAN_OUT);
new_n1->parent_slot = slot;
/* Metadata pointers cannot change slot */ for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++) if (assoc_array_ptr_is_meta(node->slots[i]))
new_n0->slots[i] = node->slots[i]; else
new_n0->slots[i] = NULL;
BUG_ON(new_n0->slots[slot] != NULL);
new_n0->slots[slot] = assoc_array_node_to_ptr(new_n1);
/* Filter the leaf pointers between the new nodes */
free_slot = -1;
next_slot = 0; for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++) { if (assoc_array_ptr_is_meta(node->slots[i])) continue; if (edit->segment_cache[i] == slot) {
new_n1->slots[next_slot++] = node->slots[i];
new_n1->nr_leaves_on_branch++;
} else { do {
free_slot++;
} while (new_n0->slots[free_slot] != NULL);
new_n0->slots[free_slot] = node->slots[i];
}
}
all_leaves_cluster_together: /* All the leaves, new and old, want to cluster together in this node *inthesameslot,sowehavetoreplacethisnodewithashortcutto *skipovertheidenticalpartsofthekeyandthenplaceapairof *nodes,oneinsidetheother,attheendoftheshortcutand *distributethekeysbetweenthem. * *Firstlyweneedtoworkoutwheretheleavesstartdivergingasa *bitpositionintotheirkeyssothatweknowhowbigtheshortcut *needstobe. * *WeonlyneedtomakeasinglepassofNoftheN+1leavesbecauseif *anykeysdifferbetweenthemselvesatbitXthenatleastoneof *themmustalsodifferwiththebasekeyatbitXorbefore.
*/
pr_devel("all leaves cluster together\n");
diff = INT_MAX; for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++) { int x = ops->diff_objects(assoc_array_ptr_to_leaf(node->slots[i]),
index_key); if (x < diff) {
BUG_ON(x < 0);
diff = x;
}
}
BUG_ON(diff == INT_MAX);
BUG_ON(diff < level + ASSOC_ARRAY_LEVEL_STEP);
/* This now reduces to a node splitting exercise for which we'll need *toregeneratethedisparitytable.
*/ for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++) {
ptr = node->slots[i];
base_seg = ops->get_object_key_chunk(assoc_array_ptr_to_leaf(ptr),
level);
base_seg >>= level & ASSOC_ARRAY_KEY_CHUNK_MASK;
edit->segment_cache[i] = base_seg & ASSOC_ARRAY_FAN_MASK;
}
/* We need to split a shortcut and insert a node between the two *pieces.Zero-lengthpieceswillbedispensedwithentirely. * *Firstofall,weneedtofindoutinwhichlevelthefirst *differencewas.
*/
diff = __ffs(dissimilarity);
diff &= ~ASSOC_ARRAY_LEVEL_STEP_MASK;
diff += sc_level & ~ASSOC_ARRAY_KEY_CHUNK_MASK;
pr_devel("diff=%d\n", diff);
/* Create a new node now since we're going to need it anyway */
new_n0 = kzalloc(sizeof(struct assoc_array_node), GFP_KERNEL); if (!new_n0) returnfalse;
edit->new_meta[0] = assoc_array_node_to_ptr(new_n0);
edit->adjust_count_on = new_n0;
/* Insert a new shortcut before the new node if this segment isn't of *zerolength-otherwisewejustconnectthenewnodedirectlytothe *parent.
*/
level += ASSOC_ARRAY_LEVEL_STEP; if (diff > level) {
pr_devel("pre-shortcut %d...%d\n", level, diff);
keylen = round_up(diff, ASSOC_ARRAY_KEY_CHUNK_SIZE);
keylen >>= ASSOC_ARRAY_KEY_CHUNK_SHIFT;
side = assoc_array_ptr_to_node(shortcut->next_node);
new_n0->nr_leaves_on_branch = side->nr_leaves_on_branch;
/* We need to know which slot in the new node is going to take a *metadatapointer.
*/
sc_slot = sc_segments >> (diff & ASSOC_ARRAY_KEY_CHUNK_MASK);
sc_slot &= ASSOC_ARRAY_FAN_MASK;
/* Determine whether we need to follow the new node with a replacement *forthecurrentshortcut.Wecouldintheoryreusethecurrent *shortcutifitsparentslotnumberdoesn'tchange-butthat'sa *1-in-16chancesonotworthexpendingthecodeupon.
*/
level = diff + ASSOC_ARRAY_LEVEL_STEP; if (level < shortcut->skip_to_level) {
pr_devel("post-shortcut %d...%d\n", level, shortcut->skip_to_level);
keylen = round_up(shortcut->skip_to_level, ASSOC_ARRAY_KEY_CHUNK_SIZE);
keylen >>= ASSOC_ARRAY_KEY_CHUNK_SHIFT;
/* We don't have to replace the pointed-to node as long as we *usememorybarrierstomakesuretheparentslotnumberis *changedbeforethebackpointer(theparentslotnumberis *irrelevanttotheoldparentshortcut).
*/
new_n0->slots[sc_slot] = shortcut->next_node;
edit->set_parent_slot[0].p = &side->parent_slot;
edit->set_parent_slot[0].to = sc_slot;
edit->set[1].ptr = &side->back_pointer;
edit->set[1].to = assoc_array_node_to_ptr(new_n0);
}
/* Install the new leaf in a spare slot in the new node. */ if (sc_slot == 0)
edit->leaf_p = &new_n0->slots[1]; else
edit->leaf_p = &new_n0->slots[0];
pr_devel("<--%s() = ok [split shortcut]\n", __func__); returntrue;
}
/* The leaf pointer we're given must not have the bottom bit set as we *usethosefortype-markingthepointer.NULLpointersarealsonot *allowedastheyindicateanemptyslotbutwehavetoallowthem *hereastheycanbeupdatedlater.
*/
BUG_ON(assoc_array_ptr_is_meta(object));
switch (assoc_array_walk(array, ops, index_key, &result)) { case assoc_array_walk_tree_empty: /* Allocate a root node if there isn't one yet */ if (!assoc_array_insert_in_empty_tree(edit)) goto enomem; return edit;
case assoc_array_walk_found_terminal_node: /* We found a node that doesn't have a node/shortcut pointer in *theslotcorrespondingtotheindexkeythatwehaveto *follow.
*/ if (!assoc_array_insert_into_terminal_node(edit, ops, index_key,
&result)) goto enomem; return edit;
case assoc_array_walk_found_wrong_shortcut: /* We found a shortcut that didn't match our key in a slot we *neededtofollow.
*/ if (!assoc_array_insert_mid_shortcut(edit, ops, &result)) goto enomem; return edit;
}
enomem: /* Clean up after an out of memory error */
pr_devel("enomem\n");
assoc_array_cancel_edit(edit); return ERR_PTR(-ENOMEM);
}
switch (assoc_array_walk(array, ops, index_key, &result)) { case assoc_array_walk_found_terminal_node: /* We found a node that should contain the leaf we've been *askedtoremove-*if*it'sinthetree.
*/
pr_devel("terminal_node\n");
node = result.terminal_node.node;
for (slot = 0; slot < ASSOC_ARRAY_FAN_OUT; slot++) {
ptr = node->slots[slot]; if (ptr &&
assoc_array_ptr_is_leaf(ptr) &&
ops->compare_object(assoc_array_ptr_to_leaf(ptr),
index_key)) goto found_leaf;
}
fallthrough; case assoc_array_walk_tree_empty: case assoc_array_walk_found_wrong_shortcut: default:
assoc_array_cancel_edit(edit);
pr_devel("not found\n"); return NULL;
}
/* In the simplest form of deletion we just clear the slot and release *theleafafterasuitableinterval.
*/
edit->dead_leaf = node->slots[slot];
edit->set[0].ptr = &node->slots[slot];
edit->set[0].to = NULL;
edit->adjust_count_on = node;
/* If that concludes erasure of the last leaf, then delete the entire *internalarray.
*/ if (array->nr_leaves_on_tree == 1) {
edit->set[1].ptr = &array->root;
edit->set[1].to = NULL;
edit->adjust_count_on = NULL;
edit->excised_subtree = array->root;
pr_devel("all gone\n"); return edit;
}
/* However, we'd also like to clear up some metadata blocks if we *possiblycan. * *Wegoforasimplealgorithmof:ifthisnodehasFAN_OUTorfewer *leavesinit,thenattempttocollapseit-andattemptto *recursivelycollapseupthetree. * *Wecouldalsotryandcollapseinpartiallyfilledsubtreestotake *upspaceinthisnode.
*/ if (node->nr_leaves_on_branch <= ASSOC_ARRAY_FAN_OUT + 1) { struct assoc_array_node *parent, *grandparent; struct assoc_array_ptr *ptr;
/* First of all, we need to know if this node has metadata so *thatwedon'ttrycollapsingifalltheleavesarealready *here.
*/
has_meta = false; for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++) {
ptr = node->slots[i]; if (assoc_array_ptr_is_meta(ptr)) {
has_meta = true; break;
}
}
/* Look further up the tree to see if we can collapse this node *intoamoreproximalnodetoo.
*/
parent = node;
collapse_up:
pr_devel("collapse subtree: %ld\n", parent->nr_leaves_on_branch);
ptr = parent->back_pointer; if (!ptr) goto do_collapse; if (assoc_array_ptr_is_shortcut(ptr)) { struct assoc_array_shortcut *s = assoc_array_ptr_to_shortcut(ptr);
ptr = s->back_pointer; if (!ptr) goto do_collapse;
}
do_collapse: /* There's no point collapsing if the original node has no meta *pointerstodiscardandifwedidn'tmergeintooneofthat *node'sancestry.
*/ if (has_meta || parent != node) {
node = parent;
/* Create a new node to collapse into */
new_n0 = kzalloc(sizeof(struct assoc_array_node), GFP_KERNEL); if (!new_n0) goto enomem;
edit->new_meta[0] = assoc_array_node_to_ptr(new_n0);
if (edit->dead_leaf)
edit->ops->free_object(assoc_array_ptr_to_leaf(edit->dead_leaf)); for (i = 0; i < ARRAY_SIZE(edit->excised_meta); i++) if (edit->excised_meta[i])
kfree(assoc_array_ptr_to_node(edit->excised_meta[i]));
smp_wmb(); if (edit->leaf_p)
*edit->leaf_p = edit->leaf;
smp_wmb(); for (i = 0; i < ARRAY_SIZE(edit->set_parent_slot); i++) if (edit->set_parent_slot[i].p)
*edit->set_parent_slot[i].p = edit->set_parent_slot[i].to;
smp_wmb(); for (i = 0; i < ARRAY_SIZE(edit->set_backpointers); i++) if (edit->set_backpointers[i])
*edit->set_backpointers[i] = edit->set_backpointers_to;
smp_wmb(); for (i = 0; i < ARRAY_SIZE(edit->set); i++) if (edit->set[i].ptr)
*edit->set[i].ptr = edit->set[i].to;
/* Clean up after an out of memory error */ for (i = 0; i < ARRAY_SIZE(edit->new_meta); i++) {
ptr = edit->new_meta[i]; if (ptr) { if (assoc_array_ptr_is_node(ptr))
kfree(assoc_array_ptr_to_node(ptr)); else
kfree(assoc_array_ptr_to_shortcut(ptr));
}
}
kfree(edit);
}
descend: /* If this point is a shortcut, then we need to duplicate it and *advancethetargetcursor.
*/ if (assoc_array_ptr_is_shortcut(cursor)) {
shortcut = assoc_array_ptr_to_shortcut(cursor);
keylen = round_up(shortcut->skip_to_level, ASSOC_ARRAY_KEY_CHUNK_SIZE);
keylen >>= ASSOC_ARRAY_KEY_CHUNK_SHIFT;
new_s = kmalloc(struct_size(new_s, index_key, keylen),
GFP_KERNEL); if (!new_s) goto enomem;
pr_devel("dup shortcut %p -> %p\n", shortcut, new_s);
memcpy(new_s, shortcut, struct_size(new_s, index_key, keylen));
new_s->back_pointer = new_parent;
new_s->parent_slot = shortcut->parent_slot;
*new_ptr_pp = new_parent = assoc_array_shortcut_to_ptr(new_s);
new_ptr_pp = &new_s->next_node;
cursor = shortcut->next_node;
}
/* Duplicate the node at this position */
node = assoc_array_ptr_to_node(cursor);
new_n = kzalloc(sizeof(struct assoc_array_node), GFP_KERNEL); if (!new_n) goto enomem;
pr_devel("dup node %p -> %p\n", node, new_n);
new_n->back_pointer = new_parent;
new_n->parent_slot = node->parent_slot;
*new_ptr_pp = new_parent = assoc_array_node_to_ptr(new_n);
new_ptr_pp = NULL;
slot = 0;
continue_node: /* Filter across any leaves and gc any subtrees */ for (; slot < ASSOC_ARRAY_FAN_OUT; slot++) {
ptr = node->slots[slot]; if (!ptr) continue;
if (assoc_array_ptr_is_leaf(ptr)) { if (iterator(assoc_array_ptr_to_leaf(ptr),
iterator_data)) /* The iterator will have done any reference *countingontheobjectforus.
*/
new_n->slots[slot] = ptr; continue;
}
/* Count up the number of empty slots in this node and work out the *subtreeleafcount.
*/
new_n->nr_leaves_on_branch = 0;
nr_free = 0; for (slot = 0; slot < ASSOC_ARRAY_FAN_OUT; slot++) {
ptr = new_n->slots[slot]; if (!ptr)
nr_free++; elseif (assoc_array_ptr_is_leaf(ptr))
new_n->nr_leaves_on_branch++;
}
pr_devel("free=%d, leaves=%lu\n", nr_free, new_n->nr_leaves_on_branch);
/* See what we can fold in */
retained = false;
next_slot = 0; for (slot = 0; slot < ASSOC_ARRAY_FAN_OUT; slot++) { struct assoc_array_shortcut *s; struct assoc_array_node *child;
ptr = new_n->slots[slot]; if (!ptr || assoc_array_ptr_is_leaf(ptr)) continue;
s = NULL; if (assoc_array_ptr_is_shortcut(ptr)) {
s = assoc_array_ptr_to_shortcut(ptr);
ptr = s->next_node;
}
/* Excise this node if it is singly occupied by a shortcut */ if (nr_free == ASSOC_ARRAY_FAN_OUT - 1) { for (slot = 0; slot < ASSOC_ARRAY_FAN_OUT; slot++) if ((ptr = new_n->slots[slot])) break;
if (assoc_array_ptr_is_shortcut(new_parent)) { /* We can discard any preceding shortcut also */ struct assoc_array_shortcut *s =
assoc_array_ptr_to_shortcut(new_parent);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.