3 // namespace: System.Text.RegularExpressions
6 // author: Dan Lewis (dlewis@gmx.co.uk)
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:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
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.
31 using System
.Collections
;
33 namespace System
.Text
.RegularExpressions
{
35 struct Interval
: IComparable
{
38 public bool contiguous
;
40 public static Interval Empty
{
51 public static Interval Entire
{
52 get { return new Interval (Int32.MinValue, Int32.MaxValue); }
55 public Interval (int low
, int high
) {
64 this.contiguous
= true;
67 public bool IsDiscontiguous
{
68 get { return !contiguous; }
71 public bool IsSingleton
{
72 get { return contiguous && low == high; }
76 get { return !IsSingleton && !IsEmpty; }
80 get { return low > high; }
88 return high
- low
+ 1;
92 public bool IsDisjoint (Interval i
) {
93 if (IsEmpty
|| i
.IsEmpty
)
96 return !(low
<= i
.high
&& i
.low
<= high
);
99 public bool IsAdjacent (Interval i
) {
100 if (IsEmpty
|| i
.IsEmpty
)
103 return low
== i
.high
+ 1 || high
== i
.low
- 1;
106 public bool Contains (Interval i
) {
107 if (!IsEmpty
&& i
.IsEmpty
)
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
)
123 return ((Contains (i
.low
) && !Contains (i
.high
)) ||
124 (Contains (i
.high
) && !Contains (i
.low
)));
127 public void Merge (Interval i
) {
141 public void Intersect (Interval i
) {
142 if (IsDisjoint (i
)) {
154 public int CompareTo (object o
) {
155 return low
- ((Interval
)o
).low
;
158 public new string ToString () {
161 else if (!contiguous
)
162 return "{" + low + ", " + high + "}";
163 else if (IsSingleton
)
164 return "(" + low
+ ")";
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
) {
184 public void Clear () {
188 public void Sort () {
192 public void Normalize () {
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
)) {
203 intervals
.RemoveAt (j
+ 1);
211 public delegate double CostDelegate (Interval i
);
213 public IntervalCollection
GetMetaCollection (CostDelegate cost_del
) {
214 IntervalCollection meta
= new IntervalCollection ();
217 Optimize (0, Count
- 1, meta
, cost_del
);
218 meta
.intervals
.Sort ();
223 private void Optimize (int begin
, int end
, IntervalCollection meta
, CostDelegate cost_del
) {
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
;
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
) {
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
)
255 // found set: add it ...
257 set.low
= this[best_set_begin
].low
;
258 set.high
= this[best_set_end
].high
;
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
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
)
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
) {
306 public object Current
{
308 if (ptr
>= list
.Count
)
309 throw new InvalidOperationException ();
315 public bool MoveNext () {
316 if (ptr
> list
.Count
)
317 throw new InvalidOperationException ();
319 return ++ ptr
< list
.Count
;
322 public void Reset () {
332 private ArrayList intervals
;