/* Copyright (c) Microsoft Corporation All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. */ using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Globalization; using System.Reflection; using System.Linq.Expressions; using System.Linq; using System.Diagnostics; using Microsoft.Research.DryadLinq.Internal; namespace Microsoft.Research.DryadLinq { /// /// The base interface to access a collection of IQueryable instances. The /// DryadLINQ Fork operator returns a value that implements this interface. /// public interface IMultiQueryable { /// /// Gets the element type of the query at a specified index. /// /// The index /// A Type that represents the type of the elements Type ElementType(int index); /// /// Gets the expression tree that is associated with this instance of IMultiQueryable /// Expression Expression { get; } /// /// Gets the query provider that is associated with this instance of IMultiQueryable /// IQueryProvider Provider { get; } /// /// Gets the number of queries in this instance of IMultiQueryable /// UInt32 NumberOfInputs { get; } } /// /// The interface to access a collection of two IQueryable{T} instances. /// /// The element type of the first IQueryable{T} /// The element type of the second IQueryable{T} public interface IMultiQueryable : IMultiQueryable { /// /// Gets the first IQueryable{T} /// IQueryable First { get; } /// /// Gets the second IQueryable{T} /// IQueryable Second { get; } } /// /// The interface to access a collection of three IQueryable{T} instances. /// /// The element type of the first IQueryable{T} /// The element type of the second IQueryable{T} /// The element type of the third IQueryable{T} public interface IMultiQueryable : IMultiQueryable { /// /// Gets the first IQueryable{T} /// IQueryable First { get; } /// /// Gets the second IQueryable{T} /// IQueryable Second { get; } /// /// Gets the third IQueryable{T} /// IQueryable Third { get; } } /// /// The interface to access a collection of IQueryable{T} instances. Each IQueryable{T} /// contains only elements of the same key. The IQueryable{T}s are indexed by a set of keys. /// /// The element type of IQueryable{T}s /// The key type public interface IKeyedMultiQueryable : IMultiQueryable { /// /// Gets the IQueryable{T} associated with a specified key. /// /// A key /// The IQueryable{T} associated with the key IQueryable this[K key] { get; } /// /// Gets the keys. /// K[] Keys { get; } } internal class MultiQueryable : IKeyedMultiQueryable { private IQueryable m_source; private Expression m_queryExpression; private IMultiEnumerable m_enumerables; private K[] m_keys; private Dictionary m_keyMap; public MultiQueryable(IQueryable source, K[] keys, IMultiEnumerable enumerables) { this.m_source = source; this.m_queryExpression = null; this.m_enumerables = enumerables; this.m_keys = new K[keys.Length]; this.m_keyMap = new Dictionary(keys.Length); for (int i = 0; i < keys.Length; i++) { this.m_keys[i] = keys[i]; this.m_keyMap.Add(keys[i], i); } } public MultiQueryable(IQueryable source, K[] keys, Expression queryExpr) { this.m_source = source; this.m_queryExpression = queryExpr; this.m_enumerables = null; this.m_keys = new K[keys.Length]; this.m_keyMap = new Dictionary(keys.Length); for (int i = 0; i < keys.Length; i++) { this.m_keys[i] = keys[i]; this.m_keyMap.Add(keys[i], i); } } public Type ElementType(int index) { return typeof(T); } public Expression Expression { get { return this.m_queryExpression; } } public IQueryProvider Provider { get { return this.m_source.Provider; } } public UInt32 NumberOfInputs { get { if (this.m_enumerables != null) { return (UInt32)this.m_enumerables.NumberOfInputs; } return (UInt32)this.m_keys.Length; } } public K[] Keys { get { return this.m_keys; } } public IQueryable this[K key] { get { int index; if (this.m_keyMap.TryGetValue(key, out index)) { if (this.m_enumerables != null) { var q = this.m_enumerables[index].AsQueryable(); return new DryadLinqLocalQuery(this.Provider, q); } return this.ForkChoose(index); } throw new DryadLinqException(DryadLinqErrorCode.MultiQueryableKeyOutOfRange, SR.MultiQueryableKeyOutOfRange); } } } internal class MultiQueryable : IMultiQueryable { private IQueryable m_source; private Expression m_queryExpression; private IMultiEnumerable m_enumerables; public MultiQueryable(IQueryable source, IMultiEnumerable enumerables) { this.m_source = source; this.m_queryExpression = null; this.m_enumerables = enumerables; } public MultiQueryable(IQueryable source, Expression queryExpr) { this.m_source = source; this.m_queryExpression = queryExpr; this.m_enumerables = null; } public Type ElementType(int index) { if (index == 0) { return typeof(R1); } else if (index == 1) { return typeof(R2); } else { throw new DryadLinqException(DryadLinqErrorCode.IndexOutOfRange, SR.IndexOutOfRange); } } public Expression Expression { get { return this.m_queryExpression; } } public IQueryProvider Provider { get { return this.m_source.Provider; } } public UInt32 NumberOfInputs { get { return 2; } } public IQueryable First { get { if (this.m_enumerables != null) { var q = this.m_enumerables.First.AsQueryable(); return new DryadLinqLocalQuery(this.Provider, q); } return this.ForkChoose(0); } } public IQueryable Second { get { if (this.m_enumerables != null) { var q = this.m_enumerables.Second.AsQueryable(); return new DryadLinqLocalQuery(this.Provider, q); } return this.ForkChoose(1); } } } internal class MultiQueryable : IMultiQueryable { private IQueryable m_source; private Expression m_queryExpression; private IMultiEnumerable m_enumerables; public MultiQueryable(IQueryable source, Expression queryExpr) { this.m_source = source; this.m_queryExpression = queryExpr; this.m_enumerables = null; } public MultiQueryable(IQueryable source, IMultiEnumerable enumerables) { this.m_source = source; this.m_queryExpression = null; this.m_enumerables = enumerables; } public Type ElementType(int index) { if (index == 0) { return typeof(R1); } else if (index == 1) { return typeof(R2); } else if (index == 2) { return typeof(R3); } else { throw new DryadLinqException(DryadLinqErrorCode.IndexOutOfRange, SR.IndexOutOfRange); } } public Expression Expression { get { return this.m_queryExpression; } } public IQueryProvider Provider { get { return this.m_source.Provider; } } public UInt32 NumberOfInputs { get { return 3; } } public IQueryable First { get { if (this.m_enumerables != null) { var q = this.m_enumerables.First.AsQueryable(); return new DryadLinqLocalQuery(this.Provider, q); } return this.ForkChoose(0); } } public IQueryable Second { get { if (this.m_enumerables != null) { var q = this.m_enumerables.Second.AsQueryable(); return new DryadLinqLocalQuery(this.Provider, q); } return this.ForkChoose(1); } } public IQueryable Third { get { if (this.m_enumerables != null) { var q = this.m_enumerables.Third.AsQueryable(); return new DryadLinqLocalQuery(this.Provider, q); } return this.ForkChoose(2); } } } }