-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add CollectionsMarshal support for the Stack<T> collection #82999
Comments
Tagging subscribers to this area: @dotnet/area-system-collections Issue DetailsBackground and motivationI am coming from the API proposal #15922 about allowing random access in the Specific scenario: A API Proposalnamespace System.Runtime.InteropServices
{
public static partial class CollectionsMarshal
{
public static Span<T> AsSpan<T> (Stack<T> stack);
public static void SetCount<T>(Stack<T> stack, int count);
}
} API UsageBelow is the aforementioned public static void PushReverseRange<T>(this Stack<T> source, IEnumerable<T> items)
{
int originalCount = source.Count;
try
{
foreach (T item in items)
source.Push(item);
}
catch
{
CollectionsMarshal.SetCount(source, originalCount); throw;
}
Span<T> span = CollectionsMarshal.AsSpan(source);
span.Slice(originalCount, source.Count - originalCount).Reverse();
} Alternative DesignsNo response RisksExposing the backing storage of the Labels: area-System.Collections / api-suggestion.
|
I've often had need for something similar to "PushReverseRange" as currently there is no good way to clone a stack without using an intermediate buffer. Perhaps though having a set of methods in CollectionMarshal is overkill when trying to solve this problem? Could a new instance method be more helpful here? |
@eiriktsarpalis having the Another scenario where the |
I think the general point of things like Notably, we have to consider whether such changes "block" our ability to change or otherwise optimize the data structure later on. For example, For For |
Sounds like you should be using |
My point is that unlike That being said, @theodorzoulias's use case is definitely there, and cannot be addressed currently without using an intermediate buffer. See also #83086. I think any static footprint concerns that have prevented us from adding a number of instance methods to List do not apply here: Stack isn't nearly as ubiquitous as List. |
@Joe4evr no, definitely not. Traversing a tree using a |
Note that the proposed |
Background and motivation
I am coming from the API proposal #15922 about allowing random access in the
Stack<T>
(andQueue<T>
) collection, after having experienced recently myself a lack of features in theStack<T>
collection, that induced me to use reluctantly aList<T>
instead. I would like to suggest giving to theStack<T>
collection the sameCollectionsMarshal
support that theList<T>
enjoys, in order to make it a more flexible and powerful collection: theAsSpan
andSetCount
APIs.Specific scenario: A
Stack<T>
is the collection of choice when someone wants to transform a recursive algorithm to an iterative algorithm, for example traversing a tree. It is desirable that the children of each node are pushed in the stack in the reverse order, so that the first child is popped first. TheStack<T>
offers no way to push a sequence of items in the reverse order, without materializing the sequence, causing multiple array allocations along the way. If theCollectionsMarshal.AsSpan
was available, someone could easily implement an efficientPushReverseRange
extension method for theStack<T>
collection, instead of being forced to switch to aList<T>
, in the detriment of the readability of their code (List<T> stack = new();
is semantically incorrect).API Proposal
API Usage
Below is the aforementioned
PushReverseRange
extension method, that pushes an enumerable sequence in theStack<T>
in reverse order, with minimal allocations. Theitems
are inserted in normal order, and then they are reversed directly on the backing array of theStack<T>
. In case of an exception during the enumeration of theitems
, the originalCount
of the stack is restored with theCollectionsMarshal.SetCount
API:Alternative Designs
Another option could be to add directly in the
Stack<T>
class a couple of APIs, intended to optimize common scenarios that currently require intermediate buffers:Cloning a
Stack<T>
, a scenario mentioned below by @eiriktsarpalis, could be accomplished with either of these two APIs:Risks
Exposing the backing storage of the
Stack<T>
will reduce the freedom of optimizing the internal structure of the collection in the future, for example switching from the array to a linked-list.Labels: area-System.Collections / api-suggestion.
The text was updated successfully, but these errors were encountered: