**** Merged from MCS ****
[mono-project.git] / mcs / class / System / System.Text.RegularExpressions / interval.cs
blobeb247bb6edc24dc5598dda201eca2debfedb9ec1
1 //
2 // assembly: System
3 // namespace: System.Text.RegularExpressions
4 // file: interval.cs
5 //
6 // author: Dan Lewis (dlewis@gmx.co.uk)
7 // (c) 2002
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System;
31 using System.Collections;
33 namespace System.Text.RegularExpressions {
35 struct Interval : IComparable {
36 public int low;
37 public int high;
38 public bool contiguous;
40 public static Interval Empty {
41 get {
42 Interval i;
43 i.low = 0;
44 i.high = i.low - 1;
45 i.contiguous = true;
47 return i;
51 public static Interval Entire {
52 get { return new Interval (Int32.MinValue, Int32.MaxValue); }
55 public Interval (int low, int high) {
56 if (low > high) {
57 int t = low;
58 low = high;
59 high = t;
62 this.low = low;
63 this.high = high;
64 this.contiguous = true;
67 public bool IsDiscontiguous {
68 get { return !contiguous; }
71 public bool IsSingleton {
72 get { return contiguous && low == high; }
75 public bool IsRange {
76 get { return !IsSingleton && !IsEmpty; }
79 public bool IsEmpty {
80 get { return low > high; }
83 public int Size {
84 get {
85 if (IsEmpty)
86 return 0;
88 return high - low + 1;
92 public bool IsDisjoint (Interval i) {
93 if (IsEmpty || i.IsEmpty)
94 return true;
96 return !(low <= i.high && i.low <= high);
99 public bool IsAdjacent (Interval i) {
100 if (IsEmpty || i.IsEmpty)
101 return false;
103 return low == i.high + 1 || high == i.low - 1;
106 public bool Contains (Interval i) {
107 if (!IsEmpty && i.IsEmpty)
108 return true;
109 if (IsEmpty)
110 return false;
112 return low <= i.low && i.high <= high;
115 public bool Contains (int i) {
116 return low <= i && i <= high;
119 public bool Intersects (Interval i) {
120 if (IsEmpty || i.IsEmpty)
121 return false;
123 return ((Contains (i.low) && !Contains (i.high)) ||
124 (Contains (i.high) && !Contains (i.low)));
127 public void Merge (Interval i) {
128 if (i.IsEmpty)
129 return;
130 if (IsEmpty) {
131 this.low = i.low;
132 this.high = i.high;
135 if (i.low < low)
136 low = i.low;
137 if (i.high > high)
138 high = i.high;
141 public void Intersect (Interval i) {
142 if (IsDisjoint (i)) {
143 low = 0;
144 high = low - 1;
145 return;
148 if (i.low > low)
149 low = i.low;
150 if (i.high > high)
151 high = i.high;
154 public int CompareTo (object o) {
155 return low - ((Interval)o).low;
158 public new string ToString () {
159 if (IsEmpty)
160 return "(EMPTY)";
161 else if (!contiguous)
162 return "{" + low + ", " + high + "}";
163 else if (IsSingleton)
164 return "(" + low + ")";
165 else
166 return "(" + low + ", " + high + ")";
170 class IntervalCollection : ICollection, IEnumerable {
171 public IntervalCollection () {
172 intervals = new ArrayList ();
175 public Interval this[int i] {
176 get { return (Interval)intervals[i]; }
177 set { intervals[i] = value; }
180 public void Add (Interval i) {
181 intervals.Add (i);
184 public void Clear () {
185 intervals.Clear ();
188 public void Sort () {
189 intervals.Sort ();
192 public void Normalize () {
193 intervals.Sort ();
195 int j = 0;
196 while (j < intervals.Count - 1) {
197 Interval a = (Interval)intervals[j];
198 Interval b = (Interval)intervals[j + 1];
200 if (!a.IsDisjoint (b) || a.IsAdjacent (b)) {
201 a.Merge (b);
202 intervals[j] = a;
203 intervals.RemoveAt (j + 1);
205 else
206 ++ j;
211 public delegate double CostDelegate (Interval i);
213 public IntervalCollection GetMetaCollection (CostDelegate cost_del) {
214 IntervalCollection meta = new IntervalCollection ();
216 Normalize ();
217 Optimize (0, Count - 1, meta, cost_del);
218 meta.intervals.Sort ();
220 return meta;
223 private void Optimize (int begin, int end, IntervalCollection meta, CostDelegate cost_del) {
224 Interval set;
225 set.contiguous = false;
227 int best_set_begin = -1;
228 int best_set_end = -1;
229 double best_set_cost = 0;
231 for (int i = begin; i <= end; ++ i) {
232 set.low = this[i].low;
234 double cost = 0.0;
235 for (int j = i; j <= end; ++ j) {
236 set.high = this[j].high;
237 cost += cost_del (this[j]);
239 double set_cost = cost_del (set);
240 if (set_cost < cost && cost > best_set_cost) {
241 best_set_begin = i;
242 best_set_end = j;
243 best_set_cost = cost;
248 if (best_set_begin < 0) {
249 // didn't find an optimal set: add original members
251 for (int i = begin; i <= end; ++ i)
252 meta.Add (this[i]);
254 else {
255 // found set: add it ...
257 set.low = this[best_set_begin].low;
258 set.high = this[best_set_end].high;
260 meta.Add (set);
262 // ... and optimize to the left and right
264 if (best_set_begin > begin)
265 Optimize (begin, best_set_begin - 1, meta, cost_del);
266 if (best_set_end < end)
267 Optimize (best_set_end + 1, end, meta, cost_del);
271 // ICollection implementation
273 public int Count {
274 get { return intervals.Count; }
277 public bool IsSynchronized {
278 get { return false; }
281 public object SyncRoot {
282 get { return intervals; }
285 public void CopyTo (Array array, int index) {
286 foreach (Interval i in intervals) {
287 if (index > array.Length)
288 break;
290 array.SetValue (i, index ++);
294 // IEnumerator implementation
296 public IEnumerator GetEnumerator () {
297 return new Enumerator (intervals);
300 private class Enumerator : IEnumerator {
301 public Enumerator (IList list) {
302 this.list = list;
303 Reset ();
306 public object Current {
307 get {
308 if (ptr >= list.Count)
309 throw new InvalidOperationException ();
311 return list[ptr];
315 public bool MoveNext () {
316 if (ptr > list.Count)
317 throw new InvalidOperationException ();
319 return ++ ptr < list.Count;
322 public void Reset () {
323 ptr = -1;
326 private IList list;
327 private int ptr;
330 // private fields
332 private ArrayList intervals;