private readonly int[] _rules; // negative -> group #, positive -> string # /// <summary> /// Since RegexReplacement shares the same parser as Regex, /// the constructor takes a RegexNode which is a concatenation /// of constant strings and backreferences. /// </summary> public RegexReplacement(string rep, RegexNode concat, Hashtable _caps) { if (concat.Type != RegexNode.Concatenate) { throw ThrowHelper.CreateArgumentException(ExceptionResource.ReplacementError); } Span <char> vsbStack = stackalloc char[256]; var vsb = new ValueStringBuilder(vsbStack); FourStackStrings stackStrings = default; var strings = new ValueListBuilder <string>(MemoryMarshal.CreateSpan(ref stackStrings.Item1 !, 4)); var rules = new ValueListBuilder <int>(stackalloc int[64]); int childCount = concat.ChildCount(); for (int i = 0; i < childCount; i++) { RegexNode child = concat.Child(i); switch (child.Type) { case RegexNode.Multi: vsb.Append(child.Str !); break; case RegexNode.One: vsb.Append(child.Ch); break; case RegexNode.Ref: if (vsb.Length > 0) { rules.Append(strings.Length); strings.Append(vsb.ToString()); vsb = new ValueStringBuilder(vsbStack); } int slot = child.M; if (_caps != null && slot >= 0) { slot = (int)_caps[slot] !; } rules.Append(-Specials - 1 - slot); break; default: throw ThrowHelper.CreateArgumentException(ExceptionResource.ReplacementError); } } if (vsb.Length > 0) { rules.Append(strings.Length); strings.Append(vsb.ToString()); } Pattern = rep; _strings = strings.AsSpan().ToArray(); _rules = rules.AsSpan().ToArray(); rules.Dispose(); }
private bool _hasBackreferences; // true if the replacement has any backreferences; otherwise, false /// <summary> /// Since RegexReplacement shares the same parser as Regex, /// the constructor takes a RegexNode which is a concatenation /// of constant strings and backreferences. /// </summary> public RegexReplacement(string rep, RegexNode concat, Hashtable _caps) { Debug.Assert(concat.Kind == RegexNodeKind.Concatenate, $"Expected Concatenate, got {concat.Kind}"); var vsb = new ValueStringBuilder(stackalloc char[256]); FourStackStrings stackStrings = default; var strings = new ValueListBuilder <string>(MemoryMarshal.CreateSpan(ref stackStrings.Item1 !, 4)); var rules = new ValueListBuilder <int>(stackalloc int[64]); int childCount = concat.ChildCount(); for (int i = 0; i < childCount; i++) { RegexNode child = concat.Child(i); switch (child.Kind) { case RegexNodeKind.Multi: vsb.Append(child.Str !); break; case RegexNodeKind.One: vsb.Append(child.Ch); break; case RegexNodeKind.Backreference: if (vsb.Length > 0) { rules.Append(strings.Length); strings.Append(vsb.AsSpan().ToString()); vsb.Length = 0; } int slot = child.M; if (_caps != null && slot >= 0) { slot = (int)_caps[slot] !; } rules.Append(-Specials - 1 - slot); _hasBackreferences = true; break; default: Debug.Fail($"Unexpected child kind {child.Kind}"); break; } } if (vsb.Length > 0) { rules.Append(strings.Length); strings.Append(vsb.ToString()); } vsb.Dispose(); Pattern = rep; _strings = strings.AsSpan().ToArray(); _rules = rules.AsSpan().ToArray(); rules.Dispose(); }