unsafe int ReifyStagingNode(int parent, int indexInParent, Node *stagingNodes, int stagingNodeIndex, ref QuickList <int> subtrees, ref QuickList <int> treeletInternalNodes, ref int nextInternalNodeIndexToUse, ref QuickList <int> spareNodes, out bool nodesInvalidated) { nodesInvalidated = false; int internalNodeIndex; if (nextInternalNodeIndexToUse < treeletInternalNodes.Count) { //There is an internal node that we can use. //Note that we remove from the end to guarantee that the treelet root does not change location. //The CollectSubtrees function guarantees that the treelet root is enqueued first. internalNodeIndex = treeletInternalNodes.Elements[nextInternalNodeIndexToUse++]; } else if (!spareNodes.TryPop(out internalNodeIndex)) { //There was no pre-existing internal node that we could use. Apparently, the tree gained some internal nodes. //Watch out, calls to AllocateNode potentially invalidate all extant node pointers. //Fortunately, there are no pointers to invalidate... here. Propagate it up. //Note that this is a locking operation to support multithreading. In practice, n-ary trees should hit this very rarely. //In binary trees, this will never get hit at all. bool addCausedInvalidation; internalNodeIndex = AllocateNodeLocking(out addCausedInvalidation); if (addCausedInvalidation) { nodesInvalidated = true; } } //To make the staging node real, it requires an accurate parent pointer, index in parent, and child indices. //Copy the staging node into the real tree. //We take the staging node's child bounds, child indices, leaf counts, and child count. //The parent and index in parent are provided by the caller. var stagingNode = stagingNodes + stagingNodeIndex; var internalNode = nodes + internalNodeIndex; *internalNode = *stagingNode; internalNode->RefineFlag = 0; //The staging node could have contained arbitrary refine flag data. internalNode->Parent = parent; internalNode->IndexInParent = indexInParent; ReifyChildren(internalNodeIndex, stagingNodes, ref subtrees, ref treeletInternalNodes, ref nextInternalNodeIndexToUse, ref spareNodes, out nodesInvalidated); return(internalNodeIndex); }
public void RemoveUnusedInternalNodes(ref QuickList <int> spareNodes) { if (spareNodes.Count > 0) { lock (nodeLocker) { //Locked to protect against multiple threads dumping at once, and against other thread simultaneously running AllocateNodeLocking. //Both of these can occur during multithreaded refinements. //Since this only executes once, the cost doesn't really matter. And on binary trees, it will never execute. //There were some spare internal nodes left. Apparently, the tree was compressed a little bit. //Remove them from the real tree. //Remove highest to lowest to avoid any situation where removing could invalidate an index. Array.Sort(spareNodes.Elements, 0, spareNodes.Count); int nodeIndex; while (spareNodes.TryPop(out nodeIndex)) { RemoveNodeAt(nodeIndex); } } } }
unsafe int ReifyStagingNode(int parent, int indexInParent, Node* stagingNodes, int stagingNodeIndex, ref QuickList<int> subtrees, ref QuickList<int> treeletInternalNodes, ref int nextInternalNodeIndexToUse, ref QuickList<int> spareNodes, out bool nodesInvalidated) { nodesInvalidated = false; int internalNodeIndex; if (nextInternalNodeIndexToUse < treeletInternalNodes.Count) { //There is an internal node that we can use. //Note that we remove from the end to guarantee that the treelet root does not change location. //The CollectSubtrees function guarantees that the treelet root is enqueued first. internalNodeIndex = treeletInternalNodes.Elements[nextInternalNodeIndexToUse++]; } else if (!spareNodes.TryPop(out internalNodeIndex)) { //There was no pre-existing internal node that we could use. Apparently, the tree gained some internal nodes. //Watch out, calls to AllocateNode potentially invalidate all extant node pointers. //Fortunately, there are no pointers to invalidate... here. Propagate it up. //Note that this is a locking operation to support multithreading. In practice, n-ary trees should hit this very rarely. //In binary trees, this will never get hit at all. bool addCausedInvalidation; internalNodeIndex = AllocateNodeLocking(out addCausedInvalidation); if (addCausedInvalidation) nodesInvalidated = true; } //To make the staging node real, it requires an accurate parent pointer, index in parent, and child indices. //Copy the staging node into the real tree. //We take the staging node's child bounds, child indices, leaf counts, and child count. //The parent and index in parent are provided by the caller. var stagingNode = stagingNodes + stagingNodeIndex; var internalNode = nodes + internalNodeIndex; *internalNode = *stagingNode; internalNode->RefineFlag = 0; //The staging node could have contained arbitrary refine flag data. internalNode->Parent = parent; internalNode->IndexInParent = indexInParent; ReifyChildren(internalNodeIndex, stagingNodes, ref subtrees, ref treeletInternalNodes, ref nextInternalNodeIndexToUse, ref spareNodes, out nodesInvalidated); return internalNodeIndex; }
public void RemoveUnusedInternalNodes(ref QuickList<int> spareNodes) { if (spareNodes.Count > 0) { lock (nodeLocker) { //Locked to protect against multiple threads dumping at once, and against other thread simultaneously running AllocateNodeLocking. //Both of these can occur during multithreaded refinements. //Since this only executes once, the cost doesn't really matter. And on binary trees, it will never execute. //There were some spare internal nodes left. Apparently, the tree was compressed a little bit. //Remove them from the real tree. //Remove highest to lowest to avoid any situation where removing could invalidate an index. Array.Sort(spareNodes.Elements, 0, spareNodes.Count); int nodeIndex; while (spareNodes.TryPop(out nodeIndex)) { RemoveNodeAt(nodeIndex); } } } }