//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // // [....] // [....] //------------------------------------------------------------------------------ using System; using System.Collections.Generic; using System.Collections; using System.Text; using System.Data; using System.Linq; using System.Diagnostics; namespace System.Data { /// /// This class represents a combined sort expression build using mutiple sort expressions. /// /// internal class SortExpressionBuilder : IComparer> { /** * This class ensures multiple orderby/thenbys are handled correctly. Its semantics is as follows: * * Query 1: * orderby a * thenby b * orderby c * orderby d * thenby e * * is equivalent to: * * Query 2: * orderby d * thenby e * thenby c * thenby a * thenby b * **/ //Selectors and comparers are mapped using the index in the list. //E.g: _comparers[i] is used with _selectors[i] LinkedList> _selectors = new LinkedList>(); LinkedList> _comparers = new LinkedList>(); LinkedListNode> _currentSelector = null; LinkedListNode> _currentComparer = null; /// /// Adds a sorting selector/comparer in the correct order /// internal void Add(Func keySelector, Comparison compare, bool isOrderBy) { Debug.Assert(keySelector != null); Debug.Assert(compare != null); //Inputs are assumed to be valid. The burden for ensuring it is on the caller. if (isOrderBy) { _currentSelector = _selectors.AddFirst(keySelector); _currentComparer = _comparers.AddFirst(compare); } else { //ThenBy can only be called after OrderBy Debug.Assert(_currentSelector != null); Debug.Assert(_currentComparer != null); _currentSelector = _selectors.AddAfter(_currentSelector, keySelector); _currentComparer = _comparers.AddAfter(_currentComparer, compare); } } /// /// Represents a Combined selector of all selectors added thusfar. /// /// List of 'objects returned by each selector'. This list is the combined-selector public List Select(T row) { List result = new List(); foreach (Func selector in _selectors) { result.Add(selector(row)); } return result; } /// /// Represents a Comparer (of IComparer) that compares two combined-selectors using /// provided comparers for each individual selector. /// Note: Comparison is done in the order it was Added. /// /// Comparison result of the combined Sort comparer expression public int Compare(List a, List b) { Debug.Assert(a.Count == Count); int i = 0; foreach (Comparison compare in _comparers) { int result = compare(a[i], b[i]); if (result != 0) { return result; } i++; } return 0; } internal int Count { get { Debug.Assert(_selectors.Count == _comparers.Count); //weak now that we have two dimensions return _selectors.Count; } } /// /// Clones the SortexpressionBuilder and returns a new object /// that points to same comparer and selectors (in the same order). /// /// internal SortExpressionBuilder Clone() { SortExpressionBuilder builder = new SortExpressionBuilder(); foreach (Func selector in _selectors) { if (selector == _currentSelector.Value) { builder._currentSelector = builder._selectors.AddLast(selector); } else { builder._selectors.AddLast(selector); } } foreach (Comparison comparer in _comparers) { if (comparer == _currentComparer.Value) { builder._currentComparer = builder._comparers.AddLast(comparer); } else { builder._comparers.AddLast(comparer); } } return builder; } /// /// Clones the SortExpressinBuilder and casts to type TResult. /// internal SortExpressionBuilder CloneCast() { SortExpressionBuilder builder = new SortExpressionBuilder(); foreach (Func selector in _selectors) { if (selector == _currentSelector.Value) { builder._currentSelector = builder._selectors.AddLast(r => selector((T)(object)r)); } else { builder._selectors.AddLast(r => selector((T)(object)r)); } } foreach (Comparison comparer in _comparers) { if (comparer == _currentComparer.Value) { builder._currentComparer = builder._comparers.AddLast(comparer); } else { builder._comparers.AddLast(comparer); } } return builder; } } //end SortExpressionBuilder }