/// <summary>The actual insertion function, recursive version.</summary> /// <remarks> /// The actual insertion function, recursive version. /// PLEASE NOTE that the implementation has been adapted to consume less stack memory /// </remarks> private char Insert(TernaryTree.TreeInsertionParams @params) { char?newBranch = InsertNewBranchIfNeeded(@params); if (newBranch == null) { return(InsertIntoExistingBranch(@params)); } else { return((char)newBranch); } }
// PLEASE NOTE that this function is a result of refactoring "insert" method which // is a modification of the original work // Returns null if insertion is not needed and the id of the new node if insertion was performed private char?InsertNewBranchIfNeeded(TernaryTree.TreeInsertionParams @params) { char p = @params.p; char[] key = @params.key; int start = @params.start; char val = @params.val; int len = Strlen(key, start); if (p == 0) { // this means there is no branch, this node will start a new branch. // Instead of doing that, we store the key somewhere else and create // only one node with a pointer to the key p = freenode++; // holds data eq[p] = val; length++; hi[p] = (char)0; if (len > 0) { // indicates branch is compressed sc[p] = (char)0xFFFF; // use 'lo' to hold pointer to key lo[p] = (char)kv.Alloc(len + 1); Strcpy(kv.GetArray(), lo[p], key, start); } else { sc[p] = (char)0; lo[p] = (char)0; } return(p); } else { return(null); } }
// PLEASE NOTE that this function is a result of refactoring "insert" method which // is a modification of the original work private char InsertIntoExistingBranch(TernaryTree.TreeInsertionParams @params) { char initialP = @params.p; TernaryTree.TreeInsertionParams paramsToInsertNext = @params; while (paramsToInsertNext != null) { char p = paramsToInsertNext.p; // We are inserting into an existing branch hence the id must be non-zero System.Diagnostics.Debug.Assert(p != 0); char[] key = paramsToInsertNext.key; int start = paramsToInsertNext.start; char val = paramsToInsertNext.val; int len = Strlen(key, start); paramsToInsertNext = null; if (sc[p] == 0xFFFF) { // branch is compressed: need to decompress // this will generate garbage in the external key array // but we can do some garbage collection later char pp = freenode++; // previous pointer to key lo[pp] = lo[p]; // previous pointer to data eq[pp] = eq[p]; lo[p] = (char)0; if (len > 0) { sc[p] = kv.Get(lo[pp]); eq[p] = pp; lo[pp]++; if (kv.Get(lo[pp]) == 0) { // key completly decompressed leaving garbage in key array lo[pp] = (char)0; sc[pp] = (char)0; hi[pp] = (char)0; } else { // we only got first char of key, rest is still there sc[pp] = (char)0xFFFF; } } else { // In this case we can save a node by swapping the new node // with the compressed node sc[pp] = (char)0xFFFF; hi[p] = pp; sc[p] = (char)0; eq[p] = val; length++; break; } } char s = key[start]; if (s < sc[p]) { TernaryTree.TreeInsertionParams branchParams = new TernaryTree.TreeInsertionParams(lo[p], key, start, val); char?insertNew = InsertNewBranchIfNeeded(branchParams); if (insertNew == null) { paramsToInsertNext = branchParams; } else { lo[p] = (char)insertNew; } } else { if (s == sc[p]) { if (s != 0) { TernaryTree.TreeInsertionParams branchParams = new TernaryTree.TreeInsertionParams(eq[p], key, start + 1, val); char?insertNew = InsertNewBranchIfNeeded(branchParams); if (insertNew == null) { paramsToInsertNext = branchParams; } else { eq[p] = (char)insertNew; } } else { // key already in tree, overwrite data eq[p] = val; } } else { TernaryTree.TreeInsertionParams branchParams = new TernaryTree.TreeInsertionParams(hi[p], key, start, val); char?insertNew = InsertNewBranchIfNeeded(branchParams); if (insertNew == null) { paramsToInsertNext = branchParams; } else { hi[p] = (char)insertNew; } } } } return(initialP); }