#if NET_4_0 // // QueryZipNode.cs // // Author: // Jérémie "Garuma" Laval // // Copyright (c) 2010 Jérémie "Garuma" Laval // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. using System; using System.Threading; using System.Linq; using System.Collections.Generic; using System.Collections.Concurrent; namespace System.Linq { internal class QueryZipNode : QueryMuxNode { Func resultSelector; public QueryZipNode (Func resultSelector, QueryBaseNode first, QueryBaseNode second) : base (first, second) { this.resultSelector = resultSelector; } internal override IEnumerable GetSequential () { IEnumerable first = Parent.GetSequential (); IEnumerable second = Second.GetSequential (); return first.Zip (second, resultSelector); } internal override IList> GetEnumerables (QueryOptions options) { IList> first = Parent.GetEnumerables (options); IList> second = Second.GetEnumerables (options); if (first.Count != second.Count) throw new InvalidOperationException ("Internal size mismatch"); IEnumerable[] result = new IEnumerable[first.Count]; for (int i = 0; i < result.Length; i++) result[i] = GetEnumerable (first[i], second[i]); return result; } IEnumerable GetEnumerable (IEnumerable first, IEnumerable second) { IEnumerator eFirst = first.GetEnumerator (); IEnumerator eSecond = second.GetEnumerator (); while (eFirst.MoveNext ()) { if (!eSecond.MoveNext ()) yield break; yield return resultSelector (eFirst.Current, eSecond.Current); } } internal override IList>> GetOrderedEnumerables (QueryOptions options) { IList>> first = Parent.GetOrderedEnumerables (options); IList>> second = Second.GetOrderedEnumerables (options); if (first.Count != second.Count) throw new InvalidOperationException ("Internal size mismatch"); IEnumerable>[] result = new IEnumerable>[first.Count]; KeyValuePair[] store1 = new KeyValuePair[result.Length]; KeyValuePair[] store2 = new KeyValuePair[result.Length]; Barrier barrier = new Barrier (result.Length, delegate { Array.Sort (store1, (e1, e2) => e1.Key.CompareTo (e2.Key)); Array.Sort (store2, (e1, e2) => e1.Key.CompareTo (e2.Key)); }); for (int i = 0; i < result.Length; i++) result[i] = GetEnumerable (first[i], second[i], i, store1, store2, barrier); return result; } IEnumerable> GetEnumerable (IEnumerable> first, IEnumerable> second, int index, KeyValuePair[] store1, KeyValuePair[] store2, Barrier barrier) { IEnumerator> eFirst = first.GetEnumerator (); IEnumerator> eSecond = second.GetEnumerator (); while (eFirst.MoveNext ()) { if (!eSecond.MoveNext ()) break; store1[index] = eFirst.Current; store2[index] = eSecond.Current; barrier.SignalAndWait (); yield return new KeyValuePair (store1[index].Key, resultSelector (store1[index].Value, store2[index].Value)); } barrier.RemoveParticipant (); } } } #endif