namespace System.Text.RegularExpressions {
[Serializable]
- public class Regex : ISerializable {
+ public partial class Regex : ISerializable {
#if NET_2_0
private static int cache_size = 15;
#endif
-
+#if !TARGET_JVM
[MonoTODO]
public static void CompileToAssembly (RegexCompilationInfo [] regexes, AssemblyName aname)
{
asmBuilder.Save(aname.Name);
*/
}
+#endif
public static string Escape (string str)
{
}
#if NET_2_0
- [MonoTODO ("should be used somewhere ? FactoryCache ?")]
+ static FactoryCache cache = new FactoryCache (15);
public static int CacheSize {
- get { return cache_size; }
+ get { return cache.Capacity; }
set {
if (value < 0)
throw new ArgumentOutOfRangeException ("CacheSize");
- cache_size = value;
+
+ cache.Capacity = value;
}
}
+#else
+ static FactoryCache cache = new FactoryCache (200);
#endif
// private
- private static FactoryCache cache = new FactoryCache (200); // TODO put some meaningful number here
// constructors
this.roptions = options;
Init ();
}
-
+#if !TARGET_JVM
private void Init ()
{
this.machineFactory = cache.Lookup (this.pattern, this.roptions);
if (this.machineFactory == null) {
- // parse and install group mapping
-
- Parser psr = new Parser ();
- RegularExpression re = psr.ParseRegularExpression (this.pattern, this.roptions);
- this.group_count = re.GroupCount;
- this.mapping = psr.GetMapping ();
-
- // compile
-
- ICompiler cmp;
- //if ((this.roptions & RegexOptions.Compiled) != 0)
- // //throw new Exception ("Not implemented.");
- // cmp = new CILCompiler ();
- //else
- cmp = new PatternCompiler ();
+ InitNewRegex();
+ } else {
+ this.group_count = this.machineFactory.GroupCount;
+ this.mapping = this.machineFactory.Mapping;
+ this._groupNumberToNameMap = this.machineFactory.NamesMapping;
+ }
+ }
+#endif
+
+ private void InitNewRegex ()
+ {
+ this.machineFactory = CreateMachineFactory (this.pattern, this.roptions);
+ cache.Add (this.pattern, this.roptions, this.machineFactory);
+ this.group_count = machineFactory.GroupCount;
+ this.mapping = machineFactory.Mapping;
+ this._groupNumberToNameMap = this.machineFactory.NamesMapping;
+ }
- re.Compile (cmp, RightToLeft);
+ // The new rx engine has blocking bugs like
+ // https://bugzilla.novell.com/show_bug.cgi?id=470827
+ static readonly bool old_rx =
+#if !NET_2_1
+ Environment.GetEnvironmentVariable ("MONO_NEW_RX") == null;
+#else
+ true;
+#endif
- // install machine factory and add to pattern cache
+ private static IMachineFactory CreateMachineFactory (string pattern, RegexOptions options)
+ {
+ Parser psr = new Parser ();
+ RegularExpression re = psr.ParseRegularExpression (pattern, options);
- this.machineFactory = cmp.GetMachineFactory ();
- this.machineFactory.Mapping = mapping;
- cache.Add (this.pattern, this.roptions, this.machineFactory);
+ ICompiler cmp;
+ if (!old_rx) {
+ if ((options & RegexOptions.Compiled) != 0)
+ cmp = new CILCompiler ();
+ else
+ cmp = new RxCompiler ();
} else {
- this.group_count = this.machineFactory.GroupCount;
- this.mapping = this.machineFactory.Mapping;
+ cmp = new PatternCompiler ();
}
+
+ re.Compile (cmp, (options & RegexOptions.RightToLeft) != 0);
+
+ IMachineFactory machineFactory = cmp.GetMachineFactory ();
+ machineFactory.Mapping = psr.GetMapping ();
+ machineFactory.NamesMapping = GetGroupNamesArray (machineFactory.GroupCount, machineFactory.Mapping);
+
+ return machineFactory;
}
#if NET_2_0
{
}
-#if NET_1_1 && !TARGET_JVM
+#if ONLY_1_1 && !TARGET_JVM
// fixes public API signature
~Regex ()
{
public string GroupNameFromNumber (int i)
{
- if (i > group_count)
+ if (i < 0 || i > group_count)
return "";
-
- foreach (string name in mapping.Keys) {
- if ((int) mapping [name] == i)
- return name;
- }
- return "";
+ return _groupNumberToNameMap [i];
}
public int GroupNumberFromName (string name)
public void Evaluate (Match m, StringBuilder sb) { sb.Append (ev (m)); }
}
- delegate void MatchAppendEvaluator (Match match, StringBuilder sb);
-
public string Replace (string input, MatchEvaluator evaluator, int count, int startat)
{
- Adapter a = new Adapter (evaluator);
- return Replace (input, new MatchAppendEvaluator (a.Evaluate), count, startat);
- }
-
- string Replace (string input, MatchAppendEvaluator evaluator, int count, int startat)
- {
- StringBuilder result = new StringBuilder ();
- int ptr = startat;
- int counter = count;
+ BaseMachine m = (BaseMachine)CreateMachine ();
- result.Append (input, 0, ptr);
+ if (RightToLeft)
+ return m.RTLReplace (this, input, evaluator, count, startat);
- Match m = Match (input, startat);
- while (m.Success) {
- if (count != -1)
- if(counter -- <= 0)
- break;
- if (m.Index < ptr)
- throw new SystemException ("how");
- result.Append (input, ptr, m.Index - ptr);
- evaluator (m, result);
-
- ptr = m.Index + m.Length;
- m = m.NextMatch ();
- }
-
- if (ptr == 0)
- return input;
-
- result.Append (input, ptr, input.Length - ptr);
+ // NOTE: If this is a cause of a lot of allocations, we can convert it to
+ // use a ThreadStatic allocation mitigator
+ Adapter a = new Adapter (evaluator);
- return result.ToString ();
+ return m.LTRReplace (this, input, new BaseMachine.MatchAppendEvaluator (a.Evaluate),
+ count, startat);
}
public string Replace (string input, string replacement)
public string Replace (string input, string replacement, int count, int startat)
{
- ReplacementEvaluator ev = new ReplacementEvaluator (this, replacement);
- return Replace (input, new MatchAppendEvaluator (ev.EvaluateAppend), count, startat);
+ return CreateMachine ().Replace (this, input, replacement, count, startat);
}
// split methods
public string [] Split (string input, int count, int startat)
{
- ArrayList splits = new ArrayList ();
- if (count == 0)
- count = Int32.MaxValue;
-
- int ptr = startat;
- Match m = null;
- while (--count > 0) {
- if (m != null)
- m = m.NextMatch ();
- else
- m = Match (input, ptr);
-
- if (!m.Success)
- break;
-
- if (RightToLeft)
- splits.Add (input.Substring (m.Index + m.Length, ptr - m.Index - m.Length));
- else
- splits.Add (input.Substring (ptr, m.Index - ptr));
-
- int gcount = m.Groups.Count;
- for (int gindex = 1; gindex < gcount; gindex++) {
- Group grp = m.Groups [gindex];
- splits.Add (input.Substring (grp.Index, grp.Length));
- }
-
- if (RightToLeft)
- ptr = m.Index;
- else
- ptr = m.Index + m.Length;
-
- }
-
- if (RightToLeft && ptr >= 0)
- splits.Add (input.Substring (0, ptr));
- if (!RightToLeft && ptr <= input.Length)
- splits.Add (input.Substring (ptr));
-
- return (string []) splits.ToArray (typeof (string));
+ return CreateMachine ().Split (this, input, count, startat);
}
// This method is called at the end of the constructor of compiled
return machineFactory.NewInstance ();
}
+ private static string [] GetGroupNamesArray (int groupCount, IDictionary mapping)
+ {
+ string [] groupNumberToNameMap = new string [groupCount + 1];
+ foreach (string name in mapping.Keys) {
+ groupNumberToNameMap [(int) mapping [name]] = name;
+ }
+ return groupNumberToNameMap;
+ }
+
private IMachineFactory machineFactory;
private IDictionary mapping;
private int group_count;
private bool refsInitialized;
+ private string [] _groupNumberToNameMap;
// protected members
protected internal RegexOptions roptions;
// MS undocumented members
+#if NET_2_1
+ [MonoTODO]
+ protected internal System.Collections.Generic.Dictionary<string, int> capnames;
+ [MonoTODO]
+ protected internal System.Collections.Generic.Dictionary<int, int> caps;
+#else
[MonoTODO]
protected internal System.Collections.Hashtable capnames;
[MonoTODO]
protected internal System.Collections.Hashtable caps;
+#endif
[MonoTODO]
protected internal int capsize;
[MonoTODO]