Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
`lastIndexOfRange`, `lastIndexOfRangeWith`, `binarySearch`, `binarySearchWithComparer`,
`binarySearchRangeWithComparer`) and copies elements into an array (`blit`). `replace` throws `ArgumentException` for a
value that no element equals, as the builder of an indexed list does.
* `Stack` has every function of the FSharp.Core `List` module that applies to an immutable stack, with its semantics and
exceptions and with stable sorts, plus `consMany`, `ofReadOnlySpan`, `ofSpan`, `skipLast`, `sortWithComparer`,
`takeLast`, `tryTail`, `tryUncons` and `uncons`. A stack enumerates its elements from the top, and every function
treats it as a list in that order; `rev` puts the last element on top. Its functions name their stacks `stack`,
`stack1` and `stacks` where `List` names its lists, and the exceptions report these names. `consMany`, `uncons`,
`tryHead`, `tryTail` and `tryUncons` compile to `PushMany`, `PeekPop`, `TryPeek`, `TryPop` and `TryPeekPop`, in the
`IStack`, `Option` and `Tuple` modules too. A function that takes a sequence throws `ArgumentNullException` that names
the parameter for a `null` sequence and for a default `FlatList` given as a sequence, which would fail with
`InvalidOperationException` while the function enumerates it; the `IStack` module and the `stack { }` expression do the
same.
* The `IStack` module has the functions of `Stack` for `IImmutableStack<'T>`, without the creation functions, plus
`clear`. Its functions keep the implementation of the input stack where the result has the element type of the input,
and return a `Stack` otherwise. `append` pushes the first stack onto the second one, which receives the elements, so
its result keeps the implementation and the nodes of the second stack, as `List.append` shares its second list.
* The `FSharp.Collections.Immutable.Option` and `FSharp.Collections.Immutable.Tuple` namespaces have `Stack` and `IStack`
modules that repeat the functions that use value options or struct tuples with options and reference tuples.
* `stack { }` builds a stack whose first element is on top.

### Changed

Expand Down Expand Up @@ -124,6 +141,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* `IndexedList.rev` builds the reversed list from a reversed copy of the elements. At 100 000 integers it takes about 3 ms
where `reverse`, which called `ImmutableList.Reverse`, took about 23 ms, and it allocates 5.2 MB where `reverse`
allocated 4.8 MB.
* `Stack`: `ofSeq` and `ofArray` put the first element on top, so that the stack enumerates the elements in the order of
the input. They wrapped `ImmutableStack.CreateRange`, which puts the last element on top. A `null` input throws
`ArgumentNullException` for `source` in `ofSeq` and for `array` in `ofArray`, where 1.0.0 named both parameters `items`.
A default `FlatList` given as a sequence to `ofSeq` throws the same exception as a `null` sequence, where it threw
`InvalidOperationException`.
* `Stack`: `cons`, `head` and `tail` take and return `ImmutableStack<'T>`, where they took and returned
`IImmutableStack<'T>`; the `IStack` module has them for the interface. They compile to `Push`, `Peek` and `Pop`, where
1.0.0 compiled them under their F# names.
* `Stack`: `head` and `tail` of an empty stack throw the `ArgumentException` of `List.head` and `List.tail`, where they
threw the `InvalidOperationException` of `ImmutableStack`.
* `Stack`: the complete active pattern `Cons | Nil`, which matched a reference tuple, is replaced by the struct partial
active patterns `Cons`, which matches a struct tuple, and `Nil`.

### Removed

Expand Down Expand Up @@ -161,6 +190,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* The `IndexedSeq` module and the `IIndexedSeq<'T>` abbreviation of `IReadOnlyList<'T>`: use `IReadOnlyList<'T>`, whose
`Count` and indexer replace `IndexedSeq.length` and `IndexedSeq.item`. `IndexedSeq.check` needs no replacement, because
every function of the list modules throws `ArgumentNullException` for a `null` list.
* `Stack.push`, `peek` and `pop`: use `cons`, `head` and `uncons`. `pop` returned the top and the stack below it as a
reference tuple; `uncons` returns a struct tuple.

## [1.0.0] - 2020-02-23

Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ Please also join the [F# Open Source Group](http://fsharp.github.com)
| `FlatList` | `ImmutableArray<'T>` | `flatList { }` |
| `IndexedList` | `ImmutableList<'T>` | `indexedList { }` |
| `IIndexedList` | `IImmutableList<'T>` | – |
| `Stack` | `ImmutableStack<'T>` | – |
| `Stack` | `ImmutableStack<'T>` | `stack { }` |
| `IStack` | `IImmutableStack<'T>` | – |
| `Queue` | `ImmutableQueue<'T>` | – |
| `HashMap` | `ImmutableDictionary<'Key, 'Value>` | – |
| `SortedMap` | `ImmutableSortedDictionary<'Key, 'Value>` | – |
Expand Down
3 changes: 2 additions & 1 deletion docsSrc/Explanations/Background.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ While F# has its own built-in immutable collections, System.Collections.Immutabl
| `FlatList` | `ImmutableArray<'T>` | `flatList { }` |
| `IndexedList` | `ImmutableList<'T>` | `indexedList { }` |
| `IIndexedList` | `IImmutableList<'T>` | – |
| `Stack` | `ImmutableStack<'T>` | – |
| `Stack` | `ImmutableStack<'T>` | `stack { }` |
| `IStack` | `IImmutableStack<'T>` | – |
| `Queue` | `ImmutableQueue<'T>` | – |
| `HashMap` | `ImmutableDictionary<'Key, 'Value>` | – |
| `SortedMap` | `ImmutableSortedDictionary<'Key, 'Value>` | – |
Expand Down
3 changes: 2 additions & 1 deletion docsSrc/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ F# bindings for [System.Collections.Immutable](https://learn.microsoft.com/en-us
| `FlatList` | `ImmutableArray<'T>` | `flatList { }` |
| `IndexedList` | `ImmutableList<'T>` | `indexedList { }` |
| `IIndexedList` | `IImmutableList<'T>` | – |
| `Stack` | `ImmutableStack<'T>` | – |
| `Stack` | `ImmutableStack<'T>` | `stack { }` |
| `IStack` | `IImmutableStack<'T>` | – |
| `Queue` | `ImmutableQueue<'T>` | – |
| `HashMap` | `ImmutableDictionary<'Key, 'Value>` | – |
| `SortedMap` | `ImmutableSortedDictionary<'Key, 'Value>` | – |
Expand Down
2 changes: 2 additions & 0 deletions src/FSharp.Collections.Immutable/ComputationExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ module FSharp.Collections.Immutable.ComputationExpressions
let flatList = FlatListCE ()

let indexedList = IndexedListCE ()

let stack = StackCE ()
16 changes: 16 additions & 0 deletions src/FSharp.Collections.Immutable/ComputationExpressions.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,19 @@ val flatList : FlatListCE
/// Evaluates to an indexed list of 0, 1, 4, 9, 100 and 200.
/// </example>
val indexedList : IndexedListCE

/// <summary>
/// Builds a stack, with the first element of the expression on top.
/// </summary>
/// <example id="stack-1">
/// <code lang="fsharp">
/// let squares = stack {
/// yield 0
/// for i in 1..3 do
/// yield i * i
/// yield! [ 100; 200 ]
/// }
/// </code>
/// Evaluates to a stack of 0, 1, 4, 9, 100 and 200, with 0 on top.
/// </example>
val stack : StackCE
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
<Compile Include="Helper\Lengths.fs" />
<Compile Include="Helper\DescendingSorts.fs" />
<Compile Include="Helper\ListRanges.fs" />
<Compile Include="Helper\StackConstruction.fs" />
<Compile Include="FlatList\FlatListTypes.fs" />
<Compile Include="FlatList\FlatList.fsi" />
<Compile Include="FlatList\FlatList.fs" />
Expand Down Expand Up @@ -68,7 +69,21 @@
<Compile Include="IndexedList\IndexedListBuilder.fs" />
<Compile Include="IndexedList\IndexedListCE.fsi" />
<Compile Include="IndexedList\IndexedListCE.fs" />
<Compile Include="Stack.fs" />
<Compile Include="Stack\StackTypes.fs" />
<Compile Include="Stack\Stack.fsi" />
<Compile Include="Stack\Stack.fs" />
<Compile Include="Stack\StackOption.fsi" />
<Compile Include="Stack\StackOption.fs" />
<Compile Include="Stack\StackTuple.fsi" />
<Compile Include="Stack\StackTuple.fs" />
<Compile Include="Stack\IStack.fsi" />
<Compile Include="Stack\IStack.fs" />
<Compile Include="Stack\IStackOption.fsi" />
<Compile Include="Stack\IStackOption.fs" />
<Compile Include="Stack\IStackTuple.fsi" />
<Compile Include="Stack\IStackTuple.fs" />
<Compile Include="Stack\StackCE.fsi" />
<Compile Include="Stack\StackCE.fs" />
<Compile Include="Queue.fs" />
<Compile Include="Maps.fs" />
<Compile Include="Sets.fs" />
Expand Down
46 changes: 46 additions & 0 deletions src/FSharp.Collections.Immutable/Helper/StackConstruction.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/// <summary>
/// The construction of the stacks that the stack modules and the <c>stack { }</c> expression return.
/// </summary>
/// <remarks>
/// <see cref="M:System.Collections.Immutable.ImmutableStack.CreateRange``1(System.Collections.Generic.IEnumerable{``0})"/>
/// pushes the elements in order and leaves the last element on top. The stack modules keep the first element on top
/// instead, so that a stack enumerates its elements in the order in which it was created (ADR 0001, D5). The module serves
/// the stack modules, their <c>Tuple</c> counterparts and the computation expression, so that they build their stacks with
/// one implementation.
/// </remarks>
module internal FSharp.Collections.Immutable.StackConstruction

open System.Collections.Immutable

/// <summary>
/// Pushes the elements of an array onto a stack, from the last element to the first one.
/// </summary>
/// <param name="items">The elements; neither checked for <see langword="null"/> nor kept.</param>
/// <param name="stack">
/// The stack to push the elements onto, an <see cref="T:System.Collections.Immutable.ImmutableStack`1"/> or an
/// <see cref="T:System.Collections.Immutable.IImmutableStack`1"/>.
/// </param>
/// <returns>A stack of the elements of the array, the first one on top, followed by the elements of the stack.</returns>
/// <remarks>
/// O(m), where m is the length of the array. The result shares the nodes of the stack and keeps its implementation.
/// </remarks>
let inline pushArray (items : 'T array) (stack : ^Stack) : ^Stack when ^Stack : (member Push : 'T -> ^Stack) =
// The constraint serves the concrete stack and the interface with one loop: each Push returns the type it is called
// on, so the result keeps the implementation of the stack
let mutable result = stack

// Pushing from the last element leaves the first one on top, so that the result enumerates the array in its order
for index = items.Length - 1 downto 0 do
result <- (^Stack : (member Push : 'T -> ^Stack) (result, items[index]))

result

/// <summary>
/// A stack whose top is the first element of an array, which enumerates the elements in the order of the array.
/// </summary>
/// <param name="array">The elements; neither checked for <see langword="null"/> nor kept.</param>
/// <returns>The stack of the elements.</returns>
/// <remarks>
/// O(n). The function pushes the elements onto the empty stack from the last one to the first one.
/// </remarks>
let ofArrayUnchecked (array : 'T array) : ImmutableStack<'T> = pushArray array ImmutableStack<'T>.Empty
52 changes: 0 additions & 52 deletions src/FSharp.Collections.Immutable/Stack.fs

This file was deleted.

Loading