浏览代码

Reducing size of linked list nodes.

Bart De Smet 8 年之前
父节点
当前提交
1cf439007c

+ 30 - 17
Ix.NET/Source/System.Linq.Async/System/Linq/Operators/AppendPrepend.cs

@@ -21,7 +21,7 @@ namespace System.Linq
                 return appendable.Append(element);
             }
 
-            return new AppendPrepend1AsyncIterator<TSource>(source, element, true);
+            return new AppendPrepend1AsyncIterator<TSource>(source, element, appending: true);
         }
 
         public static IAsyncEnumerable<TSource> Prepend<TSource>(this IAsyncEnumerable<TSource> source, TSource element)
@@ -34,7 +34,7 @@ namespace System.Linq
                 return appendable.Prepend(element);
             }
 
-            return new AppendPrepend1AsyncIterator<TSource>(source, element, false);
+            return new AppendPrepend1AsyncIterator<TSource>(source, element, appending: false);
         }
 
         private abstract class AppendPrependAsyncIterator<TSource> : AsyncIterator<TSource>, IAsyncIListProvider<TSource>
@@ -158,20 +158,24 @@ namespace System.Linq
             {
                 if (appending)
                 {
-                    return new AppendPrependNAsyncIterator<TSource>(source, null, new SingleLinkedNode<TSource>(item, element));
+                    return new AppendPrependNAsyncIterator<TSource>(source, null, new SingleLinkedNode<TSource>(item).Add(element), prependCount: 0, appendCount: 2);
+                }
+                else
+                {
+                    return new AppendPrependNAsyncIterator<TSource>(source, new SingleLinkedNode<TSource>(item), new SingleLinkedNode<TSource>(element), prependCount: 1, appendCount: 1);
                 }
-
-                return new AppendPrependNAsyncIterator<TSource>(source, new SingleLinkedNode<TSource>(item), new SingleLinkedNode<TSource>(element));
             }
 
             public override AppendPrependAsyncIterator<TSource> Prepend(TSource element)
             {
                 if (appending)
                 {
-                    return new AppendPrependNAsyncIterator<TSource>(source, new SingleLinkedNode<TSource>(element), new SingleLinkedNode<TSource>(item));
+                    return new AppendPrependNAsyncIterator<TSource>(source, new SingleLinkedNode<TSource>(element), new SingleLinkedNode<TSource>(item), prependCount: 1, appendCount: 1);
+                }
+                else
+                {
+                    return new AppendPrependNAsyncIterator<TSource>(source, new SingleLinkedNode<TSource>(item).Add(element), null, prependCount: 2, appendCount: 0);
                 }
-
-                return new AppendPrependNAsyncIterator<TSource>(source, new SingleLinkedNode<TSource>(item, element), null);
             }
 
             public override async Task<TSource[]> ToArrayAsync(CancellationToken cancellationToken)
@@ -273,21 +277,28 @@ namespace System.Linq
         {
             private readonly SingleLinkedNode<TSource> prepended;
             private readonly SingleLinkedNode<TSource> appended;
-
+            private readonly int prependCount;
+            private readonly int appendCount;
             private SingleLinkedNode<TSource> node;
 
-            public AppendPrependNAsyncIterator(IAsyncEnumerable<TSource> source, SingleLinkedNode<TSource> prepended, SingleLinkedNode<TSource> appended)
+            public AppendPrependNAsyncIterator(IAsyncEnumerable<TSource> source, SingleLinkedNode<TSource> prepended, SingleLinkedNode<TSource> appended, int prependCount, int appendCount)
                 : base(source)
             {
                 Debug.Assert(prepended != null || appended != null);
+                Debug.Assert(prependCount > 0 || appendCount > 0);
+                Debug.Assert(prependCount + appendCount >= 2);
+                Debug.Assert((prepended?.GetCount() ?? 0) == prependCount);
+                Debug.Assert((appended?.GetCount() ?? 0) == appendCount);
 
                 this.prepended = prepended;
                 this.appended = appended;
+                this.prependCount = prependCount;
+                this.appendCount = appendCount;
             }
 
             public override AsyncIterator<TSource> Clone()
             {
-                return new AppendPrependNAsyncIterator<TSource>(source, prepended, appended);
+                return new AppendPrependNAsyncIterator<TSource>(source, prepended, appended, prependCount, appendCount);
             }
 
             int mode;
@@ -341,7 +352,7 @@ namespace System.Linq
 
                                 if (appended != null)
                                 {
-                                    appendedEnumerator = appended.GetEnumerator();
+                                    appendedEnumerator = appended.GetEnumerator(appendCount);
                                     mode = 4;
                                     goto case 4;
                                 }
@@ -367,12 +378,14 @@ namespace System.Linq
 
             public override AppendPrependAsyncIterator<TSource> Append(TSource item)
             {
-                return new AppendPrependNAsyncIterator<TSource>(source, prepended, appended != null ? appended.Add(item) : new SingleLinkedNode<TSource>(item));
+                var res = appended != null ? appended.Add(item) : new SingleLinkedNode<TSource>(item);
+                return new AppendPrependNAsyncIterator<TSource>(source, prepended, res, prependCount, appendCount + 1);
             }
 
             public override AppendPrependAsyncIterator<TSource> Prepend(TSource item)
             {
-                return new AppendPrependNAsyncIterator<TSource>(source, prepended != null ? prepended.Add(item) : new SingleLinkedNode<TSource>(item), appended);
+                var res = prepended != null ? prepended.Add(item) : new SingleLinkedNode<TSource>(item);
+                return new AppendPrependNAsyncIterator<TSource>(source, res, appended, prependCount + 1, appendCount);
             }
 
             public override async Task<TSource[]> ToArrayAsync(CancellationToken cancellationToken)
@@ -448,7 +461,7 @@ namespace System.Linq
 
                 if (appended != null)
                 {
-                    using (var en2 = appended.GetEnumerator())
+                    using (var en2 = appended.GetEnumerator(appendCount))
                     {
                         while (en2.MoveNext())
                         {
@@ -465,10 +478,10 @@ namespace System.Linq
                 if (source is IAsyncIListProvider<TSource> listProv)
                 {
                     var count = await listProv.GetCountAsync(onlyIfCheap, cancellationToken).ConfigureAwait(false);
-                    return count == -1 ? -1 : count + (appended == null ? 0 : appended.Count) + (prepended == null ? 0 : prepended.Count);
+                    return count == -1 ? -1 : count + appendCount + prependCount;
                 }
 
-                return !onlyIfCheap || source is ICollection<TSource> ? await source.Count(cancellationToken).ConfigureAwait(false) + (appended == null ? 0 : appended.Count) + (prepended == null ? 0 : prepended.Count) : -1;
+                return !onlyIfCheap || source is ICollection<TSource> ? await source.Count(cancellationToken).ConfigureAwait(false) + appendCount + prependCount : -1;
             }
         }
     }

+ 81 - 17
Ix.NET/Source/System.Linq.Async/System/Linq/Operators/SingleLinkedNode.cs

@@ -2,54 +2,118 @@
 // The .NET Foundation licenses this file to you under the Apache 2.0 License.
 // See the LICENSE file in the project root for more information. 
 
+// Copied from https://github.com/dotnet/corefx/blob/f17f1e847aeab830de77f8a46656339d7b0f1b43/src/System.Linq/src/System/Linq/SingleLinkedNode.cs
+
 using System.Collections.Generic;
 using System.Diagnostics;
 
 namespace System.Linq
 {
+    /// <summary>
+    /// An immutable node in a singly-linked list of items.
+    /// </summary>
+    /// <typeparam name="TSource">The type of the node's item.</typeparam>
     internal sealed class SingleLinkedNode<TSource>
     {
-        public SingleLinkedNode(TSource first, TSource second)
-        {
-            Linked = new SingleLinkedNode<TSource>(first);
-            Item = second;
-            Count = 2;
-        }
-
+        /// <summary>
+        /// Constructs a tail node.
+        /// </summary>
+        /// <param name="item">The item to place in the tail node.</param>
         public SingleLinkedNode(TSource item)
         {
             Item = item;
-            Count = 1;
         }
 
+        /// <summary>
+        /// Constructs a node linked to the specified node.
+        /// </summary>
+        /// <param name="linked">The linked node.</param>
+        /// <param name="item">The item to place in this node.</param>
         private SingleLinkedNode(SingleLinkedNode<TSource> linked, TSource item)
         {
             Debug.Assert(linked != null);
             Linked = linked;
             Item = item;
-            Count = linked.Count + 1;
         }
 
+        /// <summary>
+        /// The item held by this node.
+        /// </summary>
         public TSource Item { get; }
 
+        /// <summary>
+        /// The next node in the singly-linked list.
+        /// </summary>
         public SingleLinkedNode<TSource> Linked { get; }
 
-        public int Count { get; }
-
+        /// <summary>
+        /// Creates a new node that holds the specified item and is linked to this node.
+        /// </summary>
+        /// <param name="item">The item to place in the new node.</param>
         public SingleLinkedNode<TSource> Add(TSource item) => new SingleLinkedNode<TSource>(this, item);
 
-        public IEnumerator<TSource> GetEnumerator()
+        /// <summary>
+        /// Gets the number of items in this and subsequent nodes by walking the linked list.
+        /// </summary>
+        public int GetCount()
+        {
+            int count = 0;
+            for (SingleLinkedNode<TSource> node = this; node != null; node = node.Linked)
+            {
+                count++;
+            }
+
+            return count;
+        }
+
+        /// <summary>
+        /// Gets an <see cref="IEnumerator{TSource}"/> that enumerates the items of this node's singly-linked list in reverse.
+        /// </summary>
+        /// <param name="count">The number of items in this node.</param>
+        public IEnumerator<TSource> GetEnumerator(int count)
         {
-            var array = new TSource[Count];
-            var index = Count;
-            for (var n = this; n != null; n = n.Linked)
+            return ((IEnumerable<TSource>)ToArray(count)).GetEnumerator();
+        }
+
+        /// <summary>
+        /// Gets the node at a logical index by walking the linked list.
+        /// </summary>
+        /// <param name="index">The logical index.</param>
+        /// <remarks>
+        /// The caller should make sure <paramref name="index"/> is less than this node's count.
+        /// </remarks>
+        public SingleLinkedNode<TSource> GetNode(int index)
+        {
+            Debug.Assert(index >= 0 && index < GetCount());
+
+            SingleLinkedNode<TSource> node = this;
+            for (; index > 0; index--)
+            {
+                node = node.Linked;
+            }
+
+            Debug.Assert(node != null);
+            return node;
+        }
+
+        /// <summary>
+        /// Returns an <see cref="T:TSource[]"/> that contains the items of this node's singly-linked list in reverse.
+        /// </summary>
+        /// <param name="count">The number of items in this node.</param>
+        private TSource[] ToArray(int count)
+        {
+            Debug.Assert(count == GetCount());
+
+            TSource[] array = new TSource[count];
+            int index = count;
+            for (SingleLinkedNode<TSource> node = this; node != null; node = node.Linked)
             {
                 --index;
-                array[index] = n.Item;
+                array[index] = node.Item;
             }
 
             Debug.Assert(index == 0);
-            return ((IEnumerable<TSource>)array).GetEnumerator();
+            return array;
         }
     }
 }