private AppendPrependNIterator(AppendPrependNIterator <TSource> source) { _source = source._source; _prepended = source._prepended; _appended = source._appended; _prependedCount = source._prependedCount; _appendedCount = source._appendedCount; }
/// <summary> /// This method may look like a bit of magic is going on, so I'll explain it here /// If we append an item to an <see cref = "AppendPrependNIterator{TSource}"/> we just add an item to the end of the <see cref = "_appended"/> list of the original iterator, and increases its personal <see cref = "_appendedCount"/> by 1. /// However, if the <see cref = "AppendPrependNIterator{TSource}"/> already has an item appended to the end of its <see cref = "_appended"/> list, we cannot do that. /// Instead we have a choice: /// 1. We can copy the <see cref = "_appended"/> list, excluding the extra appended items. /// 2. We can treat the iterator like any other list, and set it as the <see cref = "_source"/> /// Both have costs. /// The first has a cost proportional to the <see cref = "_appendedCount"/>. /// The second increases the level of recursion when indexing into the list by one, and so when iterating through the list has a cost proportional to the total length of the existing iterator /// The total cost can be minimized by taking the first option when the list is small, but the second when the list is large. /// How big is small and large? /// A little bit of calculus tells us that in the worst case scenario, the length that a list has to be before we copy it should be proportional to the square root of the total length of the iterator. /// What is that proportion? /// A little bit of preliminary testing suggests it to be around the 10 - 15 region, leaning towards 15. Hopefully I'll benchmark it more thoroughly in the future. This is the <see cref = "recursionCostMultiplier"/> /// /// Everything above applies to prepending as well of course /// </summary> /// <param name="source"></param> /// <param name="item"></param> /// <param name="append"></param> private AppendPrependNIterator(AppendPrependNIterator <TSource> source, TSource item, bool append) { const int recursionCostMultiplier = 15; _source = source._source; if (append) { if (source._appended.Count > source._appendedCount && source._appendedCount > Math.Sqrt(source._source.Count) * recursionCostMultiplier) { _source = source; _appended = new List <TSource>(1) { item }; _prepended = new List <TSource>(); _appendedCount = 1; _prependedCount = 0; } else { _appended = source._appended.Count > source._appendedCount ? source._appended.GetRange(0, source._appendedCount) : source._appended; _prepended = source._prepended; _prependedCount = source._prependedCount; _appendedCount = source._appendedCount + 1; _appended.Add(item); } } else { if (source._prepended.Count > source._prependedCount && source._prependedCount > Math.Sqrt(source._source.Count) * recursionCostMultiplier) { _source = source; _appended = new List <TSource>(); _prepended = new List <TSource>(1) { item }; _appendedCount = 0; _prependedCount = 1; } else { _appended = source._appended; _prepended = source._prepended.Count > source._prependedCount ? source._prepended.GetRange(0, source._prependedCount) : source._prepended; _prependedCount = source._prependedCount + 1; _appendedCount = source._appendedCount; _prepended.Add(item); } } }