/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. * * 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 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ using System.Collections; using System.Collections.Generic; namespace QuantConnect.Util { /// /// Defines an enumerable that can be enumerated many times while /// only performing a single enumeration of the root enumerable /// /// public class MemoizingEnumerable : IEnumerable { private List _buffer; private IEnumerator _enumerator; /// /// Allow disableing the buffering /// /// Should be called before the enumeration starts public bool Enabled { get; set; } /// /// Initializes a new instance of the class /// /// The source enumerable to be memoized public MemoizingEnumerable(IEnumerable enumerable) { Enabled = true; _enumerator = enumerable.GetEnumerator(); } /// /// Returns an enumerator that iterates through the collection. /// /// /// A that can be used to iterate through the collection. /// /// 1 public IEnumerator GetEnumerator() { if (!Enabled) { if (_enumerator != null) { while (_enumerator.MoveNext()) { yield return _enumerator.Current; } // important to avoid leak! _enumerator.Dispose(); _enumerator = null; } } else { if (_buffer == null) { // lazy create our buffer _buffer = new List(); } int i = 0; while (i <= _buffer.Count) { // sync for multiple threads access to _enumerator and _buffer lock (_buffer) { // check to see if we need to move next if (_enumerator != null && i >= _buffer.Count) { if (_enumerator.MoveNext()) { var value = _enumerator.Current; _buffer.Add(value); yield return value; } else { // important to avoid leak! _enumerator.Dispose(); _enumerator = null; } } else { // we have a value if it's in the buffer if (_buffer.Count > i) { yield return _buffer[i]; } } } // increment for next time i++; } } } /// /// Returns an enumerator that iterates through a collection. /// /// /// An object that can be used to iterate through the collection. /// /// 2 IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } }