using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Text; namespace HeuristicLab.Problems.GrammaticalOptimization { public class ReadonlySequence : Sequence { private int symbolsOffset = 0; // the sequence does not have to start with the first symbol of the symbols array (when we reuse these arrays) // cloning constructor for readonly sequences // does not allocate the symbols array of the base class // instead: reuse the symbols array (both sequences are readonly) private ReadonlySequence(ReadonlySequence original) : base() { base.symbols = original.symbols; this.symbolsOffset = original.symbolsOffset; } public ReadonlySequence(string s) : base(s, s.Length) { } public ReadonlySequence(char ch) : base(ch, 1) { } public ReadonlySequence(Sequence s) : base(s, s.Length) { } public override void ReplaceAt(int position, int len, Sequence replacement) { throw new NotSupportedException(); } public override char this[int idx] { get { return base[idx + symbolsOffset]; } set { throw new NotSupportedException(); } } public override IEnumerator GetEnumerator() { return symbols.Skip(symbolsOffset).Take(Length).GetEnumerator(); } public override string ToString() { var sb = new StringBuilder(Length); sb.Append(symbols, symbolsOffset, Length); return sb.ToString(); } public new ReadonlySequence Subsequence(int startIdx, int len) { if (startIdx < 0 || len < 0) throw new ArgumentException(); if (startIdx >= this.Length) throw new ArgumentException(); if (startIdx + len > this.Length) throw new ArgumentException(); var subsequence = new ReadonlySequence(this) { symbolsOffset = startIdx + this.symbolsOffset, Length = len }; if (FirstNonTerminalIndex < 0) { subsequence.FirstNonTerminalIndex = -1; } else if (FirstNonTerminalIndex < startIdx) { // need to find first nt in subsequence subsequence.FirstNonTerminalIndex = -1; for (int i = 0; subsequence.FirstNonTerminalIndex == -1 && i < len; i++) { if (subsequence[i] >= 'A' && subsequence[i] <= 'Z') subsequence.FirstNonTerminalIndex = i; } } else if (FirstNonTerminalIndex >= startIdx && FirstNonTerminalIndex < startIdx + len) { subsequence.FirstNonTerminalIndex = FirstNonTerminalIndex - startIdx; } else { Debug.Assert(FirstNonTerminalIndex >= startIdx + len); subsequence.FirstNonTerminalIndex = -1; } return subsequence; } public override bool Equals(object obj) { var other = obj as ReadonlySequence; if (other == null) return false; if (other.Length != this.Length) return false; for (int i = 0; i < Length; i++) if (other[i] != this[i]) return false; // length and all symbols are the same return true; } public override int GetHashCode() { int h = 31 * Length; for (int i = 0; i < Length; i++) { h += 31 * (byte)this[i]; } return h; } } }