fix build with csc
[mono.git] / mcs / class / System.Core / System.Linq / InternalOrderedSequence.cs
1 //
2 // InternalOrderedSequence.cs
3 //
4 // Authors:
5 //      Alejandro Serrano "Serras" (trupill@yahoo.es)
6 //      Marek Safar  <marek.safar@gmail.com>
7 //
8 // Copyright (C) 2007 Novell, Inc (http://www.novell.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29
30 using System;
31 using System.Collections;
32 using System.Collections.Generic;
33
34 namespace System.Linq
35 {
36         sealed class InternalOrderedSequence<TElement, TKey> : AOrderedEnumerable<TElement>
37         {
38                 readonly IEnumerable<TElement> source;
39                 readonly Func<TElement, TKey> key_selector;
40                 readonly IComparer<TKey> comparer;
41                 readonly bool descending;
42                 
43                 internal InternalOrderedSequence (IEnumerable<TElement> source, Func<TElement, TKey> keySelector,
44                                                   IComparer<TKey> comparer, bool descending)
45                 {
46                         this.source = source;
47                         this.key_selector = keySelector;
48                         this.comparer = comparer ?? Comparer<TKey>.Default;
49                         this.descending = descending;
50                 }
51                 
52                 public override IEnumerable<TElement> Sort (IEnumerable<TElement> parentSource)
53                 {
54                         if (parent != null)
55                                 return parent.Sort (source);
56                         return PerformSort (parentSource);
57                 }
58                 
59                 public override IEnumerator<TElement> GetEnumerator ()
60                 {
61                         return PerformSort (source).GetEnumerator ();
62                 }
63                 
64                 List<TElement> source_list;
65                 TKey[] keys;
66                 int[] indexes;
67                 
68                 IEnumerable<TElement> PerformSort (IEnumerable<TElement> items)
69                 {
70                         // It first enumerates source, collecting all elements
71                         source_list = new List<TElement> (items);
72                         
73                         // If the source contains just zero or one element, there's no need to sort
74                         if (source_list.Count <= 1)
75                                 return source_list;
76                         
77                         // Then evaluate the keySelector function for each element,
78                         // collecting the key values
79                         keys = new TKey [source_list.Count];
80                         indexes = new int [source_list.Count];
81                         for (int i = 0; i < source_list.Count; i++) {
82                                 keys [i] = key_selector (source_list [i]);
83                                 indexes [i] = i;
84                         }
85                         
86                         // Then sorts the elements according to the collected
87                         // key values and the selected ordering
88                         QuickSort(0, indexes.Length - 1);
89                         
90                         // Return the values as IEnumerable<TElement>
91                         TElement[] orderedList = new TElement [indexes.Length];
92                         for (int i = 0; i < indexes.Length; i++)
93                                 orderedList [i] = source_list [indexes [i]];
94                         return orderedList;
95                 }
96                 
97                 int CompareItems (int firstIndex, int secondIndex)
98                 {
99                         int comparison = comparer.Compare (keys [firstIndex], keys [secondIndex]);
100                        
101                         // If descending, return the opposite comparison
102                         return (descending ? -comparison : comparison);
103                 }
104                 
105                 // We look at the first, middle, and last items in the subarray.
106                 // Then we put the largest on the right side, the smallest on
107                 // the left side, and the median becomes our pivot.
108                 int MedianOfThree (int left, int right)
109                 {
110                         int center = (left + right) / 2;
111                         if (CompareItems (indexes [center], indexes [left]) < 0)
112                                 Swap (left, center);
113                         if (CompareItems (indexes [right], indexes [left]) < 0)
114                                 Swap (left, right);
115                         if (CompareItems (indexes [right], indexes [center]) < 0)
116                                 Swap (center, right);
117                         Swap (center, right - 1);
118                         return indexes [right - 1];
119                 }
120                 
121                 void QuickSort (int left, int right)
122                 {
123                         if (left + 3 <= right) {
124                                 int l = left, r = right - 1, pivot = MedianOfThree (left, right);
125                                 while (true) {
126                                         while (CompareItems (indexes [++l], pivot) < 0) {}
127                                         while (CompareItems (indexes [--r], pivot) > 0) {}
128                                         if (l < r)
129                                                 Swap (l, r);
130                                         else
131                                                 break;
132                                 }
133                                 // Restore pivot
134                                 Swap (l, right - 1);
135                                 // Partition and sort
136                                 QuickSort (left, l - 1);
137                                 QuickSort (l + 1, right);
138                         } else
139                                 // If there are three items in the subarray, insertion sort is better
140                                 InsertionSort (left, right);
141                 }
142                 
143                 void InsertionSort (int left, int right)
144                 {
145                         for (int i = left + 1; i <= right; i++) {
146                                 int j, tmp = indexes [i];
147                                 for (j = i; j > left && CompareItems (tmp, indexes [j - 1]) < 0; j--)
148                                      indexes [j] = indexes [j - 1];
149                                 indexes [j] = tmp;
150                         }
151                 }
152                 
153                 void Swap (int left, int right)
154                 {
155                         int temp = indexes [right];
156                         indexes [right] = indexes [left];
157                         indexes [left] = temp;
158                 }
159                 
160         }
161 }