335 lines
7.1 KiB
C#
335 lines
7.1 KiB
C#
//
|
|
// assembly: System
|
|
// namespace: System.Text.RegularExpressions
|
|
// file: interval.cs
|
|
//
|
|
// author: Dan Lewis (dlewis@gmx.co.uk)
|
|
// (c) 2002
|
|
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
// a copy of this software and associated documentation files (the
|
|
// "Software"), to deal in the Software without restriction, including
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
// the following conditions:
|
|
//
|
|
// The above copyright notice and this permission notice shall be
|
|
// included in all copies or substantial portions of the Software.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
//
|
|
|
|
using System;
|
|
using System.Collections;
|
|
|
|
namespace System.Text.RegularExpressions {
|
|
|
|
struct Interval : IComparable {
|
|
public int low;
|
|
public int high;
|
|
public bool contiguous;
|
|
|
|
public static Interval Empty {
|
|
get {
|
|
Interval i;
|
|
i.low = 0;
|
|
i.high = i.low - 1;
|
|
i.contiguous = true;
|
|
|
|
return i;
|
|
}
|
|
}
|
|
|
|
public static Interval Entire {
|
|
get { return new Interval (Int32.MinValue, Int32.MaxValue); }
|
|
}
|
|
|
|
public Interval (int low, int high) {
|
|
if (low > high) {
|
|
int t = low;
|
|
low = high;
|
|
high = t;
|
|
}
|
|
|
|
this.low = low;
|
|
this.high = high;
|
|
this.contiguous = true;
|
|
}
|
|
|
|
public bool IsDiscontiguous {
|
|
get { return !contiguous; }
|
|
}
|
|
|
|
public bool IsSingleton {
|
|
get { return contiguous && low == high; }
|
|
}
|
|
|
|
public bool IsRange {
|
|
get { return !IsSingleton && !IsEmpty; }
|
|
}
|
|
|
|
public bool IsEmpty {
|
|
get { return low > high; }
|
|
}
|
|
|
|
public int Size {
|
|
get {
|
|
if (IsEmpty)
|
|
return 0;
|
|
|
|
return high - low + 1;
|
|
}
|
|
}
|
|
|
|
public bool IsDisjoint (Interval i) {
|
|
if (IsEmpty || i.IsEmpty)
|
|
return true;
|
|
|
|
return !(low <= i.high && i.low <= high);
|
|
}
|
|
|
|
public bool IsAdjacent (Interval i) {
|
|
if (IsEmpty || i.IsEmpty)
|
|
return false;
|
|
|
|
return low == i.high + 1 || high == i.low - 1;
|
|
}
|
|
|
|
public bool Contains (Interval i) {
|
|
if (!IsEmpty && i.IsEmpty)
|
|
return true;
|
|
if (IsEmpty)
|
|
return false;
|
|
|
|
return low <= i.low && i.high <= high;
|
|
}
|
|
|
|
public bool Contains (int i) {
|
|
return low <= i && i <= high;
|
|
}
|
|
|
|
public bool Intersects (Interval i) {
|
|
if (IsEmpty || i.IsEmpty)
|
|
return false;
|
|
|
|
return ((Contains (i.low) && !Contains (i.high)) ||
|
|
(Contains (i.high) && !Contains (i.low)));
|
|
}
|
|
|
|
public void Merge (Interval i) {
|
|
if (i.IsEmpty)
|
|
return;
|
|
if (IsEmpty) {
|
|
this.low = i.low;
|
|
this.high = i.high;
|
|
}
|
|
|
|
if (i.low < low)
|
|
low = i.low;
|
|
if (i.high > high)
|
|
high = i.high;
|
|
}
|
|
|
|
public void Intersect (Interval i) {
|
|
if (IsDisjoint (i)) {
|
|
low = 0;
|
|
high = low - 1;
|
|
return;
|
|
}
|
|
|
|
if (i.low > low)
|
|
low = i.low;
|
|
if (i.high > high)
|
|
high = i.high;
|
|
}
|
|
|
|
public int CompareTo (object o) {
|
|
return low - ((Interval)o).low;
|
|
}
|
|
|
|
public new string ToString () {
|
|
if (IsEmpty)
|
|
return "(EMPTY)";
|
|
else if (!contiguous)
|
|
return "{" + low + ", " + high + "}";
|
|
else if (IsSingleton)
|
|
return "(" + low + ")";
|
|
else
|
|
return "(" + low + ", " + high + ")";
|
|
}
|
|
}
|
|
|
|
class IntervalCollection : ICollection, IEnumerable {
|
|
public IntervalCollection () {
|
|
intervals = new ArrayList ();
|
|
}
|
|
|
|
public Interval this[int i] {
|
|
get { return (Interval)intervals[i]; }
|
|
set { intervals[i] = value; }
|
|
}
|
|
|
|
public void Add (Interval i) {
|
|
intervals.Add (i);
|
|
}
|
|
|
|
public void Clear () {
|
|
intervals.Clear ();
|
|
}
|
|
|
|
public void Sort () {
|
|
intervals.Sort ();
|
|
}
|
|
|
|
public void Normalize () {
|
|
intervals.Sort ();
|
|
|
|
int j = 0;
|
|
while (j < intervals.Count - 1) {
|
|
Interval a = (Interval)intervals[j];
|
|
Interval b = (Interval)intervals[j + 1];
|
|
|
|
if (!a.IsDisjoint (b) || a.IsAdjacent (b)) {
|
|
a.Merge (b);
|
|
intervals[j] = a;
|
|
intervals.RemoveAt (j + 1);
|
|
}
|
|
else
|
|
++ j;
|
|
}
|
|
|
|
}
|
|
|
|
public delegate double CostDelegate (Interval i);
|
|
|
|
public IntervalCollection GetMetaCollection (CostDelegate cost_del) {
|
|
IntervalCollection meta = new IntervalCollection ();
|
|
|
|
Normalize ();
|
|
Optimize (0, Count - 1, meta, cost_del);
|
|
meta.intervals.Sort ();
|
|
|
|
return meta;
|
|
}
|
|
|
|
private void Optimize (int begin, int end, IntervalCollection meta, CostDelegate cost_del) {
|
|
Interval set;
|
|
set.contiguous = false;
|
|
|
|
int best_set_begin = -1;
|
|
int best_set_end = -1;
|
|
double best_set_cost = 0;
|
|
|
|
for (int i = begin; i <= end; ++ i) {
|
|
set.low = this[i].low;
|
|
|
|
double cost = 0.0;
|
|
for (int j = i; j <= end; ++ j) {
|
|
set.high = this[j].high;
|
|
cost += cost_del (this[j]);
|
|
|
|
double set_cost = cost_del (set);
|
|
if (set_cost < cost && cost > best_set_cost) {
|
|
best_set_begin = i;
|
|
best_set_end = j;
|
|
best_set_cost = cost;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (best_set_begin < 0) {
|
|
// didn't find an optimal set: add original members
|
|
|
|
for (int i = begin; i <= end; ++ i)
|
|
meta.Add (this[i]);
|
|
}
|
|
else {
|
|
// found set: add it ...
|
|
|
|
set.low = this[best_set_begin].low;
|
|
set.high = this[best_set_end].high;
|
|
|
|
meta.Add (set);
|
|
|
|
// ... and optimize to the left and right
|
|
|
|
if (best_set_begin > begin)
|
|
Optimize (begin, best_set_begin - 1, meta, cost_del);
|
|
if (best_set_end < end)
|
|
Optimize (best_set_end + 1, end, meta, cost_del);
|
|
}
|
|
}
|
|
|
|
// ICollection implementation
|
|
|
|
public int Count {
|
|
get { return intervals.Count; }
|
|
}
|
|
|
|
public bool IsSynchronized {
|
|
get { return false; }
|
|
}
|
|
|
|
public object SyncRoot {
|
|
get { return intervals; }
|
|
}
|
|
|
|
public void CopyTo (Array array, int index) {
|
|
foreach (Interval i in intervals) {
|
|
if (index > array.Length)
|
|
break;
|
|
|
|
array.SetValue (i, index ++);
|
|
}
|
|
}
|
|
|
|
// IEnumerator implementation
|
|
|
|
public IEnumerator GetEnumerator () {
|
|
return new Enumerator (intervals);
|
|
}
|
|
|
|
private class Enumerator : IEnumerator {
|
|
public Enumerator (IList list) {
|
|
this.list = list;
|
|
Reset ();
|
|
}
|
|
|
|
public object Current {
|
|
get {
|
|
if (ptr >= list.Count)
|
|
throw new InvalidOperationException ();
|
|
|
|
return list[ptr];
|
|
}
|
|
}
|
|
|
|
public bool MoveNext () {
|
|
if (ptr > list.Count)
|
|
throw new InvalidOperationException ();
|
|
|
|
return ++ ptr < list.Count;
|
|
}
|
|
|
|
public void Reset () {
|
|
ptr = -1;
|
|
}
|
|
|
|
private IList list;
|
|
private int ptr;
|
|
}
|
|
|
|
// private fields
|
|
|
|
private ArrayList intervals;
|
|
}
|
|
}
|