/// <summary> /// Add the given key associated with the given patch command. If either /// parameter is null this method will return without executing. /// </summary> /// <param name="key">the key</param> /// <param name="cmd">the patch command</param> public virtual void Add(string key, string cmd) { if (key == null || cmd == null) { return; } if (cmd.Length == 0) { return; } int id_cmd = cmds.IndexOf(cmd); if (id_cmd == -1) { id_cmd = cmds.Count; cmds.Add(cmd); } int node = root; Row r = GetRow(node); StrEnum e = new StrEnum(key, forward); for (int i = 0; i < e.Length - 1; i++) { char ch = e.Next(); node = r.GetRef(ch); if (node >= 0) { r = GetRow(node); } else { node = rows.Count; Row n; rows.Add(n = new Row()); r.SetRef(ch, node); r = n; } } r.SetCmd(e.Next(), id_cmd); }
/// <summary> /// Construct a <see cref="Row"/> using the cells of the given <see cref="Row"/>. /// </summary> /// <param name="old">the <see cref="Row"/> to copy</param> public Row(Row old) { cells = old.cells; }
/// <summary> /// Test whether the given Row of Cells in a Trie should be included in an /// optimized Trie. /// </summary> /// <param name="in">the Row to test</param> /// <param name="remap">Description of the Parameter</param> /// <returns><c>true</c> if the Row should remain; otherwise, <c>false</c></returns> public bool Eat(Row @in, int[] remap) { int sum = 0; for (IEnumerator<Cell> i = @in.cells.Values.GetEnumerator(); i.MoveNext();) { Cell c = i.Current; sum += c.cnt; if (c.@ref >= 0) { if (remap[c.@ref] == 0) { c.@ref = -1; } } } int frame = sum / 10; bool live = false; for (IEnumerator<Cell> i = @in.cells.Values.GetEnumerator(); i.MoveNext();) { Cell c = i.Current; if (c.cnt < frame && c.cmd >= 0) { c.cnt = 0; c.cmd = -1; } if (c.cmd >= 0 || c.@ref >= 0) { live |= true; } } return !live; }
/// <summary> /// Merge the given rows and return the resulting <see cref="Row"/>. /// </summary> /// <param name="master">the master <see cref="Row"/></param> /// <param name="existing">the existing <see cref="Row"/></param> /// <returns>the resulting <see cref="Row"/>, or <c>null</c> if the operation cannot be realized</returns> public Row Merge(Row master, Row existing) { var i = master.cells.Keys.GetEnumerator(); Row n = new Row(); for (; i.MoveNext();) { char ch = i.Current; // XXX also must handle Cnt and Skip !! Cell a = master.cells.ContainsKey(ch) ? master.cells[ch] : null; Cell b = existing.cells.ContainsKey(ch) ? existing.cells[ch] : null; Cell s = (b == null) ? new Cell(a) : Merge(a, b); if (s == null) { return null; } n.cells[ch] = s; } i = existing.cells.Keys.GetEnumerator(); for (; i.MoveNext();) { char ch = i.Current; if (master.At(ch) != null) { continue; } n.cells[ch] = existing.At(ch); } return n; }
/// <summary> /// Reduce the trie using Lift-Up reduction. /// <para> /// The Lift-Up reduction propagates all leaf-values (patch commands), where /// possible, to higher levels which are closer to the root of the trie. /// </para> /// </summary> /// <param name="in">the Row to consider when optimizing</param> /// <param name="nodes">contains the patch commands</param> public void LiftUp(Row @in, IList<Row> nodes) { IEnumerator<Cell> i = @in.cells.Values.GetEnumerator(); for (; i.MoveNext();) { Cell c = i.Current; if (c.@ref >= 0) { Row to = nodes[c.@ref]; int sum = to.UniformCmd(changeSkip); if (sum >= 0) { if (sum == c.cmd) { if (changeSkip) { if (c.skip != to.uniformSkip + 1) { continue; } c.skip = to.uniformSkip + 1; } else { c.skip = 0; } c.cnt += to.uniformCnt; c.@ref = -1; } else if (c.cmd < 0) { c.cnt = to.uniformCnt; c.cmd = sum; c.@ref = -1; if (changeSkip) { c.skip = to.uniformSkip + 1; } else { c.skip = 0; } } } } } }