Project

General

Profile

root / branches / compiler / cSharp / ooasCompiler / src / libs / c5 / C5 / trees / RedBlackTreeBag.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
#define MAINTAIN_SIZE
23
#define BAG
24
#define NCP
25

    
26
#if BAG
27
#if !MAINTAIN_SIZE
28
#error  BAG defined without MAINTAIN_SIZE!
29
#endif
30
#endif
31

    
32

    
33
using System;
34
using SCG = System.Collections.Generic;
35

    
36
// NOTE NOTE NOTE NOTE
37
// This source file is used to produce both TreeBag<T> and TreeBag<T>
38
// It should be copied to a file called TreeBag.cs in which all code mentions of 
39
// TreeBag is changed to TreeBag and the preprocessor symbol BAG is defined.
40
// NOTE: there may be problems with documentation comments.
41

    
42
namespace C5
43
{
44
#if BAG
45
  /// <summary>
46
  /// An implementation of Red-Black trees as an indexed, sorted collection with bag semantics,
47
  /// cf. <a href="litterature.htm#CLRS">CLRS</a>. (<see cref="T:C5.TreeBag`1"/> for an 
48
  /// implementation with set semantics).
49
  /// <br/>
50
  /// The comparer (sorting order) may be either natural, because the item type is comparable 
51
  /// (generic: <see cref="T:C5.IComparable`1"/> or non-generic: System.IComparable) or it can
52
  /// be external and supplied by the user in the constructor.
53
  /// <br/>
54
  /// Each distinct item is only kept in one place in the tree - together with the number
55
  /// of times it is a member of the bag. Thus, if two items that are equal according
56
  /// </summary>
57
#else
58
  /// <summary>
59
  /// An implementation of Red-Black trees as an indexed, sorted collection with set semantics,
60
  /// cf. <a href="litterature.htm#CLRS">CLRS</a>. <see cref="T:C5.TreeBag`1"/> for a version 
61
  /// with bag semantics. <see cref="T:C5.TreeDictionary`2"/> for a sorted dictionary 
62
  /// based on this tree implementation.
63
  /// <i>
64
  /// The comparer (sorting order) may be either natural, because the item type is comparable 
65
  /// (generic: <see cref="T:C5.IComparable`1"/> or non-generic: System.IComparable) or it can
66
  /// be external and supplied by the user in the constructor.</i>
67
  ///
68
  /// <i>TODO: describe performance here</i>
69
  /// <i>TODO: discuss persistence and its useful usage modes. Warn about the space
70
  /// leak possible with other usage modes.</i>
71
  /// </summary>
72
#endif
73
  [Serializable]
74
  public class TreeBag<T> : SequencedBase<T>, IIndexedSorted<T>, IPersistentSorted<T>
75
  {
76
    #region Fields
77

    
78
    SCG.IComparer<T> comparer;
79

    
80
    Node root;
81

    
82
    //TODO: wonder if we should remove that
83
    int blackdepth = 0;
84

    
85
    //We double these stacks for the iterative add and remove on demand
86
    //TODO: refactor dirs[] into bool fields on Node (?)
87
    private int[] dirs = new int[2];
88

    
89
    private Node[] path = new Node[2];
90
#if NCP
91
    //TODO: refactor into separate class
92
    bool isSnapShot = false;
93

    
94
    int generation;
95

    
96
    bool isValid = true;
97

    
98
    SnapRef snapList;
99
#endif
100
    #endregion
101

    
102
    #region Events
103

    
104
    /// <summary>
105
    /// 
106
    /// </summary>
107
    /// <value></value>
108
    public override EventTypeEnum ListenableEvents { get { return EventTypeEnum.Basic; } }
109

    
110
    #endregion
111
    #region Util
112

    
113
    /// <summary>
114
    /// Fetch the left child of n taking node-copying persistence into
115
    /// account if relevant. 
116
    /// </summary>
117
    /// <param name="n"></param>
118
    /// <returns></returns>
119
    private Node left(Node n)
120
    {
121
#if NCP
122
      if (isSnapShot)
123
      {
124
#if SEPARATE_EXTRA
125
				Node.Extra e = n.extra;
126

    
127
				if (e != null && e.lastgeneration >= treegen && e.leftnode)
128
					return e.oldref;
129
#else
130
        if (n.lastgeneration >= generation && n.leftnode)
131
          return n.oldref;
132
#endif
133
      }
134
#endif
135
      return n.left;
136
    }
137

    
138

    
139
    private Node right(Node n)
140
    {
141
#if NCP
142
      if (isSnapShot)
143
      {
144
#if SEPARATE_EXTRA
145
				Node.Extra e = n.extra;
146

    
147
				if (e != null && e.lastgeneration >= treegen && !e.leftnode)
148
					return e.oldref;
149
#else
150
        if (n.lastgeneration >= generation && !n.leftnode)
151
          return n.oldref;
152
#endif
153
      }
154
#endif
155
      return n.right;
156
    }
157

    
158

    
159
    //This method should be called by methods that use the internal 
160
    //traversal stack, unless certain that there is room enough
161
    private void stackcheck()
162
    {
163
      while (dirs.Length < 2 * blackdepth)
164
      {
165
        dirs = new int[2 * dirs.Length];
166
        path = new Node[2 * dirs.Length];
167
      }
168
    }
169

    
170
    #endregion
171

    
172
    #region Node nested class
173

    
174

    
175
    /// <summary>
176
    /// The type of node in a Red-Black binary tree
177
    /// </summary>
178
    [Serializable]
179
    class Node
180
    {
181
      public bool red = true;
182

    
183
      public T item;
184

    
185
      public Node left;
186

    
187
      public Node right;
188

    
189
#if MAINTAIN_SIZE
190
      public int size = 1;
191
#endif
192

    
193
#if BAG
194
      public int items = 1;
195
#endif
196

    
197
#if NCP
198
      //TODO: move everything into (separate) Extra
199
      public int generation;
200
#if SEPARATE_EXTRA
201
			internal class Extra
202
			{
203
				public int lastgeneration;
204

    
205
				public Node oldref;
206

    
207
				public bool leftnode;
208

    
209
				//public Node next;
210
			}
211

    
212
			public Extra extra;
213

    
214
#else
215
      public int lastgeneration = -1;
216

    
217
      public Node oldref;
218

    
219
      public bool leftnode;
220
#endif
221

    
222
      /// <summary>
223
      /// Update a child pointer
224
      /// </summary>
225
      /// <param name="cursor"></param>
226
      /// <param name="leftnode"></param>
227
      /// <param name="child"></param>
228
      /// <param name="maxsnapid"></param>
229
      /// <param name="generation"></param>
230
      /// <returns>True if node was *copied*</returns>
231
      internal static bool update(ref Node cursor, bool leftnode, Node child, int maxsnapid, int generation)
232
      {
233
        Node oldref = leftnode ? cursor.left : cursor.right;
234

    
235
        if (child == oldref)
236
          return false;
237

    
238
        bool retval = false;
239

    
240
        if (cursor.generation <= maxsnapid)
241
        {
242
#if SEPARATE_EXTRA
243
					if (cursor.extra == null)
244
					{
245
						Extra extra = cursor.extra = new Extra();	
246

    
247
						extra.leftnode = leftnode;
248
						extra.lastgeneration = maxsnapid;
249
						extra.oldref = oldref;
250
					}
251
					else if (cursor.extra.leftnode != leftnode || cursor.extra.lastgeneration < maxsnapid)
252
#else
253
          if (cursor.lastgeneration == -1)
254
          {
255
            cursor.leftnode = leftnode;
256
            cursor.lastgeneration = maxsnapid;
257
            cursor.oldref = oldref;
258
          }
259
          else if (cursor.leftnode != leftnode || cursor.lastgeneration < maxsnapid)
260
#endif
261
          {
262
            CopyNode(ref cursor, maxsnapid, generation);
263
            retval = true;
264
          }
265
        }
266

    
267
        if (leftnode)
268
          cursor.left = child;
269
        else
270
          cursor.right = child;
271

    
272
        return retval;
273
      }
274

    
275

    
276
      //If cursor.extra.lastgeneration==maxsnapid, the extra pointer will 
277
      //always be used in the old copy of cursor. Therefore, after 
278
      //making the clone, we should update the old copy by restoring
279
      //the child pointer and setting extra to null.
280
      //OTOH then we cannot clean up unused Extra objects unless we link
281
      //them together in a doubly linked list.
282
      public static bool CopyNode(ref Node cursor, int maxsnapid, int generation)
283
      {
284
        if (cursor.generation <= maxsnapid)
285
        {
286
          cursor = (Node)(cursor.MemberwiseClone());
287
          cursor.generation = generation;
288
#if SEPARATE_EXTRA
289
					cursor.extra = null;
290
#else
291
          cursor.lastgeneration = -1;
292
#endif
293
          return true;
294
        }
295
        else
296
          return false;
297
      }
298

    
299
#endif
300
    }
301

    
302
    #endregion
303

    
304
    #region Constructors
305

    
306
    /// <summary>
307
    /// Create a red-black tree collection with natural comparer and item equalityComparer.
308
    /// We assume that if <code>T</code> is comparable, its default equalityComparer 
309
    /// will be compatible with the comparer.
310
    /// </summary>
311
    /// <exception cref="NotComparableException">If <code>T</code> is not comparable.
312
    /// </exception>
313
    public TreeBag() : this(Comparer<T>.Default, EqualityComparer<T>.Default) { }
314

    
315

    
316
    /// <summary>
317
    /// Create a red-black tree collection with an external comparer. 
318
    /// <para>The itemequalityComparer will be a compatible 
319
    /// <see cref="T:C5.ComparerZeroHashCodeEqualityComparer`1"/> since the 
320
    /// default equalityComparer for T (<see cref="P:C5.EqualityComparer`1.Default"/>)
321
    /// is unlikely to be compatible with the external comparer. This makes the
322
    /// tree inadequate for use as item in a collection of unsequenced or sequenced sets or bags
323
    /// (<see cref="T:C5.ICollection`1"/> and <see cref="T:C5.ISequenced`1"/>)
324
    /// </para>
325
    /// </summary>
326
    /// <param name="comparer">The external comparer</param>
327
    public TreeBag(SCG.IComparer<T> comparer) : this(comparer, new ComparerZeroHashCodeEqualityComparer<T>(comparer)) { }
328

    
329
    /// <summary>
330
    /// Create a red-black tree collection with an external comparer and an external
331
    /// item equalityComparer, assumed consistent.
332
    /// </summary>
333
    /// <param name="comparer">The external comparer</param>
334
    /// <param name="equalityComparer">The external item equalityComparer</param>
335
    public TreeBag(SCG.IComparer<T> comparer, SCG.IEqualityComparer<T> equalityComparer)
336
      : base(equalityComparer)
337
    {
338
      if (comparer == null)
339
        throw new NullReferenceException("Item comparer cannot be null");
340
      this.comparer = comparer;
341
    }
342

    
343
    #endregion
344

    
345
    #region TreeBag.Enumerator nested class
346

    
347
    /// <summary>
348
    /// An enumerator for a red-black tree collection. Based on an explicit stack
349
    /// of subtrees waiting to be enumerated. Currently only used for the tree set 
350
    /// enumerators (tree bag enumerators use an iterator block based enumerator).
351
    /// </summary>
352
    internal class Enumerator : SCG.IEnumerator<T>
353
    {
354
      #region Private Fields
355
      TreeBag<T> tree;
356

    
357
      bool valid = false;
358

    
359
      int stamp;
360

    
361
      T current;
362

    
363
      Node cursor;
364

    
365
      Node[] path; // stack of nodes
366

    
367
      int level = 0;
368
      #endregion
369
      /// <summary>
370
      /// Create a tree enumerator
371
      /// </summary>
372
      /// <param name="tree">The red-black tree to enumerate</param>
373
      public Enumerator(TreeBag<T> tree)
374
      {
375
        this.tree = tree;
376
        stamp = tree.stamp;
377
        path = new Node[2 * tree.blackdepth];
378
        cursor = new Node();
379
        cursor.right = tree.root;
380
      }
381

    
382

    
383
      /// <summary>
384
      /// Undefined if enumerator is not valid (MoveNext hash been called returning true)
385
      /// </summary>
386
      /// <value>The current item of the enumerator.</value>
387
      [Tested]
388
      public T Current
389
      {
390
        [Tested]
391
        get
392
        {
393
          if (valid)
394
            return current;
395
          else
396
            throw new InvalidOperationException();
397
        }
398
      }
399

    
400

    
401
      //Maintain a stack of nodes that are roots of
402
      //subtrees not completely exported yet. Invariant:
403
      //The stack nodes together with their right subtrees
404
      //consists of exactly the items we have not passed
405
      //yet (the top of the stack holds current item).
406
      /// <summary>
407
      /// Move enumerator to next item in tree, or the first item if
408
      /// this is the first call to MoveNext. 
409
      /// <exception cref="CollectionModifiedException"/> if underlying tree was modified.
410
      /// </summary>
411
      /// <returns>True if enumerator is valid now</returns>
412
      [Tested]
413
      public bool MoveNext()
414
      {
415
        tree.modifycheck(stamp);
416
        if (cursor.right != null)
417
        {
418
          path[level] = cursor = cursor.right;
419
          while (cursor.left != null)
420
            path[++level] = cursor = cursor.left;
421
        }
422
        else if (level == 0)
423
          return valid = false;
424
        else
425
          cursor = path[--level];
426

    
427
        current = cursor.item;
428
        return valid = true;
429
      }
430

    
431

    
432
      #region IDisposable Members for Enumerator
433

    
434
      bool disposed;
435

    
436

    
437
      /// <summary>
438
      /// Call Dispose(true) and then suppress finalization of this enumerator.
439
      /// </summary>
440
      [Tested]
441
      public void Dispose()
442
      {
443
        Dispose(true);
444
        GC.SuppressFinalize(this);
445
      }
446

    
447

    
448
      /// <summary>
449
      /// Remove the internal data (notably the stack array).
450
      /// </summary>
451
      /// <param name="disposing">True if called from Dispose(),
452
      /// false if called from the finalizer</param>
453
      protected virtual void Dispose(bool disposing)
454
      {
455
        if (!disposed)
456
        {
457
          if (disposing)
458
          {
459
          }
460

    
461
          current = default(T);
462
          cursor = null;
463
          path = null;
464
          disposed = true;
465
        }
466
      }
467

    
468

    
469
      /// <summary>
470
      /// Finalizer for enumerator
471
      /// </summary>
472
      ~Enumerator()
473
      {
474
        Dispose(false);
475
      }
476
      #endregion
477

    
478

    
479
      #region IEnumerator Members
480

    
481
      object System.Collections.IEnumerator.Current
482
      {
483
        get { return Current; }
484
      }
485

    
486
      bool System.Collections.IEnumerator.MoveNext()
487
      {
488
        return MoveNext();
489
      }
490

    
491
      void System.Collections.IEnumerator.Reset()
492
      {
493
        throw new Exception("The method or operation is not implemented.");
494
      }
495

    
496
      #endregion
497
    }
498
#if NCP
499
    /// <summary>
500
    /// An enumerator for a snapshot of a node copy persistent red-black tree
501
    /// collection.
502
    /// </summary>
503
    internal class SnapEnumerator : SCG.IEnumerator<T>
504
    {
505
      #region Private Fields
506
      TreeBag<T> tree;
507

    
508
      bool valid = false;
509

    
510
      int stamp;
511
#if BAG
512
      int togo;
513
#endif
514

    
515
      T current;
516

    
517
      Node cursor;
518

    
519
      Node[] path; // stack of nodes
520

    
521
      int level;
522
      #endregion
523

    
524
      /// <summary>
525
      /// Creta an enumerator for a snapshot of a node copy persistent red-black tree
526
      /// collection
527
      /// </summary>
528
      /// <param name="tree">The snapshot</param>
529
      public SnapEnumerator(TreeBag<T> tree)
530
      {
531
        this.tree = tree;
532
        stamp = tree.stamp;
533
        path = new Node[2 * tree.blackdepth];
534
        cursor = new Node();
535
        cursor.right = tree.root;
536
      }
537

    
538

    
539
      #region SCG.IEnumerator<T> Members
540

    
541
      /// <summary>
542
      /// Move enumerator to next item in tree, or the first item if
543
      /// this is the first call to MoveNext. 
544
      /// <exception cref="CollectionModifiedException"/> if underlying tree was modified.
545
      /// </summary>
546
      /// <returns>True if enumerator is valid now</returns>
547
      [Tested]
548
      public bool MoveNext()
549
      {
550
        tree.modifycheck(stamp);//???
551

    
552
#if BAG
553
        if (--togo > 0)
554
          return true;
555
#endif
556
        Node next = tree.right(cursor);
557

    
558
        if (next != null)
559
        {
560
          path[level] = cursor = next;
561
          next = tree.left(cursor);
562
          while (next != null)
563
          {
564
            path[++level] = cursor = next;
565
            next = tree.left(cursor);
566
          }
567
        }
568
        else if (level == 0)
569
          return valid = false;
570
        else
571
          cursor = path[--level];
572

    
573
#if BAG
574
        togo = cursor.items;
575
#endif
576
        current = cursor.item;
577
        return valid = true;
578
      }
579

    
580

    
581
      /// <summary>
582
      /// Undefined if enumerator is not valid (MoveNext hash been called returning true)
583
      /// </summary>
584
      /// <value>The current value of the enumerator.</value>
585
      [Tested]
586
      public T Current
587
      {
588
        [Tested]
589
        get
590
        {
591
          if (valid)
592
            return current;
593
          else
594
            throw new InvalidOperationException();
595
        }
596
      }
597

    
598
      #endregion
599

    
600
      #region IDisposable Members
601

    
602
      [Tested]
603
      void System.IDisposable.Dispose()
604
      {
605
        tree = null;
606
        valid = false;
607
        current = default(T);
608
        cursor = null;
609
        path = null;
610
      }
611

    
612
      #endregion
613

    
614
      #region IEnumerator Members
615

    
616
      object System.Collections.IEnumerator.Current
617
      {
618
        get { return Current; }
619
      }
620

    
621
      bool System.Collections.IEnumerator.MoveNext()
622
      {
623
        return MoveNext();
624
      }
625

    
626
      void System.Collections.IEnumerator.Reset()
627
      {
628
        throw new Exception("The method or operation is not implemented.");
629
      }
630

    
631
      #endregion
632
    }
633
#endif
634
    #endregion
635

    
636
    #region IEnumerable<T> Members
637

    
638
    private SCG.IEnumerator<T> getEnumerator(Node node, int origstamp)
639
    {
640
      if (node == null)
641
        yield break;
642

    
643
      if (node.left != null)
644
      {
645
        SCG.IEnumerator<T> child = getEnumerator(node.left, origstamp);
646

    
647
        while (child.MoveNext())
648
        {
649
          modifycheck(origstamp);
650
          yield return child.Current;
651
        }
652
      }
653
#if BAG
654
      int togo = node.items;
655
      while (togo-- > 0)
656
      {
657
        modifycheck(origstamp);
658
        yield return node.item;
659
      }
660
#else
661
      modifycheck(origstamp);
662
      yield return node.item;
663
#endif
664
      if (node.right != null)
665
      {
666
        SCG.IEnumerator<T> child = getEnumerator(node.right, origstamp);
667

    
668
        while (child.MoveNext())
669
        {
670
          modifycheck(origstamp);
671
          yield return child.Current;
672
        }
673
      }
674
    }
675

    
676
    /// <summary>
677
    /// 
678
    /// </summary>
679
    /// <exception cref="NoSuchItemException">If tree is empty</exception>
680
    /// <returns></returns>
681
    [Tested]
682
    public override T Choose()
683
    {
684
      if (!isValid)
685
        throw new ViewDisposedException("Snapshot has been disposed");
686

    
687
      if (size == 0)
688
        throw new NoSuchItemException();
689
      return root.item;
690
    }
691

    
692

    
693
    /// <summary>
694
    /// Create an enumerator for this tree
695
    /// </summary>
696
    /// <returns>The enumerator</returns>
697
    [Tested]
698
    public override SCG.IEnumerator<T> GetEnumerator()
699
    {
700
      if (!isValid)
701
        throw new ViewDisposedException("Snapshot has been disposed");
702
#if NCP
703
      if (isSnapShot)
704
        return new SnapEnumerator(this);
705
#endif
706
#if BAG
707
      return getEnumerator(root, stamp);
708
#else
709
      return new Enumerator(this);
710
#endif
711
    }
712

    
713
    #endregion
714

    
715
    #region ISink<T> Members
716

    
717
    /// <summary>
718
    /// Add item to tree. If already there, return the found item in the second argument.
719
    /// </summary>
720
    /// <param name="item">Item to add</param>
721
    /// <param name="founditem">item found</param>
722
    /// <param name="update">whether item in node should be updated</param>
723
    /// <param name="wasfound">true if found in bag, false if not found or tre is a set</param>
724
    /// <returns>True if item was added</returns>
725
    bool addIterative(T item, ref T founditem, bool update, out bool wasfound)
726
    {
727
      wasfound = false;
728
      if (root == null)
729
      {
730
        root = new Node();
731
        root.red = false;
732
        blackdepth = 1;
733
        root.item = item;
734
#if NCP
735
        root.generation = generation;
736
#endif
737
        return true;
738
      }
739

    
740
      stackcheck();
741

    
742
      int level = 0;
743
      Node cursor = root;
744

    
745
      while (true)
746
      {
747
        int comp = comparer.Compare(cursor.item, item);
748

    
749
        if (comp == 0)
750
        {
751
          founditem = cursor.item;
752
#if BAG
753
          wasfound = true;
754
          bool nodeWasUpdated = true;
755
#if NCP
756
          Node.CopyNode(ref cursor, maxsnapid, generation);
757
#endif
758
          if (update)
759
            cursor.item = item;
760
          else
761
          {
762
            cursor.items++;
763
            cursor.size++;
764
          }
765
#else
766
          bool nodeWasUpdated = update;
767
          if (update)
768
          {
769
#if NCP
770
            Node.CopyNode(ref cursor, maxsnapid, generation);
771
#endif
772
            cursor.item = item;
773
          }
774
#endif
775

    
776
          while (level-- > 0)
777
          {
778
            if (nodeWasUpdated)
779
            {
780
              Node kid = cursor;
781

    
782
              cursor = path[level];
783
#if NCP
784
              Node.update(ref cursor, dirs[level] > 0, kid, maxsnapid, generation);
785
#endif
786
#if BAG
787
              if (!update)
788
                cursor.size++;
789
#endif
790
            }
791

    
792
            path[level] = null;
793
          }
794
#if BAG
795
          return !update;
796
#else
797
          if (update)
798
            root = cursor;
799

    
800
          return false;
801
#endif
802
        }
803

    
804
        //else
805
        Node child = comp > 0 ? cursor.left : cursor.right;
806

    
807
        if (child == null)
808
        {
809
          child = new Node();
810
          child.item = item;
811
#if NCP
812
          child.generation = generation;
813
          Node.update(ref cursor, comp > 0, child, maxsnapid, generation);
814
#else
815
					if (comp > 0) { cursor.left = child; }
816
					else { cursor.right = child; }
817
#endif
818
#if MAINTAIN_SIZE
819
          cursor.size++;
820
#endif
821
          dirs[level] = comp;
822
          break;
823
        }
824
        else
825
        {
826
          dirs[level] = comp;
827
          path[level++] = cursor;
828
          cursor = child;
829
        }
830
      }
831

    
832
      //We have just added the red node child to "cursor"
833
      while (cursor.red)
834
      {
835
        //take one step up:
836
        Node child = cursor;
837

    
838
        cursor = path[--level];
839
        path[level] = null;
840
#if NCP
841
        Node.update(ref cursor, dirs[level] > 0, child, maxsnapid, generation);
842
#endif
843
#if MAINTAIN_SIZE
844
        cursor.size++;
845
#endif
846
        int comp = dirs[level];
847
        Node childsibling = comp > 0 ? cursor.right : cursor.left;
848

    
849
        if (childsibling != null && childsibling.red)
850
        {
851
          //Promote
852
          child.red = false;
853
#if NCP
854
          Node.update(ref cursor, comp < 0, childsibling, maxsnapid, generation);
855
#endif
856
          childsibling.red = false;
857

    
858
          //color cursor red & take one step up the tree unless at root
859
          if (level == 0)
860
          {
861
            root = cursor;
862
            blackdepth++;
863
            return true;
864
          }
865
          else
866
          {
867
            cursor.red = true;
868
#if NCP
869
            child = cursor;
870
            cursor = path[--level];
871
            Node.update(ref cursor, dirs[level] > 0, child, maxsnapid, generation);
872
#endif
873
            path[level] = null;
874
#if MAINTAIN_SIZE
875
            cursor.size++;
876
#endif
877
          }
878
        }
879
        else
880
        {
881
          //ROTATE!!!
882
          int childcomp = dirs[level + 1];
883

    
884
          cursor.red = true;
885
          if (comp > 0)
886
          {
887
            if (childcomp > 0)
888
            {//zagzag
889
#if NCP
890
              Node.update(ref cursor, true, child.right, maxsnapid, generation);
891
              Node.update(ref child, false, cursor, maxsnapid, generation);
892
#else
893
							cursor.left = child.right;
894
							child.right = cursor;
895
#endif
896
              cursor = child;
897
            }
898
            else
899
            {//zagzig
900
              Node badgrandchild = child.right;
901
#if NCP
902
              Node.update(ref cursor, true, badgrandchild.right, maxsnapid, generation);
903
              Node.update(ref child, false, badgrandchild.left, maxsnapid, generation);
904
              Node.CopyNode(ref badgrandchild, maxsnapid, generation);
905
#else
906
							cursor.left = badgrandchild.right;
907
							child.right = badgrandchild.left;
908
#endif
909
              badgrandchild.left = child;
910
              badgrandchild.right = cursor;
911
              cursor = badgrandchild;
912
            }
913
          }
914
          else
915
          {//comp < 0
916
            if (childcomp < 0)
917
            {//zigzig
918
#if NCP
919
              Node.update(ref cursor, false, child.left, maxsnapid, generation);
920
              Node.update(ref child, true, cursor, maxsnapid, generation);
921
#else
922
							cursor.right = child.left;
923
							child.left = cursor;
924
#endif
925
              cursor = child;
926
            }
927
            else
928
            {//zigzag
929
              Node badgrandchild = child.left;
930
#if NCP
931
              Node.update(ref cursor, false, badgrandchild.left, maxsnapid, generation);
932
              Node.update(ref child, true, badgrandchild.right, maxsnapid, generation);
933
              Node.CopyNode(ref badgrandchild, maxsnapid, generation);
934
#else
935
							cursor.right = badgrandchild.left;
936
							child.left = badgrandchild.right;
937
#endif
938
              badgrandchild.right = child;
939
              badgrandchild.left = cursor;
940
              cursor = badgrandchild;
941
            }
942
          }
943

    
944
          cursor.red = false;
945

    
946
#if MAINTAIN_SIZE
947
          Node n;
948

    
949
#if BAG
950
          n = cursor.right;
951
          cursor.size = n.size = (n.left == null ? 0 : n.left.size) + (n.right == null ? 0 : n.right.size) + n.items;
952
          n = cursor.left;
953
          n.size = (n.left == null ? 0 : n.left.size) + (n.right == null ? 0 : n.right.size) + n.items;
954
          cursor.size += n.size + cursor.items;
955
#else
956
          n = cursor.right;
957
          cursor.size = n.size = (n.left == null ? 0 : n.left.size) + (n.right == null ? 0 : n.right.size) + 1;
958
          n = cursor.left;
959
          n.size = (n.left == null ? 0 : n.left.size) + (n.right == null ? 0 : n.right.size) + 1;
960
          cursor.size += n.size + 1;
961
#endif
962
#endif
963
          if (level == 0)
964
          {
965
            root = cursor;
966
            return true;
967
          }
968
          else
969
          {
970
            child = cursor;
971
            cursor = path[--level];
972
            path[level] = null;
973
#if NCP
974
            Node.update(ref cursor, dirs[level] > 0, child, maxsnapid, generation);
975
#else
976
						if (dirs[level] > 0)
977
							cursor.left = child;
978
						else
979
							cursor.right = child;
980
#endif
981
#if MAINTAIN_SIZE
982
            cursor.size++;
983
#endif
984
            break;
985
          }
986
        }
987
      }
988
#if NCP
989
      bool stillmore = true;
990
#endif
991
      while (level > 0)
992
      {
993
        Node child = cursor;
994

    
995
        cursor = path[--level];
996
        path[level] = null;
997
#if NCP
998
        if (stillmore)
999
          stillmore = Node.update(ref cursor, dirs[level] > 0, child, maxsnapid, generation);
1000
#endif
1001
#if MAINTAIN_SIZE
1002
        cursor.size++;
1003
#endif
1004
      }
1005

    
1006
      root = cursor;
1007
      return true;
1008
    }
1009

    
1010

    
1011
    /// <summary>
1012
    /// Add an item to this collection if possible. If this collection has set
1013
    /// semantics, the item will be added if not already in the collection. If
1014
    /// bag semantics, the item will always be added.
1015
    /// </summary>
1016
    /// <param name="item">The item to add.</param>
1017
    /// <returns>True if item was added.</returns>
1018
    [Tested]
1019
    public bool Add(T item)
1020
    {
1021
      if (!isValid)
1022
        throw new ViewDisposedException("Snapshot has been disposed");
1023
      updatecheck();
1024

    
1025
      //Note: blackdepth of the tree is set inside addIterative
1026
      T jtem = default(T);
1027
      if (!add(item, ref jtem))
1028
        return false;
1029
      if (ActiveEvents != 0)
1030
        raiseForAdd(jtem);
1031
      return true;
1032
    }
1033

    
1034
    /// <summary>
1035
    /// Add an item to this collection if possible. If this collection has set
1036
    /// semantics, the item will be added if not already in the collection. If
1037
    /// bag semantics, the item will always be added.
1038
    /// </summary>
1039
    /// <param name="item">The item to add.</param>
1040
    [Tested]
1041
    void SCG.ICollection<T>.Add(T item)
1042
    {
1043
        Add(item);
1044
    }
1045

    
1046
    private bool add(T item, ref T j)
1047
    {
1048
      bool wasFound;
1049

    
1050
      if (addIterative(item, ref j, false, out wasFound))
1051
      {
1052
        size++;
1053
        if (!wasFound)
1054
          j = item;
1055
        return true;
1056
      }
1057
      else
1058
        return false;
1059
    }
1060

    
1061
    /// <summary>
1062
    /// Add the elements from another collection with a more specialized item type 
1063
    /// to this collection. If this
1064
    /// collection has set semantics, only items not already in the collection
1065
    /// will be added.
1066
    /// </summary>
1067
    /// <typeparam name="U">The type of items to add</typeparam>
1068
    /// <param name="items">The items to add</param>
1069
    [Tested]
1070
    public void AddAll<U>(SCG.IEnumerable<U> items) where U : T
1071
    {
1072
      if (!isValid)
1073
        throw new ViewDisposedException("Snapshot has been disposed");
1074
      updatecheck();
1075

    
1076
      int c = 0;
1077
      T j = default(T);
1078
      bool tmp;
1079

    
1080
      bool raiseAdded = (ActiveEvents & EventTypeEnum.Added) != 0;
1081
      CircularQueue<T> wasAdded = raiseAdded ? new CircularQueue<T>() : null;
1082

    
1083
      foreach (T i in items)
1084
        if (addIterative(i, ref j, false, out tmp))
1085
        {
1086
          c++;
1087
          if (raiseAdded)
1088
            wasAdded.Enqueue(tmp ? j : i);
1089
        }
1090
      if (c == 0)
1091
        return;
1092

    
1093
      size += c;
1094
      //TODO: implement a RaiseForAddAll() method
1095
      if (raiseAdded)
1096
        foreach (T item in wasAdded)
1097
          raiseItemsAdded(item, 1);
1098
      if (((ActiveEvents & EventTypeEnum.Changed) != 0))
1099
        raiseCollectionChanged();
1100
    }
1101

    
1102

    
1103
    /// <summary>
1104
    /// Add all the items from another collection with an enumeration order that 
1105
    /// is increasing in the items. <para>The idea is that the implementation may use
1106
    /// a faster algorithm to merge the two collections.</para>
1107
    /// <exception cref="ArgumentException"/> if the enumerated items turns out
1108
    /// not to be in increasing order.
1109
    /// </summary>
1110
    /// <param name="items">The collection to add.</param>
1111
    /// <typeparam name="U"></typeparam>
1112
    [Tested]
1113
    public void AddSorted<U>(SCG.IEnumerable<U> items) where U : T
1114
    {
1115
      if (size > 0)
1116
        AddAll(items);
1117
      else
1118
      {
1119
        if (!isValid)
1120
          throw new ViewDisposedException("Snapshot has been disposed");
1121
        updatecheck();
1122
        addSorted(items, true, true);
1123
      }
1124
    }
1125

    
1126
    #region add-sorted helpers
1127

    
1128
    //Create a RB tree from x+2^h-1  (x < 2^h, h>=1) nodes taken from a
1129
    //singly linked list of red nodes using only the right child refs.
1130
    //The x nodes at depth h+1 will be red, the rest black.
1131
    //(h is the blackdepth of the resulting tree)
1132
    static Node maketreer(ref Node rest, int blackheight, int maxred, int red)
1133
    {
1134
      if (blackheight == 1)
1135
      {
1136
        Node top = rest;
1137

    
1138
        rest = rest.right;
1139
        if (red > 0)
1140
        {
1141
          top.right = null;
1142
          rest.left = top;
1143
          top = rest;
1144
#if BAG
1145
          top.size += top.left.size;
1146
#elif MAINTAIN_SIZE
1147
          top.size = 1 + red;
1148
#endif
1149
          rest = rest.right;
1150
          red--;
1151
        }
1152

    
1153
        if (red > 0)
1154
        {
1155
#if BAG
1156
          top.size += rest.size;
1157
#endif
1158
          top.right = rest;
1159
          rest = rest.right;
1160
          top.right.right = null;
1161
        }
1162
        else
1163
          top.right = null;
1164

    
1165
        top.red = false;
1166
        return top;
1167
      }
1168
      else
1169
      {
1170
        maxred >>= 1;
1171

    
1172
        int lred = red > maxred ? maxred : red;
1173
        Node left = maketreer(ref rest, blackheight - 1, maxred, lred);
1174
        Node top = rest;
1175

    
1176
        rest = rest.right;
1177
        top.left = left;
1178
        top.red = false;
1179
        top.right = maketreer(ref rest, blackheight - 1, maxred, red - lred);
1180
#if BAG
1181
        top.size = top.items + top.left.size + top.right.size;
1182
#elif MAINTAIN_SIZE
1183
        top.size = (maxred << 1) - 1 + red;
1184
#endif
1185
        return top;
1186
      }
1187
    }
1188

    
1189

    
1190
    void addSorted<U>(SCG.IEnumerable<U> items, bool safe, bool raise) where U : T
1191
    {
1192
      SCG.IEnumerator<U> e = items.GetEnumerator(); ;
1193
      if (size > 0)
1194
        throw new InternalException("This can't happen");
1195

    
1196
      if (!e.MoveNext())
1197
        return;
1198

    
1199
      //To count theCollect 
1200
      Node head = new Node(), tail = head;
1201
      int z = 1;
1202
      T lastitem = tail.item = e.Current;
1203
#if BAG
1204
      int ec = 0;
1205
#endif
1206

    
1207
      while (e.MoveNext())
1208
      {
1209
#if BAG
1210
        T thisitem = e.Current;
1211
        int comp = comparer.Compare(lastitem, thisitem);
1212
        if (comp > 0)
1213
          throw new ArgumentException("Argument not sorted");
1214
        if (comp == 0)
1215
        {
1216
          tail.items++;
1217
          ec++;
1218
        }
1219
        else
1220
        {
1221
          tail.size = tail.items;
1222
          z++;
1223
          tail.right = new Node();
1224
          tail = tail.right;
1225
          lastitem = tail.item = thisitem;
1226
#if NCP
1227
          tail.generation = generation;
1228
#endif
1229
        }
1230
#else
1231
        z++;
1232
        tail.right = new Node();
1233
        tail = tail.right;
1234
        tail.item = e.Current;
1235
        if (safe)
1236
        {
1237
          if (comparer.Compare(lastitem, tail.item) >= 0)
1238
            throw new ArgumentException("Argument not sorted");
1239

    
1240
          lastitem = tail.item;
1241
        }
1242
#if NCP
1243
        tail.generation = generation;
1244
#endif
1245
#endif
1246
      }
1247
#if BAG
1248
      tail.size = tail.items;
1249
#endif
1250
      int blackheight = 0, red = z, maxred = 1;
1251

    
1252
      while (maxred <= red)
1253
      {
1254
        red -= maxred;
1255
        maxred <<= 1;
1256
        blackheight++;
1257
      }
1258

    
1259
      root = TreeBag<T>.maketreer(ref head, blackheight, maxred, red);
1260
      blackdepth = blackheight;
1261
      size = z;
1262
#if BAG
1263
      size += ec;
1264
#endif
1265

    
1266
      if (raise)
1267
      {
1268
        if ((ActiveEvents & EventTypeEnum.Added) != 0)
1269
        {
1270
          CircularQueue<T> wasAdded = new CircularQueue<T>();
1271
          foreach (T item in this)
1272
            wasAdded.Enqueue(item);
1273
          foreach (T item in wasAdded)
1274
            raiseItemsAdded(item, 1);
1275
        }
1276
        if ((ActiveEvents & EventTypeEnum.Changed) != 0)
1277
          raiseCollectionChanged();
1278
      }
1279
      return;
1280
    }
1281

    
1282
    #endregion
1283

    
1284
#if BAG
1285
    /// <summary></summary>
1286
    /// <value>True since this collection has bag semantics.</value>
1287
    [Tested]
1288
    public bool AllowsDuplicates { [Tested]get { return true; } }
1289
#else
1290
    /// <summary></summary>
1291
    /// <value>False since this tree has set semantics.</value>
1292
    [Tested]
1293
    public bool AllowsDuplicates { [Tested]get { return false; } }
1294
#endif
1295
    /// <summary>
1296
    /// By convention this is true for any collection with set semantics.
1297
    /// </summary>
1298
    /// <value>True if only one representative of a group of equal items 
1299
    /// is kept in the collection together with the total count.</value>
1300
    public virtual bool DuplicatesByCounting { get { return true; } }
1301

    
1302
    #endregion
1303

    
1304
    #region IEditableCollection<T> Members
1305

    
1306

    
1307
    /// <summary>
1308
    /// The value is symbolic indicating the type of asymptotic complexity
1309
    /// in terms of the size of this collection (worst-case or amortized as
1310
    /// relevant).
1311
    /// </summary>
1312
    /// <value>Speed.Log</value>
1313
    [Tested]
1314
    public Speed ContainsSpeed { [Tested]get { return Speed.Log; } }
1315

    
1316
    /// <summary>
1317
    /// Check if this collection contains (an item equivalent to according to the
1318
    /// itemequalityComparer) a particular value.
1319
    /// </summary>
1320
    /// <param name="item">The value to check for.</param>
1321
    /// <returns>True if the items is in this collection.</returns>
1322
    [Tested]
1323
    public bool Contains(T item)
1324
    {
1325
      if (!isValid)
1326
        throw new ViewDisposedException("Snapshot has been disposed");
1327
      Node next; int comp = 0;
1328

    
1329
      next = root;
1330
      while (next != null)
1331
      {
1332
        comp = comparer.Compare(next.item, item);
1333
        if (comp == 0)
1334
          return true;
1335

    
1336
        next = comp < 0 ? right(next) : left(next);
1337
      }
1338

    
1339
      return false;
1340
    }
1341

    
1342

    
1343
    //Variant for dictionary use
1344
    //Will return the actual matching item in the ref argument.
1345
    /// <summary>
1346
    /// Check if this collection contains an item equivalent according to the
1347
    /// itemequalityComparer to a particular value. If so, return in the ref argument (a
1348
    /// binary copy of) the actual value found.
1349
    /// </summary>
1350
    /// <param name="item">The value to look for.</param>
1351
    /// <returns>True if the items is in this collection.</returns>
1352
    [Tested]
1353
    public bool Find(ref T item)
1354
    {
1355
      if (!isValid)
1356
        throw new ViewDisposedException("Snapshot has been disposed");
1357
      Node next; int comp = 0;
1358

    
1359
      next = root;
1360
      while (next != null)
1361
      {
1362
        comp = comparer.Compare(next.item, item);
1363
        if (comp == 0)
1364
        {
1365
          item = next.item;
1366
          return true;
1367
        }
1368

    
1369
        next = comp < 0 ? right(next) : left(next);
1370
      }
1371

    
1372
      return false;
1373
    }
1374

    
1375

    
1376
    /// <summary>
1377
    /// Find or add the item to the tree. If the tree does not contain
1378
    /// an item equivalent to this item add it, else return the exisiting
1379
    /// one in the ref argument. 
1380
    ///
1381
    /// </summary>
1382
    /// <param name="item"></param>
1383
    /// <returns>True if item was found</returns>
1384
    [Tested]
1385
    public bool FindOrAdd(ref T item)
1386
    {
1387
      if (!isValid)
1388
        throw new ViewDisposedException("Snapshot has been disposed");
1389
      updatecheck();
1390
      bool wasfound;
1391

    
1392
      //Note: blackdepth of the tree is set inside addIterative
1393
      if (addIterative(item, ref item, false, out wasfound))
1394
      {
1395
        size++;
1396
        if (ActiveEvents != 0 && !wasfound)
1397
          raiseForAdd(item);
1398
        return wasfound;
1399
      }
1400
      else
1401
        return true;
1402

    
1403
    }
1404

    
1405

    
1406
    //For dictionary use. 
1407
    //If found, the matching entry will be updated with the new item.
1408
    /// <summary>
1409
    /// Check if this collection contains an item equivalent according to the
1410
    /// itemequalityComparer to a particular value. If so, update the item in the collection 
1411
    /// to with a binary copy of the supplied value. If the collection has bag semantics,
1412
    /// this updates all equivalent copies in
1413
    /// the collection.
1414
    /// </summary>
1415
    /// <param name="item">Value to update.</param>
1416
    /// <returns>True if the item was found and hence updated.</returns>
1417
    [Tested]
1418
    public bool Update(T item)
1419
    {
1420
      T olditem = item;
1421
      return Update(item, out olditem);
1422
    }
1423

    
1424
    /// <summary>
1425
    /// Check if this collection contains an item equivalent according to the
1426
    /// itemequalityComparer to a particular value. If so, update the item in the collection 
1427
    /// with a binary copy of the supplied value. If the collection has bag semantics,
1428
    /// this updates all equivalent copies in
1429
    /// the collection.
1430
    /// </summary>
1431
    /// <param name="item"></param>
1432
    /// <param name="olditem"></param>
1433
    /// <returns></returns>
1434
    public bool Update(T item, out T olditem)
1435
    {
1436
      if (!isValid)
1437
        throw new ViewDisposedException("Snapshot has been disposed");
1438
      updatecheck();
1439
#if NCP
1440
      stackcheck();
1441

    
1442
      int level = 0;
1443
#endif
1444
      Node cursor = root;
1445
      int comp = 0;
1446

    
1447
      while (cursor != null)
1448
      {
1449
        comp = comparer.Compare(cursor.item, item);
1450
        if (comp == 0)
1451
        {
1452
#if NCP
1453
          Node.CopyNode(ref cursor, maxsnapid, generation);
1454
#endif
1455
          olditem = cursor.item;
1456
#if BAG
1457
          int items = cursor.items;
1458
#endif
1459
          cursor.item = item;
1460
#if NCP
1461
          while (level > 0)
1462
          {
1463
            Node child = cursor;
1464

    
1465
            cursor = path[--level];
1466
            path[level] = null;
1467
#if NCP
1468
            Node.update(ref cursor, dirs[level] > 0, child, maxsnapid, generation);
1469
#else
1470
						if (Node.CopyNode(maxsnapid, ref cursor, generation))
1471
						{
1472
							if (dirs[level] > 0)
1473
								cursor.left = child;
1474
							else
1475
								cursor.right = child;
1476
						}
1477
#endif
1478
          }
1479

    
1480
          root = cursor;
1481
#endif
1482
#if BAG
1483
          if (ActiveEvents != 0)
1484
            raiseForUpdate(item, olditem, items);
1485
#else
1486
          if (ActiveEvents != 0)
1487
            raiseForUpdate(item, olditem);
1488
#endif
1489
          return true;
1490
        }
1491
#if NCP
1492
        dirs[level] = comp;
1493
        path[level++] = cursor;
1494
#endif
1495
        cursor = comp < 0 ? cursor.right : cursor.left;
1496
      }
1497

    
1498
      olditem = default(T);
1499
      return false;
1500
    }
1501

    
1502

    
1503
    /// <summary>
1504
    /// Check if this collection contains an item equivalent according to the
1505
    /// itemequalityComparer to a particular value. If so, update the item in the collection 
1506
    /// with a binary copy of the supplied value; else add the value to the collection. 
1507
    ///
1508
    /// <i>NOTE: the bag implementation is currently wrong! ?????</i>
1509
    /// </summary>
1510
    /// <param name="item">Value to add or update.</param>
1511
    /// <returns>True if the item was found and updated (hence not added).</returns>
1512
    [Tested]
1513
    public bool UpdateOrAdd(T item)
1514
    { T olditem; return UpdateOrAdd(item, out olditem); }
1515

    
1516
    /// <summary>
1517
    /// 
1518
    /// </summary>
1519
    /// <param name="item"></param>
1520
    /// <param name="olditem"></param>
1521
    /// <returns></returns>
1522
    public bool UpdateOrAdd(T item, out T olditem)
1523
    {
1524
      if (!isValid)
1525
        throw new ViewDisposedException("Snapshot has been disposed");
1526
      updatecheck();
1527
      bool wasfound;
1528
      olditem = default(T);
1529

    
1530

    
1531
      //Note: blackdepth of the tree is set inside addIterative
1532
      if (addIterative(item, ref olditem, true, out wasfound))
1533
      {
1534
        size++;
1535
        if (ActiveEvents != 0)
1536
          raiseForAdd(wasfound ? olditem : item);
1537
        return wasfound;
1538
      }
1539
      else
1540
      {
1541
#warning for bag implementation: count is wrong
1542
        if (ActiveEvents != 0)
1543
          raiseForUpdate(item, olditem, 1);
1544
        return true;
1545
      }
1546
    }
1547

    
1548

    
1549
    /// <summary>
1550
    /// Remove a particular item from this collection. If the collection has bag
1551
    /// semantics only one copy equivalent to the supplied item is removed. 
1552
    /// </summary>
1553
    /// <param name="item">The value to remove.</param>
1554
    /// <returns>True if the item was found (and removed).</returns>
1555
    [Tested]
1556
    public bool Remove(T item)
1557
    {
1558
      if (!isValid)
1559
        throw new ViewDisposedException("Snapshot has been disposed");
1560
      updatecheck();
1561
      if (root == null)
1562
        return false;
1563

    
1564
      int junk;
1565
      bool retval = removeIterative(ref item, false, out junk);
1566
      if (ActiveEvents != 0 && retval)
1567
        raiseForRemove(item);
1568
      return retval;
1569
    }
1570

    
1571
    /// <summary>
1572
    /// Remove a particular item from this collection if found. If the collection
1573
    /// has bag semantics only one copy equivalent to the supplied item is removed,
1574
    /// which one is implementation dependent. 
1575
    /// If an item was removed, report a binary copy of the actual item removed in 
1576
    /// the argument.
1577
    /// </summary>
1578
    /// <param name="item">The value to remove.</param>
1579
    /// <param name="removeditem">The removed value.</param>
1580
    /// <returns>True if the item was found (and removed).</returns>
1581
    [Tested]
1582
    public bool Remove(T item, out T removeditem)
1583
    {
1584
      if (!isValid)
1585
        throw new ViewDisposedException("Snapshot has been disposed");
1586
      updatecheck();
1587
      removeditem = item;
1588
      if (root == null)
1589
        return false;
1590

    
1591
      int junk;
1592
      bool retval = removeIterative(ref removeditem, false, out junk);
1593
      if (ActiveEvents != 0 && retval)
1594
        raiseForRemove(item);
1595
      return retval;
1596
    }
1597

    
1598
    /// <summary>
1599
    /// 
1600
    /// </summary>
1601
    /// <param name="item">input: item to remove; output: item actually removed</param>
1602
    /// <param name="all">If true, remove all copies</param>
1603
    /// <param name="wasRemoved"></param>
1604
    /// <returns></returns>
1605
    private bool removeIterative(ref T item, bool all, out int wasRemoved)
1606
    {
1607
      wasRemoved = 0;
1608
      //Stage 1: find item
1609
      stackcheck();
1610

    
1611
      int level = 0, comp;
1612
      Node cursor = root;
1613

    
1614
      while (true)
1615
      {
1616
        comp = comparer.Compare(cursor.item, item);
1617
        if (comp == 0)
1618
        {
1619
          item = cursor.item;
1620
#if BAG
1621
          if (!all && cursor.items > 1)
1622
          {
1623
#if NCP
1624
            Node.CopyNode(ref cursor, maxsnapid, generation);
1625
#endif
1626
            cursor.items--;
1627
            cursor.size--;
1628
            while (level-- > 0)
1629
            {
1630
              Node kid = cursor;
1631

    
1632
              cursor = path[level];
1633
#if NCP
1634
              Node.update(ref cursor, dirs[level] > 0, kid, maxsnapid, generation);
1635
#endif
1636
              cursor.size--;
1637
              path[level] = null;
1638
            }
1639
            size--;
1640
            wasRemoved = 1;
1641
            return true;
1642
          }
1643
          wasRemoved = cursor.items;
1644
#else
1645
          wasRemoved = 1;
1646
#endif
1647
          break;
1648
        }
1649

    
1650
        Node child = comp > 0 ? cursor.left : cursor.right;
1651

    
1652
        if (child == null)
1653
          return false;
1654

    
1655
        dirs[level] = comp;
1656
        path[level++] = cursor;
1657
        cursor = child;
1658
      }
1659

    
1660
      return removeIterativePhase2(cursor, level);
1661
    }
1662

    
1663

    
1664
    private bool removeIterativePhase2(Node cursor, int level)
1665
    {
1666
      if (size == 1)
1667
      {
1668
        clear();
1669
        return true;
1670
      }
1671

    
1672
#if BAG
1673
      int removedcount = cursor.items;
1674
      size -= removedcount;
1675
#else
1676
      //We are certain to remove one node:
1677
      size--;
1678
#endif
1679
      //Stage 2: if item's node has no null child, find predecessor
1680
      int level_of_item = level;
1681

    
1682
      if (cursor.left != null && cursor.right != null)
1683
      {
1684
        dirs[level] = 1;
1685
        path[level++] = cursor;
1686
        cursor = cursor.left;
1687
        while (cursor.right != null)
1688
        {
1689
          dirs[level] = -1;
1690
          path[level++] = cursor;
1691
          cursor = cursor.right;
1692
        }
1693
#if NCP
1694
        Node.CopyNode(ref path[level_of_item], maxsnapid, generation);
1695
#endif
1696
        path[level_of_item].item = cursor.item;
1697
#if BAG
1698
        path[level_of_item].items = cursor.items;
1699
#endif
1700
      }
1701

    
1702
      //Stage 3: splice out node to be removed
1703
      Node newchild = cursor.right == null ? cursor.left : cursor.right;
1704
      bool demote_or_rotate = newchild == null && !cursor.red;
1705

    
1706
      //assert newchild.red 
1707
      if (newchild != null)
1708
      {
1709
        newchild.red = false;
1710
      }
1711

    
1712
      if (level == 0)
1713
      {
1714
        root = newchild;
1715
        return true;
1716
      }
1717

    
1718
      level--;
1719
      cursor = path[level];
1720
      path[level] = null;
1721

    
1722
      int comp = dirs[level];
1723
      Node childsibling;
1724
#if NCP
1725
      Node.update(ref cursor, comp > 0, newchild, maxsnapid, generation);
1726
#else
1727
			if (comp > 0)
1728
				cursor.left = newchild;
1729
			else
1730
				cursor.right = newchild;
1731
#endif
1732
      childsibling = comp > 0 ? cursor.right : cursor.left;
1733
#if BAG
1734
      cursor.size -= removedcount;
1735
#elif MAINTAIN_SIZE
1736
      cursor.size--;
1737
#endif
1738

    
1739
      //Stage 4: demote till we must rotate
1740
      Node farnephew = null, nearnephew = null;
1741

    
1742
      while (demote_or_rotate)
1743
      {
1744
        if (childsibling.red)
1745
          break; //rotate 2+?
1746

    
1747
        farnephew = comp > 0 ? childsibling.right : childsibling.left;
1748
        if (farnephew != null && farnephew.red)
1749
          break; //rotate 1b
1750

    
1751
        nearnephew = comp > 0 ? childsibling.left : childsibling.right;
1752
        if (nearnephew != null && nearnephew.red)
1753
          break; //rotate 1c
1754

    
1755
        //demote cursor
1756
        childsibling.red = true;
1757
        if (level == 0)
1758
        {
1759
          cursor.red = false;
1760
          blackdepth--;
1761
#if NCP
1762
          root = cursor;
1763
#endif
1764
          return true;
1765
        }
1766
        else if (cursor.red)
1767
        {
1768
          cursor.red = false;
1769
          demote_or_rotate = false;
1770
          break; //No rotation
1771
        }
1772
        else
1773
        {
1774
          Node child = cursor;
1775

    
1776
          cursor = path[--level];
1777
          path[level] = null;
1778
          comp = dirs[level];
1779
          childsibling = comp > 0 ? cursor.right : cursor.left;
1780
#if NCP
1781
          Node.update(ref cursor, comp > 0, child, maxsnapid, generation);
1782
#endif
1783
#if BAG
1784
          cursor.size -= removedcount;
1785
#elif MAINTAIN_SIZE
1786
          cursor.size--;
1787
#endif
1788
        }
1789
      }
1790

    
1791
      //Stage 5: rotate 
1792
      if (demote_or_rotate)
1793
      {
1794
        //At start:
1795
        //parent = cursor (temporary for swapping nodes)
1796
        //childsibling is the sibling of the updated child (x)
1797
        //cursor is always the top of the subtree
1798
        Node parent = cursor;
1799

    
1800
        if (childsibling.red)
1801
        {//Case 2 and perhaps more. 
1802
          //The y.rank == px.rank >= x.rank+2 >=2 so both nephews are != null 
1803
          //(and black). The grandnephews are children of nearnephew
1804
          Node neargrandnephew, fargrandnephew;
1805

    
1806
          if (comp > 0)
1807
          {
1808
            nearnephew = childsibling.left;
1809
            farnephew = childsibling.right;
1810
            neargrandnephew = nearnephew.left;
1811
            fargrandnephew = nearnephew.right;
1812
          }
1813
          else
1814
          {
1815
            nearnephew = childsibling.right;
1816
            farnephew = childsibling.left;
1817
            neargrandnephew = nearnephew.right;
1818
            fargrandnephew = nearnephew.left;
1819
          }
1820

    
1821
          if (fargrandnephew != null && fargrandnephew.red)
1822
          {//Case 2+1b
1823
#if NCP
1824
            Node.CopyNode(ref nearnephew, maxsnapid, generation);
1825

    
1826
            //The end result of this will always be e copy of parent
1827
            Node.update(ref parent, comp < 0, neargrandnephew, maxsnapid, generation);
1828
            Node.update(ref childsibling, comp > 0, nearnephew, maxsnapid, generation);
1829
#endif
1830
            if (comp > 0)
1831
            {
1832
              nearnephew.left = parent;
1833
              parent.right = neargrandnephew;
1834
            }
1835
            else
1836
            {
1837
              nearnephew.right = parent;
1838
              parent.left = neargrandnephew;
1839
            }
1840

    
1841
            cursor = childsibling;
1842
            childsibling.red = false;
1843
            nearnephew.red = true;
1844
            fargrandnephew.red = false;
1845
#if BAG
1846
            cursor.size = parent.size;
1847
            nearnephew.size = cursor.size - cursor.items - farnephew.size;
1848
            parent.size = nearnephew.size - nearnephew.items - fargrandnephew.size;
1849
#elif MAINTAIN_SIZE
1850
            cursor.size = parent.size;
1851
            nearnephew.size = cursor.size - 1 - farnephew.size;
1852
            parent.size = nearnephew.size - 1 - fargrandnephew.size;
1853
#endif
1854
          }
1855
          else if (neargrandnephew != null && neargrandnephew.red)
1856
          {//Case 2+1c
1857
#if NCP
1858
            Node.CopyNode(ref neargrandnephew, maxsnapid, generation);
1859
#endif
1860
            if (comp > 0)
1861
            {
1862
#if NCP
1863
              Node.update(ref childsibling, true, neargrandnephew, maxsnapid, generation);
1864
              Node.update(ref nearnephew, true, neargrandnephew.right, maxsnapid, generation);
1865
              Node.update(ref parent, false, neargrandnephew.left, maxsnapid, generation);
1866
#else
1867
							childsibling.left = neargrandnephew;
1868
							nearnephew.left = neargrandnephew.right;
1869
							parent.right = neargrandnephew.left;
1870
#endif
1871
              neargrandnephew.left = parent;
1872
              neargrandnephew.right = nearnephew;
1873
            }
1874
            else
1875
            {
1876
#if NCP
1877
              Node.update(ref childsibling, false, neargrandnephew, maxsnapid, generation);
1878
              Node.update(ref nearnephew, false, neargrandnephew.left, maxsnapid, generation);
1879
              Node.update(ref parent, true, neargrandnephew.right, maxsnapid, generation);
1880
#else
1881
							childsibling.right = neargrandnephew;
1882
							nearnephew.right = neargrandnephew.left;
1883
							parent.left = neargrandnephew.right;
1884
#endif
1885
              neargrandnephew.right = parent;
1886
              neargrandnephew.left = nearnephew;
1887
            }
1888

    
1889
            cursor = childsibling;
1890
            childsibling.red = false;
1891
#if BAG
1892
            cursor.size = parent.size;
1893
            parent.size = parent.items + (parent.left == null ? 0 : parent.left.size) + (parent.right == null ? 0 : parent.right.size);
1894
            nearnephew.size = nearnephew.items + (nearnephew.left == null ? 0 : nearnephew.left.size) + (nearnephew.right == null ? 0 : nearnephew.right.size);
1895
            neargrandnephew.size = neargrandnephew.items + parent.size + nearnephew.size;
1896
#elif MAINTAIN_SIZE
1897
            cursor.size = parent.size;
1898
            parent.size = 1 + (parent.left == null ? 0 : parent.left.size) + (parent.right == null ? 0 : parent.right.size);
1899
            nearnephew.size = 1 + (nearnephew.left == null ? 0 : nearnephew.left.size) + (nearnephew.right == null ? 0 : nearnephew.right.size);
1900
            neargrandnephew.size = 1 + parent.size + nearnephew.size;
1901
#endif
1902
          }
1903
          else
1904
          {//Case 2 only
1905
#if NCP
1906
            Node.update(ref parent, comp < 0, nearnephew, maxsnapid, generation);
1907
            Node.update(ref childsibling, comp > 0, parent, maxsnapid, generation);
1908
#else
1909
						if (comp > 0)
1910
						{
1911
							childsibling.left = parent;
1912
							parent.right = nearnephew;
1913
						}
1914
						else
1915
						{
1916
							childsibling.right = parent;
1917
							parent.left = nearnephew;
1918
						}
1919
#endif
1920
            cursor = childsibling;
1921
            childsibling.red = false;
1922
            nearnephew.red = true;
1923
#if BAG
1924
            cursor.size = parent.size;
1925
            parent.size -= farnephew.size + cursor.items;
1926
#elif MAINTAIN_SIZE
1927
            cursor.size = parent.size;
1928
            parent.size -= farnephew.size + 1;
1929
#endif
1930
          }
1931
        }
1932
        else if (farnephew != null && farnephew.red)
1933
        {//Case 1b
1934
          nearnephew = comp > 0 ? childsibling.left : childsibling.right;
1935
#if NCP
1936
          Node.update(ref parent, comp < 0, nearnephew, maxsnapid, generation);
1937
          Node.CopyNode(ref childsibling, maxsnapid, generation);
1938
          if (comp > 0)
1939
          {
1940
            childsibling.left = parent;
1941
            childsibling.right = farnephew;
1942
          }
1943
          else
1944
          {
1945
            childsibling.right = parent;
1946
            childsibling.left = farnephew;
1947
          }
1948
#else
1949
					if (comp > 0)
1950
					{
1951
						childsibling.left = parent;
1952
						parent.right = nearnephew;
1953
					}
1954
					else
1955
					{
1956
						childsibling.right = parent;
1957
						parent.left = nearnephew;
1958
					}
1959
#endif
1960
          cursor = childsibling;
1961
          cursor.red = parent.red;
1962
          parent.red = false;
1963
          farnephew.red = false;
1964

    
1965
#if BAG
1966
          cursor.size = parent.size;
1967
          parent.size -= farnephew.size + cursor.items;
1968
#elif MAINTAIN_SIZE
1969
          cursor.size = parent.size;
1970
          parent.size -= farnephew.size + 1;
1971
#endif
1972
        }
1973
        else if (nearnephew != null && nearnephew.red)
1974
        {//Case 1c
1975
#if NCP
1976
          Node.CopyNode(ref nearnephew, maxsnapid, generation);
1977
#endif
1978
          if (comp > 0)
1979
          {
1980
#if NCP
1981
            Node.update(ref childsibling, true, nearnephew.right, maxsnapid, generation);
1982
            Node.update(ref parent, false, nearnephew.left, maxsnapid, generation);
1983
#else
1984
						childsibling.left = nearnephew.right;
1985
						parent.right = nearnephew.left;
1986
#endif
1987
            nearnephew.left = parent;
1988
            nearnephew.right = childsibling;
1989
          }
1990
          else
1991
          {
1992
#if NCP
1993
            Node.update(ref childsibling, false, nearnephew.left, maxsnapid, generation);
1994
            Node.update(ref parent, true, nearnephew.right, maxsnapid, generation);
1995
#else
1996
						childsibling.right = nearnephew.left;
1997
						parent.left = nearnephew.right;
1998
#endif
1999
            nearnephew.right = parent;
2000
            nearnephew.left = childsibling;
2001
          }
2002

    
2003
          cursor = nearnephew;
2004
          cursor.red = parent.red;
2005
          parent.red = false;
2006
#if BAG
2007
          cursor.size = parent.size;
2008
          parent.size = parent.items + (parent.left == null ? 0 : parent.left.size) + (parent.right == null ? 0 : parent.right.size);
2009
          childsibling.size = childsibling.items + (childsibling.left == null ? 0 : childsibling.left.size) + (childsibling.right == null ? 0 : childsibling.right.size);
2010
#elif MAINTAIN_SIZE
2011
          cursor.size = parent.size;
2012
          parent.size = 1 + (parent.left == null ? 0 : parent.left.size) + (parent.right == null ? 0 : parent.right.size);
2013
          childsibling.size = 1 + (childsibling.left == null ? 0 : childsibling.left.size) + (childsibling.right == null ? 0 : childsibling.right.size);
2014
#endif
2015
        }
2016
        else
2017
        {//Case 1a can't happen
2018
          throw new InternalException("Case 1a can't happen here");
2019
        }
2020

    
2021
        //Resplice cursor:
2022
        if (level == 0)
2023
        {
2024
          root = cursor;
2025
        }
2026
        else
2027
        {
2028
          Node swap = cursor;
2029

    
2030
          cursor = path[--level];
2031
          path[level] = null;
2032
#if NCP
2033
          Node.update(ref cursor, dirs[level] > 0, swap, maxsnapid, generation);
2034
#else
2035
				
2036
					if (dirs[level] > 0)
2037
						cursor.left = swap;
2038
					else
2039
						cursor.right = swap;
2040
#endif
2041
#if BAG
2042
          cursor.size -= removedcount;
2043
#elif MAINTAIN_SIZE
2044
          cursor.size--;
2045
#endif
2046
        }
2047
      }
2048

    
2049
      //Stage 6: fixup to the root
2050
      while (level > 0)
2051
      {
2052
        Node child = cursor;
2053

    
2054
        cursor = path[--level];
2055
        path[level] = null;
2056
#if NCP
2057
        if (child != (dirs[level] > 0 ? cursor.left : cursor.right))
2058
          Node.update(ref cursor, dirs[level] > 0, child, maxsnapid, generation);
2059
#endif
2060
#if BAG
2061
        cursor.size -= removedcount;
2062
#elif MAINTAIN_SIZE
2063
        cursor.size--;
2064
#endif
2065
      }
2066

    
2067
#if NCP
2068
      root = cursor;
2069
#endif
2070
      return true;
2071
    }
2072

    
2073

    
2074
    /// <summary>
2075
    /// Remove all items from this collection.
2076
    /// </summary>
2077
    [Tested]
2078
    public void Clear()
2079
    {
2080
      if (!isValid)
2081
        throw new ViewDisposedException("Snapshot has been disposed");
2082
      updatecheck();
2083
      if (size == 0)
2084
        return;
2085
      int oldsize = size;
2086
      clear();
2087
      if ((ActiveEvents & EventTypeEnum.Cleared) != 0)
2088
        raiseCollectionCleared(true, oldsize);
2089
      if ((ActiveEvents & EventTypeEnum.Changed) != 0)
2090
        raiseCollectionChanged();
2091
    }
2092

    
2093

    
2094
    private void clear()
2095
    {
2096
      size = 0;
2097
      root = null;
2098
      blackdepth = 0;
2099
    }
2100

    
2101

    
2102
    /// <summary>
2103
    /// Remove all items in another collection from this one. If this collection
2104
    /// has bag semantics, take multiplicities into account.
2105
    /// </summary>
2106
    /// <typeparam name="U"></typeparam>
2107
    /// <param name="items">The items to remove.</param>
2108
    [Tested]
2109
    public void RemoveAll<U>(SCG.IEnumerable<U> items) where U : T
2110
    {
2111
      if (!isValid)
2112
        throw new ViewDisposedException("Snapshot has been disposed");
2113
      updatecheck();
2114

    
2115
      T jtem;
2116

    
2117
      bool mustRaise = (ActiveEvents & (EventTypeEnum.Removed | EventTypeEnum.Changed)) != 0;
2118
      RaiseForRemoveAllHandler raiseHandler = mustRaise ? new RaiseForRemoveAllHandler(this) : null;
2119

    
2120
      foreach (T item in items)
2121
      {
2122
        if (root == null)
2123
          break;
2124

    
2125
        jtem = item;
2126
        int junk;
2127
        if (removeIterative(ref jtem, false, out junk) && mustRaise)
2128
          raiseHandler.Remove(jtem);
2129
      }
2130
      if (mustRaise)
2131
        raiseHandler.Raise();
2132
    }
2133

    
2134
    /// <summary>
2135
    /// Remove all items not in some other collection from this one. If this collection
2136
    /// has bag semantics, take multiplicities into account.
2137
    /// </summary>
2138
    /// <typeparam name="U"></typeparam>
2139
    /// <param name="items">The items to retain.</param>
2140
    [Tested]
2141
    public void RetainAll<U>(SCG.IEnumerable<U> items) where U : T
2142
    {
2143
      if (!isValid)
2144
        throw new ViewDisposedException("Snapshot has been disposed");
2145
      updatecheck();
2146

    
2147
      //A much more efficient version is possible if items is sorted like this.
2148
      //Well, it is unclear how efficient it would be.
2149
      //We could use a marking method!?
2150
#warning how does this work together with persistence?
2151
      TreeBag<T> t = (TreeBag<T>)MemberwiseClone();
2152

    
2153
      T jtem = default(T);
2154
      t.clear();
2155
      foreach (T item in items)
2156
        if (ContainsCount(item) > t.ContainsCount(item))
2157
        {
2158
          t.add(item, ref jtem);
2159
        }
2160
      if (size == t.size)
2161
        return;
2162

    
2163
#warning improve (mainly for bag) by using a Node iterator instead of ItemMultiplicities()
2164
      CircularQueue<KeyValuePair<T, int>> wasRemoved = null;
2165
      if ((ActiveEvents & EventTypeEnum.Removed) != 0)
2166
      {
2167
        wasRemoved = new CircularQueue<KeyValuePair<T, int>>();
2168
        SCG.IEnumerator<KeyValuePair<T, int>> ie = ItemMultiplicities().GetEnumerator();
2169
        foreach (KeyValuePair<T, int> p in t.ItemMultiplicities())
2170
        {
2171
          //We know p.Key is in this!
2172
          while (ie.MoveNext())
2173
          {
2174
            if (comparer.Compare(ie.Current.Key, p.Key) == 0)
2175
            {
2176
#if BAG
2177
              int removed = ie.Current.Value - p.Value;
2178
              if (removed > 0)
2179
                wasRemoved.Enqueue(new KeyValuePair<T,int>(p.Key, removed));
2180
#endif
2181
              break;
2182
            }
2183
            else
2184
              wasRemoved.Enqueue(ie.Current);
2185
          }
2186
        }
2187
        while (ie.MoveNext())
2188
          wasRemoved.Enqueue(ie.Current);
2189
      }
2190

    
2191
      root = t.root;
2192
      size = t.size;
2193
      blackdepth = t.blackdepth;
2194
      if (wasRemoved != null)
2195
        foreach (KeyValuePair<T, int> p in wasRemoved)
2196
          raiseItemsRemoved(p.Key, p.Value);
2197
      if ((ActiveEvents & EventTypeEnum.Changed) != 0)
2198
        raiseCollectionChanged();
2199
    }
2200

    
2201
    /// <summary>
2202
    /// Check if this collection contains all the values in another collection.
2203
    /// If this collection has bag semantics (<code>AllowsDuplicates==true</code>)
2204
    /// the check is made with respect to multiplicities, else multiplicities
2205
    /// are not taken into account.
2206
    /// </summary>
2207
    /// <param name="items">The </param>
2208
    /// <typeparam name="U"></typeparam>
2209
    /// <returns>True if all values in <code>items</code>is in this collection.</returns>
2210
    [Tested]
2211
    public bool ContainsAll<U>(SCG.IEnumerable<U> items) where U : T
2212
    {
2213
      //TODO: fix bag implementation
2214
      if (!isValid)
2215
        throw new ViewDisposedException("Snapshot has been disposed");
2216
      //This is worst-case O(m*logn)
2217
      foreach (T item in items)
2218
        if (!Contains(item)) return false;
2219

    
2220
      return true;
2221
    }
2222

    
2223

    
2224
    //Higher order:
2225
    /// <summary>
2226
    /// Create a new indexed sorted collection consisting of the items of this
2227
    /// indexed sorted collection satisfying a certain predicate.
2228
    /// </summary>
2229
    /// <param name="filter">The filter delegate defining the predicate.</param>
2230
    /// <returns>The new indexed sorted collection.</returns>
2231
    [Tested]
2232
    public IIndexedSorted<T> FindAll(Fun<T, bool> filter)
2233
    {
2234
      if (!isValid)
2235
        throw new ViewDisposedException("Snapshot has been disposed");
2236
      TreeBag<T> res = new TreeBag<T>(comparer);
2237
      SCG.IEnumerator<T> e = GetEnumerator();
2238
      Node head = null, tail = null;
2239
      int z = 0;
2240
#if BAG
2241
      int ec = 0;
2242
#endif
2243
      while (e.MoveNext())
2244
      {
2245
        T thisitem = e.Current;
2246
#if BAG
2247
        //We could document that filter will only be called 
2248
        //once on each unique item. That might even be good for the user!
2249
        if (tail != null && comparer.Compare(thisitem, tail.item) == 0)
2250
        {
2251
          tail.items++;
2252
          ec++;
2253
          continue;
2254
        }
2255
#endif
2256
        if (filter(thisitem))
2257
        {
2258
          if (head == null)
2259
          {
2260
            head = tail = new Node();
2261
          }
2262
          else
2263
          {
2264
#if BAG
2265
            tail.size = tail.items;
2266
#endif
2267
            tail.right = new Node();
2268
            tail = tail.right;
2269
          }
2270

    
2271
          tail.item = thisitem;
2272
          z++;
2273
        }
2274
      }
2275
#if BAG
2276
      if (tail != null)
2277
        tail.size = tail.items;
2278
#endif
2279

    
2280
      if (z == 0)
2281
        return res;
2282

    
2283
      int blackheight = 0, red = z, maxred = 1;
2284

    
2285
      while (maxred <= red)
2286
      {
2287
        red -= maxred;
2288
        maxred <<= 1;
2289
        blackheight++;
2290
      }
2291

    
2292
      res.root = TreeBag<T>.maketreer(ref head, blackheight, maxred, red);
2293
      res.blackdepth = blackheight;
2294
      res.size = z;
2295
#if BAG
2296
      res.size += ec;
2297
#endif
2298
      return res;
2299
    }
2300

    
2301

    
2302
    /// <summary>
2303
    /// Create a new indexed sorted collection consisting of the results of
2304
    /// mapping all items of this list.
2305
    /// <exception cref="ArgumentException"/> if the map is not increasing over 
2306
    /// the items of this collection (with respect to the two given comparison 
2307
    /// relations).
2308
    /// </summary>
2309
    /// <param name="mapper">The delegate definging the map.</param>
2310
    /// <param name="c">The comparion relation to use for the result.</param>
2311
    /// <returns>The new sorted collection.</returns>
2312
    [Tested]
2313
    public IIndexedSorted<V> Map<V>(Fun<T, V> mapper, SCG.IComparer<V> c)
2314
    {
2315
      if (!isValid)
2316
        throw new ViewDisposedException("Snapshot has been disposed");
2317
      TreeBag<V> res = new TreeBag<V>(c);
2318

    
2319
      if (size == 0)
2320
        return res;
2321

    
2322
      SCG.IEnumerator<T> e = GetEnumerator();
2323
      TreeBag<V>.Node head = null, tail = null;
2324
      V oldv = default(V);
2325
      int z = 0;
2326
#if BAG
2327
      T lastitem = default(T);
2328
#endif
2329
      while (e.MoveNext())
2330
      {
2331
        T thisitem = e.Current;
2332
#if BAG
2333
        //We could document that mapper will only be called 
2334
        //once on each unique item. That might even be good for the user!
2335
        if (tail != null && comparer.Compare(thisitem, lastitem) == 0)
2336
        {
2337
          tail.items++;
2338
          continue;
2339
        }
2340
#endif
2341
        V newv = mapper(thisitem);
2342

    
2343
        if (head == null)
2344
        {
2345
          head = tail = new TreeBag<V>.Node();
2346
          z++;
2347
        }
2348
        else
2349
        {
2350
          int comp = c.Compare(oldv, newv);
2351
#if BAG
2352
          if (comp == 0)
2353
          {
2354
            tail.items++;
2355
            continue;
2356
          }
2357
          if (comp > 0)
2358
#else
2359
          if (comp >= 0)
2360
#endif
2361
            throw new ArgumentException("mapper not monotonic");
2362
#if BAG
2363
          tail.size = tail.items;
2364
#endif
2365
          tail.right = new TreeBag<V>.Node();
2366
          tail = tail.right;
2367
          z++;
2368
        }
2369
#if BAG
2370
        lastitem = thisitem;
2371
#endif
2372
        tail.item = oldv = newv;
2373
      }
2374

    
2375
#if BAG
2376
      tail.size = tail.items;
2377
#endif
2378

    
2379
      int blackheight = 0, red = z, maxred = 1;
2380

    
2381
      while (maxred <= red)
2382
      {
2383
        red -= maxred;
2384
        maxred <<= 1;
2385
        blackheight++;
2386
      }
2387

    
2388
      res.root = TreeBag<V>.maketreer(ref head, blackheight, maxred, red);
2389
      res.blackdepth = blackheight;
2390
      res.size = size;
2391
      return res;
2392
    }
2393

    
2394

    
2395
    //below is the bag utility stuff
2396
    /// <summary>
2397
    /// Count the number of items of the collection equal to a particular value.
2398
    /// Returns 0 if and only if the value is not in the collection.
2399
    /// </summary>
2400
    /// <param name="item">The value to count.</param>
2401
    /// <returns>The number of copies found.</returns>
2402
    [Tested]
2403
    public int ContainsCount(T item)
2404
    {
2405
      if (!isValid)
2406
        throw new ViewDisposedException("Snapshot has been disposed");
2407
#if BAG
2408
      Node next; int comp = 0;
2409

    
2410
      next = root;
2411
      while (next != null)
2412
      {
2413
        comp = comparer.Compare(next.item, item);
2414
        if (comp == 0)
2415
          return next.items;
2416

    
2417
        next = comp < 0 ? right(next) : left(next);
2418
      }
2419

    
2420
      return 0;
2421
#else
2422
      //Since we are strictly not AllowsDuplicates we just do
2423
      return Contains(item) ? 1 : 0;
2424
#endif
2425
    }
2426

    
2427
#if BAG
2428
    //TODO: make work with snapshots
2429
    class Multiplicities : CollectionValueBase<KeyValuePair<T, int>>, ICollectionValue<KeyValuePair<T, int>>
2430
    {
2431
      TreeBag<T> treebag;
2432
      int origstamp;
2433
      internal Multiplicities(TreeBag<T> treebag) { this.treebag = treebag; this.origstamp = treebag.stamp; }
2434
      public override KeyValuePair<T, int> Choose() { return new KeyValuePair<T, int>(treebag.root.item, treebag.root.items); }
2435

    
2436
      public override SCG.IEnumerator<KeyValuePair<T, int>> GetEnumerator()
2437
      {
2438
        return getEnumerator(treebag.root, origstamp); //TODO: NBNBNB
2439
      }
2440

    
2441
      private SCG.IEnumerator<KeyValuePair<T, int>> getEnumerator(Node node, int origstamp)
2442
      {
2443
        if (node == null)
2444
          yield break;
2445

    
2446
        if (node.left != null)
2447
        {
2448
          SCG.IEnumerator<KeyValuePair<T, int>> child = getEnumerator(node.left, origstamp);
2449

    
2450
          while (child.MoveNext())
2451
          {
2452
            treebag.modifycheck(origstamp);
2453
            yield return child.Current;
2454
          }
2455
        }
2456
        yield return new KeyValuePair<T, int>(node.item, node.items);
2457
        if (node.right != null)
2458
        {
2459
          SCG.IEnumerator<KeyValuePair<T, int>> child = getEnumerator(node.right, origstamp);
2460

    
2461
          while (child.MoveNext())
2462
          {
2463
            treebag.modifycheck(origstamp);
2464
            yield return child.Current;
2465
          }
2466
        }
2467
      }
2468

    
2469
      public override bool IsEmpty { get { return treebag.IsEmpty; } }
2470
      public override int Count { get { int i = 0; foreach (KeyValuePair<T, int> p in this) i++; return i; } } //TODO: make better
2471
      public override Speed CountSpeed { get { return Speed.Linear; } } //TODO: make better
2472
    }
2473
#endif
2474

    
2475
    /// <summary>
2476
    /// 
2477
    /// </summary>
2478
    /// <returns></returns>
2479
    public virtual ICollectionValue<T> UniqueItems()
2480
    {
2481
      if (!isValid)
2482
        throw new ViewDisposedException("Snapshot has been disposed");
2483
#if BAG
2484
      return new DropMultiplicity<T>(ItemMultiplicities());
2485
#else
2486
      return this;
2487
#endif
2488
    }
2489

    
2490

    
2491
    /// <summary>
2492
    /// 
2493
    /// </summary>
2494
    /// <returns></returns>
2495
    public virtual ICollectionValue<KeyValuePair<T, int>> ItemMultiplicities()
2496
    {
2497
      if (!isValid)
2498
        throw new ViewDisposedException("Snapshot has been disposed");
2499
#if BAG
2500
      return new Multiplicities(this);
2501
#else
2502
      return new MultiplicityOne<T>(this);
2503
#endif
2504
    }
2505

    
2506
    /// <summary>
2507
    /// Remove all items equivalent to a given value.
2508
    /// </summary>
2509
    /// <param name="item">The value to remove.</param>
2510
    [Tested]
2511
    public void RemoveAllCopies(T item)
2512
    {
2513
#if BAG
2514
      if (!isValid)
2515
        throw new ViewDisposedException("Snapshot has been disposed");
2516
      updatecheck();
2517
      int removed;
2518
      if (removeIterative(ref item, true, out removed) && ActiveEvents != 0)
2519
      {
2520
        raiseForRemove(item, removed);
2521
      }
2522
#else
2523
      Remove(item);
2524
#endif
2525
    }
2526

    
2527

    
2528
    #endregion
2529

    
2530
    #region IIndexed<T> Members
2531

    
2532
    private Node findNode(int i)
2533
    {
2534
#if NCP
2535
      if (isSnapShot)
2536
        throw new NotSupportedException("Indexing not supported for snapshots");
2537
#endif
2538
#if MAINTAIN_SIZE
2539
      Node next = root;
2540

    
2541
      if (i >= 0 && i < size)
2542
        while (true)
2543
        {
2544
          int j = next.left == null ? 0 : next.left.size;
2545

    
2546
          if (i > j)
2547
          {
2548
#if BAG
2549
            i -= j + next.items;
2550
            if (i < 0)
2551
              return next;
2552
#else
2553
            i -= j + 1;
2554
#endif
2555
            next = next.right;
2556
          }
2557
          else if (i == j)
2558
            return next;
2559
          else
2560
            next = next.left;
2561
        }
2562

    
2563
      throw new IndexOutOfRangeException();
2564
#else
2565
			throw new NotSupportedException();
2566
#endif
2567
    }
2568

    
2569

    
2570
    /// <summary>
2571
    /// <exception cref="IndexOutOfRangeException"/> if i is negative or
2572
    /// &gt;= the size of the collection.
2573
    /// </summary>
2574
    /// <value>The i'th item of this list.</value>
2575
    /// <param name="i">the index to lookup</param>
2576
    [Tested]
2577
    public T this[int i] { [Tested]	get { return findNode(i).item; } }
2578

    
2579
    /// <summary>
2580
    /// 
2581
    /// </summary>
2582
    /// <value></value>
2583
    public virtual Speed IndexingSpeed { get { return Speed.Log; } }
2584

    
2585

    
2586
    //TODO: return -upper instead of -1 in case of not found
2587
    /// <summary>
2588
    /// Searches for an item in this indexed collection going forwards from the start.
2589
    /// </summary>
2590
    /// <param name="item">Item to search for.</param>
2591
    /// <returns>Index of first occurrence from start of the item
2592
    /// if found, else the two-complement 
2593
    /// (always negative) of the index at which the item would be put if it was added.</returns>
2594
    [Tested]
2595
    public int IndexOf(T item)
2596
    {
2597
      if (!isValid)
2598
        throw new ViewDisposedException("Snapshot has been disposed");
2599
      int upper;
2600
      return indexOf(item, out upper);
2601
    }
2602

    
2603

    
2604
    private int indexOf(T item, out int upper)
2605
    {
2606
#if NCP
2607
      if (isSnapShot)
2608
        throw new NotSupportedException("Indexing not supported for snapshots");
2609
#endif
2610
#if MAINTAIN_SIZE
2611
      int ind = 0; Node next = root;
2612

    
2613
      while (next != null)
2614
      {
2615
        int comp = comparer.Compare(item, next.item);
2616

    
2617
        if (comp < 0)
2618
          next = next.left;
2619
        else
2620
        {
2621
          int leftcnt = next.left == null ? 0 : next.left.size;
2622

    
2623
          if (comp == 0)
2624
          {
2625
#if BAG
2626
            upper = ind + leftcnt + next.items - 1;
2627
            return ind + leftcnt;
2628
#else
2629
            return upper = ind + leftcnt;
2630
#endif
2631
          }
2632
          else
2633
          {
2634
#if BAG
2635
            ind = ind + next.items + leftcnt;
2636
#else
2637
            ind = ind + 1 + leftcnt;
2638
#endif
2639
            next = next.right;
2640
          }
2641
        }
2642
      }
2643
#endif
2644
      upper = ~ind;
2645
      return ~ind;
2646
    }
2647

    
2648

    
2649
    /// <summary>
2650
    /// Searches for an item in the tree going backwords from the end.
2651
    /// </summary>
2652
    /// <param name="item">Item to search for.</param>
2653
    /// <returns>Index of last occurrence from the end of item if found, 
2654
    /// else the two-complement (always negative) of the index at which 
2655
    /// the item would be put if it was added.</returns>
2656
    [Tested]
2657
    public int LastIndexOf(T item)
2658
    {
2659
      if (!isValid)
2660
        throw new ViewDisposedException("Snapshot has been disposed");
2661
#if BAG
2662
      int res;
2663
      indexOf(item, out res);
2664
      return res;
2665
#else
2666
      //We have AllowsDuplicates==false for the set
2667
      return IndexOf(item);
2668
#endif
2669
    }
2670

    
2671

    
2672
    /// <summary>
2673
    /// Remove the item at a specific position of the list.
2674
    /// <exception cref="IndexOutOfRangeException"/> if i is negative or
2675
    /// &gt;= the size of the collection.
2676
    /// </summary>
2677
    /// <param name="i">The index of the item to remove.</param>
2678
    /// <returns>The removed item.</returns>
2679
    [Tested]
2680
    public T RemoveAt(int i)
2681
    {
2682
      if (!isValid)
2683
        throw new ViewDisposedException("Snapshot has been disposed");
2684
      updatecheck();
2685
      T retval = removeAt(i);
2686
      if (ActiveEvents != 0)
2687
        raiseForRemove(retval);
2688
      return retval;
2689
    }
2690

    
2691
    T removeAt(int i)
2692
    {
2693
      if (!isValid)
2694
        throw new ViewDisposedException("Snapshot has been disposed");
2695
      updatecheck();
2696
#if MAINTAIN_SIZE
2697
      if (i < 0 || i >= size)
2698
        throw new IndexOutOfRangeException("Index out of range for sequenced collectionvalue");
2699

    
2700
      //We must follow the pattern of removeIterative()
2701
      while (dirs.Length < 2 * blackdepth)
2702
      {
2703
        dirs = new int[2 * dirs.Length];
2704
        path = new Node[2 * dirs.Length];
2705
      }
2706

    
2707
      int level = 0;
2708
      Node cursor = root;
2709

    
2710
      while (true)
2711
      {
2712
        int j = cursor.left == null ? 0 : cursor.left.size;
2713

    
2714
        if (i > j)
2715
        {
2716
#if BAG
2717
          i -= j + cursor.items;
2718
          if (i < 0)
2719
            break;
2720
#else
2721
          i -= j + 1;
2722
#endif
2723
          dirs[level] = -1;
2724
          path[level++] = cursor;
2725
          cursor = cursor.right;
2726
        }
2727
        else if (i == j)
2728
          break;
2729
        else
2730
        {
2731
          dirs[level] = 1;
2732
          path[level++] = cursor;
2733
          cursor = cursor.left;
2734
        }
2735
      }
2736

    
2737
      T retval = cursor.item;
2738

    
2739
#if BAG
2740
      if (cursor.items > 1)
2741
      {
2742
        resplicebag(level, cursor);
2743
        size--;
2744
        return retval;
2745
      }
2746
#endif
2747
      removeIterativePhase2(cursor, level);
2748
      return retval;
2749
#else
2750
			throw new NotSupportedException();
2751
#endif
2752
    }
2753

    
2754
#if BAG
2755
    private void resplicebag(int level, Node cursor)
2756
    {
2757
#if NCP
2758
      Node.CopyNode(ref cursor, maxsnapid, generation);
2759
#endif
2760
      cursor.items--;
2761
      cursor.size--;
2762
      while (level-- > 0)
2763
      {
2764
        Node kid = cursor;
2765

    
2766
        cursor = path[level];
2767
#if NCP
2768
        Node.update(ref cursor, dirs[level] > 0, kid, maxsnapid, generation);
2769
#endif
2770
        cursor.size--;
2771
        path[level] = null;
2772
      }
2773
    }
2774
#endif
2775
    /// <summary>
2776
    /// Remove all items in an index interval.
2777
    /// <exception cref="IndexOutOfRangeException"/>???. 
2778
    /// </summary>
2779
    /// <param name="start">The index of the first item to remove.</param>
2780
    /// <param name="count">The number of items to remove.</param>
2781
    [Tested]
2782
    public void RemoveInterval(int start, int count)
2783
    {
2784
      if (!isValid)
2785
        throw new ViewDisposedException("Snapshot has been disposed");
2786
      if (start < 0 || count < 0 || start + count > this.size)
2787
        throw new ArgumentOutOfRangeException();
2788

    
2789
      updatecheck();
2790

    
2791
      if (count == 0)
2792
        return;
2793

    
2794
      //This is terrible for large count. We should split the tree at 
2795
      //the endpoints of the range and fuse the parts!
2796
      //We really need good internal destructive split and catenate functions!
2797
      //Alternative for large counts: rebuild tree using maketree()
2798
      for (int i = 0; i < count; i++)
2799
        removeAt(start);
2800

    
2801
      if ((ActiveEvents & EventTypeEnum.Cleared) != 0)
2802
        raiseCollectionCleared(false, count);
2803
      if ((ActiveEvents & EventTypeEnum.Changed) != 0)
2804
        raiseCollectionChanged();
2805
    }
2806

    
2807

    
2808
    /// <summary>
2809
    /// <exception cref="IndexOutOfRangeException"/>.
2810
    /// </summary>
2811
    /// <value>The directed collection of items in a specific index interval.</value>
2812
    /// <param name="start">The low index of the interval (inclusive).</param>
2813
    /// <param name="end">The high index of the interval (exclusive).</param>
2814
    [Tested]
2815
    public IDirectedCollectionValue<T> this[int start, int end]
2816
    {
2817
      [Tested]
2818
      get
2819
      {
2820
        checkRange(start, end - start);
2821
        return new Interval(this, start, end - start, true);
2822
      }
2823
    }
2824

    
2825
    #region Interval nested class
2826
    class Interval : DirectedCollectionValueBase<T>, IDirectedCollectionValue<T>
2827
    {
2828
      int start, length, stamp;
2829

    
2830
      bool forwards;
2831

    
2832
      TreeBag<T> tree;
2833

    
2834

    
2835
      internal Interval(TreeBag<T> tree, int start, int count, bool forwards)
2836
      {
2837
#if NCP
2838
        if (tree.isSnapShot)
2839
          throw new NotSupportedException("Indexing not supported for snapshots");
2840
#endif
2841
        this.start = start; this.length = count; this.forwards = forwards;
2842
        this.tree = tree; this.stamp = tree.stamp;
2843
      }
2844

    
2845
      public override bool IsEmpty { get { return length == 0; } }
2846

    
2847
      [Tested]
2848
      public override int Count { [Tested]get { return length; } }
2849

    
2850

    
2851
      public override Speed CountSpeed { get { return Speed.Constant; } }
2852

    
2853

    
2854
      public override T Choose()
2855
      {
2856
        if (length == 0)
2857
          throw new NoSuchItemException();
2858
        return tree[start];
2859
      }
2860

    
2861
      [Tested]
2862
      public override SCG.IEnumerator<T> GetEnumerator()
2863
      {
2864
#if MAINTAIN_SIZE
2865
        tree.modifycheck(stamp);
2866
#if BAG
2867
        int togo;
2868
#endif
2869
        Node cursor = tree.root;
2870
        Node[] path = new Node[2 * tree.blackdepth];
2871
        int level = 0, totaltogo = length;
2872

    
2873
        if (totaltogo == 0)
2874
          yield break;
2875

    
2876
        if (forwards)
2877
        {
2878
          int i = start;
2879

    
2880
          while (true)
2881
          {
2882
            int j = cursor.left == null ? 0 : cursor.left.size;
2883

    
2884
            if (i > j)
2885
            {
2886
#if BAG
2887
              i -= j + cursor.items;
2888
              if (i < 0)
2889
              {
2890
                togo = cursor.items + i;
2891
                break;
2892
              }
2893
#else
2894
              i -= j + 1;
2895
#endif
2896
              cursor = cursor.right;
2897
            }
2898
            else if (i == j)
2899
            {
2900
#if BAG
2901
              togo = cursor.items;
2902
#endif
2903
              break;
2904
            }
2905
            else
2906
            {
2907
              path[level++] = cursor;
2908
              cursor = cursor.left;
2909
            }
2910
          }
2911

    
2912
          T current = cursor.item;
2913

    
2914
          while (totaltogo-- > 0)
2915
          {
2916
            yield return current;
2917
            tree.modifycheck(stamp);
2918
#if BAG
2919
            if (--togo > 0)
2920
              continue;
2921
#endif
2922
            if (cursor.right != null)
2923
            {
2924
              path[level] = cursor = cursor.right;
2925
              while (cursor.left != null)
2926
                path[++level] = cursor = cursor.left;
2927
            }
2928
            else if (level == 0)
2929
              yield break;
2930
            else
2931
              cursor = path[--level];
2932

    
2933
            current = cursor.item;
2934
#if BAG
2935
            togo = cursor.items;
2936
#endif
2937
          }
2938
        }
2939
        else
2940
        {
2941
          int i = start + length - 1;
2942

    
2943
          while (true)
2944
          {
2945
            int j = cursor.left == null ? 0 : cursor.left.size;
2946

    
2947
            if (i > j)
2948
            {
2949
#if BAG
2950
              if (i - j < cursor.items)
2951
              {
2952
                togo = i - j + 1;
2953
                break;
2954
              }
2955
              i -= j + cursor.items;
2956
#else
2957
              i -= j + 1;
2958
#endif
2959
              path[level++] = cursor;
2960
              cursor = cursor.right;
2961
            }
2962
            else if (i == j)
2963
            {
2964
#if BAG
2965
              togo = 1;
2966
#endif
2967
              break;
2968
            }
2969
            else
2970
            {
2971
              cursor = cursor.left;
2972
            }
2973
          }
2974

    
2975
          T current = cursor.item;
2976

    
2977
          while (totaltogo-- > 0)
2978
          {
2979
            yield return current;
2980
            tree.modifycheck(stamp);
2981
#if BAG
2982
            if (--togo > 0)
2983
              continue;
2984
#endif
2985
            if (cursor.left != null)
2986
            {
2987
              path[level] = cursor = cursor.left;
2988
              while (cursor.right != null)
2989
                path[++level] = cursor = cursor.right;
2990
            }
2991
            else if (level == 0)
2992
              yield break;
2993
            else
2994
              cursor = path[--level];
2995

    
2996
            current = cursor.item;
2997
#if BAG
2998
            togo = cursor.items;
2999
#endif
3000
          }
3001
        }
3002

    
3003
#else
3004
			throw new NotSupportedException();
3005
#endif
3006
      }
3007

    
3008

    
3009
      [Tested]
3010
      public override IDirectedCollectionValue<T> Backwards()
3011
      { return new Interval(tree, start, length, !forwards); }
3012

    
3013

    
3014
      [Tested]
3015
      IDirectedEnumerable<T> C5.IDirectedEnumerable<T>.Backwards()
3016
      { return Backwards(); }
3017

    
3018

    
3019
      [Tested]
3020
      public override EnumerationDirection Direction
3021
      {
3022
        [Tested]
3023
        get
3024
        {
3025
          return forwards ? EnumerationDirection.Forwards : EnumerationDirection.Backwards;
3026
        }
3027
      }
3028
    }
3029
    #endregion
3030

    
3031
    /// <summary>
3032
    /// Create a collection containing the same items as this collection, but
3033
    /// whose enumerator will enumerate the items backwards. The new collection
3034
    /// will become invalid if the original is modified. Method typicaly used as in
3035
    /// <code>foreach (T x in coll.Backwards()) {...}</code>
3036
    /// </summary>
3037
    /// <returns>The backwards collection.</returns>
3038
    [Tested]
3039
    public override IDirectedCollectionValue<T> Backwards() { return RangeAll().Backwards(); }
3040

    
3041

    
3042
    [Tested]
3043
    IDirectedEnumerable<T> IDirectedEnumerable<T>.Backwards() { return Backwards(); }
3044

    
3045
    #endregion
3046

    
3047
    #region PriorityQueue Members
3048

    
3049
    /// <summary>
3050
    /// The comparer object supplied at creation time for this collection
3051
    /// </summary>
3052
    /// <value>The comparer</value>
3053
    public SCG.IComparer<T> Comparer { get { return comparer; } }
3054

    
3055

    
3056
    /// <summary>
3057
    /// Find the current least item of this priority queue.
3058
    /// </summary>
3059
    /// <returns>The least item.</returns>
3060
    [Tested]
3061
    public T FindMin()
3062
    {
3063
      if (!isValid)
3064
        throw new ViewDisposedException("Snapshot has been disposed");
3065
      if (size == 0)
3066
        throw new NoSuchItemException();
3067
      Node cursor = root, next = left(cursor);
3068

    
3069
      while (next != null)
3070
      {
3071
        cursor = next;
3072
        next = left(cursor);
3073
      }
3074

    
3075
      return cursor.item;
3076
    }
3077

    
3078

    
3079
    /// <summary>
3080
    /// Remove the least item from this  priority queue.
3081
    /// </summary>
3082
    /// <returns>The removed item.</returns>
3083
    [Tested]
3084
    public T DeleteMin()
3085
    {
3086
      if (!isValid)
3087
        throw new ViewDisposedException("Snapshot has been disposed");
3088
      updatecheck();
3089

    
3090
      //persistence guard?
3091
      if (size == 0)
3092
        throw new NoSuchItemException();
3093

    
3094
      //We must follow the pattern of removeIterative()
3095
      stackcheck();
3096

    
3097
      T retval = deleteMin();
3098
      if (ActiveEvents != 0)
3099
      {
3100
        raiseItemsRemoved(retval, 1);
3101
        raiseCollectionChanged();
3102
      }
3103
      return retval;
3104
    }
3105

    
3106
    private T deleteMin()
3107
    {
3108
      int level = 0;
3109
      Node cursor = root;
3110

    
3111
      while (cursor.left != null)
3112
      {
3113
        dirs[level] = 1;
3114
        path[level++] = cursor;
3115
        cursor = cursor.left;
3116
      }
3117

    
3118
      T retval = cursor.item;
3119

    
3120
#if BAG
3121
      if (cursor.items > 1)
3122
      {
3123
        resplicebag(level, cursor);
3124
        size--;
3125
        return retval;
3126
      }
3127
#endif
3128
      removeIterativePhase2(cursor, level);
3129
      return retval;
3130
    }
3131

    
3132

    
3133
    /// <summary>
3134
    /// Find the current largest item of this priority queue.
3135
    /// </summary>
3136
    /// <returns>The largest item.</returns>
3137
    [Tested]
3138
    public T FindMax()
3139
    {
3140
      if (!isValid)
3141
        throw new ViewDisposedException("Snapshot has been disposed");
3142
      if (size == 0)
3143
        throw new NoSuchItemException();
3144

    
3145
      Node cursor = root, next = right(cursor);
3146

    
3147
      while (next != null)
3148
      {
3149
        cursor = next;
3150
        next = right(cursor);
3151
      }
3152

    
3153
      return cursor.item;
3154
    }
3155

    
3156

    
3157
    /// <summary>
3158
    /// Remove the largest item from this  priority queue.
3159
    /// </summary>
3160
    /// <returns>The removed item.</returns>
3161
    [Tested]
3162
    public T DeleteMax()
3163
    {
3164
      if (!isValid)
3165
        throw new ViewDisposedException("Snapshot has been disposed");
3166
      //persistence guard?
3167
      updatecheck();
3168
      if (size == 0)
3169
        throw new NoSuchItemException();
3170

    
3171
      //We must follow the pattern of removeIterative()
3172
      stackcheck();
3173

    
3174
      T retval = deleteMax();
3175
      if (ActiveEvents != 0)
3176
      {
3177
        raiseItemsRemoved(retval, 1);
3178
        raiseCollectionChanged();
3179
      }
3180
      return retval;
3181
    }
3182

    
3183
    private T deleteMax()
3184
    {
3185
      int level = 0;
3186
      Node cursor = root;
3187

    
3188
      while (cursor.right != null)
3189
      {
3190
        dirs[level] = -1;
3191
        path[level++] = cursor;
3192
        cursor = cursor.right;
3193
      }
3194

    
3195
      T retval = cursor.item;
3196

    
3197
#if BAG
3198
      if (cursor.items > 1)
3199
      {
3200
        resplicebag(level, cursor);
3201
        size--;
3202
        return retval;
3203
      }
3204
#endif
3205
      removeIterativePhase2(cursor, level);
3206
      return retval;
3207
    }
3208
    #endregion
3209

    
3210
    #region ISorted<T> Members
3211

    
3212
    /// <summary>
3213
    /// Find the strict predecessor of item in the sorted collection,
3214
    /// that is, the greatest item in the collection smaller than the item.
3215
    /// </summary>
3216
    /// <param name="item">The item to find the predecessor for.</param>
3217
    /// <param name="res">The predecessor, if any; otherwise the default value for T.</param>
3218
    /// <returns>True if item has a predecessor; otherwise false.</returns>
3219
    public bool TryPredecessor(T item, out T res)
3220
    {
3221
        if (!isValid)
3222
            throw new ViewDisposedException("Snapshot has been disposed");
3223
        Node cursor = root, bestsofar = null;
3224

    
3225
        while (cursor != null)
3226
        {
3227
            int comp = comparer.Compare(cursor.item, item);
3228

    
3229
            if (comp < 0)
3230
            {
3231
                bestsofar = cursor;
3232
                cursor = right(cursor);
3233
            }
3234
            else if (comp == 0)
3235
            {
3236
                cursor = left(cursor);
3237
                while (cursor != null)
3238
                {
3239
                    bestsofar = cursor;
3240
                    cursor = right(cursor);
3241
                }
3242
            }
3243
            else
3244
                cursor = left(cursor);
3245
        }
3246
        if (bestsofar == null)
3247
        {
3248
            res = default(T);
3249
            return false;
3250
        }
3251
        else
3252
        {
3253
            res = bestsofar.item;
3254
            return true;
3255
        }
3256
    }
3257

    
3258

    
3259
    /// <summary>
3260
    /// Find the strict successor of item in the sorted collection,
3261
    /// that is, the least item in the collection greater than the supplied value.
3262
    /// </summary>
3263
    /// <param name="item">The item to find the successor for.</param>
3264
    /// <param name="res">The successor, if any; otherwise the default value for T.</param>
3265
    /// <returns>True if item has a successor; otherwise false.</returns>
3266
    public bool TrySuccessor(T item, out T res)
3267
    {
3268
        if (!isValid)
3269
            throw new ViewDisposedException("Snapshot has been disposed");
3270
        Node cursor = root, bestsofar = null;
3271

    
3272
        while (cursor != null)
3273
        {
3274
            int comp = comparer.Compare(cursor.item, item);
3275

    
3276
            if (comp > 0)
3277
            {
3278
                bestsofar = cursor;
3279
                cursor = left(cursor);
3280
            }
3281
            else if (comp == 0)
3282
            {
3283
                cursor = right(cursor);
3284
                while (cursor != null)
3285
                {
3286
                    bestsofar = cursor;
3287
                    cursor = left(cursor);
3288
                }
3289
            }
3290
            else
3291
                cursor = right(cursor);
3292
        }
3293

    
3294
        if (bestsofar == null)
3295
        {
3296
            res = default(T);
3297
            return false;
3298
        }
3299
        else
3300
        {
3301
            res = bestsofar.item;
3302
            return true;
3303
        }
3304
    }
3305

    
3306

    
3307
    /// <summary>
3308
    /// Find the weak predecessor of item in the sorted collection,
3309
    /// that is, the greatest item in the collection smaller than or equal to the item.
3310
    /// </summary>
3311
    /// <param name="item">The item to find the weak predecessor for.</param>
3312
    /// <param name="res">The weak predecessor, if any; otherwise the default value for T.</param>
3313
    /// <returns>True if item has a weak predecessor; otherwise false.</returns>
3314
    public bool TryWeakPredecessor(T item, out T res)
3315
    {
3316
        if (!isValid)
3317
            throw new ViewDisposedException("Snapshot has been disposed");
3318
        Node cursor = root, bestsofar = null;
3319

    
3320
        while (cursor != null)
3321
        {
3322
            int comp = comparer.Compare(cursor.item, item);
3323

    
3324
            if (comp < 0)
3325
            {
3326
                bestsofar = cursor;
3327
                cursor = right(cursor);
3328
            }
3329
            else if (comp == 0)
3330
            {
3331
                res = cursor.item;
3332
                return true;
3333
            }
3334
            else
3335
                cursor = left(cursor);
3336
        }
3337
        if (bestsofar == null)
3338
        {
3339
            res = default(T);
3340
            return false;
3341
        }
3342
        else
3343
        {
3344
            res = bestsofar.item;
3345
            return true;
3346
        }
3347
    }
3348

    
3349

    
3350
    /// <summary>
3351
    /// Find the weak successor of item in the sorted collection,
3352
    /// that is, the least item in the collection greater than or equal to the supplied value.
3353
    /// </summary>
3354
    /// <param name="item">The item to find the weak successor for.</param>
3355
    /// <param name="res">The weak successor, if any; otherwise the default value for T.</param>
3356
    /// <returns>True if item has a weak successor; otherwise false.</returns>
3357
    public bool TryWeakSuccessor(T item, out T res)
3358
    {
3359
        if (!isValid)
3360
            throw new ViewDisposedException("Snapshot has been disposed");
3361
        Node cursor = root, bestsofar = null;
3362

    
3363
        while (cursor != null)
3364
        {
3365
            int comp = comparer.Compare(cursor.item, item);
3366

    
3367
            if (comp == 0)
3368
            {
3369
                res = cursor.item;
3370
                return true;
3371
            }
3372
            else if (comp > 0)
3373
            {
3374
                bestsofar = cursor;
3375
                cursor = left(cursor);
3376
            }
3377
            else
3378
                cursor = right(cursor);
3379
        }
3380

    
3381
        if (bestsofar == null)
3382
        {
3383
            res = default(T);
3384
            return false;
3385
        }
3386
        else
3387
        {
3388
            res = bestsofar.item;
3389
            return true;
3390
        }
3391
    }
3392

    
3393

    
3394
    /// <summary>
3395
    /// Find the strict predecessor in the sorted collection of a particular value,
3396
    /// i.e. the largest item in the collection less than the supplied value.
3397
    /// </summary>
3398
    /// <exception cref="NoSuchItemException"> if no such element exists (the
3399
    /// supplied  value is less than or equal to the minimum of this collection.)</exception>
3400
    /// <param name="item">The item to find the predecessor for.</param>
3401
    /// <returns>The predecessor.</returns>
3402
    [Tested]
3403
    public T Predecessor(T item)
3404
    {
3405
        T res;
3406
        if (TryPredecessor(item, out res))
3407
            return res;
3408
        else
3409
            throw new NoSuchItemException();
3410
    }
3411

    
3412

    
3413
    /// <summary>
3414
    /// Find the weak predecessor in the sorted collection of a particular value,
3415
    /// i.e. the largest item in the collection less than or equal to the supplied value.
3416
    /// </summary>
3417
    /// <exception cref="NoSuchItemException"> if no such element exists (the
3418
    /// supplied  value is less than the minimum of this collection.)</exception>
3419
    /// <param name="item">The item to find the weak predecessor for.</param>
3420
    /// <returns>The weak predecessor.</returns>
3421
    [Tested]
3422
    public T WeakPredecessor(T item)
3423
    {
3424
        T res;
3425
        if (TryWeakPredecessor(item, out res))
3426
            return res;
3427
        else
3428
            throw new NoSuchItemException();
3429
    }
3430

    
3431

    
3432
    /// <summary>
3433
    /// Find the strict successor in the sorted collection of a particular value,
3434
    /// i.e. the least item in the collection greater than the supplied value.
3435
    /// </summary>
3436
    /// <exception cref="NoSuchItemException"> if no such element exists (the
3437
    /// supplied  value is greater than or equal to the maximum of this collection.)</exception>
3438
    /// <param name="item">The item to find the successor for.</param>
3439
    /// <returns>The successor.</returns>
3440
    [Tested]
3441
    public T Successor(T item)
3442
    {
3443
        T res;
3444
        if (TrySuccessor(item, out res))
3445
            return res;
3446
        else
3447
            throw new NoSuchItemException();
3448
    }
3449

    
3450

    
3451
    /// <summary>
3452
    /// Find the weak successor in the sorted collection of a particular value,
3453
    /// i.e. the least item in the collection greater than or equal to the supplied value.
3454
    /// <exception cref="NoSuchItemException"> if no such element exists (the
3455
    /// supplied  value is greater than the maximum of this collection.)</exception>
3456
    /// </summary>
3457
    /// <param name="item">The item to find the weak successor for.</param>
3458
    /// <returns>The weak successor.</returns>
3459
    [Tested]
3460
    public T WeakSuccessor(T item)
3461
    {
3462
        T res;
3463
        if (TryWeakSuccessor(item, out res))
3464
            return res;
3465
        else
3466
            throw new NoSuchItemException();
3467
    }
3468

    
3469
   
3470
    /// <summary>
3471
    /// Query this sorted collection for items greater than or equal to a supplied value.
3472
    /// </summary>
3473
    /// <param name="bot">The lower bound (inclusive).</param>
3474
    /// <returns>The result directed collection.</returns>
3475
    [Tested]
3476
    public IDirectedCollectionValue<T> RangeFrom(T bot)
3477
    {
3478
      if (!isValid)
3479
        throw new ViewDisposedException("Snapshot has been disposed");
3480
      return new Range(this, true, bot, false, default(T), EnumerationDirection.Forwards);
3481
    }
3482

    
3483

    
3484
    /// <summary>
3485
    /// Query this sorted collection for items between two supplied values.
3486
    /// </summary>
3487
    /// <param name="bot">The lower bound (inclusive).</param>
3488
    /// <param name="top">The upper bound (exclusive).</param>
3489
    /// <returns>The result directed collection.</returns>
3490
    [Tested]
3491
    public IDirectedCollectionValue<T> RangeFromTo(T bot, T top)
3492
    {
3493
      if (!isValid)
3494
        throw new ViewDisposedException("Snapshot has been disposed");
3495
      return new Range(this, true, bot, true, top, EnumerationDirection.Forwards);
3496
    }
3497

    
3498

    
3499
    /// <summary>
3500
    /// Query this sorted collection for items less than a supplied value.
3501
    /// </summary>
3502
    /// <param name="top">The upper bound (exclusive).</param>
3503
    /// <returns>The result directed collection.</returns>
3504
    [Tested]
3505
    public IDirectedCollectionValue<T> RangeTo(T top)
3506
    {
3507
      if (!isValid)
3508
        throw new ViewDisposedException("Snapshot has been disposed");
3509
      return new Range(this, false, default(T), true, top, EnumerationDirection.Forwards);
3510
    }
3511

    
3512

    
3513
    /// <summary>
3514
    /// Create a directed collection with the same items as this collection.
3515
    /// </summary>
3516
    /// <returns>The result directed collection.</returns>
3517
    [Tested]
3518
    public IDirectedCollectionValue<T> RangeAll()
3519
    {
3520
      if (!isValid)
3521
        throw new ViewDisposedException("Snapshot has been disposed");
3522
      return new Range(this, false, default(T), false, default(T), EnumerationDirection.Forwards);
3523
    }
3524

    
3525

    
3526
    [Tested]
3527
    IDirectedEnumerable<T> ISorted<T>.RangeFrom(T bot) { return RangeFrom(bot); }
3528

    
3529

    
3530
    [Tested]
3531
    IDirectedEnumerable<T> ISorted<T>.RangeFromTo(T bot, T top) { return RangeFromTo(bot, top); }
3532

    
3533

    
3534
    [Tested]
3535
    IDirectedEnumerable<T> ISorted<T>.RangeTo(T top) { return RangeTo(top); }
3536

    
3537

    
3538
    //Utility for CountXxxx. Actually always called with strict = true.
3539
    private int countTo(T item, bool strict)
3540
    {
3541
#if NCP
3542
      if (isSnapShot)
3543
        throw new NotSupportedException("Indexing not supported for snapshots");
3544
#endif
3545
#if MAINTAIN_SIZE
3546
      int ind = 0, comp = 0; Node next = root;
3547

    
3548
      while (next != null)
3549
      {
3550
        comp = comparer.Compare(item, next.item);
3551
        if (comp < 0)
3552
          next = next.left;
3553
        else
3554
        {
3555
          int leftcnt = next.left == null ? 0 : next.left.size;
3556
#if BAG
3557
          if (comp == 0)
3558
            return strict ? ind + leftcnt : ind + leftcnt + next.items;
3559
          else
3560
          {
3561
            ind = ind + next.items + leftcnt;
3562
            next = next.right;
3563
          }
3564
#else
3565
          if (comp == 0)
3566
            return strict ? ind + leftcnt : ind + leftcnt + 1;
3567
          else
3568
          {
3569
            ind = ind + 1 + leftcnt;
3570
            next = next.right;
3571
          }
3572
#endif
3573
        }
3574
      }
3575

    
3576
      //if we get here, we are at the same side of the whole collection:
3577
      return ind;
3578
#else
3579
			throw new NotSupportedException("Code compiled w/o size!");
3580
#endif
3581
    }
3582

    
3583

    
3584
    /// <summary>
3585
    /// Perform a search in the sorted collection for the ranges in which a
3586
    /// non-increasing (i.e. weakly decrerasing) function from the item type to 
3587
    /// <code>int</code> is
3588
    /// negative, zero respectively positive. If the supplied cut function is
3589
    /// not non-increasing, the result of this call is undefined.
3590
    /// </summary>
3591
    /// <param name="c">The cut function <code>T</code> to <code>int</code>, given
3592
    /// as an <code>IComparable&lt;T&gt;</code> object, where the cut function is
3593
    /// the <code>c.CompareTo(T that)</code> method.</param>
3594
    /// <param name="low">Returns the largest item in the collection, where the
3595
    /// cut function is positive (if any).</param>
3596
    /// <param name="lowIsValid">True if the cut function is positive somewhere
3597
    /// on this collection.</param>
3598
    /// <param name="high">Returns the least item in the collection, where the
3599
    /// cut function is negative (if any).</param>
3600
    /// <param name="highIsValid">True if the cut function is negative somewhere
3601
    /// on this collection.</param>
3602
    /// <returns></returns>
3603
    [Tested]
3604
    public bool Cut(IComparable<T> c, out T low, out bool lowIsValid, out T high, out bool highIsValid)
3605
    {
3606
      if (!isValid)
3607
        throw new ViewDisposedException("Snapshot has been disposed");
3608
      Node cursor = root, lbest = null, rbest = null;
3609
      bool res = false;
3610

    
3611
      while (cursor != null)
3612
      {
3613
        int comp = c.CompareTo(cursor.item);
3614

    
3615
        if (comp > 0)
3616
        {
3617
          lbest = cursor;
3618
          cursor = right(cursor);
3619
        }
3620
        else if (comp < 0)
3621
        {
3622
          rbest = cursor;
3623
          cursor = left(cursor);
3624
        }
3625
        else
3626
        {
3627
          res = true;
3628

    
3629
          Node tmp = left(cursor);
3630

    
3631
          while (tmp != null && c.CompareTo(tmp.item) == 0)
3632
            tmp = left(tmp);
3633

    
3634
          if (tmp != null)
3635
          {
3636
            lbest = tmp;
3637
            tmp = right(tmp);
3638
            while (tmp != null)
3639
            {
3640
              if (c.CompareTo(tmp.item) > 0)
3641
              {
3642
                lbest = tmp;
3643
                tmp = right(tmp);
3644
              }
3645
              else
3646
                tmp = left(tmp);
3647
            }
3648
          }
3649

    
3650
          tmp = right(cursor);
3651
          while (tmp != null && c.CompareTo(tmp.item) == 0)
3652
            tmp = right(tmp);
3653

    
3654
          if (tmp != null)
3655
          {
3656
            rbest = tmp;
3657
            tmp = left(tmp);
3658
            while (tmp != null)
3659
            {
3660
              if (c.CompareTo(tmp.item) < 0)
3661
              {
3662
                rbest = tmp;
3663
                tmp = left(tmp);
3664
              }
3665
              else
3666
                tmp = right(tmp);
3667
            }
3668
          }
3669

    
3670
          break;
3671
        }
3672
      }
3673

    
3674
      if (highIsValid = (rbest != null))
3675
        high = rbest.item;
3676
      else
3677
        high = default(T);
3678

    
3679
      if (lowIsValid = (lbest != null))
3680
        low = lbest.item;
3681
      else
3682
        low = default(T);
3683

    
3684
      return res;
3685
    }
3686

    
3687

    
3688
    /// <summary>
3689
    /// Determine the number of items at or above a supplied threshold.
3690
    /// </summary>
3691
    /// <param name="bot">The lower bound (inclusive)</param>
3692
    /// <returns>The number of matcing items.</returns>
3693
    [Tested]
3694
    public int CountFrom(T bot)
3695
    {
3696
      if (!isValid)
3697
        throw new ViewDisposedException("Snapshot has been disposed");
3698
      return size - countTo(bot, true);
3699
    }
3700

    
3701

    
3702
    /// <summary>
3703
    /// Determine the number of items between two supplied thresholds.
3704
    /// </summary>
3705
    /// <param name="bot">The lower bound (inclusive)</param>
3706
    /// <param name="top">The upper bound (exclusive)</param>
3707
    /// <returns>The number of matcing items.</returns>
3708
    [Tested]
3709
    public int CountFromTo(T bot, T top)
3710
    {
3711
      if (!isValid)
3712
        throw new ViewDisposedException("Snapshot has been disposed");
3713
      if (comparer.Compare(bot, top) >= 0)
3714
        return 0;
3715

    
3716
      return countTo(top, true) - countTo(bot, true);
3717
    }
3718

    
3719

    
3720
    /// <summary>
3721
    /// Determine the number of items below a supplied threshold.
3722
    /// </summary>
3723
    /// <param name="top">The upper bound (exclusive)</param>
3724
    /// <returns>The number of matcing items.</returns>
3725
    [Tested]
3726
    public int CountTo(T top)
3727
    {
3728
      if (!isValid)
3729
        throw new ViewDisposedException("Snapshot has been disposed");
3730
      return countTo(top, true);
3731
    }
3732

    
3733

    
3734
    /// <summary>
3735
    /// Remove all items of this collection above or at a supplied threshold.
3736
    /// </summary>
3737
    /// <param name="low">The lower threshold (inclusive).</param>
3738
    [Tested]
3739
    public void RemoveRangeFrom(T low)
3740
    {
3741
      if (!isValid)
3742
        throw new ViewDisposedException("Snapshot has been disposed");
3743
      updatecheck();
3744

    
3745
      int count = CountFrom(low);
3746

    
3747
      if (count == 0)
3748
        return;
3749

    
3750
      stackcheck();
3751
      CircularQueue<T> wasRemoved = (ActiveEvents & EventTypeEnum.Removed) != 0 ? new CircularQueue<T>() : null;
3752

    
3753
      for (int i = 0; i < count; i++)
3754
      {
3755
        T item = deleteMax();
3756
        if (wasRemoved != null)
3757
          wasRemoved.Enqueue(item);
3758
      }
3759
      if (wasRemoved != null)
3760
        raiseForRemoveAll(wasRemoved);
3761
      else if ((ActiveEvents & EventTypeEnum.Changed) != 0)
3762
        raiseCollectionChanged();
3763
    }
3764

    
3765

    
3766
    /// <summary>
3767
    /// Remove all items of this collection between two supplied thresholds.
3768
    /// </summary>
3769
    /// <param name="low">The lower threshold (inclusive).</param>
3770
    /// <param name="hi">The upper threshold (exclusive).</param>
3771
    [Tested]
3772
    public void RemoveRangeFromTo(T low, T hi)
3773
    {
3774
      if (!isValid)
3775
        throw new ViewDisposedException("Snapshot has been disposed");
3776
      updatecheck();
3777

    
3778
      int count = CountFromTo(low, hi);
3779

    
3780
      if (count == 0)
3781
        return;
3782

    
3783
      CircularQueue<T> wasRemoved = (ActiveEvents & EventTypeEnum.Removed) != 0 ? new CircularQueue<T>() : null;
3784
      int junk;
3785
      for (int i = 0; i < count; i++)
3786
      {
3787
        T item = Predecessor(hi);
3788
        removeIterative(ref item, false, out junk);
3789
        if (wasRemoved != null)
3790
          wasRemoved.Enqueue(item);
3791
      }
3792
      if (wasRemoved != null)
3793
        raiseForRemoveAll(wasRemoved);
3794
      else if ((ActiveEvents & EventTypeEnum.Changed) != 0)
3795
        raiseCollectionChanged();
3796
    }
3797

    
3798

    
3799
    /// <summary>
3800
    /// Remove all items of this collection below a supplied threshold.
3801
    /// </summary>
3802
    /// <param name="hi">The upper threshold (exclusive).</param>
3803
    [Tested]
3804
    public void RemoveRangeTo(T hi)
3805
    {
3806
      if (!isValid)
3807
        throw new ViewDisposedException("Snapshot has been disposed");
3808
      updatecheck();
3809

    
3810
      int count = CountTo(hi);
3811

    
3812
      if (count == 0)
3813
        return;
3814

    
3815
      stackcheck();
3816
      CircularQueue<T> wasRemoved = (ActiveEvents & EventTypeEnum.Removed) != 0 ? new CircularQueue<T>() : null;
3817

    
3818
      for (int i = 0; i < count; i++)
3819
      {
3820
        T item = deleteMin();
3821
        if (wasRemoved != null)
3822
          wasRemoved.Enqueue(item);
3823
      }
3824
      if (wasRemoved != null)
3825
        raiseForRemoveAll(wasRemoved);
3826
      else if ((ActiveEvents & EventTypeEnum.Changed) != 0)
3827
        raiseCollectionChanged();
3828
    }
3829

    
3830
    #endregion
3831

    
3832
    #region IPersistent<T> Members
3833
#if NCP
3834
    int maxsnapid { get { return snapList == null ? -1 : findLastLiveSnapShot(); } }
3835

    
3836
    int findLastLiveSnapShot()
3837
    {
3838
      if (snapList == null)
3839
        return -1;
3840
      SnapRef lastLiveSnapRef = snapList.Prev;
3841
      object _snapshot = null;
3842
      while (lastLiveSnapRef != null && (_snapshot = lastLiveSnapRef.Tree.Target) == null)
3843
        lastLiveSnapRef = lastLiveSnapRef.Prev;
3844
      if (lastLiveSnapRef == null)
3845
      {
3846
        snapList = null;
3847
        return -1;
3848
      }
3849
      if (snapList.Prev != lastLiveSnapRef)
3850
      {
3851
        snapList.Prev = lastLiveSnapRef;
3852
        lastLiveSnapRef.Next = snapList;
3853
      }
3854
      return ((TreeBag<T>)_snapshot).generation;
3855
    }
3856

    
3857
    [Serializable]
3858
    class SnapRef
3859
    {
3860
      public SnapRef Prev, Next;
3861
      public WeakReference Tree;
3862
      public SnapRef(TreeBag<T> tree) { Tree = new WeakReference(tree); }
3863
      public void Dispose()
3864
      {
3865
        Next.Prev = Prev;
3866
        if (Prev != null)
3867
          Prev.Next = Next;
3868
        Next = Prev = null;
3869
      }
3870
    }
3871
#endif
3872

    
3873
    /// <summary>
3874
    /// If this tree is a snapshot, remove registration in base tree
3875
    /// </summary>
3876
    [Tested]
3877
    public void Dispose()
3878
    {
3879
#if NCP
3880
      if (!isValid)
3881
        return;
3882
      if (isSnapShot)
3883
      {
3884
        snapList.Dispose();
3885
        snapDispose();
3886
      }
3887
      else
3888
      {
3889
        if (snapList != null)
3890
        {
3891
          SnapRef someSnapRef = snapList.Prev;
3892
          while (someSnapRef != null)
3893
          {
3894
            TreeBag<T> lastsnap;
3895
            if ((lastsnap = someSnapRef.Tree.Target as TreeBag<T>) != null)
3896
              lastsnap.snapDispose();
3897
            someSnapRef = someSnapRef.Prev;
3898
          }
3899
        }
3900
        snapList = null;
3901
        Clear();
3902
      }
3903
#else
3904
      Clear();
3905
#endif
3906
    }
3907

    
3908
    private void snapDispose()
3909
    {
3910
      root = null;
3911
      dirs = null;
3912
      path = null;
3913
      comparer = null;
3914
      isValid = false;
3915
      snapList = null;
3916
    }
3917

    
3918
    /// <summary>
3919
    /// Make a (read-only) snapshot of this collection.
3920
    /// </summary>
3921
    /// <returns>The snapshot.</returns>
3922
    [Tested]
3923
    public ISorted<T> Snapshot()
3924
    {
3925
#if NCP
3926
      if (isSnapShot)
3927
        throw new InvalidOperationException("Cannot snapshot a snapshot");
3928

    
3929
      TreeBag<T> res = (TreeBag<T>)MemberwiseClone();
3930
      SnapRef newSnapRef = new SnapRef(res);
3931
      res.isReadOnlyBase = true;
3932
      res.isSnapShot = true;
3933
      res.snapList = newSnapRef;
3934

    
3935
      findLastLiveSnapShot();
3936
      if (snapList == null)
3937
        snapList = new SnapRef(this);
3938
      SnapRef lastLiveSnapRef = snapList.Prev;
3939

    
3940
      newSnapRef.Prev = lastLiveSnapRef;
3941
      if (lastLiveSnapRef != null)
3942
        lastLiveSnapRef.Next = newSnapRef;
3943
      newSnapRef.Next = snapList;
3944
      snapList.Prev = newSnapRef;
3945

    
3946
      generation++;
3947

    
3948
      return res;
3949
#endif
3950
    }
3951

    
3952
    #endregion
3953

    
3954
    #region TreeBag.Range nested class
3955

    
3956
    internal class Range : DirectedCollectionValueBase<T>, IDirectedCollectionValue<T>
3957
    {
3958
      //We actually need exclusive upper and lower bounds, and flags to 
3959
      //indicate whether the bound is present (we canot rely on default(T))
3960
      private int stamp, size;
3961

    
3962
      private TreeBag<T> basis;
3963

    
3964
      private T lowend, highend;
3965

    
3966
      private bool haslowend, hashighend;
3967

    
3968
      EnumerationDirection direction;
3969

    
3970

    
3971
      [Tested]
3972
      public Range(TreeBag<T> basis, bool haslowend, T lowend, bool hashighend, T highend, EnumerationDirection direction)
3973
      {
3974
        this.basis = basis;
3975
        stamp = basis.stamp;
3976

    
3977
        //lowind will be const; should we cache highind?
3978
        this.lowend = lowend; //Inclusive
3979
        this.highend = highend;//Exclusive
3980
        this.haslowend = haslowend;
3981
        this.hashighend = hashighend;
3982
        this.direction = direction;
3983
        if (!basis.isSnapShot)
3984
          size = haslowend ?
3985
              (hashighend ? basis.CountFromTo(lowend, highend) : basis.CountFrom(lowend)) :
3986
              (hashighend ? basis.CountTo(highend) : basis.Count);
3987
      }
3988

    
3989
      #region IEnumerable<T> Members
3990

    
3991

    
3992
      #region TreeBag.Range.Enumerator nested class
3993

    
3994
      internal class Enumerator : SCG.IEnumerator<T>
3995
      {
3996
        #region Private Fields
3997
        private bool valid = false, ready = true;
3998

    
3999
        private SCG.IComparer<T> comparer;
4000

    
4001
        private T current;
4002
#if BAG
4003
        int togo;
4004
#endif
4005

    
4006
        private Node cursor;
4007

    
4008
        private Node[] path; // stack of nodes
4009

    
4010
        private int level = 0;
4011

    
4012
        private Range range;
4013

    
4014
        private bool forwards;
4015

    
4016
        #endregion
4017
        [Tested]
4018
        public Enumerator(Range range)
4019
        {
4020
          comparer = range.basis.comparer;
4021
          path = new Node[2 * range.basis.blackdepth];
4022
          this.range = range;
4023
          forwards = range.direction == EnumerationDirection.Forwards;
4024
          cursor = new Node();
4025
          if (forwards)
4026
            cursor.right = range.basis.root;
4027
          else
4028
            cursor.left = range.basis.root;
4029
          range.basis.modifycheck(range.stamp);
4030
        }
4031

    
4032

    
4033
        int compare(T i1, T i2) { return comparer.Compare(i1, i2); }
4034

    
4035

    
4036
        /// <summary>
4037
        /// Undefined if enumerator is not valid (MoveNext hash been called returning true)
4038
        /// </summary>
4039
        /// <value>The current value of the enumerator.</value>
4040
        [Tested]
4041
        public T Current
4042
        {
4043
          [Tested]
4044
          get
4045
          {
4046
            if (valid)
4047
              return current;
4048
            else
4049
              throw new InvalidOperationException();
4050
          }
4051
        }
4052

    
4053

    
4054
        //Maintain a stack of nodes that are roots of
4055
        //subtrees not completely exported yet. Invariant:
4056
        //The stack nodes together with their right subtrees
4057
        //consists of exactly the items we have not passed
4058
        //yet (the top of the stack holds current item).
4059
        /// <summary>
4060
        /// Move enumerator to next item in tree, or the first item if
4061
        /// this is the first call to MoveNext. 
4062
        /// <exception cref="CollectionModifiedException"/> if underlying tree was modified.
4063
        /// </summary>
4064
        /// <returns>True if enumerator is valid now</returns>
4065
        [Tested]
4066
        public bool MoveNext()
4067
        {
4068
          range.basis.modifycheck(range.stamp);
4069
          if (!ready)
4070
            return false;
4071
#if BAG
4072
          if (--togo > 0)
4073
            return true;
4074
#endif
4075
          if (forwards)
4076
          {
4077
            if (!valid && range.haslowend)
4078
            {
4079
              cursor = cursor.right;
4080
              while (cursor != null)
4081
              {
4082
                int comp = compare(cursor.item, range.lowend);
4083

    
4084
                if (comp > 0)
4085
                {
4086
                  path[level++] = cursor;
4087
#if NCP
4088
                  cursor = range.basis.left(cursor);
4089
#else
4090
									cursor = cursor.left;
4091
#endif
4092
                }
4093
                else if (comp < 0)
4094
                {
4095
#if NCP
4096
                  cursor = range.basis.right(cursor);
4097
#else
4098
									cursor = cursor.right;
4099
#endif
4100
                }
4101
                else
4102
                {
4103
                  path[level] = cursor;
4104
                  break;
4105
                }
4106
              }
4107

    
4108
              if (cursor == null)
4109
              {
4110
                if (level == 0)
4111
                  return valid = ready = false;
4112
                else
4113
                  cursor = path[--level];
4114
              }
4115
            }
4116
#if NCP
4117
            else if (range.basis.right(cursor) != null)
4118
            {
4119
              path[level] = cursor = range.basis.right(cursor);
4120

    
4121
              Node next = range.basis.left(cursor);
4122

    
4123
              while (next != null)
4124
              {
4125
                path[++level] = cursor = next;
4126
                next = range.basis.left(cursor);
4127
              }
4128
            }
4129
#else
4130
						else if (cursor.right != null)
4131
						{
4132
							path[level] = cursor = cursor.right;
4133
							while (cursor.left != null)
4134
								path[++level] = cursor = cursor.left;
4135
						}
4136
#endif
4137
            else if (level == 0)
4138
              return valid = ready = false;
4139
            else
4140
              cursor = path[--level];
4141

    
4142
            current = cursor.item;
4143
            if (range.hashighend && compare(current, range.highend) >= 0)
4144
              return valid = ready = false;
4145

    
4146
#if BAG
4147
            togo = cursor.items;
4148
#endif
4149
            return valid = true;
4150
          }
4151
          else
4152
          {
4153
            if (!valid && range.hashighend)
4154
            {
4155
              cursor = cursor.left;
4156
              while (cursor != null)
4157
              {
4158
                int comp = compare(cursor.item, range.highend);
4159

    
4160
                if (comp < 0)
4161
                {
4162
                  path[level++] = cursor;
4163
#if NCP
4164
                  cursor = range.basis.right(cursor);
4165
#else
4166
									cursor = cursor.right;
4167
#endif
4168
                }
4169
                else
4170
                {
4171
#if NCP
4172
                  cursor = range.basis.left(cursor);
4173
#else
4174
									cursor = cursor.left;
4175
#endif
4176
                }
4177
              }
4178

    
4179
              if (cursor == null)
4180
              {
4181
                if (level == 0)
4182
                  return valid = ready = false;
4183
                else
4184
                  cursor = path[--level];
4185
              }
4186
            }
4187
#if NCP
4188
            else if (range.basis.left(cursor) != null)
4189
            {
4190
              path[level] = cursor = range.basis.left(cursor);
4191

    
4192
              Node next = range.basis.right(cursor);
4193

    
4194
              while (next != null)
4195
              {
4196
                path[++level] = cursor = next;
4197
                next = range.basis.right(cursor);
4198
              }
4199
            }
4200
#else
4201
						else if (cursor.left != null)
4202
						{
4203
							path[level] = cursor = cursor.left;
4204
							while (cursor.right != null)
4205
								path[++level] = cursor = cursor.right;
4206
						}
4207
#endif
4208
            else if (level == 0)
4209
              return valid = ready = false;
4210
            else
4211
              cursor = path[--level];
4212

    
4213
            current = cursor.item;
4214
            if (range.haslowend && compare(current, range.lowend) < 0)
4215
              return valid = ready = false;
4216

    
4217
#if BAG
4218
            togo = cursor.items;
4219
#endif
4220
            return valid = true;
4221
          }
4222
        }
4223

    
4224

    
4225
        [Tested]
4226
        public void Dispose()
4227
        {
4228
          comparer = null;
4229
          current = default(T);
4230
          cursor = null;
4231
          path = null;
4232
          range = null;
4233
        }
4234

    
4235
        #region IEnumerator Members
4236

    
4237
        object System.Collections.IEnumerator.Current
4238
        {
4239
          get { return Current; }
4240
        }
4241

    
4242
        bool System.Collections.IEnumerator.MoveNext()
4243
        {
4244
          return MoveNext();
4245
        }
4246

    
4247
        void System.Collections.IEnumerator.Reset()
4248
        {
4249
          throw new Exception("The method or operation is not implemented.");
4250
        }
4251

    
4252
        #endregion
4253
      }
4254

    
4255
      #endregion
4256

    
4257

    
4258
      public override T Choose()
4259
      {
4260
        if (size == 0) throw new NoSuchItemException();
4261
        return lowend;
4262
      }
4263

    
4264
      [Tested]
4265
      public override SCG.IEnumerator<T> GetEnumerator() { return new Enumerator(this); }
4266

    
4267

    
4268
      [Tested]
4269
      public override EnumerationDirection Direction { [Tested]get { return direction; } }
4270

    
4271

    
4272
      #endregion
4273

    
4274
      #region Utility
4275

    
4276
      bool inside(T item)
4277
      {
4278
        return (!haslowend || basis.comparer.Compare(item, lowend) >= 0) && (!hashighend || basis.comparer.Compare(item, highend) < 0);
4279
      }
4280

    
4281

    
4282
      void checkstamp()
4283
      {
4284
        if (stamp < basis.stamp)
4285
          throw new CollectionModifiedException();
4286
      }
4287

    
4288

    
4289
      void syncstamp() { stamp = basis.stamp; }
4290

    
4291
      #endregion
4292

    
4293
      [Tested]
4294
      public override IDirectedCollectionValue<T> Backwards()
4295
      {
4296
        Range b = (Range)MemberwiseClone();
4297

    
4298
        b.direction = direction == EnumerationDirection.Forwards ? EnumerationDirection.Backwards : EnumerationDirection.Forwards;
4299
        return b;
4300
      }
4301

    
4302

    
4303
      [Tested]
4304
      IDirectedEnumerable<T> IDirectedEnumerable<T>.Backwards() { return Backwards(); }
4305

    
4306

    
4307
      public override bool IsEmpty { get { return size == 0; } }
4308

    
4309
      [Tested]
4310
      public override int Count { [Tested] get { return size; } }
4311

    
4312
      //TODO: check that this is correct
4313
      public override Speed CountSpeed { get { return Speed.Constant; } }
4314

    
4315
    }
4316

    
4317
    #endregion
4318

    
4319
    #region Diagnostics
4320
    /// <summary>
4321
    /// Display this node on the console, and recursively its subnodes.
4322
    /// </summary>
4323
    /// <param name="n">Node to display</param>
4324
    /// <param name="space">Indentation</param>
4325
    private void minidump(Node n, string space)
4326
    {
4327
      if (n == null)
4328
      {
4329
        //	System.Console.WriteLine(space + "null");
4330
      }
4331
      else
4332
      {
4333
        minidump(n.right, space + "  ");
4334
        Console.WriteLine(String.Format("{0} {4} (size={1}, items={8}, h={2}, gen={3}, id={6}){7}", space + n.item,
4335
#if MAINTAIN_SIZE
4336
 n.size,
4337
#else
4338
				0,
4339
#endif
4340
 0,
4341
#if NCP
4342
 n.generation,
4343
#endif
4344
 n.red ? "RED" : "BLACK",
4345
 0,
4346
 0,
4347
#if NCP
4348
#if SEPARATE_EXTRA
4349
				n.extra == null ? "" : String.Format(" [extra: lg={0}, c={1}, i={2}]", n.extra.lastgeneration, n.extra.leftnode ? "L" : "R", n.extra.oldref == null ? "()" : "" + n.extra.oldref.item),
4350
#else
4351
 n.lastgeneration == -1 ? "" : String.Format(" [extra: lg={0}, c={1}, i={2}]", n.lastgeneration, n.leftnode ? "L" : "R", n.oldref == null ? "()" : "" + n.oldref.item),
4352
#endif
4353
#else
4354
				"",
4355
#endif
4356
#if BAG
4357
 n.items
4358
#else
4359
 1
4360
#endif
4361
));
4362
        minidump(n.left, space + "  ");
4363
      }
4364
    }
4365

    
4366

    
4367
    /// <summary>
4368
    /// Print the tree structure to the console stdout.
4369
    /// </summary>
4370
    [Tested(via = "Sawtooth")]
4371
    public void dump() { dump(""); }
4372

    
4373

    
4374
    /// <summary>
4375
    /// Print the tree structure to the console stdout.
4376
    /// </summary>
4377
    [Tested(via = "Sawtooth")]
4378
    public void dump(string msg)
4379
    {
4380
      Console.WriteLine(String.Format(">>>>>>>>>>>>>>>>>>> dump {0} (count={1}, blackdepth={2}, depth={3}, gen={4})", msg, size, blackdepth,
4381
      0
4382
      ,
4383
#if NCP
4384
 generation
4385
#endif
4386
));
4387
      minidump(root, "");
4388
      check("", Console.Out); Console.WriteLine("<<<<<<<<<<<<<<<<<<<");
4389
    }
4390

    
4391

    
4392
    /// <summary>
4393
    /// Display this tree on the console.
4394
    /// </summary>
4395
    /// <param name="msg">Identifying string of this call to dump</param>
4396
    /// <param name="err">Extra (error)message to include</param>
4397
    void dump(string msg, string err)
4398
    {
4399
      Console.WriteLine(String.Format(">>>>>>>>>>>>>>>>>>> dump {0} (count={1}, blackdepth={2}, depth={3}, gen={4})", msg, size, blackdepth,
4400
      0
4401
      ,
4402
#if NCP
4403
 generation
4404
#endif
4405
));
4406
      minidump(root, ""); Console.Write(err);
4407
      Console.WriteLine("<<<<<<<<<<<<<<<<<<<");
4408
    }
4409

    
4410

    
4411
    /// <summary>
4412
    /// Print warning m on o if b is false.
4413
    /// </summary>
4414
    /// <param name="b">Condition that should hold</param>
4415
    /// <param name="n">Place (used for id display)</param>
4416
    /// <param name="m">Message</param>
4417
    /// <param name="o">Output stream</param>
4418
    /// <returns>b</returns>
4419
    bool massert(bool b, Node n, string m, System.IO.TextWriter o)
4420
    {
4421
      if (!b) o.WriteLine("*** Node (item={0}, id={1}): {2}", n.item,
4422
        0
4423
        , m);
4424

    
4425
      return b;
4426
    }
4427

    
4428

    
4429
    bool rbminicheck(Node n, bool redp, System.IO.TextWriter o, out T min, out T max, out int blackheight)
4430
    {//Red-Black invariant
4431
      bool res = true;
4432

    
4433
      res = massert(!(n.red && redp), n, "RED parent of RED node", o) && res;
4434
      res = massert(n.left == null || n.right != null || n.left.red, n, "Left child black, but right child empty", o) && res;
4435
      res = massert(n.right == null || n.left != null || n.right.red, n, "Right child black, but left child empty", o) && res;
4436
#if BAG
4437
      bool sb = n.size == (n.left == null ? 0 : n.left.size) + (n.right == null ? 0 : n.right.size) + n.items;
4438

    
4439
      res = massert(sb, n, "Bad size", o) && res;
4440
#elif MAINTAIN_SIZE
4441
      bool sb = n.size == (n.left == null ? 0 : n.left.size) + (n.right == null ? 0 : n.right.size) + 1;
4442

    
4443
      res = massert(sb, n, "Bad size", o) && res;
4444
#endif
4445
      min = max = n.item;
4446

    
4447
      T otherext;
4448
      int lbh = 0, rbh = 0;
4449

    
4450
      if (n.left != null)
4451
      {
4452
        res = rbminicheck(n.left, n.red, o, out min, out otherext, out lbh) && res;
4453
        res = massert(comparer.Compare(n.item, otherext) > 0, n, "Value not > all left children", o) && res;
4454
      }
4455

    
4456
      if (n.right != null)
4457
      {
4458
        res = rbminicheck(n.right, n.red, o, out otherext, out max, out rbh) && res;
4459
        res = massert(comparer.Compare(n.item, otherext) < 0, n, "Value not < all right children", o) && res;
4460
      }
4461

    
4462
      res = massert(rbh == lbh, n, "Different blackheights of children", o) && res;
4463
      blackheight = n.red ? rbh : rbh + 1;
4464
      return res;
4465
    }
4466

    
4467

    
4468

    
4469

    
4470
#if NCP
4471

    
4472
    bool rbminisnapcheck(Node n, System.IO.TextWriter o, out int size, out T min, out T max)
4473
    {
4474
      bool res = true;
4475

    
4476
      min = max = n.item;
4477

    
4478
      int lsz = 0, rsz = 0;
4479
      T otherext;
4480
#if SEPARATE_EXTRA
4481
			Node.Extra extra = n.extra;
4482
			Node child = (extra != null && extra.lastgeneration >= treegen && extra.leftnode) ? extra.oldref : n.left;
4483
#else
4484
      Node child = (n.lastgeneration >= generation && n.leftnode) ? n.oldref : n.left;
4485
#endif
4486
      if (child != null)
4487
      {
4488
        res = rbminisnapcheck(child, o, out lsz, out min, out otherext) && res;
4489
        res = massert(comparer.Compare(n.item, otherext) > 0, n, "Value not > all left children", o) && res;
4490
      }
4491

    
4492
#if SEPARATE_EXTRA
4493
			child = (extra != null && extra.lastgeneration >= treegen && !extra.leftnode) ? extra.oldref : n.right;
4494
#else
4495
      child = (n.lastgeneration >= generation && !n.leftnode) ? n.oldref : n.right;
4496
#endif
4497
      if (child != null)
4498
      {
4499
        res = rbminisnapcheck(child, o, out rsz, out otherext, out max) && res;
4500
        res = massert(comparer.Compare(n.item, otherext) < 0, n, "Value not < all right children", o) && res;
4501
      }
4502
#if BAG
4503
      size = n.items + lsz + rsz;
4504
#else
4505
      size = 1 + lsz + rsz;
4506
#endif
4507
      return res;
4508
    }
4509
#endif
4510

    
4511
    /// <summary>
4512
    /// Checks red-black invariant. Dumps tree to console if bad
4513
    /// </summary>
4514
    /// <param name="name">Title of dump</param>
4515
    /// <returns>false if invariant violation</returns>
4516
    [Tested(via = "Sawtooth")]
4517
    public bool Check(string name)
4518
    {
4519
      System.Text.StringBuilder e = new System.Text.StringBuilder();
4520
      System.IO.TextWriter o = new System.IO.StringWriter(e);
4521

    
4522
      if (!check(name, o))
4523
        return true;
4524
      else
4525
      {
4526
        dump(name, e.ToString());
4527
        return false;
4528
      }
4529
    }
4530

    
4531

    
4532
    /// <summary>
4533
    /// Checks red-black invariant. Dumps tree to console if bad
4534
    /// </summary>
4535
    /// <returns>false if invariant violation</returns>
4536
    [Tested]
4537
    public bool Check()
4538
    {
4539
      //return check("", System.IO.TextWriter.Null);
4540
      //Console.WriteLine("bamse");
4541
      if (!isValid)
4542
        return true;
4543
      return Check("-");
4544
    }
4545

    
4546

    
4547
    bool check(string msg, System.IO.TextWriter o)
4548
    {
4549
      if (root != null)
4550
      {
4551
        T max, min;
4552
        int blackheight;
4553
#if NCP
4554
        if (isSnapShot)
4555
        {
4556
          //Console.WriteLine("Im'a snapshot");
4557
          int thesize;
4558
          bool rv = rbminisnapcheck(root, o, out thesize, out min, out max);
4559

    
4560
          rv = massert(size == thesize, root, "bad snapshot size", o) && rv;
4561
          return !rv;
4562
        }
4563
#endif
4564
        bool res = rbminicheck(root, false, o, out min, out max, out blackheight);
4565
        res = massert(blackheight == blackdepth, root, "bad blackh/d", o) && res;
4566
        res = massert(!root.red, root, "root is red", o) && res;
4567
#if MAINTAIN_SIZE
4568
        res = massert(root.size == size, root, "count!=root.size", o) && res;
4569
#endif
4570
        return !res;
4571
      }
4572
      else
4573
        return false;
4574
    }
4575
    #endregion
4576

    
4577
    #region ICloneable Members
4578

    
4579
    /// <summary>
4580
    /// Make a shallow copy of this TreeBag.
4581
    /// </summary>
4582
    /// <returns></returns>
4583
    public virtual object Clone()
4584
    {
4585
      TreeBag<T> clone = new TreeBag<T>(comparer, EqualityComparer);
4586
      //TODO: make sure the TreeBag AddSorted copies tree bags smartly!!!
4587
      clone.AddSorted(this);
4588
      return clone;
4589
    }
4590

    
4591
    #endregion
4592

    
4593
  }
4594
}
4595