3 Copyright (c) 2003-2004 Niels Kokholm <kokholm@itu.dk> and Peter Sestoft <sestoft@dina.kvl.dk>
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 using System
.Diagnostics
;
25 using MSG
= System
.Collections
.Generic
;
29 /// Direction of enumeration order relative to original collection.
31 public enum EnumerationDirection
{
37 /// Opposite direction
43 class IC
: IComparer
<int>
46 public int Compare(int a
, int b
) { return a > b ? 1 : a < b ? -1 : 0; }
52 /// A hasher for int32
54 public class IntHasher
: IHasher
<int>
57 /// Get the hash code of this integer, i.e. itself
59 /// <param name="item">The integer</param>
60 /// <returns>The same</returns>
62 public int GetHashCode(int item
) { return item; }
66 /// Check if two integers are equal
68 /// <param name="i1">first integer</param>
69 /// <param name="i2">second integer</param>
70 /// <returns>True if equal</returns>
72 public bool Equals(int i1
, int i2
) { return i1 == i2; }
78 #region Natural Comparers
82 /// A natural generic IComparer for an IComparable<T> item type
84 public class NaturalComparer
<T
>: IComparer
<T
>
85 where T
: IComparable
<T
>
90 /// <param name="a">First item</param>
91 /// <param name="b">Second item</param>
92 /// <returns>a <=> b</returns>
94 public int Compare(T a
, T b
) { return a.CompareTo(b); }
100 /// A natural generic IComparer for a System.IComparable item type
102 public class NaturalComparerO
<T
>: IComparer
<T
>
103 where T
: System
.IComparable
106 /// Compare two items
108 /// <param name="a">First item</param>
109 /// <param name="b">Second item</param>
110 /// <returns>a <=> b</returns>
112 public int Compare(T a
, T b
) { return a.CompareTo(b); }
121 /// The default item hasher for a reference type. A trivial wrapper for calling
122 /// the GetHashCode and Equals methods inherited from object.
124 /// <p>Should only be instantiated with a reference type as generic type parameter.
125 /// This is asserted at instatiation time in Debug builds.</p>
127 public sealed class DefaultReferenceTypeHasher
<T
>: IHasher
<T
>
129 static DefaultReferenceTypeHasher()
131 Debug
.Assert(!typeof(T
).IsValueType
, "DefaultReferenceTypeHasher instantiated with value type: " + typeof(T
));
135 /// Get the hash code with respect to this item hasher
137 /// <param name="item">The item</param>
138 /// <returns>The hash code</returns>
140 public int GetHashCode(T item
) { return item.GetHashCode(); }
144 /// Check if two items are equal with respect to this item hasher
146 /// <param name="i1">first item</param>
147 /// <param name="i2">second item</param>
148 /// <returns>True if equal</returns>
150 public bool Equals(T i1
, T i2
)
152 //For reference types, the (object) cast should be jitted as a noop.
153 return (object)i1
== null ? (object)i2
== null : i1
.Equals(i2
);
158 /// The default item hasher for a value type. A trivial wrapper for calling
159 /// the GetHashCode and Equals methods inherited from object.
161 /// <p>Should only be instantiated with a value type as generic type parameter.
162 /// This is asserted at instatiation time in Debug builds.</p>
163 /// <p>We cannot add the constraint "where T : struct" to get a compile time check
164 /// because we need to instantiate this class in C5.HasherBuilder.ByPrototype[T].Examine()
165 /// with a T that is only known at runtime to be a value type!</p>
168 //Note: we could (now) add a constraint "where T : struct" to get a compile time check,
170 public sealed class DefaultValueTypeHasher
<T
>: IHasher
<T
>
172 static DefaultValueTypeHasher()
174 Debug
.Assert(typeof(T
).IsValueType
, "DefaultValueTypeHasher instantiated with reference type: " + typeof(T
));
177 /// Get the hash code with respect to this item hasher
179 /// <param name="item">The item</param>
180 /// <returns>The hash code</returns>
182 public int GetHashCode(T item
) { return item.GetHashCode(); }
186 /// Check if two items are equal with respect to this item hasher
188 /// <param name="i1">first item</param>
189 /// <param name="i2">second item</param>
190 /// <returns>True if equal</returns>
192 public bool Equals(T i1
, T i2
) { return i1.Equals(i2); }
200 /// A base class for implementing an IEnumerable<T>
202 public abstract class EnumerableBase
<T
>: MSG
.IEnumerable
<T
>
205 /// Create an enumerator for this collection.
207 /// <returns>The enumerator</returns>
208 public abstract MSG
.IEnumerator
<T
> GetEnumerator();
211 /// Count the number of items in an enumerable by enumeration
213 /// <param name="items">The enumerable to count</param>
214 /// <returns>The size of the enumerable</returns>
215 protected static int countItems(MSG
.IEnumerable
<T
> items
)
217 ICollectionValue
<T
> jtems
= items
as ICollectionValue
<T
>;
224 using (MSG
.IEnumerator
<T
> e
= items
.GetEnumerator())
225 while (e
.MoveNext()) count
++;
233 /// Base class for classes implementing ICollectionValue[T]
235 public abstract class CollectionValueBase
<T
>: EnumerableBase
<T
>, ICollectionValue
<T
>
237 //This forces our subclasses to make Count virtual!
239 /// The number of items in this collection.
242 public abstract int Count { get;}
245 /// The value is symbolic indicating the type of asymptotic complexity
246 /// in terms of the size of this collection (worst-case or amortized as
249 /// <value>A characterization of the speed of the
250 /// <code>Count</code> property in this collection.</value>
251 public abstract Speed CountSpeed { get; }
255 /// Copy the items of this collection to part of an array.
256 /// <exception cref="ArgumentOutOfRangeException"/> if i is negative.
257 /// <exception cref="ArgumentException"/> if the array does not have room for the items.
259 /// <param name="a">The array to copy to</param>
260 /// <param name="i">The starting index.</param>
262 public virtual void CopyTo(T
[] a
, int i
)
265 throw new ArgumentOutOfRangeException();
267 if (i
+ Count
> a
.Length
)
268 throw new ArgumentException();
270 foreach (T item
in this) a
[i
++] = item
;
274 /// Create an array with the items of this collection (in the same order as an
275 /// enumerator would output them).
277 /// <returns>The array</returns>
279 public virtual T
[] ToArray()
281 T
[] res
= new T
[Count
];
284 foreach (T item
in this) res
[i
++] = item
;
290 /// Apply an Applier<T> to this enumerable
292 /// <param name="a">The applier delegate</param>
294 public void Apply(Applier
<T
> a
)
296 foreach (T item
in this)
302 /// Check if there exists an item that satisfies a
303 /// specific predicate in this collection.
305 /// <param name="filter">A filter delegate
306 /// (<see cref="T:C5.Filter!1"/>) defining the predicate</param>
307 /// <returns>True is such an item exists</returns>
309 public bool Exists(Filter
<T
> filter
)
311 foreach (T item
in this)
320 /// Check if all items in this collection satisfies a specific predicate.
322 /// <param name="filter">A filter delegate
323 /// (<see cref="T:C5.Filter!1"/>) defining the predicate</param>
324 /// <returns>True if all items satisfies the predicate</returns>
326 public bool All(Filter
<T
> filter
)
328 foreach (T item
in this)
336 /// Create an enumerator for this collection.
338 /// <returns>The enumerator</returns>
339 public override abstract MSG
.IEnumerator
<T
> GetEnumerator();
344 /// Base class (abstract) for ICollection implementations.
346 public abstract class CollectionBase
<T
>: CollectionValueBase
<T
>
350 object syncroot
= new object();
353 /// The underlying field of the ReadOnly property
355 protected bool isReadOnly
= false;
358 /// The current stamp value
363 /// The number of items in the collection
368 /// The item hasher of the collection
370 protected IHasher
<T
> itemhasher
;
372 int iUnSequencedHashCode
, iUnSequencedHashCodeStamp
= -1;
378 //protected bool equals(T i1, T i2) { return itemhasher.Equals(i1, i2); }
380 /// Utility method for range checking.
381 /// <exception cref="ArgumentOutOfRangeException"/> if the start or count is negative
382 /// <exception cref="ArgumentException"/> if the range does not fit within collection size.
384 /// <param name="start">start of range</param>
385 /// <param name="count">size of range</param>
387 protected void checkRange(int start
, int count
)
389 if (start
< 0 || count
< 0)
390 throw new ArgumentOutOfRangeException();
392 if (start
+ count
> size
)
393 throw new ArgumentException();
398 /// Compute the unsequenced hash code of a collection
400 /// <param name="items">The collection to compute hash code for</param>
401 /// <param name="itemhasher">The item hasher</param>
402 /// <returns>The hash code</returns>
404 public static int ComputeHashCode(ICollectionValue
<T
> items
, IHasher
<T
> itemhasher
)
408 foreach (T item
in items
)
409 h ^
= itemhasher
.GetHashCode(item
);
411 return (items
.Count
<< 16) + h
;
416 /// Examine if tit and tat are equal as unsequenced collections
417 /// using the specified item hasher (assumed compatible with the two collections).
419 /// <param name="tit">The first collection</param>
420 /// <param name="tat">The second collection</param>
421 /// <param name="itemhasher">The item hasher to use for comparison</param>
422 /// <returns>True if equal</returns>
424 public static bool StaticEquals(ICollection
<T
> tit
, ICollection
<T
> tat
, IHasher
<T
> itemhasher
)
429 if (tit
.Count
!= tat
.Count
)
432 //This way we might run through both enumerations twice, but
433 //probably not (if the hash codes are good)
434 if (tit
.GetHashCode() != tat
.GetHashCode())
437 if (!tit
.AllowsDuplicates
&& (tat
.AllowsDuplicates
|| tat
.ContainsSpeed
>= tit
.ContainsSpeed
))
439 //TODO: use foreach construction
440 using (MSG
.IEnumerator
<T
> dit
= tit
.GetEnumerator())
442 while (dit
.MoveNext())
443 if (!tat
.Contains(dit
.Current
))
447 else if (!tat
.AllowsDuplicates
)
449 using (MSG
.IEnumerator
<T
> dat
= tat
.GetEnumerator())
451 while (dat
.MoveNext())
452 if (!tit
.Contains(dat
.Current
))
457 {//both are bags, we only have a slow one
458 //unless the bags are based on a fast T->int dictinary (tree or hash)
459 using (MSG
.IEnumerator
<T
> dat
= tat
.GetEnumerator())
461 while (dat
.MoveNext())
463 T item
= dat
.Current
;
465 if (tit
.ContainsCount(item
) != tat
.ContainsCount(item
))
469 //That was O(n^3) - completely unacceptable.
470 //If we use an auxiliary bool[] we can do the comparison in O(n^2)
478 /// Get the unsequenced collection hash code of this collection: from the cached
479 /// value if present and up to date, else (re)compute.
481 /// <returns>The hash code</returns>
482 protected int unsequencedhashcode()
484 if (iUnSequencedHashCodeStamp
== stamp
)
485 return iUnSequencedHashCode
;
487 iUnSequencedHashCode
= ComputeHashCode(this, itemhasher
);
488 iUnSequencedHashCodeStamp
= stamp
;
489 return iUnSequencedHashCode
;
494 /// Check if the contents of that is equal to the contents of this
495 /// in the unsequenced sense. Using the item hasher of this collection.
497 /// <param name="that">The collection to compare to.</param>
498 /// <returns>True if equal</returns>
499 protected bool unsequencedequals(ICollection
<T
> that
)
501 return StaticEquals((ICollection
<T
>)this, that
, itemhasher
);
506 /// <exception cref="InvalidOperationException"/> if this collection has been updated
507 /// since a target time
509 /// <param name="thestamp">The stamp identifying the target time</param>
510 protected virtual void modifycheck(int thestamp
)
512 if (this.stamp
!= thestamp
)
513 throw new InvalidOperationException("Collection was modified");
518 /// Check if it is valid to perform update operations, and if so increment stamp
520 protected virtual void updatecheck()
523 throw new InvalidOperationException("Collection cannot be modified through this guard object");
530 #region IEditableCollection<T> members
535 /// <value>True if this collection is read only</value>
537 public bool IsReadOnly { [Tested]get { return isReadOnly; }
}
541 #region ICollection<T> members
545 /// <value>The size of this collection</value>
547 public override int Count { [Tested]get { return size; }
}
550 /// The value is symbolic indicating the type of asymptotic complexity
551 /// in terms of the size of this collection (worst-case or amortized as
554 /// <value>A characterization of the speed of the
555 /// <code>Count</code> property in this collection.</value>
556 public override Speed CountSpeed { get { return Speed.Constant; }
}
561 #region ISink<T> members
565 /// <value>A distinguished object to use for locking to synchronize multithreaded access</value>
567 public object SyncRoot { get { return syncroot; }
}
573 /// <value>True is this collection is empty</value>
575 public bool IsEmpty { [Tested]get { return size == 0; }
}
578 #region IEnumerable<T> Members
580 /// Create an enumerator for this collection.
582 /// <returns>The enumerator</returns>
583 public override abstract MSG
.IEnumerator
<T
> GetEnumerator();
589 /// Base class (abstract) for sequenced collection implementations.
591 public abstract class SequencedBase
<T
>: CollectionBase
<T
>
595 int iSequencedHashCode
, iSequencedHashCodeStamp
= -1;
602 /// Compute the unsequenced hash code of a collection
604 /// <param name="items">The collection to compute hash code for</param>
605 /// <param name="itemhasher">The item hasher</param>
606 /// <returns>The hash code</returns>
608 public static int ComputeHashCode(ISequenced
<T
> items
, IHasher
<T
> itemhasher
)
610 //NOTE: It must be possible to devise a much stronger combined hashcode,
611 //but unfortunately, it has to be universal. OR we could use a (strong)
612 //family and initialise its parameter randomly at load time of this class!
613 //(We would not want to have yet a flag to check for invalidation?!)
614 int iIndexedHashCode
= 0;
616 foreach (T item
in items
)
617 iIndexedHashCode
= iIndexedHashCode
* 31 + itemhasher
.GetHashCode(item
);
619 return iIndexedHashCode
;
624 /// Examine if tit and tat are equal as sequenced collections
625 /// using the specified item hasher (assumed compatible with the two collections).
627 /// <param name="tit">The first collection</param>
628 /// <param name="tat">The second collection</param>
629 /// <param name="itemhasher">The item hasher to use for comparison</param>
630 /// <returns>True if equal</returns>
632 public static bool StaticEquals(ISequenced
<T
> tit
, ISequenced
<T
> tat
, IHasher
<T
> itemhasher
)
637 if (tit
.Count
!= tat
.Count
)
640 //This way we might run through both enumerations twice, but
641 //probably not (if the hash codes are good)
642 if (tit
.GetHashCode() != tat
.GetHashCode())
645 using (MSG
.IEnumerator
<T
> dat
= tat
.GetEnumerator(), dit
= tit
.GetEnumerator())
647 while (dit
.MoveNext())
650 if (!itemhasher
.Equals(dit
.Current
, dat
.Current
))
660 /// Get the sequenced collection hash code of this collection: from the cached
661 /// value if present and up to date, else (re)compute.
663 /// <returns>The hash code</returns>
664 protected int sequencedhashcode()
666 if (iSequencedHashCodeStamp
== stamp
)
667 return iSequencedHashCode
;
669 iSequencedHashCode
= ComputeHashCode((ISequenced
<T
>)this, itemhasher
);
670 iSequencedHashCodeStamp
= stamp
;
671 return iSequencedHashCode
;
676 /// Check if the contents of that is equal to the contents of this
677 /// in the sequenced sense. Using the item hasher of this collection.
679 /// <param name="that">The collection to compare to.</param>
680 /// <returns>True if equal</returns>
681 protected bool sequencedequals(ISequenced
<T
> that
)
683 return StaticEquals((ISequenced
<T
>)this, that
, itemhasher
);
690 /// Create an enumerator for this collection.
692 /// <returns>The enumerator</returns>
693 public override abstract MSG
.IEnumerator
<T
> GetEnumerator();
697 /// <code>Forwards</code> if same, else <code>Backwards</code>
699 /// <value>The enumeration direction relative to the original collection.</value>
701 public EnumerationDirection Direction { [Tested]get { return EnumerationDirection.Forwards; }
}
706 /// Base class for collection classes of dynamic array type implementations.
708 public class ArrayBase
<T
>: SequencedBase
<T
>
712 /// The actual internal array container. Will be extended on demand.
717 /// The offset into the internal array container of the first item. The offset is 0 for a
718 /// base dynamic array and may be positive for an updatable view into a base dynamic array.
720 protected int offset
;
725 /// Double the size of the internal array.
727 protected virtual void expand()
729 expand(2 * array
.Length
, size
);
734 /// Expand the internal array container.
736 /// <param name="newcapacity">The new size of the internal array -
737 /// will be rounded upwards to a power of 2.</param>
738 /// <param name="newsize">The (new) size of the (base) collection.</param>
739 protected virtual void expand(int newcapacity
, int newsize
)
741 Debug
.Assert(newcapacity
>= newsize
);
743 int newlength
= array
.Length
;
745 while (newlength
< newcapacity
) newlength
*= 2;
747 T
[] newarray
= new T
[newlength
];
749 Array
.Copy(array
, newarray
, newsize
);
755 /// Insert an item at a specific index, moving items to the right
756 /// upwards and expanding the array if necessary.
758 /// <param name="i">The index at which to insert.</param>
759 /// <param name="item">The item to insert.</param>
760 protected virtual void insert(int i
, T item
)
762 if (size
== array
.Length
)
766 Array
.Copy(array
, i
, array
, i
+ 1, size
- i
);
777 /// Create an empty ArrayBase object.
779 /// <param name="capacity">The initial capacity of the internal array container.
780 /// Will be rounded upwards to the nearest power of 2 greater than or equal to 8.</param>
781 /// <param name="hasher">The item hasher to use, primarily for item equality</param>
782 public ArrayBase(int capacity
, IHasher
<T
> hasher
)
786 while (newlength
< capacity
) newlength
*= 2;
788 array
= new T
[newlength
];
794 #region IIndexed members
797 /// <exception cref="IndexOutOfRangeException"/>.
799 /// <value>The directed collection of items in a specific index interval.</value>
800 /// <param name="start">The low index of the interval (inclusive).</param>
801 /// <param name="count">The size of the range.</param>
803 public IDirectedCollectionValue
<T
> this[int start
, int count
]
808 checkRange(start
, count
);
809 return new Range(this, start
, count
, true);
815 #region IEditableCollection members
817 /// Remove all items and reset size of internal array container.
820 public virtual void Clear()
829 /// Create an array containing (copies) of the items of this collection in enumeration order.
831 /// <returns>The new array</returns>
833 public override T
[] ToArray()
835 T
[] res
= new T
[size
];
837 Array
.Copy(array
, res
, size
);
843 /// Perform an internal consistency (invariant) test on the array base.
845 /// <returns>True if test succeeds.</returns>
847 public virtual bool Check()
851 if (size
> array
.Length
)
853 Console
.WriteLine("Bad size ({0}) > array.Length ({1})", size
, array
.Length
);
857 for (int i
= 0; i
< size
; i
++)
859 if ((object)(array
[i
]) == null)
861 Console
.WriteLine("Bad element: null at index {0}", i
);
871 #region IDirectedCollection<T> Members
874 /// Create a directed collection with the same contents as this one, but
875 /// opposite enumeration sequence.
877 /// <returns>The mirrored collection.</returns>
879 public IDirectedCollectionValue
<T
> Backwards() { return this[0, size].Backwards(); }
883 #region IEnumerable<T> Members
885 /// Create an enumerator for this array based collection.
887 /// <returns>The enumerator</returns>
889 public override MSG
.IEnumerator
<T
> GetEnumerator()
891 int thestamp
= stamp
, theend
= size
+ offset
, thestart
= offset
;
893 for (int i
= thestart
; i
< theend
; i
++)
895 modifycheck(thestamp
);
896 yield return array
[i
];
901 #region Range nested class
903 /// A helper class for defining results of interval queries on array based collections.
905 protected class Range
: CollectionValueBase
<T
>, IDirectedCollectionValue
<T
>
907 int start
, count
, delta
, stamp
;
909 ArrayBase
<T
> thebase
;
912 internal Range(ArrayBase
<T
> thebase
, int start
, int count
, bool forwards
)
914 this.thebase
= thebase
; stamp
= thebase
.stamp
;
915 delta
= forwards
? 1 : -1;
916 this.start
= start
+ thebase
.offset
; this.count
= count
;
923 /// <value>The number of items in the range</value>
925 public override int Count { [Tested]get { thebase.modifycheck(stamp); return count; }
}
928 /// The value is symbolic indicating the type of asymptotic complexity
929 /// in terms of the size of this collection (worst-case or amortized as
932 /// <value>A characterization of the speed of the
933 /// <code>Count</code> property in this collection.</value>
934 public override Speed CountSpeed { get { thebase.modifycheck(stamp); return Speed.Constant; }
}
937 /// Create an enumerator for this range of an array based collection.
939 /// <returns>The enumerator</returns>
941 public override MSG
.IEnumerator
<T
> GetEnumerator()
943 for (int i
= 0; i
< count
; i
++)
945 thebase
.modifycheck(stamp
);
946 yield return thebase
.array
[start
+ delta
* i
];
952 /// Create a araay collection range with the same contents as this one, but
953 /// opposite enumeration sequence.
955 /// <returns>The mirrored collection.</returns>
957 public IDirectedCollectionValue
<T
> Backwards()
959 thebase
.modifycheck(stamp
);
961 Range res
= (Range
)MemberwiseClone();
964 res
.start
= start
+ (count
- 1) * delta
;
969 IDirectedEnumerable
<T
> C5
.IDirectedEnumerable
<T
>.Backwards()
976 /// <code>Forwards</code> if same, else <code>Backwards</code>
978 /// <value>The enumeration direction relative to the original collection.</value>
980 public EnumerationDirection Direction
985 thebase
.modifycheck(stamp
);
986 return delta
> 0 ? EnumerationDirection
.Forwards
: EnumerationDirection
.Backwards
;
997 /// A utility class with functions for sorting arrays with respect to an IComparer<T>
1002 /// Sort part of array in place using IntroSort
1004 /// <param name="a">Array to sort</param>
1005 /// <param name="f">Index of first position to sort</param>
1006 /// <param name="b">Index of first position beyond the part to sort</param>
1007 /// <param name="c">IComparer<T> to sort by</param>
1009 public static void IntroSort
<T
>(T
[] a
, int f
, int b
, IComparer
<T
> c
)
1011 new Sorter
<T
>(a
, c
).IntroSort(f
, b
);
1016 /// Sort part of array in place using Insertion Sort
1018 /// <param name="a">Array to sort</param>
1019 /// <param name="f">Index of first position to sort</param>
1020 /// <param name="b">Index of first position beyond the part to sort</param>
1021 /// <param name="c">IComparer<T> to sort by</param>
1023 public static void InsertionSort
<T
>(T
[] a
, int f
, int b
, IComparer
<T
> c
)
1025 new Sorter
<T
>(a
, c
).InsertionSort(f
, b
);
1030 /// Sort part of array in place using Heap Sort
1032 /// <param name="a">Array to sort</param>
1033 /// <param name="f">Index of first position to sort</param>
1034 /// <param name="b">Index of first position beyond the part to sort</param>
1035 /// <param name="c">IComparer<T> to sort by</param>
1037 public static void HeapSort
<T
>(T
[] a
, int f
, int b
, IComparer
<T
> c
)
1039 new Sorter
<T
>(a
, c
).HeapSort(f
, b
);
1050 internal Sorter(T
[] a
, IComparer
<T
> c
) { this.a = a; this.c = c; }
1053 internal void IntroSort(int f
, int b
)
1057 int depth_limit
= (int)Math
.Floor(2.5 * Math
.Log(b
- f
, 2));
1059 introSort(f
, b
, depth_limit
);
1062 InsertionSort(f
, b
);
1066 private void introSort(int f
, int b
, int depth_limit
)
1068 const int size_threshold
= 14;//24;
1070 if (depth_limit
-- == 0)
1072 else if (b
- f
<= size_threshold
)
1073 InsertionSort(f
, b
);
1076 int p
= partition(f
, b
);
1078 introSort(f
, p
, depth_limit
);
1079 introSort(p
, b
, depth_limit
);
1084 private int compare(T i1
, T i2
) { return c.Compare(i1, i2); }
1087 private int partition(int f
, int b
)
1089 int bot
= f
, mid
= (b
+ f
) / 2, top
= b
- 1;
1090 T abot
= a
[bot
], amid
= a
[mid
], atop
= a
[top
];
1092 if (compare(abot
, amid
) < 0)
1094 if (compare(atop
, abot
) < 0)//atop<abot<amid
1095 { a[top] = amid; amid = a[mid] = abot; a[bot] = atop; }
1096 else if (compare(atop
, amid
) < 0) //abot<=atop<amid
1097 { a[top] = amid; amid = a[mid] = atop; }
1098 //else abot<amid<=atop
1102 if (compare(amid
, atop
) > 0) //atop<amid<=abot
1103 { a[bot] = atop; a[top] = abot; }
1104 else if (compare(abot
, atop
) > 0) //amid<=atop<abot
1105 { a[bot] = amid; amid = a[mid] = atop; a[top] = abot; }
1106 else //amid<=abot<=atop
1107 { a[bot] = amid; amid = a[mid] = abot; }
1110 int i
= bot
, j
= top
;
1114 while (compare(a
[++i
], amid
) < 0);
1116 while (compare(amid
, a
[--j
]) < 0);
1120 T tmp
= a
[i
]; a
[i
] = a
[j
]; a
[j
] = tmp
;
1128 internal void InsertionSort(int f
, int b
)
1130 for (int j
= f
+ 1; j
< b
; j
++)
1132 T key
= a
[j
], other
;
1135 if (c
.Compare(other
= a
[i
], key
) > 0)
1138 while (i
> f
&& c
.Compare(other
= a
[i
- 1], key
) > 0) { a[i--] = other; }
1146 internal void HeapSort(int f
, int b
)
1148 for (int i
= (b
+ f
) / 2; i
>= f
; i
--) heapify(f
, b
, i
);
1150 for (int i
= b
- 1; i
> f
; i
--)
1152 T tmp
= a
[f
]; a
[f
] = a
[i
]; a
[i
] = tmp
;
1158 private void heapify(int f
, int b
, int i
)
1160 T pv
= a
[i
], lv
, rv
, max
= pv
;
1161 int j
= i
, maxpt
= j
;
1165 int l
= 2 * j
- f
+ 1, r
= l
+ 1;
1167 if (l
< b
&& compare(lv
= a
[l
], max
) > 0) { maxpt = l; max = lv; }
1169 if (r
< b
&& compare(rv
= a
[r
], max
) > 0) { maxpt = r; max = rv; }
1189 /// A modern random number generator based on (whatever)
1191 public class C5Random
: Random
1193 private uint[] Q
= new uint[16];
1195 private uint c
= 362436, i
= 15;
1200 ulong t
, a
= 487198574UL;
1201 uint x
, r
= 0xfffffffe;
1205 c
= (uint)(t
>> 32);
1213 return Q
[i
] = r
- x
;
1218 /// Get a new random System.Double value
1220 /// <returns>The random double</returns>
1221 public override double NextDouble()
1223 return Cmwc() / 4294967296.0;
1228 /// Get a new random System.Double value
1230 /// <returns>The random double</returns>
1231 protected override double Sample()
1233 return NextDouble();
1238 /// Get a new random System.Int32 value
1240 /// <returns>The random int</returns>
1241 public override int Next()
1248 /// Get a random non-negative integer less than a given upper bound
1250 /// <param name="max">The upper bound (exclusive)</param>
1251 /// <returns></returns>
1252 public override int Next(int max
)
1255 throw new ApplicationException("max must be non-negative");
1257 return (int)(Cmwc() / 4294967296.0 * max
);
1262 /// Get a random integer between two given bounds
1264 /// <param name="min">The lower bound (inclusive)</param>
1265 /// <param name="max">The upper bound (exclusive)</param>
1266 /// <returns></returns>
1267 public override int Next(int min
, int max
)
1270 throw new ApplicationException("min must be less than or equal to max");
1272 return min
+ (int)(Cmwc() / 4294967296.0 * max
);
1276 /// Fill a array of byte with random bytes
1278 /// <param name="buffer">The array to fill</param>
1279 public override void NextBytes(byte[] buffer
)
1281 for (int i
= 0, length
= buffer
.Length
; i
< length
; i
++)
1282 buffer
[i
] = (byte)Cmwc();
1287 /// Create a random number generator seed by system time.
1289 public C5Random() : this(DateTime
.Now
.Ticks
)
1295 /// Create a random number generator with a given seed
1297 /// <param name="seed">The seed</param>
1298 public C5Random(long seed
)
1301 throw new ApplicationException("Seed must be non-zero");
1303 uint j
= (uint)(seed
& 0xFFFFFFFF);
1305 for (int i
= 0; i
< 16; i
++)
1313 Q
[15] = (uint)(seed ^
(seed
>> 32));
1319 #region Custom code attributes
1322 /// A custom attribute to mark methods and properties as being tested
1323 /// sufficiently in the regression test suite.
1325 [AttributeUsage(AttributeTargets
.All
, AllowMultiple
= true)]
1326 public class TestedAttribute
: Attribute
1330 /// Optional reference to test case
1337 /// Pretty print attribute value
1339 /// <returns>"Tested via " + via</returns>
1341 public override string ToString() { return "Tested via " + via; }