--- trunk/libxmltv/Extensions.cs 2013/03/16 21:53:19 196 +++ trunk/libxmltv/Extensions.cs 2013/03/16 22:02:01 197 @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using System.Diagnostics; namespace libxmltv { @@ -28,16 +29,50 @@ namespace libxmltv public static class extensions { - /// <summary> - /// Break a list of items into chunks of a specific size - /// </summary> - public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> source, int chunksize) + public static IEnumerable<IEnumerable<T>> Chunk<T>(this IEnumerable<T> source, + int chunkSize) { - while (source.Any()) + // Validate parameters. + if (source == null) throw new ArgumentNullException("source"); + if (chunkSize <= 0) throw new ArgumentOutOfRangeException("chunkSize", + "The chunkSize parameter must be a positive value."); + + // Call the internal implementation. + return source.ChunkInternal(chunkSize); + } + private static IEnumerable<IEnumerable<T>> ChunkInternal<T>(this IEnumerable<T> source, int chunkSize) + { + // Validate parameters. + Debug.Assert(source != null); + Debug.Assert(chunkSize > 0); + + // Get the enumerator. Dispose of when done. + using (IEnumerator<T> enumerator = source.GetEnumerator()) + do + { + // Move to the next element. If there's nothing left + // then get out. + if (!enumerator.MoveNext()) yield break; + + // Return the chunked sequence. + yield return ChunkSequence(enumerator, chunkSize); + } while (true); + } + private static IEnumerable<T> ChunkSequence<T>(IEnumerator<T> enumerator, int chunkSize) + { + // Validate parameters. + Debug.Assert(enumerator != null); + Debug.Assert(chunkSize > 0); + + // The count. + int count = 0; + + // There is at least one item. Yield and then continue. + do { - yield return source.Take(chunksize); - source = source.Skip(chunksize); - } + // Yield the item. + yield return enumerator.Current; + } while (++count < chunkSize && enumerator.MoveNext()); } } } |