module mtree{Type}; /* ================================================================================================ * MTree, Bitmap-based tree * ================================================================================================ * * Overview * -------- * The MTree is a bitmap-based tree structure composed of three core elements: * - Element Vector: Stores user data. * - Reference Node Vector: Manages node relationships. * - Bitmap: Marks used indices. * * The name "MTree" originates from "Matrix Tree," where the vector is divided into * sectors of power-of-two sizes. Each node's bitmap marks the positions of its * children within the same sector. * * If a parent and its children are in different sectors, a new node is created. * The parent's "next" field points to this new node, forming a chain that must * be traversed during iteration. * * * Example (sector size = 8) * ------------------------- * * _________________________________ * |__ __ _______________________ | * | | | | _ | * | v v vv |v * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ * refs_vec:| 0| 1| 2| 3| 4| 5| 6| 7| 8| 9|10|11|12|13|14|15|16|... * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ * \__________ __________/ \__________ __________/ \__ * V V * sector 0 sector 1 * * * Node Relationships: * ------------------- * - Root (Element 0) has three direct children: 1, 2, and 10. * - Node 10 is in a different sector than the root, so root.next points to Node 11. * - Node 11 has Node 10 as a direct child and Node 0 (root) as its parent. * * Bitmap Representation: * --------------------- * * root = { * .parent = -1; // Root has no parent * .next = 11; // Points to Node 11 * .children = 0b00000110; // [0|1|1|0|0|0|0|0] (Children: 1, 2) * } * * node11 = { * .parent = 0; // Parent is root (Node 0) * .next = -1; // Last in the chain * .children = 0b00000100; // [0|0|1|0|0|0|0|0] (Child: 10) * } * * ================================================================================================ */ import std::core::mem; import std::core::mem::allocator; import std::io; import std::bits; import std::collections::list; alias Bitmap = ulong; const BITS = Bitmap.sizeof*8; alias IdxList = List{int}; // next: if positive it contains the index of the next node that contains the children information struct RefNode { int next; int parent; Bitmap children; } struct MTree { usz elements; Allocator allocator; IdxList queue; Bitmap[] used; Type[] elem_vec; // element vector RefNode[] refs_vec; // relationship vector } <* @param [&inout] tree *> fn void MTree.init(&tree, usz size, Allocator allocator = mem) { // round size to the nearest multiple of BITS size = size + size%BITS; tree.elements = 0; tree.allocator = allocator; tree.queue.init(tree.allocator, size); tree.used = allocator::new_array(tree.allocator, Bitmap, size/BITS); tree.elem_vec = allocator::new_array(tree.allocator, Type, size); tree.refs_vec = allocator::new_array(tree.allocator, RefNode, size); foreach (&r: tree.refs_vec) { r.next = -1; } } <* @param [&inout] tree *> fn void MTree.free(&tree) { tree.elements = 0; tree.queue.free(); (void)allocator::free(tree.allocator, tree.used); (void)allocator::free(tree.allocator, tree.elem_vec); (void)allocator::free(tree.allocator, tree.refs_vec); } <* @param [&inout] tree *> fn int? MTree.get_free_spot(&tree) { foreach (idx, d: tree.used) { if (d != $typeof(d).max) { int spot = (int)idx*BITS + BITS-(int)d.clz(); return spot; } } return CAPACITY_EXCEEDED?; } <* @require idx >= 0 *> macro void MTree.set_used(&tree, int idx) { int r = idx % BITS; int q = idx / BITS; tree.used[q] |= (1l << r); } <* @require idx >= 0 *> macro void MTree.unset_used(&tree, int idx) { int r = idx % BITS; int q = idx / BITS; tree.used[q] &= ~(1l << r); } <* @require idx >= 0 *> macro bool MTree.is_used(&tree, int idx) { int r = idx % BITS; int q = idx / BITS; return !!(tree.used[q] & (1l << r)); } // get the last node in the "next" chain <* @require tree.is_used(parent) == true *> fn int MTree.last_node(&tree, int parent) { while(tree.refs_vec[parent].next >= 0) { parent = tree.refs_vec[parent].next; } return parent; } <* @require tree.elements == 0 || tree.is_used(parent) == true @param [&inout] tree *> fn int? MTree.add(&tree, int parent, Type t) { int idx = tree.get_free_spot()!; int subtree = idx / BITS; tree.set_used(idx); tree.elem_vec[idx] = t; tree.refs_vec[idx] = (RefNode){ .parent = parent, .next = -1, }; tree.elements++; // root element, has no parent if (tree.elements == 1) { tree.refs_vec[idx].parent = -1; return idx; } // if the parent already has a node in the same subtree as the child then update that node's // children bitmap bool done; for (int p = parent; p >= 0; p = tree.refs_vec[p].next) { int ps = p/BITS; if (ps == subtree) { tree.refs_vec[p].children |= (1l << (idx%BITS)); done = true; break; } } // on fail we need to create another parent node if (!done) { int new_next = tree.get_free_spot()!; // if the new node does not land in the same subtree as the child we cannot do // anything since the references are immutable if (new_next/BITS != subtree) { return CAPACITY_EXCEEDED?; } tree.set_used(new_next); tree.elements++; // update the "next" chain int last_link = tree.last_node(parent); tree.refs_vec[last_link].next = new_next; tree.refs_vec[new_next].next = -1; tree.refs_vec[new_next].children |= (long)(1 << (idx%BITS)); tree.refs_vec[new_next].parent = last_link; // FIXME: the elem_vec is not updated, do we need to? } return idx; } // get the index of the n-th children of parent, -1 otherwise // usage: for (int i, c; (c = tree.children_it(parent, i)) >= 0; i++) { ... } <* @param [&in] tree *> fn int MTree.children_it(&tree, int parent, int n) { int tot_children; int child; for (int p = parent; p >= 0; p = tree.refs_vec[p].next) { int cn = (int)tree.refs_vec[p].children.popcount(); tot_children += cn; // we are in the right subtree if (tot_children > n) { child = (p/BITS) * BITS; // start at the parent's subtree index int j = cn - (tot_children - n); // we need the j-th children of this node Bitmap u = tree.refs_vec[p].children; child += j; // add the children number do { child += (int)u.ctz(); // increment by the skipped zeroes u >>= u.ctz() + 1; j--; } while (j >= 0); return child; } } return -1; } <* @param [&in] tree *> fn int MTree.children_num(&tree, int parent) { int n; for (int p = parent; p >= 0; p = tree.refs_vec[p].next) { n += (int)tree.refs_vec[p].children.popcount(); } return n; } <* @param [&in] tree *> fn int MTree.subtree_size(&tree, int parent) { int x = tree.children_num(parent); int c; for (int n; (c = tree.children_it(parent, n)) >= 0; n++) { x += tree.subtree_size(c); } return x; } <* @param [&inout] tree *> fn int MTree.level_order_it(&tree, int parent, int i) { if (i == 0) { tree.queue.clear(); tree.queue.push(parent); } if (tree.queue.len() == 0) return -1; int p = tree.queue.pop_first()!!; int c; for (int n; (c = tree.children_it(p, n)) >= 0; n++) { tree.queue.push(c); } return p; } <* @param [&inout] tree *> fn void MTree.prune(&tree, int parent) { if (!tree.is_used(parent)) return; int c; for (int i = 0; (c = tree.children_it(parent, i)) >= 0; i++) { tree.prune(c); // prune the subtree // delete all children including their next chain for (int p = c; p >= 0;) { int next = tree.refs_vec[p].next; tree.unset_used(p); tree.refs_vec[p] = {.next = -1}; p = next; } } // finally delete the parent for (int p = parent; p >= 0;) { int next = tree.refs_vec[p].next; tree.unset_used(p); tree.elements--; tree.refs_vec[p] = {.next = -1}; p = next; } } <* @require ref >= 0 , ref < tree.elem_vec.len @param [&inout] tree *> fn Type? MTree.get(&tree, int ref) @operator([]) { if (tree.is_used(ref)) return tree.elem_vec[ref]; return NOT_FOUND?; } <* @param [&in] tree *> fn Type? MTree.parentof(&tree, int ref) { if (!tree.is_used(ref)) return NOT_FOUND?; return tree.refs_vec[ref].parent; } <* @param [&inout] tree *> fn void MTree.nuke(&tree) { foreach (idx, &b: tree.used) { *b = 0; tree.refs_vec[idx] = {.next = -1}; } tree.elements = 0; } <* @param [&in] t *> macro bool MTree.is_root(&t, int i) => t.is_used(i) && t.refs_vec[i].parent == -1; <* @param [&in] tree *> fn void MTree.print(&tree) { foreach (idx, c: tree.elem_vec) { if (tree.is_used((int)idx)) { io::printfn("[%d](%s) parent:%d next:%d children:%b", idx, c, tree.refs_vec[idx].parent, tree.refs_vec[idx].next, tree.refs_vec[idx].children ); } } }