private ValueNode <T> GetNode(GetNodeOptions options, int[] rptIdx) { Debug.Assert(rptIdx != null); bool createIfNecessary = (options == GetNodeOptions.CreateNodesAsNecessary); bool valuesBubbleAndFlow = (options != GetNodeOptions.NoBubbleAndFlow); if (createIfNecessary && rptIdx.Length > Depth) { // make sure our value tree is the appropriate depth _value.Expand(rptIdx.Length - Depth, false); Depth = rptIdx.Length; } return(GetNodeHelper(_value, 0, createIfNecessary, valuesBubbleAndFlow, rptIdx)); }
// private recursive helper function private ValueNode <T> GetNodeHelper(ValueNode <T> node, int atDepth, bool createIfNecessary, bool valuesBubbleAndFlow, int[] rptIdx) { // this can be invoked with the following flag combinations: // createIfNecessary == true && valuesBubbleAndFlow == true // we will be setting an answer // createIfNecessary == false && valuesBubbleAndFlow == true // we will be getting an answer // createIfNecessary == false && valuesBubbleAndFlow == false // we are looking up a node to count or manipulate its children // if we're recursing deeper than the _depth of this answer, we should not be creating nodes as we go! // (In that case, ValueNode<T>.Expand should have been called first to push values down the tree as necessary.) Debug.Assert(atDepth <= Depth || !createIfNecessary); if (node == null) { throw new ArgumentNullException("node"); } if (rptIdx == null) { throw new ArgumentNullException("rptIdx"); } // see if we're done recursing through all the repeat levels if (rptIdx.Length == 0 && atDepth == Depth) { ValueNode <T> result = node; if (valuesBubbleAndFlow) { // if we've found a node but it still has children in the tree, // then the value from a 0-indexed descendant node will "bubble up". while (result.HasChildren) { result = result.Children[0]; } } return(result); } int idx; int[] newIdx; if (rptIdx.Length > 0) { idx = rptIdx[0]; // continue recursing down through the repeat levels newIdx = new int[rptIdx.Length - 1]; if (rptIdx.Length > 1) { Array.Copy(rptIdx, 1, newIdx, 0, newIdx.Length); } } else // rptIdx.Length == 0 ... we've run out of repeat indices { Debug.Assert(atDepth < Depth); if (valuesBubbleAndFlow) // create new, zero indices so we can continue recursion { idx = 0; newIdx = new int[Depth - atDepth - 1]; // make sure value gets set down at the appropriate repeat level } else { Debug.Assert(!createIfNecessary); // we don't want to allow setting values at non-leaf nodes of the tree! return(node); } } // there are still repeat indices through which to recurse... if (createIfNecessary) // expand current node as necessary { if (!node.HasChildren) { node.Expand(1, true); } if (idx >= node.Children.SetCount) { node.Children.PrepareForIndex(idx); } } else if (!node.HasChildren) { // requested node does not exist -- given indexes exceed depth of repeated values return((valuesBubbleAndFlow && idx == 0 && RepeatIndices.IsFirst(newIdx)) ? node : null); } else if (idx >= node.Children.SetCount) { // requested node does not exist -- given indexes exceed number of repeated values return(null); } return(GetNodeHelper(node.Children[idx], ++atDepth, createIfNecessary, valuesBubbleAndFlow, newIdx)); }