Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Commit

Permalink
Reduce linked node size in Append/Prepend/Union/Concat
Browse files Browse the repository at this point in the history
  • Loading branch information
jamesqo committed Jan 30, 2017
1 parent 6e2d907 commit 5f1dd82
Show file tree
Hide file tree
Showing 7 changed files with 266 additions and 501 deletions.
1 change: 1 addition & 0 deletions src/System.Linq/src/System.Linq.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
<Compile Include="System\Linq\SequenceEqual.cs" />
<Compile Include="System\Linq\Set.cs" />
<Compile Include="System\Linq\Single.cs" />
<Compile Include="System\Linq\SingleLinkedNode.cs" />
<Compile Include="System\Linq\Skip.cs" />
<Compile Include="System\Linq\Sum.cs" />
<Compile Include="System\Linq\Take.cs" />
Expand Down
131 changes: 27 additions & 104 deletions src/System.Linq/src/System/Linq/AppendPrepend.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static IEnumerable<TSource> Append<TSource>(this IEnumerable<TSource> sou
return appendable.Append(element);
}

return new AppendPrepend1Iterator<TSource>(source, element, true);
return new AppendPrepend1Iterator<TSource>(source, element, appending: true);
}

public static IEnumerable<TSource> Prepend<TSource>(this IEnumerable<TSource> source, TSource element)
Expand All @@ -38,7 +38,7 @@ public static IEnumerable<TSource> Prepend<TSource>(this IEnumerable<TSource> so
return appendable.Prepend(element);
}

return new AppendPrepend1Iterator<TSource>(source, element, false);
return new AppendPrepend1Iterator<TSource>(source, element, appending: false);
}

/// <summary>
Expand Down Expand Up @@ -154,23 +154,23 @@ public override AppendPrependIterator<TSource> Append(TSource item)
{
if (_appending)
{
return new AppendPrependN<TSource>(_source, null, new SingleLinkedNode<TSource>(_item, item));
return new AppendPrependN<TSource>(_source, null, new SingleLinkedNode<TSource>(_item).Add(item), prependCount: 0, appendCount: 2);
}
else
{
return new AppendPrependN<TSource>(_source, new SingleLinkedNode<TSource>(_item), new SingleLinkedNode<TSource>(item));
return new AppendPrependN<TSource>(_source, new SingleLinkedNode<TSource>(_item), new SingleLinkedNode<TSource>(item), prependCount: 1, appendCount: 1);
}
}

public override AppendPrependIterator<TSource> Prepend(TSource item)
{
if (_appending)
{
return new AppendPrependN<TSource>(_source, new SingleLinkedNode<TSource>(item), new SingleLinkedNode<TSource>(_item));
return new AppendPrependN<TSource>(_source, new SingleLinkedNode<TSource>(item), new SingleLinkedNode<TSource>(_item), prependCount: 1, appendCount: 1);
}
else
{
return new AppendPrependN<TSource>(_source, new SingleLinkedNode<TSource>(_item, item), null);
return new AppendPrependN<TSource>(_source, new SingleLinkedNode<TSource>(_item).Add(item), null, prependCount: 2, appendCount: 0);
}
}

Expand Down Expand Up @@ -256,94 +256,6 @@ public override int GetCount(bool onlyIfCheap)
}
}

/// <summary>
/// An immutable node in a singly-linked list of items.
/// </summary>
/// <typeparam name="TSource">The type of the node's item.</typeparam>
private sealed class SingleLinkedNode<TSource>
{
/// <summary>
/// Constructs a node linked to the tail node.
/// </summary>
/// <param name="first">The first item, to be placed in the tail node.</param>
/// <param name="second">The second item, to be placed in this node.</param>
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; }

/// <summary>
/// The number of items stored in this and subsequent nodes.
/// </summary>
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);

/// <summary>
/// Gets an <see cref="IEnumerator{TSource}"/> that enumerates the items of this node's singly-linked list in reverse.
/// </summary>
public IEnumerator<TSource> GetEnumerator()
{
return ((IEnumerable<TSource>)ToArray()).GetEnumerator();
}

/// <summary>
/// Returns an <see cref="T:TSource[]"/> that contains the items of this node's singly-linked list in reverse.
/// </summary>
public TSource[] ToArray()
{
TSource[] array = new TSource[Count];
int index = Count;
for (SingleLinkedNode<TSource> node = this; node != null; node = node.Linked)
{
--index;
array[index] = node.Item;
}

Debug.Assert(index == 0);
return array;
}
}

/// <summary>
/// Represents the insertion of multiple items before or after an <see cref="IEnumerable{TSource}"/>.
/// </summary>
Expand All @@ -352,17 +264,26 @@ private class AppendPrependN<TSource> : AppendPrependIterator<TSource>
{
private readonly SingleLinkedNode<TSource> _prepended;
private readonly SingleLinkedNode<TSource> _appended;
private readonly int _prependCount;
private readonly int _appendCount;
private SingleLinkedNode<TSource> _node;

public AppendPrependN(IEnumerable<TSource> source, SingleLinkedNode<TSource> prepended, SingleLinkedNode<TSource> appended)
public AppendPrependN(IEnumerable<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);

_prepended = prepended;
_appended = appended;
_prependCount = prependCount;
_appendCount = appendCount;
}

public override Iterator<TSource> Clone() => new AppendPrependN<TSource>(_source, _prepended, _appended);
public override Iterator<TSource> Clone() => new AppendPrependN<TSource>(_source, _prepended, _appended, _prependCount, _appendCount);

public override bool MoveNext()
{
Expand Down Expand Up @@ -394,7 +315,7 @@ public override bool MoveNext()
return false;
}

_enumerator = _appended.GetEnumerator();
_enumerator = _appended.GetEnumerator(_appendCount);
_state = 4;
goto case 4;
case 4:
Expand All @@ -407,12 +328,14 @@ public override bool MoveNext()

public override AppendPrependIterator<TSource> Append(TSource item)
{
return new AppendPrependN<TSource>(_source, _prepended, _appended != null ? _appended.Add(item) : new SingleLinkedNode<TSource>(item));
var appended = _appended != null ? _appended.Add(item) : new SingleLinkedNode<TSource>(item);
return new AppendPrependN<TSource>(_source, _prepended, appended, _prependCount, _appendCount + 1);
}

public override AppendPrependIterator<TSource> Prepend(TSource item)
{
return new AppendPrependN<TSource>(_source, _prepended != null ? _prepended.Add(item) : new SingleLinkedNode<TSource>(item), _appended);
var prepended = _prepended != null ? _prepended.Add(item) : new SingleLinkedNode<TSource>(item);
return new AppendPrependN<TSource>(_source, prepended, _appended, _prependCount + 1, _appendCount);
}

private TSource[] LazyToArray()
Expand All @@ -423,14 +346,14 @@ private TSource[] LazyToArray()

if (_prepended != null)
{
builder.Reserve(_prepended.Count);
builder.Reserve(_prependCount);
}

builder.AddRange(_source);

if (_appended != null)
{
builder.Reserve(_appended.Count);
builder.Reserve(_appendCount);
}

TSource[] array = builder.ToArray();
Expand Down Expand Up @@ -502,7 +425,7 @@ public override List<TSource> ToList()
list.AddRange(_source);
if (_appended != null)
{
IEnumerator<TSource> e = _appended.GetEnumerator();
IEnumerator<TSource> e = _appended.GetEnumerator(_appendCount);
while (e.MoveNext())
{
list.Add(e.Current);
Expand All @@ -518,10 +441,10 @@ public override int GetCount(bool onlyIfCheap)
if (listProv != null)
{
int count = listProv.GetCount(onlyIfCheap);
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> ? _source.Count() + (_appended == null ? 0 : _appended.Count) + (_prepended == null ? 0 : _prepended.Count) : -1;
return !onlyIfCheap || _source is ICollection<TSource> ? _source.Count() + _appendCount + _prependCount : -1;
}
}
}
Expand Down
Loading

0 comments on commit 5f1dd82

Please sign in to comment.