Project

General

Profile

root / branches / compiler / cSharp / ooasCompiler / src / libs / c5 / C5 / Wrappers.cs @ 3

1
/*
2
 Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
3
 Permission is hereby granted, free of charge, to any person obtaining a copy
4
 of this software and associated documentation files (the "Software"), to deal
5
 in the Software without restriction, including without limitation the rights
6
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
 copies of the Software, and to permit persons to whom the Software is
8
 furnished to do so, subject to the following conditions:
9
 
10
 The above copyright notice and this permission notice shall be included in
11
 all copies or substantial portions of the Software.
12
 
13
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
 SOFTWARE.
20
*/
21

    
22
using System;
23
using System.Diagnostics;
24
using SCG = System.Collections.Generic;
25
namespace C5
26
{
27
  /// <summary>
28
  /// A read-only wrapper class for a generic enumerator
29
  /// </summary>
30
  public class GuardedEnumerator<T> : SCG.IEnumerator<T>
31
  {
32
    #region Fields
33

    
34
    SCG.IEnumerator<T> enumerator;
35

    
36
    #endregion
37

    
38
    #region Constructor
39

    
40
    /// <summary>
41
    /// Create a wrapper around a generic enumerator
42
    /// </summary>
43
    /// <param name="enumerator">The enumerator to wrap</param>
44
    public GuardedEnumerator(SCG.IEnumerator<T> enumerator)
45
    { this.enumerator = enumerator; }
46

    
47
    #endregion
48

    
49
    #region IEnumerator<T> Members
50

    
51
    /// <summary>
52
    /// Move wrapped enumerator to next item, or the first item if
53
    /// this is the first call to MoveNext. 
54
    /// </summary>
55
    /// <returns>True if enumerator is valid now</returns>
56
    public bool MoveNext() { return enumerator.MoveNext(); }
57

    
58

    
59
    /// <summary>
60
    /// Undefined if enumerator is not valid (MoveNext hash been called returning true)
61
    /// </summary>
62
    /// <value>The current item of the wrapped enumerator.</value>
63
    public T Current { get { return enumerator.Current; } }
64

    
65
    #endregion
66

    
67
    #region IDisposable Members
68

    
69
    //TODO: consider possible danger of calling through to Dispose. 
70
    /// <summary>
71
    /// Dispose wrapped enumerator.
72
    /// </summary>
73
    public void Dispose() { enumerator.Dispose(); }
74

    
75
    #endregion
76

    
77

    
78
    #region IEnumerator Members
79

    
80
    object System.Collections.IEnumerator.Current
81
    {
82
      get { return enumerator.Current; }
83
    }
84

    
85
    void System.Collections.IEnumerator.Reset()
86
    {
87
      enumerator.Reset();
88
    }
89

    
90
    #endregion
91
  }
92

    
93

    
94

    
95
  /// <summary>
96
  /// A read-only wrapper class for a generic enumerable
97
  ///
98
  /// <i>This is mainly interesting as a base of other guard classes</i>
99
  /// </summary>
100
  public class GuardedEnumerable<T> : SCG.IEnumerable<T>
101
  {
102
    #region Fields
103

    
104
    SCG.IEnumerable<T> enumerable;
105

    
106
    #endregion
107

    
108
    #region Constructor
109

    
110
    /// <summary>
111
    /// Wrap an enumerable in a read-only wrapper
112
    /// </summary>
113
    /// <param name="enumerable">The enumerable to wrap</param>
114
    public GuardedEnumerable(SCG.IEnumerable<T> enumerable)
115
    { this.enumerable = enumerable; }
116

    
117
    #endregion
118

    
119
    #region SCG.IEnumerable<T> Members
120

    
121
    /// <summary>
122
    /// Get an enumerator from the wrapped enumerable
123
    /// </summary>
124
    /// <returns>The enumerator (itself wrapped)</returns>
125
    public SCG.IEnumerator<T> GetEnumerator()
126
    { return new GuardedEnumerator<T>(enumerable.GetEnumerator()); }
127

    
128
    #endregion
129

    
130
    #region IEnumerable Members
131

    
132
    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
133
    {
134
      return GetEnumerator();
135
    }
136

    
137
    #endregion
138

    
139
  }
140

    
141

    
142

    
143
  /// <summary>
144
  /// A read-only wrapper for a generic directed enumerable
145
  ///
146
  /// <i>This is mainly interesting as a base of other guard classes</i>
147
  /// </summary>
148
  public class GuardedDirectedEnumerable<T> : GuardedEnumerable<T>, IDirectedEnumerable<T>
149
  {
150
    #region Fields
151

    
152
    IDirectedEnumerable<T> directedenumerable;
153

    
154
    #endregion
155

    
156
    #region Constructor
157

    
158
    /// <summary>
159
    /// Wrap a directed enumerable in a read-only wrapper
160
    /// </summary>
161
    /// <param name="directedenumerable">the collection to wrap</param>
162
    public GuardedDirectedEnumerable(IDirectedEnumerable<T> directedenumerable)
163
      : base(directedenumerable)
164
    { this.directedenumerable = directedenumerable; }
165

    
166
    #endregion
167

    
168
    #region IDirectedEnumerable<T> Members
169

    
170
    /// <summary>
171
    /// Get a enumerable that enumerates the wrapped collection in the opposite direction
172
    /// </summary>
173
    /// <returns>The mirrored enumerable</returns>
174
    public IDirectedEnumerable<T> Backwards()
175
    { return new GuardedDirectedEnumerable<T>(directedenumerable.Backwards()); }
176

    
177

    
178
    /// <summary>
179
    /// <code>Forwards</code> if same, else <code>Backwards</code>
180
    /// </summary>
181
    /// <value>The enumeration direction relative to the original collection.</value>
182
    public EnumerationDirection Direction
183
    { get { return directedenumerable.Direction; } }
184

    
185
    #endregion
186
  }
187

    
188

    
189

    
190
  /// <summary>
191
  /// A read-only wrapper for an ICollectionValue&lt;T&gt;
192
  ///
193
  /// <i>This is mainly interesting as a base of other guard classes</i>
194
  /// </summary>
195
  public class GuardedCollectionValue<T> : GuardedEnumerable<T>, ICollectionValue<T>
196
  {
197
    #region Events
198
    /// <summary>
199
    /// The ListenableEvents value of the wrapped collection
200
    /// </summary>
201
    /// <value></value>
202
    public virtual EventTypeEnum ListenableEvents { get { return collectionvalue.ListenableEvents; } }
203

    
204
    /// <summary>
205
    /// The ActiveEvents value of the wrapped collection
206
    /// </summary>
207
    /// <value></value>
208
    public virtual EventTypeEnum ActiveEvents { get { return collectionvalue.ActiveEvents; } }
209

    
210
    ProxyEventBlock<T> eventBlock;
211
    /// <summary>
212
    /// The change event. Will be raised for every change operation on the collection.
213
    /// </summary>
214
    public event CollectionChangedHandler<T> CollectionChanged
215
    {
216
      add { (eventBlock ?? (eventBlock = new ProxyEventBlock<T>(this, collectionvalue))).CollectionChanged += value; }
217
      remove { if (eventBlock != null) eventBlock.CollectionChanged -= value; }
218
    }
219

    
220
    /// <summary>
221
    /// The change event. Will be raised for every change operation on the collection.
222
    /// </summary>
223
    public event CollectionClearedHandler<T> CollectionCleared
224
    {
225
      add { (eventBlock ?? (eventBlock = new ProxyEventBlock<T>(this, collectionvalue))).CollectionCleared += value; }
226
      remove { if (eventBlock != null) eventBlock.CollectionCleared -= value; }
227
    }
228

    
229
    /// <summary>
230
    /// The item added  event. Will be raised for every individual addition to the collection.
231
    /// </summary>
232
    public event ItemsAddedHandler<T> ItemsAdded
233
    {
234
      add { (eventBlock ?? (eventBlock = new ProxyEventBlock<T>(this, collectionvalue))).ItemsAdded += value; }
235
      remove { if (eventBlock != null) eventBlock.ItemsAdded -= value; }
236
    }
237

    
238
    /// <summary>
239
    /// The item added  event. Will be raised for every individual addition to the collection.
240
    /// </summary>
241
    public event ItemInsertedHandler<T> ItemInserted
242
    {
243
      add { (eventBlock ?? (eventBlock = new ProxyEventBlock<T>(this, collectionvalue))).ItemInserted += value; }
244
      remove { if (eventBlock != null) eventBlock.ItemInserted -= value; }
245
    }
246

    
247
    /// <summary>
248
    /// The item removed event. Will be raised for every individual removal from the collection.
249
    /// </summary>
250
    public event ItemsRemovedHandler<T> ItemsRemoved
251
    {
252
      add { (eventBlock ?? (eventBlock = new ProxyEventBlock<T>(this, collectionvalue))).ItemsRemoved += value; }
253
      remove { if (eventBlock != null) eventBlock.ItemsRemoved -= value; }
254
    }
255

    
256
    /// <summary>
257
    /// The item removed event. Will be raised for every individual removal from the collection.
258
    /// </summary>
259
    public event ItemRemovedAtHandler<T> ItemRemovedAt
260
    {
261
      add { (eventBlock ?? (eventBlock = new ProxyEventBlock<T>(this, collectionvalue))).ItemRemovedAt += value; }
262
      remove { if (eventBlock != null) eventBlock.ItemRemovedAt -= value; }
263
    }
264
    #endregion
265

    
266
    #region Fields
267

    
268
    ICollectionValue<T> collectionvalue;
269

    
270
    #endregion
271

    
272
    #region Constructor
273

    
274
    /// <summary>
275
    /// Wrap a ICollectionValue&lt;T&gt; in a read-only wrapper
276
    /// </summary>
277
    /// <param name="collectionvalue">the collection to wrap</param>
278
    public GuardedCollectionValue(ICollectionValue<T> collectionvalue)
279
      : base(collectionvalue)
280
    { this.collectionvalue = collectionvalue; }
281

    
282
    #endregion
283

    
284
    #region ICollection<T> Members
285

    
286
    /// <summary>
287
    /// Get the size of the wrapped collection
288
    /// </summary>
289
    /// <value>The size</value>
290
    public virtual bool IsEmpty { get { return collectionvalue.IsEmpty; } }
291

    
292
    /// <summary>
293
    /// Get the size of the wrapped collection
294
    /// </summary>
295
    /// <value>The size</value>
296
    public virtual int Count { get { return collectionvalue.Count; } }
297

    
298
    /// <summary>
299
    /// The value is symbolic indicating the type of asymptotic complexity
300
    /// in terms of the size of this collection (worst-case or amortized as
301
    /// relevant).
302
    /// </summary>
303
    /// <value>A characterization of the speed of the 
304
    /// <code>Count</code> property in this collection.</value>
305
    public virtual Speed CountSpeed { get { return collectionvalue.CountSpeed; } }
306

    
307
    /// <summary>
308
    /// Copy the items of the wrapped collection to an array
309
    /// </summary>
310
    /// <param name="a">The array</param>
311
    /// <param name="i">Starting offset</param>
312
    public virtual void CopyTo(T[] a, int i) { collectionvalue.CopyTo(a, i); }
313

    
314
    /// <summary>
315
    /// Create an array from the items of the wrapped collection
316
    /// </summary>
317
    /// <returns>The array</returns>
318
    public virtual T[] ToArray() { return collectionvalue.ToArray(); }
319

    
320
    /// <summary>
321
    /// Apply a delegate to all items of the wrapped enumerable.
322
    /// </summary>
323
    /// <param name="a">The delegate to apply</param>
324
    //TODO: change this to throw an exception?
325
    public virtual void Apply(Act<T> a) { collectionvalue.Apply(a); }
326

    
327

    
328
    /// <summary>
329
    /// Check if there exists an item  that satisfies a
330
    /// specific predicate in the wrapped enumerable.
331
    /// </summary>
332
    /// <param name="filter">A filter delegate 
333
    /// (<see cref="T:C5.Filter`1"/>) defining the predicate</param>
334
    /// <returns>True is such an item exists</returns>
335
    public virtual bool Exists(Fun<T, bool> filter) { return collectionvalue.Exists(filter); }
336

    
337
    /// <summary>
338
    /// 
339
    /// </summary>
340
    /// <param name="filter"></param>
341
    /// <param name="item"></param>
342
    /// <returns></returns>
343
    public virtual bool Find(Fun<T, bool> filter, out T item) { return collectionvalue.Find(filter, out item); }
344

    
345
    /// <summary>
346
    /// Check if all items in the wrapped enumerable satisfies a specific predicate.
347
    /// </summary>
348
    /// <param name="filter">A filter delegate 
349
    /// (<see cref="T:C5.Filter`1"/>) defining the predicate</param>
350
    /// <returns>True if all items satisfies the predicate</returns>
351
    public virtual bool All(Fun<T, bool> filter) { return collectionvalue.All(filter); }
352

    
353
    /// <summary>
354
    /// Create an enumerable, enumerating the items of this collection that satisfies 
355
    /// a certain condition.
356
    /// </summary>
357
    /// <param name="filter">The T->bool filter delegate defining the condition</param>
358
    /// <returns>The filtered enumerable</returns>
359
    public virtual SCG.IEnumerable<T> Filter(Fun<T, bool> filter) { return collectionvalue.Filter(filter); }
360

    
361
    /// <summary>
362
    /// Choose some item of this collection. 
363
    /// </summary>
364
    /// <exception cref="NoSuchItemException">if collection is empty.</exception>
365
    /// <returns></returns>
366
    public virtual T Choose() { return collectionvalue.Choose(); }
367

    
368
    #endregion
369

    
370
    #region IShowable Members
371

    
372
    /// <summary>
373
    /// 
374
    /// </summary>
375
    /// <param name="stringbuilder"></param>
376
    /// <param name="formatProvider"></param>
377
    /// <param name="rest"></param>
378
    /// <returns></returns>
379
    public bool Show(System.Text.StringBuilder stringbuilder, ref int rest, IFormatProvider formatProvider)
380
    {
381
      return collectionvalue.Show(stringbuilder, ref rest, formatProvider);
382
    }
383
    #endregion
384

    
385
    #region IFormattable Members
386

    
387
    /// <summary>
388
    /// 
389
    /// </summary>
390
    /// <param name="format"></param>
391
    /// <param name="formatProvider"></param>
392
    /// <returns></returns>
393
    public string ToString(string format, IFormatProvider formatProvider)
394
    {
395
      return collectionvalue.ToString(format, formatProvider);
396
    }
397

    
398
    #endregion
399
  }
400

    
401

    
402

    
403
  /// <summary>
404
  /// A read-only wrapper for a directed collection
405
  ///
406
  /// <i>This is mainly interesting as a base of other guard classes</i>
407
  /// </summary>
408
  public class GuardedDirectedCollectionValue<T> : GuardedCollectionValue<T>, IDirectedCollectionValue<T>
409
  {
410
    #region Fields
411

    
412
    IDirectedCollectionValue<T> directedcollection;
413

    
414
    #endregion
415

    
416
    #region Constructor
417

    
418
    /// <summary>
419
    /// Wrap a directed collection in a read-only wrapper
420
    /// </summary>
421
    /// <param name="directedcollection">the collection to wrap</param>
422
    public GuardedDirectedCollectionValue(IDirectedCollectionValue<T> directedcollection)
423
      :
424
      base(directedcollection)
425
    { this.directedcollection = directedcollection; }
426

    
427
    #endregion
428

    
429
    #region IDirectedCollection<T> Members
430

    
431
    /// <summary>
432
    /// Get a collection that enumerates the wrapped collection in the opposite direction
433
    /// </summary>
434
    /// <returns>The mirrored collection</returns>
435
    public virtual IDirectedCollectionValue<T> Backwards()
436
    { return new GuardedDirectedCollectionValue<T>(directedcollection.Backwards()); }
437

    
438
    /// <summary>
439
    /// 
440
    /// </summary>
441
    /// <param name="predicate"></param>
442
    /// <param name="item"></param>
443
    /// <returns></returns>
444
    public virtual bool FindLast(Fun<T, bool> predicate, out T item) { return directedcollection.FindLast(predicate, out item); }
445

    
446
    #endregion
447

    
448
    #region IDirectedEnumerable<T> Members
449

    
450
    IDirectedEnumerable<T> IDirectedEnumerable<T>.Backwards()
451
    { return Backwards(); }
452

    
453

    
454
    /// <summary>
455
    /// <code>Forwards</code> if same, else <code>Backwards</code>
456
    /// </summary>
457
    /// <value>The enumeration direction relative to the original collection.</value>
458
    public EnumerationDirection Direction
459
    { get { return directedcollection.Direction; } }
460

    
461
    #endregion
462
  }
463

    
464

    
465

    
466
  /// <summary>
467
  /// A read-only wrapper for an <see cref="T:C5.ICollection`1"/>,
468
  /// <para>
469
  /// <i>Suitable for wrapping hash tables, <see cref="T:C5.HashSet`1"/>
470
  /// and <see cref="T:C5.HashBag`1"/>  </i></para>
471
  /// </summary>
472
  public class GuardedCollection<T> : GuardedCollectionValue<T>, ICollection<T>
473
  {
474
    #region Fields
475

    
476
    ICollection<T> collection;
477

    
478
    #endregion
479

    
480
    #region Constructor
481

    
482
    /// <summary>
483
    /// Wrap an ICollection&lt;T&gt; in a read-only wrapper
484
    /// </summary>
485
    /// <param name="collection">the collection to wrap</param>
486
    public GuardedCollection(ICollection<T> collection)
487
      : base(collection)
488
    {
489
      this.collection = collection;
490
    }
491

    
492
    #endregion
493

    
494
    #region ICollection<T> Members
495

    
496
    /// <summary>
497
    /// (This is a read-only wrapper)
498
    /// </summary>
499
    /// <value>True</value>
500
    public virtual bool IsReadOnly { get { return true; } }
501

    
502

    
503
    /// <summary> </summary>
504
    /// <value>Speed of wrapped collection</value>
505
    public virtual Speed ContainsSpeed { get { return collection.ContainsSpeed; } }
506

    
507
    /// <summary>
508
    /// 
509
    /// </summary>
510
    /// <returns></returns>
511
    public virtual int GetUnsequencedHashCode()
512
    { return collection.GetUnsequencedHashCode(); }
513

    
514
    /// <summary>
515
    /// 
516
    /// </summary>
517
    /// <param name="that"></param>
518
    /// <returns></returns>
519
    public virtual bool UnsequencedEquals(ICollection<T> that)
520
    { return collection.UnsequencedEquals(that); }
521

    
522

    
523
    /// <summary>
524
    /// Check if an item is in the wrapped collection
525
    /// </summary>
526
    /// <param name="item">The item</param>
527
    /// <returns>True if found</returns>
528
    public virtual bool Contains(T item) { return collection.Contains(item); }
529

    
530

    
531
    /// <summary>
532
    /// Count the number of times an item appears in the wrapped collection
533
    /// </summary>
534
    /// <param name="item">The item</param>
535
    /// <returns>The number of copies</returns>
536
    public virtual int ContainsCount(T item) { return collection.ContainsCount(item); }
537

    
538
    /// <summary>
539
    /// 
540
    /// </summary>
541
    /// <returns></returns>
542
    public virtual ICollectionValue<T> UniqueItems() { return new GuardedCollectionValue<T>(collection.UniqueItems()); }
543

    
544
    /// <summary>
545
    /// 
546
    /// </summary>
547
    /// <returns></returns>
548
    public virtual ICollectionValue<KeyValuePair<T, int>> ItemMultiplicities() { return new GuardedCollectionValue<KeyValuePair<T, int>>(collection.ItemMultiplicities()); }
549

    
550
    /// <summary>
551
    /// Check if all items in the argument is in the wrapped collection
552
    /// </summary>
553
    /// <param name="items">The items</param>
554
    /// <typeparam name="U"></typeparam>
555
    /// <returns>True if so</returns>
556
    public virtual bool ContainsAll<U>(SCG.IEnumerable<U> items) where U : T { return collection.ContainsAll(items); }
557

    
558
    /// <summary> 
559
    /// Search for an item in the wrapped collection
560
    /// </summary>
561
    /// <param name="item">On entry the item to look for, on exit the equivalent item found (if any)</param>
562
    /// <returns></returns>
563
    public virtual bool Find(ref T item) { return collection.Find(ref item); }
564

    
565

    
566
    /// <summary>
567
    /// </summary>
568
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
569
    /// <param name="item"></param>
570
    /// <returns></returns>
571
    public virtual bool FindOrAdd(ref T item)
572
    { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
573

    
574

    
575
    /// <summary>
576
    /// </summary>
577
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
578
    /// <param name="item"></param>
579
    /// <returns></returns>
580
    public virtual bool Update(T item)
581
    { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
582

    
583

    
584
    /// <summary>
585
    /// </summary>
586
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
587
    /// <param name="item"></param>
588
    /// <param name="olditem"></param>
589
    /// <returns></returns>
590
    public virtual bool Update(T item, out T olditem)
591
    { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
592

    
593

    
594
    /// <summary>
595
    /// </summary>
596
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
597
    /// <param name="item"></param>
598
    /// <returns></returns>
599
    public virtual bool UpdateOrAdd(T item)
600
    { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
601

    
602

    
603
    /// <summary>
604
    /// </summary>
605
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
606
    /// <param name="item"></param>
607
    /// <param name="olditem"></param>
608
    /// <returns></returns>
609
    public virtual bool UpdateOrAdd(T item, out T olditem)
610
    { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
611

    
612
    /// <summary>
613
    /// </summary>
614
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
615
    /// <param name="item"></param>
616
    /// <returns></returns>
617
    public virtual bool Remove(T item)
618
    { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
619

    
620

    
621
    /// <summary>
622
    /// </summary>
623
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
624
    /// <param name="item">The value to remove.</param>
625
    /// <param name="removeditem">The removed value.</param>
626
    /// <returns></returns>
627
    public virtual bool Remove(T item, out T removeditem)
628
    { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
629

    
630

    
631
    /// <summary>
632
    /// </summary>
633
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
634
    /// <param name="item"></param>
635
    public virtual void RemoveAllCopies(T item)
636
    { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
637

    
638

    
639
    /// <summary>
640
    /// </summary>
641
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
642
    /// <typeparam name="U"></typeparam>
643
    /// <param name="items"></param>
644
    public virtual void RemoveAll<U>(SCG.IEnumerable<U> items) where U : T
645
    { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
646

    
647
    /// <summary>
648
    /// </summary>
649
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
650
    public virtual void Clear()
651
    { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
652

    
653

    
654
    /// <summary>
655
    /// </summary>
656
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
657
    /// <typeparam name="U"></typeparam>
658
    /// <param name="items"></param>
659
    public virtual void RetainAll<U>(SCG.IEnumerable<U> items) where U : T
660
    { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
661

    
662
    /// <summary>
663
    /// Check  wrapped collection for internal consistency
664
    /// </summary>
665
    /// <returns>True if check passed</returns>
666
    public virtual bool Check() { return collection.Check(); }
667

    
668
    #endregion
669

    
670
    #region IExtensible<T> Members
671

    
672
    /// <summary> </summary>
673
    /// <value>False if wrapped collection has set semantics</value>
674
    public virtual bool AllowsDuplicates { get { return collection.AllowsDuplicates; } }
675

    
676
    //TODO: the equalityComparer should be guarded
677
    /// <summary>
678
    /// 
679
    /// </summary>
680
    /// <value></value>
681
    public virtual SCG.IEqualityComparer<T> EqualityComparer { get { return collection.EqualityComparer; } }
682

    
683
    /// <summary>
684
    /// By convention this is true for any collection with set semantics.
685
    /// </summary>
686
    /// <value>True if only one representative of a group of equal items 
687
    /// is kept in the collection together with the total count.</value>
688
    public virtual bool DuplicatesByCounting { get { return collection.DuplicatesByCounting; } }
689

    
690

    
691
    /// <summary> </summary>
692
    /// <value>True if wrapped collection is empty</value>
693
    public override bool IsEmpty { get { return collection.IsEmpty; } }
694

    
695

    
696
    /// <summary>
697
    /// </summary>
698
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
699
    /// <param name="item"></param>
700
    /// <returns></returns>
701
    public virtual bool Add(T item)
702
    { throw new ReadOnlyCollectionException(); }
703

    
704
    /// <summary>
705
    /// </summary>
706
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
707
    /// <param name="item"></param>
708
    void SCG.ICollection<T>.Add(T item)
709
    { throw new ReadOnlyCollectionException(); }
710

    
711
    /// <summary>
712
    /// </summary>
713
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
714
    /// <typeparam name="U"></typeparam>
715
    /// <param name="items"></param>
716
    public virtual void AddAll<U>(SCG.IEnumerable<U> items) where U : T
717
    { throw new ReadOnlyCollectionException(); }
718

    
719
    #endregion
720

    
721
    #region ICloneable Members
722

    
723
    /// <summary>
724
    /// 
725
    /// </summary>
726
    /// <returns></returns>
727
    public virtual object Clone()
728
    {
729
      return new GuardedCollection<T>((ICollection<T>)(collection.Clone()));
730
    }
731

    
732
    #endregion
733

    
734
  }
735

    
736

    
737
  /// <summary>
738
  /// A read-only wrapper for a sequenced collection
739
  ///
740
  /// <i>This is mainly interesting as a base of other guard classes</i>
741
  /// </summary>
742
  public class GuardedSequenced<T> : GuardedCollection<T>, ISequenced<T>
743
  {
744
    #region Fields
745

    
746
    ISequenced<T> sequenced;
747

    
748
    #endregion
749

    
750
    #region Constructor
751

    
752
    /// <summary>
753
    /// Wrap a sequenced collection in a read-only wrapper
754
    /// </summary>
755
    /// <param name="sorted"></param>
756
    public GuardedSequenced(ISequenced<T> sorted) : base(sorted) { this.sequenced = sorted; }
757

    
758
    #endregion
759

    
760
    /// <summary>
761
    /// Check if there exists an item  that satisfies a
762
    /// specific predicate in this collection and return the index of the first one.
763
    /// </summary>
764
    /// <param name="predicate">A delegate 
765
    /// (<see cref="T:C5.Fun`2"/> with <code>R == bool</code>) defining the predicate</param>
766
    /// <returns>the index, if found, a negative value else</returns>
767
    public int FindIndex(Fun<T, bool> predicate)
768
    {
769
      IIndexed<T> indexed = sequenced as IIndexed<T>;
770
      if (indexed != null)
771
        return indexed.FindIndex(predicate);
772
      int index = 0;
773
      foreach (T item in this)
774
      {
775
        if (predicate(item))
776
          return index;
777
        index++;
778
      }
779
      return -1;
780
    }
781

    
782
    /// <summary>
783
    /// Check if there exists an item  that satisfies a
784
    /// specific predicate in this collection and return the index of the last one.
785
    /// </summary>
786
    /// <param name="predicate">A delegate 
787
    /// (<see cref="T:C5.Fun`2"/> with <code>R == bool</code>) defining the predicate</param>
788
    /// <returns>the index, if found, a negative value else</returns>
789
    public int FindLastIndex(Fun<T, bool> predicate)
790
    {
791
      IIndexed<T> indexed = sequenced as IIndexed<T>;
792
      if (indexed != null)
793
        return indexed.FindLastIndex(predicate);
794
      int index = Count - 1;
795
      foreach (T item in Backwards())
796
      {
797
        if (predicate(item))
798
          return index;
799
        index--;
800
      }
801
      return -1;
802
    }
803

    
804

    
805

    
806
    #region ISequenced<T> Members
807

    
808
    /// <summary>
809
    /// 
810
    /// </summary>
811
    /// <returns></returns>
812
    public int GetSequencedHashCode()
813
    { return sequenced.GetSequencedHashCode(); }
814

    
815
    /// <summary>
816
    /// 
817
    /// </summary>
818
    /// <param name="that"></param>
819
    /// <returns></returns>
820
    public bool SequencedEquals(ISequenced<T> that)
821
    { return sequenced.SequencedEquals(that); }
822

    
823
    #endregion
824

    
825
    #region IDirectedCollection<T> Members
826

    
827
    /// <summary>
828
    /// Get a collection that enumerates the wrapped collection in the opposite direction
829
    /// </summary>
830
    /// <returns>The mirrored collection</returns>
831
    public virtual IDirectedCollectionValue<T> Backwards()
832
    { return new GuardedDirectedCollectionValue<T>(sequenced.Backwards()); }
833

    
834
    /// <summary>
835
    /// 
836
    /// </summary>
837
    /// <param name="predicate"></param>
838
    /// <param name="item"></param>
839
    /// <returns></returns>
840
    public virtual bool FindLast(Fun<T, bool> predicate, out T item) { return sequenced.FindLast(predicate, out item); }
841

    
842
    #endregion
843

    
844
    #region IDirectedEnumerable<T> Members
845

    
846
    IDirectedEnumerable<T> IDirectedEnumerable<T>.Backwards()
847
    { return Backwards(); }
848

    
849

    
850

    
851
    /// <summary>
852
    /// <code>Forwards</code> if same, else <code>Backwards</code>
853
    /// </summary>
854
    /// <value>The enumeration direction relative to the original collection.</value>
855
    public EnumerationDirection Direction
856
    { get { return EnumerationDirection.Forwards; } }
857

    
858
    #endregion
859

    
860
    #region ICloneable Members
861

    
862
    /// <summary>
863
    /// 
864
    /// </summary>
865
    /// <returns></returns>
866
    public override object Clone()
867
    {
868
      return new GuardedCollection<T>((ISequenced<T>)(sequenced.Clone()));
869
    }
870

    
871
    #endregion
872

    
873
  }
874

    
875

    
876
  /// <summary>
877
  /// A read-only wrapper for a sorted collection
878
  ///
879
  /// <i>This is mainly interesting as a base of other guard classes</i>
880
  /// </summary>
881
  public class GuardedSorted<T> : GuardedSequenced<T>, ISorted<T>
882
  {
883
    #region Fields
884

    
885
    ISorted<T> sorted;
886

    
887
    #endregion
888

    
889
    #region Constructor
890

    
891
    /// <summary>
892
    /// Wrap a sorted collection in a read-only wrapper
893
    /// </summary>
894
    /// <param name="sorted"></param>
895
    public GuardedSorted(ISorted<T> sorted) : base(sorted) { this.sorted = sorted; }
896

    
897
    #endregion
898

    
899
    #region ISorted<T> Members
900

    
901
    /// <summary>
902
    /// Find the strict predecessor of item in the guarded sorted collection,
903
    /// that is, the greatest item in the collection smaller than the item.
904
    /// </summary>
905
    /// <param name="item">The item to find the predecessor for.</param>
906
    /// <param name="res">The predecessor, if any; otherwise the default value for T.</param>
907
    /// <returns>True if item has a predecessor; otherwise false.</returns>
908
    public bool TryPredecessor(T item, out T res) { return sorted.TryPredecessor(item, out res); }
909

    
910

    
911
    /// <summary>
912
    /// Find the strict successor of item in the guarded sorted collection,
913
    /// that is, the least item in the collection greater than the supplied value.
914
    /// </summary>
915
    /// <param name="item">The item to find the successor for.</param>
916
    /// <param name="res">The successor, if any; otherwise the default value for T.</param>
917
    /// <returns>True if item has a successor; otherwise false.</returns>
918
    public bool TrySuccessor(T item, out T res) { return sorted.TrySuccessor(item, out res); }
919

    
920

    
921
    /// <summary>
922
    /// Find the weak predecessor of item in the guarded sorted collection,
923
    /// that is, the greatest item in the collection smaller than or equal to the item.
924
    /// </summary>
925
    /// <param name="item">The item to find the weak predecessor for.</param>
926
    /// <param name="res">The weak predecessor, if any; otherwise the default value for T.</param>
927
    /// <returns>True if item has a weak predecessor; otherwise false.</returns>
928
    public bool TryWeakPredecessor(T item, out T res) { return sorted.TryWeakPredecessor(item, out res); }
929

    
930

    
931
    /// <summary>
932
    /// Find the weak successor of item in the sorted collection,
933
    /// that is, the least item in the collection greater than or equal to the supplied value.
934
    /// </summary>
935
    /// <param name="item">The item to find the weak successor for.</param>
936
    /// <param name="res">The weak successor, if any; otherwise the default value for T.</param>
937
    /// <returns>True if item has a weak successor; otherwise false.</returns>
938
    public bool TryWeakSuccessor(T item, out T res) { return sorted.TryWeakSuccessor(item, out res); }
939

    
940

    
941
    /// <summary>
942
    /// Find the predecessor of the item in the wrapped sorted collection
943
    /// </summary>
944
    /// <exception cref="NoSuchItemException"> if no such element exists </exception>    
945
    /// <param name="item">The item</param>
946
    /// <returns>The predecessor</returns>
947
    public T Predecessor(T item) { return sorted.Predecessor(item); }
948

    
949

    
950
    /// <summary>
951
    /// Find the Successor of the item in the wrapped sorted collection
952
    /// </summary>
953
    /// <exception cref="NoSuchItemException"> if no such element exists </exception>    
954
    /// <param name="item">The item</param>
955
    /// <returns>The Successor</returns>
956
    public T Successor(T item) { return sorted.Successor(item); }
957

    
958

    
959
    /// <summary>
960
    /// Find the weak predecessor of the item in the wrapped sorted collection
961
    /// </summary>
962
    /// <exception cref="NoSuchItemException"> if no such element exists </exception>    
963
    /// <param name="item">The item</param>
964
    /// <returns>The weak predecessor</returns>
965
    public T WeakPredecessor(T item) { return sorted.WeakPredecessor(item); }
966

    
967

    
968
    /// <summary>
969
    /// Find the weak Successor of the item in the wrapped sorted collection
970
    /// </summary>
971
    /// <exception cref="NoSuchItemException"> if no such element exists </exception>    
972
    /// <param name="item">The item</param>
973
    /// <returns>The weak Successor</returns>
974
    public T WeakSuccessor(T item) { return sorted.WeakSuccessor(item); }
975

    
976

    
977
    /// <summary>
978
    /// Run Cut on the wrapped sorted collection
979
    /// </summary>
980
    /// <param name="c"></param>
981
    /// <param name="low"></param>
982
    /// <param name="lval"></param>
983
    /// <param name="high"></param>
984
    /// <param name="hval"></param>
985
    /// <returns></returns>
986
    public bool Cut(IComparable<T> c, out T low, out bool lval, out T high, out bool hval)
987
    { return sorted.Cut(c, out low, out lval, out high, out hval); }
988

    
989

    
990
    /// <summary>
991
    /// Get the specified range from the wrapped collection. 
992
    /// (The current implementation erroneously does not wrap the result.)
993
    /// </summary>
994
    /// <param name="bot"></param>
995
    /// <returns></returns>
996
    public IDirectedEnumerable<T> RangeFrom(T bot) { return sorted.RangeFrom(bot); }
997

    
998

    
999
    /// <summary>
1000
    /// Get the specified range from the wrapped collection. 
1001
    /// (The current implementation erroneously does not wrap the result.)
1002
    /// </summary>
1003
    /// <param name="bot"></param>
1004
    /// <param name="top"></param>
1005
    /// <returns></returns>
1006
    public IDirectedEnumerable<T> RangeFromTo(T bot, T top)
1007
    { return sorted.RangeFromTo(bot, top); }
1008

    
1009

    
1010
    /// <summary>
1011
    /// Get the specified range from the wrapped collection. 
1012
    /// (The current implementation erroneously does not wrap the result.)
1013
    /// </summary>
1014
    /// <param name="top"></param>
1015
    /// <returns></returns>
1016
    public IDirectedEnumerable<T> RangeTo(T top) { return sorted.RangeTo(top); }
1017

    
1018

    
1019
    /// <summary>
1020
    /// Get the specified range from the wrapped collection. 
1021
    /// (The current implementation erroneously does not wrap the result.)
1022
    /// </summary>
1023
    /// <returns></returns>
1024
    public IDirectedCollectionValue<T> RangeAll() { return sorted.RangeAll(); }
1025

    
1026
    /// <summary>
1027
    /// </summary>
1028
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1029
    /// <param name="items"></param>
1030
    /// <typeparam name="U"></typeparam>
1031
    public void AddSorted<U>(SCG.IEnumerable<U> items) where U : T
1032
    { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
1033

    
1034
    /// <summary>
1035
    /// </summary>
1036
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1037
    /// <param name="low"></param>
1038
    public void RemoveRangeFrom(T low)
1039
    { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
1040

    
1041

    
1042
    /// <summary>
1043
    /// </summary>
1044
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1045
    /// <param name="low"></param>
1046
    /// <param name="hi"></param>
1047
    public void RemoveRangeFromTo(T low, T hi)
1048
    { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
1049

    
1050

    
1051
    /// <summary>
1052
    /// </summary>
1053
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1054
    /// <param name="hi"></param>
1055
    public void RemoveRangeTo(T hi)
1056
    { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
1057

    
1058
    #endregion
1059

    
1060
    #region IPriorityQueue<T> Members
1061

    
1062
    /// <summary>
1063
    /// Find the minimum of the wrapped collection
1064
    /// </summary>
1065
    /// <returns>The minimum</returns>
1066
    public T FindMin() { return sorted.FindMin(); }
1067

    
1068

    
1069
    /// <summary>
1070
    /// </summary>
1071
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1072
    /// <returns></returns>
1073
    public T DeleteMin()
1074
    { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
1075

    
1076

    
1077
    /// <summary>
1078
    /// Find the maximum of the wrapped collection
1079
    /// </summary>
1080
    /// <returns>The maximum</returns>
1081
    public T FindMax() { return sorted.FindMax(); }
1082

    
1083

    
1084
    /// <summary>
1085
    /// </summary>
1086
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1087
    /// <returns></returns>
1088
    public T DeleteMax()
1089
    { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
1090

    
1091
    //TODO: we should guard the comparer!
1092
    /// <summary>
1093
    /// The comparer object supplied at creation time for the underlying collection
1094
    /// </summary>
1095
    /// <value>The comparer</value>
1096
    public SCG.IComparer<T> Comparer { get { return sorted.Comparer; } }
1097
    #endregion
1098

    
1099
    #region IDirectedEnumerable<T> Members
1100

    
1101
    IDirectedEnumerable<T> IDirectedEnumerable<T>.Backwards()
1102
    { return Backwards(); }
1103

    
1104
    #endregion
1105

    
1106
    /// <summary>
1107
    /// 
1108
    /// </summary>
1109
    /// <returns></returns>
1110
    public override object Clone()
1111
    {
1112
      return new GuardedSorted<T>((ISorted<T>)(sorted.Clone()));
1113
    }
1114

    
1115
  }
1116

    
1117

    
1118

    
1119
  /// <summary>
1120
  /// Read-only wrapper for indexed sorted collections
1121
  ///
1122
  /// <i>Suitable for wrapping TreeSet, TreeBag and SortedArray</i>
1123
  /// </summary>
1124
  public class GuardedIndexedSorted<T> : GuardedSorted<T>, IIndexedSorted<T>
1125
  {
1126
    #region Fields
1127

    
1128
    IIndexedSorted<T> indexedsorted;
1129

    
1130
    #endregion
1131

    
1132
    #region Constructor
1133

    
1134
    /// <summary>
1135
    /// Wrap an indexed sorted collection in a read-only wrapper
1136
    /// </summary>
1137
    /// <param name="list">the indexed sorted collection</param>
1138
    public GuardedIndexedSorted(IIndexedSorted<T> list)
1139
      : base(list)
1140
    { this.indexedsorted = list; }
1141

    
1142
    #endregion
1143

    
1144
    #region IIndexedSorted<T> Members
1145

    
1146
    /// <summary>
1147
    /// Get the specified range from the wrapped collection. 
1148
    /// (The current implementation erroneously does not wrap the result.)
1149
    /// </summary>
1150
    /// <param name="bot"></param>
1151
    /// <returns></returns>
1152
    public new IDirectedCollectionValue<T> RangeFrom(T bot)
1153
    { return indexedsorted.RangeFrom(bot); }
1154

    
1155

    
1156
    /// <summary>
1157
    /// Get the specified range from the wrapped collection. 
1158
    /// (The current implementation erroneously does not wrap the result.)
1159
    /// </summary>
1160
    /// <param name="bot"></param>
1161
    /// <param name="top"></param>
1162
    /// <returns></returns>
1163
    public new IDirectedCollectionValue<T> RangeFromTo(T bot, T top)
1164
    { return indexedsorted.RangeFromTo(bot, top); }
1165

    
1166

    
1167
    /// <summary>
1168
    /// Get the specified range from the wrapped collection. 
1169
    /// (The current implementation erroneously does not wrap the result.)
1170
    /// </summary>
1171
    /// <param name="top"></param>
1172
    /// <returns></returns>
1173
    public new IDirectedCollectionValue<T> RangeTo(T top)
1174
    { return indexedsorted.RangeTo(top); }
1175

    
1176

    
1177
    /// <summary>
1178
    /// Report the number of items in the specified range of the wrapped collection
1179
    /// </summary>
1180
    /// <param name="bot"></param>
1181
    /// <returns></returns>
1182
    public int CountFrom(T bot) { return indexedsorted.CountFrom(bot); }
1183

    
1184

    
1185
    /// <summary>
1186
    /// Report the number of items in the specified range of the wrapped collection
1187
    /// </summary>
1188
    /// <param name="bot"></param>
1189
    /// <param name="top"></param>
1190
    /// <returns></returns>
1191
    public int CountFromTo(T bot, T top) { return indexedsorted.CountFromTo(bot, top); }
1192

    
1193

    
1194
    /// <summary>
1195
    /// Report the number of items in the specified range of the wrapped collection
1196
    /// </summary>
1197
    /// <param name="top"></param>
1198
    /// <returns></returns>
1199
    public int CountTo(T top) { return indexedsorted.CountTo(top); }
1200

    
1201

    
1202
    /// <summary>
1203
    /// Run FindAll on the wrapped collection with the indicated filter.
1204
    /// The result will <b>not</b> be read-only.
1205
    /// </summary>
1206
    /// <param name="f"></param>
1207
    /// <returns></returns>
1208
    public IIndexedSorted<T> FindAll(Fun<T, bool> f)
1209
    { return indexedsorted.FindAll(f); }
1210

    
1211

    
1212
    /// <summary>
1213
    /// Run Map on the wrapped collection with the indicated mapper.
1214
    /// The result will <b>not</b> be read-only.
1215
    /// </summary>
1216
    /// <param name="m"></param>
1217
    /// <param name="c">The comparer to use in the result</param>
1218
    /// <returns></returns>
1219
    public IIndexedSorted<V> Map<V>(Fun<T, V> m, SCG.IComparer<V> c)
1220
    { return indexedsorted.Map(m, c); }
1221

    
1222
    #endregion
1223

    
1224
    #region IIndexed<T> Members
1225

    
1226
    /// <summary>
1227
    /// 
1228
    /// </summary>
1229
    /// <value>The i'th item of the wrapped sorted collection</value>
1230
    public T this[int i] { get { return indexedsorted[i]; } }
1231

    
1232
    /// <summary>
1233
    /// 
1234
    /// </summary>
1235
    /// <value></value>
1236
    public virtual Speed IndexingSpeed { get { return indexedsorted.IndexingSpeed; } }
1237

    
1238
    /// <summary> </summary>
1239
    /// <value>A directed collection of the items in the indicated interval of the wrapped collection</value>
1240
    public IDirectedCollectionValue<T> this[int start, int end]
1241
    { get { return new GuardedDirectedCollectionValue<T>(indexedsorted[start, end]); } }
1242

    
1243

    
1244
    /// <summary>
1245
    /// Find the (first) index of an item in the wrapped collection
1246
    /// </summary>
1247
    /// <param name="item"></param>
1248
    /// <returns></returns>
1249
    public int IndexOf(T item) { return indexedsorted.IndexOf(item); }
1250

    
1251

    
1252
    /// <summary>
1253
    /// Find the last index of an item in the wrapped collection
1254
    /// </summary>
1255
    /// <param name="item"></param>
1256
    /// <returns></returns>
1257
    public int LastIndexOf(T item) { return indexedsorted.LastIndexOf(item); }
1258

    
1259

    
1260
    /// <summary>
1261
    /// </summary>
1262
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1263
    /// <param name="i"></param>
1264
    /// <returns></returns>
1265
    public T RemoveAt(int i)
1266
    { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
1267

    
1268

    
1269
    /// <summary>
1270
    /// </summary>
1271
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1272
    /// <param name="start"></param>
1273
    /// <param name="count"></param>
1274
    public void RemoveInterval(int start, int count)
1275
    { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
1276

    
1277
    #endregion
1278

    
1279
    #region IDirectedEnumerable<T> Members
1280

    
1281
    IDirectedEnumerable<T> IDirectedEnumerable<T>.Backwards()
1282
    { return Backwards(); }
1283

    
1284
    #endregion
1285

    
1286
    /// <summary>
1287
    /// 
1288
    /// </summary>
1289
    /// <returns></returns>
1290
    public override object Clone()
1291
    {
1292
      return new GuardedIndexedSorted<T>((IIndexedSorted<T>)(indexedsorted.Clone()));
1293
    }
1294

    
1295
  }
1296

    
1297

    
1298

    
1299
  /// <summary>
1300
  /// A read-only wrapper for a generic list collection
1301
  /// <i>Suitable as a wrapper for LinkedList, HashedLinkedList, ArrayList and HashedArray.
1302
  /// <see cref="T:C5.LinkedList`1"/>, 
1303
  /// <see cref="T:C5.HashedLinkedList`1"/>, 
1304
  /// <see cref="T:C5.ArrayList`1"/> or
1305
  /// <see cref="T:C5.HashedArray`1"/>.
1306
  /// </i>
1307
  /// </summary>
1308
  public class GuardedList<T> : GuardedSequenced<T>, IList<T>, SCG.IList<T>
1309
  {
1310
    #region Fields
1311

    
1312
    IList<T> innerlist;
1313
    GuardedList<T> underlying;
1314
    bool slidableView = false;
1315

    
1316
    #endregion
1317

    
1318
    #region Constructor
1319

    
1320
    /// <summary>
1321
    /// Wrap a list in a read-only wrapper.  A list gets wrapped as read-only,
1322
    /// a list view gets wrapped as read-only and non-slidable.
1323
    /// </summary>
1324
    /// <param name="list">The list</param>
1325
    public GuardedList(IList<T> list)
1326
      : base(list)
1327
    {
1328
      this.innerlist = list;
1329
      // If wrapping a list view, make innerlist = the view, and make 
1330
      // underlying = a guarded version of the view's underlying list
1331
      if (list.Underlying != null)
1332
        underlying = new GuardedList<T>(list.Underlying, null, false);
1333
    }
1334

    
1335
    GuardedList(IList<T> list, GuardedList<T> underlying, bool slidableView)
1336
      : base(list)
1337
    {
1338
      this.innerlist = list; this.underlying = underlying; this.slidableView = slidableView;
1339
    }
1340
    #endregion
1341

    
1342
    #region IList<T> Members
1343

    
1344
    /// <summary>
1345
    /// 
1346
    /// </summary>
1347
    /// <value>The first item of the wrapped list</value>
1348
    public T First { get { return innerlist.First; } }
1349

    
1350

    
1351
    /// <summary>
1352
    /// 
1353
    /// </summary>
1354
    /// <value>The last item of the wrapped list</value>
1355
    public T Last { get { return innerlist.Last; } }
1356

    
1357

    
1358
    /// <summary>
1359
    /// </summary>
1360
    /// <exception cref="ReadOnlyCollectionException"> if used as setter</exception>
1361
    /// <value>True if wrapped list has FIFO semantics for the Add(T item) and Remove() methods</value>
1362
    public bool FIFO
1363
    {
1364
      get { return innerlist.FIFO; }
1365
      set { throw new ReadOnlyCollectionException("List is read only"); }
1366
    }
1367

    
1368
    /// <summary>
1369
    /// 
1370
    /// </summary>
1371
    public virtual bool IsFixedSize
1372
    {
1373
      get { return true; }
1374
    }
1375

    
1376

    
1377
    /// <summary>
1378
    /// </summary>
1379
    /// <exception cref="ReadOnlyCollectionException"> if used as setter</exception>
1380
    /// <value>The i'th item of the wrapped list</value>
1381
    public T this[int i]
1382
    {
1383
      get { return innerlist[i]; }
1384
      set { throw new ReadOnlyCollectionException("List is read only"); }
1385
    }
1386

    
1387
    /// <summary>
1388
    /// 
1389
    /// </summary>
1390
    /// <value></value>
1391
    public virtual Speed IndexingSpeed { get { return innerlist.IndexingSpeed; } }
1392

    
1393
    /// <summary>
1394
    /// </summary>
1395
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1396
    /// <param name="index"></param>
1397
    /// <param name="item"></param>
1398
    public void Insert(int index, T item)
1399
    { throw new ReadOnlyCollectionException(); }
1400

    
1401
    /// <summary>
1402
    /// </summary>
1403
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1404
    /// <param name="pointer"></param>
1405
    /// <param name="item"></param>
1406
    public void Insert(IList<T> pointer, T item)
1407
    { throw new ReadOnlyCollectionException(); }
1408

    
1409
    /// <summary>
1410
    /// </summary>
1411
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1412
    /// <param name="item"></param>
1413
    public void InsertFirst(T item)
1414
    { throw new ReadOnlyCollectionException("List is read only"); }
1415

    
1416
    /// <summary>
1417
    /// </summary>
1418
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1419
    /// <param name="item"></param>
1420
    public void InsertLast(T item)
1421
    { throw new ReadOnlyCollectionException("List is read only"); }
1422

    
1423
    /// <summary>
1424
    /// </summary>
1425
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1426
    /// <param name="item"></param>
1427
    /// <param name="target"></param>
1428
    public void InsertBefore(T item, T target)
1429
    { throw new ReadOnlyCollectionException("List is read only"); }
1430

    
1431

    
1432
    /// <summary>
1433
    /// </summary>
1434
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1435
    /// <param name="item"></param>
1436
    /// <param name="target"></param>
1437
    public void InsertAfter(T item, T target)
1438
    { throw new ReadOnlyCollectionException("List is read only"); }
1439

    
1440

    
1441
    /// <summary>
1442
    /// </summary>
1443
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1444
    /// <param name="i"></param>
1445
    /// <param name="items"></param>
1446
    public void InsertAll<U>(int i, SCG.IEnumerable<U> items) where U : T
1447
    { throw new ReadOnlyCollectionException("List is read only"); }
1448

    
1449

    
1450
    /// <summary>
1451
    /// Perform FindAll on the wrapped list. The result is <b>not</b> necessarily read-only.
1452
    /// </summary>
1453
    /// <param name="filter">The filter to use</param>
1454
    /// <returns></returns>
1455
    public IList<T> FindAll(Fun<T, bool> filter) { return innerlist.FindAll(filter); }
1456

    
1457

    
1458
    /// <summary>
1459
    /// Perform Map on the wrapped list. The result is <b>not</b> necessarily read-only.
1460
    /// </summary>
1461
    /// <typeparam name="V">The type of items of the new list</typeparam>
1462
    /// <param name="mapper">The mapper to use.</param>
1463
    /// <returns>The mapped list</returns>
1464
    public IList<V> Map<V>(Fun<T, V> mapper) { return innerlist.Map(mapper); }
1465

    
1466
    /// <summary>
1467
    /// Perform Map on the wrapped list. The result is <b>not</b> necessarily read-only.
1468
    /// </summary>
1469
    /// <typeparam name="V">The type of items of the new list</typeparam>
1470
    /// <param name="mapper">The delegate defining the map.</param>
1471
    /// <param name="itemequalityComparer">The itemequalityComparer to use for the new list</param>
1472
    /// <returns>The new list.</returns>
1473
    public IList<V> Map<V>(Fun<T, V> mapper, SCG.IEqualityComparer<V> itemequalityComparer) { return innerlist.Map(mapper, itemequalityComparer); }
1474

    
1475
    /// <summary>
1476
    /// </summary>
1477
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1478
    /// <returns></returns>
1479
    public T Remove() { throw new ReadOnlyCollectionException("List is read only"); }
1480

    
1481

    
1482
    /// <summary>
1483
    /// </summary>
1484
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1485
    /// <returns></returns>
1486
    public T RemoveFirst() { throw new ReadOnlyCollectionException("List is read only"); }
1487

    
1488

    
1489
    /// <summary>
1490
    /// </summary>
1491
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1492
    /// <returns></returns>
1493
    public T RemoveLast() { throw new ReadOnlyCollectionException("List is read only"); }
1494

    
1495

    
1496
    /// <summary>
1497
    /// Create the indicated view on the wrapped list and wrap it read-only.
1498
    /// </summary>
1499
    /// <param name="start"></param>
1500
    /// <param name="count"></param>
1501
    /// <returns></returns>
1502
    public IList<T> View(int start, int count)
1503
    {
1504
      IList<T> view = innerlist.View(start, count);
1505
      return view == null ? null : new GuardedList<T>(view, underlying ?? this, true);
1506
    }
1507

    
1508
    /// <summary>
1509
    /// Create the indicated view on the wrapped list and wrap it read-only.
1510
    /// </summary>
1511
    /// <param name="item"></param>
1512
    /// <returns></returns>
1513
    public IList<T> ViewOf(T item)
1514
    {
1515
      IList<T> view = innerlist.ViewOf(item);
1516
      return view == null ? null : new GuardedList<T>(view, underlying ?? this, true);
1517
    }
1518

    
1519
    /// <summary>
1520
    /// Create the indicated view on the wrapped list and wrap it read-only.
1521
    /// </summary>
1522
    /// <param name="item"></param>
1523
    /// <returns></returns>
1524
    public IList<T> LastViewOf(T item)
1525
    {
1526
      IList<T> view = innerlist.LastViewOf(item);
1527
      return view == null ? null : new GuardedList<T>(view, underlying ?? this, true);
1528
    }
1529

    
1530

    
1531
    /// <summary>
1532
    /// </summary>
1533
    /// <value>The wrapped underlying list of the wrapped view </value>
1534
    public IList<T> Underlying { get { return underlying; } }
1535

    
1536

    
1537
    /// <summary>
1538
    /// 
1539
    /// </summary>
1540
    /// <value>The offset of the wrapped list as a view.</value>
1541
    public int Offset { get { return innerlist.Offset; } }
1542

    
1543
    /// <summary>
1544
    /// 
1545
    /// </summary>
1546
    /// <value></value>
1547
    public virtual bool IsValid { get { return innerlist.IsValid; } }
1548

    
1549
    /// <summary>
1550
    /// </summary>
1551
    /// <exception cref="ReadOnlyCollectionException"> if this is a wrapped view and not a view that was made on a wrapper</exception>
1552
    /// <param name="offset"></param>
1553
    public IList<T> Slide(int offset)
1554
    {
1555
      if (slidableView)
1556
      {
1557
        innerlist.Slide(offset);
1558
        return this;
1559
      }
1560
      else
1561
        throw new ReadOnlyCollectionException("List is read only");
1562
    }
1563

    
1564

    
1565
    /// <summary>
1566
    /// </summary>
1567
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1568
    /// <param name="offset"></param>
1569
    /// <param name="size"></param>
1570
    public IList<T> Slide(int offset, int size)
1571
    {
1572
      if (slidableView)
1573
      {
1574
        innerlist.Slide(offset, size);
1575
        return this;
1576
      }
1577
      else
1578
        throw new ReadOnlyCollectionException("List is read only");
1579
    }
1580

    
1581

    
1582
    /// <summary>
1583
    /// 
1584
    /// </summary>
1585
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1586
    /// <param name="offset"></param>
1587
    /// <returns></returns>
1588
    public bool TrySlide(int offset)
1589
    {
1590
      if (slidableView)
1591
        return innerlist.TrySlide(offset);
1592
      else
1593
        throw new ReadOnlyCollectionException("List is read only");
1594
    }
1595

    
1596
    /// <summary>
1597
    /// 
1598
    /// </summary>
1599
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1600
    /// <param name="offset"></param>
1601
    /// <param name="size"></param>
1602
    /// <returns></returns>
1603
    public bool TrySlide(int offset, int size)
1604
    {
1605
      if (slidableView)
1606
        return innerlist.TrySlide(offset, size);
1607
      else
1608
        throw new ReadOnlyCollectionException("List is read only");
1609
    }
1610

    
1611
    /// <summary>
1612
    /// 
1613
    /// </summary>
1614
    /// <param name="otherView"></param>
1615
    /// <returns></returns>
1616
    public IList<T> Span(IList<T> otherView)
1617
    {
1618
      GuardedList<T> otherGuardedList = otherView as GuardedList<T>;
1619
      if (otherGuardedList == null)
1620
        throw new IncompatibleViewException();
1621
      IList<T> span = innerlist.Span(otherGuardedList.innerlist);
1622
      if (span == null)
1623
        return null;
1624
      return new GuardedList<T>(span, underlying ?? otherGuardedList.underlying ?? this, true);
1625
    }
1626

    
1627
    /// <summary>
1628
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1629
    /// </summary>
1630
    public void Reverse() { throw new ReadOnlyCollectionException("List is read only"); }
1631

    
1632

    
1633
    /// <summary>
1634
    /// </summary>
1635
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1636
    /// <param name="start"></param>
1637
    /// <param name="count"></param>
1638
    public void Reverse(int start, int count)
1639
    { throw new ReadOnlyCollectionException("List is read only"); }
1640

    
1641

    
1642
    /// <summary>
1643
    /// Check if wrapped list is sorted according to the default sorting order
1644
    /// for the item type T, as defined by the <see cref="T:C5.Comparer`1"/> class 
1645
    /// </summary>
1646
    /// <exception cref="NotComparableException">if T is not comparable</exception>
1647
    /// <returns>True if the list is sorted, else false.</returns>
1648
    public bool IsSorted() { return innerlist.IsSorted(Comparer<T>.Default); }
1649

    
1650
    /// <summary>
1651
    /// Check if wrapped list is sorted
1652
    /// </summary>
1653
    /// <param name="c">The sorting order to use</param>
1654
    /// <returns>True if sorted</returns>
1655
    public bool IsSorted(SCG.IComparer<T> c) { return innerlist.IsSorted(c); }
1656

    
1657

    
1658
    /// <summary>
1659
    /// </summary>
1660
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1661
    public void Sort()
1662
    { throw new ReadOnlyCollectionException("List is read only"); }
1663

    
1664

    
1665
    /// <summary>
1666
    /// </summary>
1667
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1668
    /// <param name="c"></param>
1669
    public void Sort(SCG.IComparer<T> c)
1670
    { throw new ReadOnlyCollectionException("List is read only"); }
1671

    
1672
    /// <summary>
1673
    /// </summary>
1674
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1675
    public void Shuffle()
1676
    { throw new ReadOnlyCollectionException("List is read only"); }
1677

    
1678

    
1679
    /// <summary>
1680
    /// </summary>
1681
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1682
    /// <param name="rnd"></param>
1683
    public void Shuffle(Random rnd)
1684
    { throw new ReadOnlyCollectionException("List is read only"); }
1685

    
1686
    #endregion
1687

    
1688
    #region IIndexed<T> Members
1689

    
1690
    /// <summary> </summary>
1691
    /// <value>A directed collection of the items in the indicated interval of the wrapped collection</value>
1692
    public IDirectedCollectionValue<T> this[int start, int end]
1693
    { get { return new GuardedDirectedCollectionValue<T>(innerlist[start, end]); } }
1694

    
1695

    
1696
    /// <summary>
1697
    /// Find the (first) index of an item in the wrapped collection
1698
    /// </summary>
1699
    /// <param name="item"></param>
1700
    /// <returns></returns>
1701
    public int IndexOf(T item) { return innerlist.IndexOf(item); }
1702

    
1703

    
1704
    /// <summary>
1705
    /// Find the last index of an item in the wrapped collection
1706
    /// </summary>
1707
    /// <param name="item"></param>
1708
    /// <returns></returns>
1709
    public int LastIndexOf(T item) { return innerlist.LastIndexOf(item); }
1710

    
1711

    
1712
    /// <summary>
1713
    /// </summary>
1714
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1715
    /// <param name="i"></param>
1716
    /// <returns></returns>
1717
    public T RemoveAt(int i)
1718
    { throw new ReadOnlyCollectionException("List is read only"); }
1719

    
1720

    
1721
    /// <summary>
1722
    /// </summary>
1723
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1724
    /// <param name="start"></param>
1725
    /// <param name="count"></param>
1726
    public void RemoveInterval(int start, int count)
1727
    { throw new ReadOnlyCollectionException("List is read only"); }
1728

    
1729
    #endregion
1730

    
1731
    #region IDirectedEnumerable<T> Members
1732

    
1733
    IDirectedEnumerable<T> IDirectedEnumerable<T>.Backwards()
1734
    { return Backwards(); }
1735

    
1736
    #endregion
1737

    
1738
    #region IStack<T> Members
1739

    
1740

    
1741
    /// <summary>
1742
    /// 
1743
    /// </summary>
1744
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1745
    /// <returns>-</returns>
1746
    public void Push(T item)
1747
    { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
1748

    
1749
    /// <summary>
1750
    /// 
1751
    /// </summary>
1752
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1753
    /// <returns>-</returns>
1754
    public T Pop()
1755
    { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
1756

    
1757
    #endregion
1758

    
1759
    #region IQueue<T> Members
1760

    
1761
    /// <summary>
1762
    /// 
1763
    /// </summary>
1764
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1765
    /// <returns>-</returns>
1766
    public void Enqueue(T item)
1767
    { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
1768

    
1769
    /// <summary>
1770
    /// 
1771
    /// </summary>
1772
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1773
    /// <returns>-</returns>
1774
    public T Dequeue()
1775
    { throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object"); }
1776

    
1777
    #endregion
1778

    
1779
    #region IDisposable Members
1780

    
1781
    /// <summary>
1782
    /// Ignore: this may be called by a foreach or using statement.
1783
    /// </summary>
1784
    public void Dispose() { }
1785

    
1786
    #endregion
1787

    
1788
    /// <summary>
1789
    /// 
1790
    /// </summary>
1791
    /// <returns></returns>
1792
    public override object Clone()
1793
    {
1794
      return new GuardedList<T>((IList<T>)(innerlist.Clone()));
1795
    }
1796

    
1797
    #region System.Collections.Generic.IList<T> Members
1798

    
1799
    void System.Collections.Generic.IList<T>.RemoveAt(int index)
1800
    {
1801
      throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object");
1802
    }
1803

    
1804
    void System.Collections.Generic.ICollection<T>.Add(T item)
1805
    {
1806
      throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object");
1807
    }
1808

    
1809
    #endregion
1810

    
1811
    #region System.Collections.ICollection Members
1812

    
1813
    bool System.Collections.ICollection.IsSynchronized
1814
    {
1815
      get { return false; }
1816
    }
1817

    
1818
    [Obsolete]
1819
    Object System.Collections.ICollection.SyncRoot
1820
    {
1821
      get { return innerlist.SyncRoot; }
1822
    }
1823

    
1824
    void System.Collections.ICollection.CopyTo(Array arr, int index)
1825
    {
1826
      if (index < 0 || index + Count > arr.Length)
1827
        throw new ArgumentOutOfRangeException();
1828

    
1829
      foreach (T item in this)
1830
        arr.SetValue(item, index++);
1831
    }
1832

    
1833
    #endregion
1834

    
1835
    #region System.Collections.IList Members
1836
    
1837
    Object System.Collections.IList.this[int index]
1838
    {
1839
      get { return this[index]; }
1840
      set
1841
      {
1842
        throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object");
1843
      }
1844
    }
1845

    
1846
    int System.Collections.IList.Add(Object o)
1847
    {
1848
      throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object");
1849
    }
1850

    
1851
    bool System.Collections.IList.Contains(Object o)
1852
    {
1853
      return Contains((T)o);
1854
    }
1855

    
1856
    int System.Collections.IList.IndexOf(Object o)
1857
    {
1858
      return Math.Max(-1, IndexOf((T)o));
1859
    }
1860

    
1861
    void System.Collections.IList.Insert(int index, Object o)
1862
    {
1863
      throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object");
1864
    }
1865

    
1866
    void System.Collections.IList.Remove(Object o)
1867
    {
1868
      throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object");
1869
    }
1870

    
1871
    void System.Collections.IList.RemoveAt(int index)
1872
    {
1873
      throw new ReadOnlyCollectionException("Collection cannot be modified through this guard object");
1874
    }
1875

    
1876
    #endregion
1877
  }
1878

    
1879
  /// <summary>
1880
  /// A read-only wrapper for a generic indexable queue (allows indexing).
1881
  /// 
1882
  /// <para>Suitable for wrapping a <see cref="T:C5.CircularQueue`1"/></para>
1883
  /// </summary>
1884
  /// <typeparam name="T">The item type.</typeparam>
1885
  public class GuardedQueue<T> : GuardedDirectedCollectionValue<T>, IQueue<T>
1886
  {
1887
    #region Fields
1888

    
1889
    IQueue<T> queue;
1890

    
1891
    #endregion
1892

    
1893
    #region Constructor
1894

    
1895
    /// <summary>
1896
    /// Wrap a queue in a read-only wrapper
1897
    /// </summary>
1898
    /// <param name="queue">The queue</param>
1899
    public GuardedQueue(IQueue<T> queue) : base(queue) { this.queue = queue; }
1900

    
1901
    #endregion
1902

    
1903
    #region IQueue<T> Members
1904
    /// <summary>
1905
    /// 
1906
    /// </summary>
1907
    /// <value></value>
1908
    public bool AllowsDuplicates { get { return queue.AllowsDuplicates; } }
1909

    
1910
    /// <summary>
1911
    /// Index into the wrapped queue
1912
    /// </summary>
1913
    /// <param name="i"></param>
1914
    /// <returns></returns>
1915
    public T this[int i] { get { return queue[i]; } }
1916

    
1917
    /// <summary>
1918
    /// 
1919
    /// </summary>
1920
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1921
    /// <returns>-</returns>
1922
    public void Enqueue(T item)
1923
    { throw new ReadOnlyCollectionException("Queue cannot be modified through this guard object"); }
1924

    
1925
    /// <summary>
1926
    /// 
1927
    /// </summary>
1928
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
1929
    /// <returns>-</returns>
1930
    public T Dequeue()
1931
    { throw new ReadOnlyCollectionException("Queue cannot be modified through this guard object"); }
1932

    
1933
    #endregion
1934
  }
1935

    
1936
  /// <summary>
1937
  /// A read-only wrapper for a dictionary.
1938
  ///
1939
  /// <i>Suitable for wrapping a HashDictionary. <see cref="T:C5.HashDictionary`2"/></i>
1940
  /// </summary>
1941
  public class GuardedDictionary<K, V> : GuardedCollectionValue<KeyValuePair<K, V>>, IDictionary<K, V>
1942
  {
1943
    #region Fields
1944

    
1945
    IDictionary<K, V> dict;
1946

    
1947
    #endregion
1948

    
1949
    #region Constructor
1950

    
1951
    /// <summary>
1952
    /// Wrap a dictionary in a read-only wrapper
1953
    /// </summary>
1954
    /// <param name="dict">the dictionary</param>
1955
    public GuardedDictionary(IDictionary<K, V> dict) : base(dict) { this.dict = dict; }
1956

    
1957
    #endregion
1958

    
1959
    #region IDictionary<K,V> Members
1960

    
1961
    /// <summary>
1962
    /// 
1963
    /// </summary>
1964
    /// <value></value>
1965
    public SCG.IEqualityComparer<K> EqualityComparer { get { return dict.EqualityComparer; } }
1966

    
1967
    /// <summary>
1968
    /// </summary>
1969
    /// <exception cref="ReadOnlyCollectionException"> since this is a
1970
    /// read-only wrappper if used as a setter</exception>
1971
    /// <value>Get the value corresponding to a key in the wrapped dictionary</value>
1972
    public V this[K key]
1973
    {
1974
      get { return dict[key]; }
1975
      set { throw new ReadOnlyCollectionException(); }
1976
    }
1977

    
1978
    /// <summary>
1979
    /// (This is a read-only wrapper)
1980
    /// </summary>
1981
    /// <value>True</value>
1982
    public bool IsReadOnly { get { return true; } }
1983

    
1984

    
1985
    //TODO: guard with a read-only wrapper? Probably so!
1986
    /// <summary> </summary>
1987
    /// <value>The collection of keys of the wrapped dictionary</value>
1988
    public ICollectionValue<K> Keys
1989
    { get { return dict.Keys; } }
1990

    
1991

    
1992
    /// <summary> </summary>
1993
    /// <value>The collection of values of the wrapped dictionary</value>
1994
    public ICollectionValue<V> Values { get { return dict.Values; } }
1995

    
1996
    /// <summary>
1997
    /// 
1998
    /// </summary>
1999
    public virtual Fun<K, V> Fun { get { return delegate(K k) { return this[k]; }; } }
2000

    
2001
    /// <summary>
2002
    /// </summary>
2003
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
2004
    /// <param name="key"></param>
2005
    /// <param name="val"></param>
2006
    public void Add(K key, V val)
2007
    { throw new ReadOnlyCollectionException(); }
2008

    
2009
    /// <summary>
2010
    /// 
2011
    /// </summary>
2012
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
2013
    /// <param name="items"></param>
2014
    public void AddAll<L, W>(SCG.IEnumerable<KeyValuePair<L, W>> items)
2015
      where L : K
2016
      where W : V
2017
    { throw new ReadOnlyCollectionException(); }
2018

    
2019
    /// <summary>
2020
    /// </summary>
2021
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
2022
    /// <param name="key"></param>
2023
    /// <returns></returns>
2024
    public bool Remove(K key)
2025
    { throw new ReadOnlyCollectionException(); }
2026

    
2027

    
2028
    /// <summary>
2029
    /// </summary>
2030
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
2031
    /// <param name="key"></param>
2032
    /// <param name="val"></param>
2033
    /// <returns></returns>
2034
    public bool Remove(K key, out V val)
2035
    { throw new ReadOnlyCollectionException(); }
2036

    
2037

    
2038
    /// <summary>
2039
    /// </summary>
2040
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
2041
    public void Clear()
2042
    { throw new ReadOnlyCollectionException(); }
2043

    
2044
    /// <summary>
2045
    /// 
2046
    /// </summary>
2047
    /// <value></value>
2048
    public Speed ContainsSpeed { get { return dict.ContainsSpeed; } }
2049

    
2050
    /// <summary>
2051
    /// Check if the wrapped dictionary contains a specific key
2052
    /// </summary>
2053
    /// <param name="key">The key</param>
2054
    /// <returns>True if it does</returns>
2055
    public bool Contains(K key) { return dict.Contains(key); }
2056

    
2057
    /// <summary>
2058
    /// 
2059
    /// </summary>
2060
    /// <param name="keys"></param>
2061
    /// <returns></returns>
2062
    public bool ContainsAll<H>(SCG.IEnumerable<H> keys) where H : K { return dict.ContainsAll(keys); }
2063

    
2064
    /// <summary>
2065
    /// Search for a key in the wrapped dictionary, reporting the value if found
2066
    /// </summary>
2067
    /// <param name="key">The key</param>
2068
    /// <param name="val">On exit: the value if found</param>
2069
    /// <returns>True if found</returns>
2070
    public bool Find(K key, out V val) { return dict.Find(key, out val); }
2071

    
2072
    /// <summary>
2073
    /// Search for a key in the wrapped dictionary, reporting the value if found
2074
    /// </summary>
2075
    /// <param name="key">The key</param>
2076
    /// <param name="val">On exit: the value if found</param>
2077
    /// <returns>True if found</returns>
2078
    public bool Find(ref K key, out V val) { return dict.Find(ref key, out val); }
2079

    
2080

    
2081
    /// <summary>
2082
    /// </summary>
2083
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
2084
    /// <param name="key"></param>
2085
    /// <param name="val"></param>
2086
    /// <returns></returns>
2087
    public bool Update(K key, V val)
2088
    { throw new ReadOnlyCollectionException(); }
2089

    
2090

    
2091
    /// <summary>
2092
    /// </summary>
2093
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
2094
    /// <param name="key"></param>
2095
    /// <param name="val"></param>
2096
    /// <param name="oldval"></param>
2097
    /// <returns></returns>
2098
    public bool Update(K key, V val, out V oldval)
2099
    { throw new ReadOnlyCollectionException(); }
2100

    
2101

    
2102
    /// <summary>
2103
    /// </summary>
2104
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
2105
    /// <param name="key"></param>
2106
    /// <param name="val"></param>
2107
    /// <returns></returns>
2108
    public bool FindOrAdd(K key, ref V val)
2109
    { throw new ReadOnlyCollectionException(); }
2110

    
2111

    
2112
    /// <summary>
2113
    /// </summary>
2114
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
2115
    /// <param name="key"></param>
2116
    /// <param name="val"></param>
2117
    /// <returns></returns>
2118
    public bool UpdateOrAdd(K key, V val)
2119
    { throw new ReadOnlyCollectionException(); }
2120

    
2121
    /// <summary>
2122
    /// </summary>
2123
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
2124
    /// <param name="key"></param>
2125
    /// <param name="val"></param>
2126
    /// <param name="oldval"></param>
2127
    /// <returns></returns>
2128
    public bool UpdateOrAdd(K key, V val, out V oldval)
2129
    { throw new ReadOnlyCollectionException(); }
2130

    
2131

    
2132
    /// <summary>
2133
    /// Check the internal consistency of the wrapped dictionary
2134
    /// </summary>
2135
    /// <returns>True if check passed</returns>
2136
    public bool Check() { return dict.Check(); }
2137

    
2138
    #endregion
2139

    
2140
    /// <summary>
2141
    /// 
2142
    /// </summary>
2143
    /// <returns></returns>
2144
    public virtual object Clone()
2145
    {
2146
      return new GuardedDictionary<K, V>((IDictionary<K, V>)(dict.Clone()));
2147
    }
2148
  }
2149

    
2150

    
2151

    
2152
  /// <summary>
2153
  /// A read-only wrapper for a sorted dictionary.
2154
  ///
2155
  /// <i>Suitable for wrapping a Dictionary. <see cref="T:C5.Dictionary`2"/></i>
2156
  /// </summary>
2157
  public class GuardedSortedDictionary<K, V> : GuardedDictionary<K, V>, ISortedDictionary<K, V>
2158
  {
2159
    #region Fields
2160

    
2161
    ISortedDictionary<K, V> sorteddict;
2162

    
2163
    #endregion
2164

    
2165
    #region Constructor
2166

    
2167
    /// <summary>
2168
    /// Wrap a sorted dictionary in a read-only wrapper
2169
    /// </summary>
2170
    /// <param name="sorteddict">the dictionary</param>
2171
    public GuardedSortedDictionary(ISortedDictionary<K, V> sorteddict)
2172
      : base(sorteddict)
2173
    { this.sorteddict = sorteddict; }
2174

    
2175
    #endregion
2176

    
2177
    #region ISortedDictionary<K,V> Members
2178

    
2179
    /// <summary>
2180
    /// The key comparer used by this dictionary.
2181
    /// </summary>
2182
    /// <value></value>
2183
    public SCG.IComparer<K> Comparer { get { return sorteddict.Comparer; } }
2184

    
2185
    /// <summary>
2186
    /// 
2187
    /// </summary>
2188
    /// <value></value>
2189
    public new ISorted<K> Keys { get { return null; } }
2190

    
2191
    /// <summary>
2192
    /// Find the entry in the dictionary whose key is the
2193
    /// predecessor of the specified key.
2194
    /// </summary>
2195
    /// <param name="key">The key</param>
2196
    /// <param name="res">The predecessor, if any</param>
2197
    /// <returns>True if key has a predecessor</returns>
2198
    public bool TryPredecessor(K key, out KeyValuePair<K, V> res)
2199
    {
2200
      return sorteddict.TryPredecessor(key, out res);
2201
    }
2202

    
2203
    /// <summary>
2204
    /// Find the entry in the dictionary whose key is the
2205
    /// successor of the specified key.
2206
    /// </summary>
2207
    /// <param name="key">The key</param>
2208
    /// <param name="res">The successor, if any</param>
2209
    /// <returns>True if the key has a successor</returns>
2210
    public bool TrySuccessor(K key, out KeyValuePair<K, V> res)
2211
    {
2212
      return sorteddict.TrySuccessor(key, out res);
2213
    }
2214

    
2215
    /// <summary>
2216
    /// Find the entry in the dictionary whose key is the
2217
    /// weak predecessor of the specified key.
2218
    /// </summary>
2219
    /// <param name="key">The key</param>
2220
    /// <param name="res">The predecessor, if any</param>
2221
    /// <returns>True if key has a weak predecessor</returns>
2222
    public bool TryWeakPredecessor(K key, out KeyValuePair<K, V> res)
2223
    {
2224
      return sorteddict.TryWeakPredecessor(key, out res);
2225
    }
2226

    
2227
    /// <summary>
2228
    /// Find the entry in the dictionary whose key is the
2229
    /// weak successor of the specified key.
2230
    /// </summary>
2231
    /// <param name="key">The key</param>
2232
    /// <param name="res">The weak successor, if any</param>
2233
    /// <returns>True if the key has a weak successor</returns>
2234
    public bool TryWeakSuccessor(K key, out KeyValuePair<K, V> res)
2235
    {
2236
      return sorteddict.TryWeakSuccessor(key, out res);
2237
    }
2238

    
2239
    /// <summary>
2240
    /// Get the entry in the wrapped dictionary whose key is the
2241
    /// predecessor of a specified key.
2242
    /// </summary>
2243
    /// <exception cref="NoSuchItemException"> if no such entry exists </exception>    
2244
    /// <param name="key">The key</param>
2245
    /// <returns>The entry</returns>
2246
    public KeyValuePair<K, V> Predecessor(K key)
2247
    { return sorteddict.Predecessor(key); }
2248

    
2249
    /// <summary>
2250
    /// Get the entry in the wrapped dictionary whose key is the
2251
    /// successor of a specified key.
2252
    /// </summary>
2253
    /// <exception cref="NoSuchItemException"> if no such entry exists </exception>    
2254
    /// <param name="key">The key</param>
2255
    /// <returns>The entry</returns>
2256
    public KeyValuePair<K, V> Successor(K key)
2257
    { return sorteddict.Successor(key); }
2258

    
2259

    
2260
    /// <summary>
2261
    /// Get the entry in the wrapped dictionary whose key is the
2262
    /// weak predecessor of a specified key.
2263
    /// </summary>
2264
    /// <exception cref="NoSuchItemException"> if no such entry exists </exception>    
2265
    /// <param name="key">The key</param>
2266
    /// <returns>The entry</returns>
2267
    public KeyValuePair<K, V> WeakPredecessor(K key)
2268
    { return sorteddict.WeakPredecessor(key); }
2269

    
2270

    
2271
    /// <summary>
2272
    /// Get the entry in the wrapped dictionary whose key is the
2273
    /// weak successor of a specified key.
2274
    /// </summary>
2275
    /// <exception cref="NoSuchItemException"> if no such entry exists </exception>    
2276
    /// <param name="key">The key</param>
2277
    /// <returns>The entry</returns>
2278
    public KeyValuePair<K, V> WeakSuccessor(K key)
2279
    { return sorteddict.WeakSuccessor(key); }
2280

    
2281
    /// <summary>
2282
    /// 
2283
    /// </summary>
2284
    /// <returns></returns>
2285
    public KeyValuePair<K, V> FindMin()
2286
    {
2287
      return sorteddict.FindMin();
2288
    }
2289

    
2290
    /// <summary>
2291
    /// 
2292
    /// </summary>
2293
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
2294
    /// <returns></returns>
2295
    public KeyValuePair<K, V> DeleteMin()
2296
    { throw new ReadOnlyCollectionException(); }
2297

    
2298
    /// <summary>
2299
    /// 
2300
    /// </summary>
2301
    /// <returns></returns>
2302
    public KeyValuePair<K, V> FindMax()
2303
    {
2304
      return sorteddict.FindMax();
2305
    }
2306

    
2307
    /// <summary>
2308
    /// 
2309
    /// </summary>
2310
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
2311
    /// <returns></returns>
2312
    public KeyValuePair<K, V> DeleteMax()
2313
    { throw new ReadOnlyCollectionException(); }
2314

    
2315
    /// <summary>
2316
    /// 
2317
    /// </summary>
2318
    /// <param name="c"></param>
2319
    /// <param name="lowEntry"></param>
2320
    /// <param name="lowIsValid"></param>
2321
    /// <param name="highEntry"></param>
2322
    /// <param name="highIsValid"></param>
2323
    /// <returns></returns>
2324
    public bool Cut(IComparable<K> c, out KeyValuePair<K, V> lowEntry, out bool lowIsValid, out KeyValuePair<K, V> highEntry, out bool highIsValid)
2325
    {
2326
      return sorteddict.Cut(c, out lowEntry, out lowIsValid, out highEntry, out highIsValid); ;
2327
    }
2328

    
2329
    /// <summary>
2330
    /// 
2331
    /// </summary>
2332
    /// <param name="bot"></param>
2333
    /// <returns></returns>
2334
    public IDirectedEnumerable<KeyValuePair<K, V>> RangeFrom(K bot)
2335
    {
2336
      return new GuardedDirectedEnumerable<KeyValuePair<K, V>>(sorteddict.RangeFrom(bot));
2337
    }
2338

    
2339
    /// <summary>
2340
    /// 
2341
    /// </summary>
2342
    /// <param name="bot"></param>
2343
    /// <param name="top"></param>
2344
    /// <returns></returns>
2345
    public IDirectedEnumerable<KeyValuePair<K, V>> RangeFromTo(K bot, K top)
2346
    {
2347
      return new GuardedDirectedEnumerable<KeyValuePair<K, V>>(sorteddict.RangeFromTo(bot, top));
2348
    }
2349

    
2350
    /// <summary>
2351
    /// 
2352
    /// </summary>
2353
    /// <param name="top"></param>
2354
    /// <returns></returns>
2355
    public IDirectedEnumerable<KeyValuePair<K, V>> RangeTo(K top)
2356
    {
2357
      return new GuardedDirectedEnumerable<KeyValuePair<K, V>>(sorteddict.RangeTo(top));
2358
    }
2359

    
2360
    /// <summary>
2361
    /// 
2362
    /// </summary>
2363
    /// <returns></returns>
2364
    public IDirectedCollectionValue<KeyValuePair<K, V>> RangeAll()
2365
    {
2366
      return new GuardedDirectedCollectionValue<KeyValuePair<K, V>>(sorteddict.RangeAll());
2367
    }
2368

    
2369
    /// <summary>
2370
    /// 
2371
    /// </summary>
2372
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
2373
    /// <param name="items"></param>
2374
    public void AddSorted(System.Collections.Generic.IEnumerable<KeyValuePair<K, V>> items)
2375
    { throw new ReadOnlyCollectionException(); }
2376

    
2377
    /// <summary>
2378
    /// 
2379
    /// </summary>
2380
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
2381
    /// <param name="low"></param>
2382
    public void RemoveRangeFrom(K low)
2383
    { throw new ReadOnlyCollectionException(); }
2384

    
2385
    /// <summary>
2386
    /// 
2387
    /// </summary>
2388
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
2389
    /// <param name="low"></param>
2390
    /// <param name="hi"></param>
2391
    public void RemoveRangeFromTo(K low, K hi)
2392
    { throw new ReadOnlyCollectionException(); }
2393

    
2394
    /// <summary>
2395
    /// 
2396
    /// </summary>
2397
    /// <exception cref="ReadOnlyCollectionException"> since this is a read-only wrappper</exception>
2398
    /// <param name="hi"></param>
2399
    public void RemoveRangeTo(K hi)
2400
    { throw new ReadOnlyCollectionException(); }
2401

    
2402
    #endregion
2403
  }
2404

    
2405
}