#region Disclaimer / License // Copyright (C) 2011, Kenneth Skovhede // http://www.hexad.dk, opensource@hexad.dk // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA // #endregion using System; using System.Collections.Generic; using System.Text; namespace Duplicati.Library.Utility { //TODO: Remove this delegate if we upgrade to .Net Framework 3.5, as it is built in public delegate TResult Func(T input); /// /// This class puts a filter over an IEnumerable, /// giving the illusion that the sequence only contains certain values. /// This is semantically the same as the FindAll function, /// but does not create a copy of the source /// /// The type of enumerable to filter public class PlugableEnumerable : IEnumerable { /// ///The predicate used to filter the list /// private Predicate m_predicate; /// ///The conversion function /// private Func m_converter; /// ///The list being wrapped /// private IEnumerable m_wrappedList; /// /// An optional call back function that determines if an element is visible or not /// public Predicate Predicate { get { return m_predicate; } set { m_predicate = value; } } /// /// An optional callback method that converts the element returned by the Current method of the enumerator /// public Func Converter { get { return m_converter; } set { m_converter = value; } } /// /// The inner list being wrapped /// public IEnumerable WrappedList { get { return m_wrappedList; } set { m_wrappedList = value; } } /// /// Constructs a new filtered enumeration /// /// The filter function /// The converter function /// The sequence to filter public PlugableEnumerable(Predicate predicate, Func converter, IEnumerable wrappedlist) { Predicate = predicate; Converter = converter; WrappedList = wrappedlist; } /// /// Constructs a new filtered enumeration /// /// The sequence of items to filter public PlugableEnumerable(IEnumerable sequence) { WrappedList = sequence; } /// /// Constructs a new filtered enumeration /// /// The filter function /// The converter function /// The sequence to filter public PlugableEnumerable(Predicate predicate, Func converter) { Predicate = predicate; Converter = converter; } /// /// Applies the filtering from this instance to another list /// /// The sequence to wrap /// A filtered sequence public PlugableEnumerable WrapList(IEnumerable sequence) { return new PlugableEnumerable(Predicate, Converter, sequence); } #region IEnumerable Members /// /// Gets a new enumerator /// /// An enumerator public IEnumerator GetEnumerator() { return new FilterableIEnumerableEnumerator(Predicate, Converter, WrappedList.GetEnumerator()); } #endregion #region IEnumerable Members /// /// Gets a new enumerator /// /// An enumerator System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return new FilterableIEnumerableEnumerator(Predicate, Converter, WrappedList.GetEnumerator()); } #endregion /// /// Constructs an enumerable that wraps another enumerator, filtering elements in the process /// public class FilterableIEnumerableEnumerator : IEnumerator { private IEnumerator m_parent; private Predicate m_predicate; private Func m_converter; /// /// Constructs a new enumerator wrapping the parent enumerator /// /// The predicate each item must match /// The parent enumerator public FilterableIEnumerableEnumerator(Predicate predicate, Func converter, IEnumerator parent) { m_predicate = predicate; m_converter = converter; m_parent = parent; } #region IEnumerator Members /// /// Gets the current element /// public T Current { get { if (m_converter == null) return m_parent.Current; else return m_converter(m_parent.Current); } } #endregion #region IDisposable Members public void Dispose() { m_parent.Dispose(); } #endregion #region IEnumerator Members /// /// Gets the current element /// object System.Collections.IEnumerator.Current { get { return this.Current; } } /// /// Advances the enumerator one element, this may be multiple elements, depending on the filter /// /// True if the operation suceeded, false if there are no more elements public bool MoveNext() { if (m_predicate == null) return m_parent.MoveNext(); bool more; while (more = m_parent.MoveNext()) if (m_predicate(m_parent.Current)) return true; return false; } /// /// Resest the enumerator to its start position, this is directly mapped to the wrapping enumerator /// public void Reset() { m_parent.Reset(); } #endregion } } }