From 4dcc50747097663b009d3fe2b13771f7985380e2 Mon Sep 17 00:00:00 2001 From: Anthony Minchenko <65635298+anthony-mi@users.noreply.github.com> Date: Sun, 28 Feb 2021 15:26:48 +0200 Subject: [PATCH 01/17] Implemented SortedMap functions --- .../FSharp.Collections.Immutable.fsproj | 9 +-- src/FSharp.Collections.Immutable/maps.fs | 60 +++++++++++++++++++ 2 files changed, 62 insertions(+), 7 deletions(-) diff --git a/src/FSharp.Collections.Immutable/FSharp.Collections.Immutable.fsproj b/src/FSharp.Collections.Immutable/FSharp.Collections.Immutable.fsproj index f19c4a9..b408f24 100644 --- a/src/FSharp.Collections.Immutable/FSharp.Collections.Immutable.fsproj +++ b/src/FSharp.Collections.Immutable/FSharp.Collections.Immutable.fsproj @@ -1,7 +1,7 @@  - netstandard1.6;netstandard2.0 + netstandard2.0 F# bindings for System.Collections.Immutable Copyright © XperiAndri 2016 FSharp.Collections.Immutable @@ -27,13 +27,8 @@ - - - - - - + diff --git a/src/FSharp.Collections.Immutable/maps.fs b/src/FSharp.Collections.Immutable/maps.fs index 1c53dbf..4295470 100644 --- a/src/FSharp.Collections.Immutable/maps.fs +++ b/src/FSharp.Collections.Immutable/maps.fs @@ -1,5 +1,7 @@ namespace FSharp.Collections.Immutable +open System.Collections.Generic + type IMap<'Key, 'Value> = System.Collections.Immutable.IImmutableDictionary<'Key, 'Value> type HashMap<'Key, 'Value> = @@ -16,6 +18,12 @@ module HashMap = checkNotNull "items" items HashMapFactory.CreateRange(items) + let inline ofSeqWith getId items = + checkNotNull "items" items + items + |> Seq.map (fun i -> KeyValuePair(getId i, i)) + |> HashMapFactory.CreateRange + let inline builder() = HashMapFactory.CreateBuilder() let inline ofBuilder (mapBuilder: HashMapBuilder<_,_>) = @@ -71,3 +79,55 @@ type internal SortedMapFactory = System.Collections.Immutable.ImmutableSortedDictionary module SortedMap = let inline empty<'Key, 'Value> = SortedMapFactory.Create<'Key, 'Value>() + + let inline ofSeq items = + checkNotNull "items" items + SortedMapFactory.CreateRange(items) + + let inline ofSeqWith getId items = + checkNotNull "items" items + items + |> Seq.map (fun i -> KeyValuePair(getId i, i)) + |> SortedMapFactory.CreateRange + + let inline builder() = SortedMapFactory.CreateBuilder() + + let inline ofBuilder (mapBuilder: SortedMapBuilder<_,_>) = + checkNotNull "mapBuilder" mapBuilder + mapBuilder.ToImmutable() + + let inline check (map: SortedMap<_, _>) = checkNotNull "map" map + + let inline isEmpty map = check map; map.IsEmpty + let inline length map = check map; map.Count + + let inline keyComparer map = check map; map.KeyComparer + + let inline containsKey key map = check map; map.ContainsKey key + + let inline find key map = check map; map.[key] + let inline tryFind key map = + check map + let mutable value = Unchecked.defaultof<_> + if map.TryGetValue(key, &value) then Some value else None + + let inline add key value map : SortedMap<_,_> = check map; map.Add(key, value) + let inline append map pairs : SortedMap<_,_> = + check map + checkNotNull "pairs" pairs + map.AddRange pairs + + let inline remove key map : SortedMap<_,_> = check map; map.Remove key + let inline except keys map : SortedMap<_,_> = check map; map.RemoveRange keys + + let inline clear map: SortedMap<_,_> = check map; map.Clear() + + let inline toBuilder map : SortedMapBuilder<_,_> = check map; map.ToBuilder() + + // consider alternate implementation using range functions + let inline filter predicate map = + let builder = toBuilder map + for kvp in map do + if predicate kvp.Key kvp.Value then + builder.Add kvp + builder.ToImmutable() From c004b75da5f9845dbeb454fdba226422fec0ad15 Mon Sep 17 00:00:00 2001 From: Anthony Minchenko <65635298+anthony-mi@users.noreply.github.com> Date: Sun, 28 Feb 2021 17:04:16 +0200 Subject: [PATCH 02/17] Updated message text --- src/FSharp.Collections.Immutable/maps.fs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/FSharp.Collections.Immutable/maps.fs b/src/FSharp.Collections.Immutable/maps.fs index 4295470..89dc348 100644 --- a/src/FSharp.Collections.Immutable/maps.fs +++ b/src/FSharp.Collections.Immutable/maps.fs @@ -77,6 +77,7 @@ type SortedMapBuilder<'Key, 'Value> = SortedMap<'Key, 'Value>.Builder type internal SortedMapFactory = System.Collections.Immutable.ImmutableSortedDictionary + module SortedMap = let inline empty<'Key, 'Value> = SortedMapFactory.Create<'Key, 'Value>() @@ -93,10 +94,10 @@ module SortedMap = let inline builder() = SortedMapFactory.CreateBuilder() let inline ofBuilder (mapBuilder: SortedMapBuilder<_,_>) = - checkNotNull "mapBuilder" mapBuilder + checkNotNull "sortedMapBuilder" mapBuilder mapBuilder.ToImmutable() - let inline check (map: SortedMap<_, _>) = checkNotNull "map" map + let inline check (map: SortedMap<_, _>) = checkNotNull "sortedMap" map let inline isEmpty map = check map; map.IsEmpty let inline length map = check map; map.Count From 666365f284f7cad18d281b4ece1a435395c74ffa Mon Sep 17 00:00:00 2001 From: Anthony Minchenko <65635298+anthony-mi@users.noreply.github.com> Date: Mon, 1 Mar 2021 03:15:00 +0200 Subject: [PATCH 03/17] Implemented `SortedMap` and some `HashMap` functions --- src/FSharp.Collections.Immutable/maps.fs | 145 +++++++++++++++++------ 1 file changed, 106 insertions(+), 39 deletions(-) diff --git a/src/FSharp.Collections.Immutable/maps.fs b/src/FSharp.Collections.Immutable/maps.fs index 89dc348..40cbadb 100644 --- a/src/FSharp.Collections.Immutable/maps.fs +++ b/src/FSharp.Collections.Immutable/maps.fs @@ -14,43 +14,64 @@ type internal HashMapFactory = System.Collections.Immutable.ImmutableDictionary module HashMap = let inline empty<'Key, 'Value> = HashMapFactory.Create<'Key, 'Value>() - let inline ofSeq items = - checkNotNull "items" items - HashMapFactory.CreateRange(items) - + let inline ofSeq items = HashMapFactory.CreateRange(items) let inline ofSeqWith getId items = - checkNotNull "items" items + checkNotNull (nameof items) items items |> Seq.map (fun i -> KeyValuePair(getId i, i)) |> HashMapFactory.CreateRange + let inline ofArray items = HashMapFactory.CreateRange(items) + + let inline check (map: HashMap<_, _>) = checkNotNull (nameof map) map let inline builder() = HashMapFactory.CreateBuilder() + let inline builderWithKeyComparer comparer = HashMapFactory.CreateBuilder(comparer) + let inline builderWithComparers keyComparer valueComparer = HashMapFactory.CreateBuilder(keyComparer, valueComparer) let inline ofBuilder (mapBuilder: HashMapBuilder<_,_>) = - checkNotNull "mapBuilder" mapBuilder + checkNotNull (nameof mapBuilder) mapBuilder mapBuilder.ToImmutable() - ///////// + let inline toBuilder map : HashMapBuilder<_,_> = check map; map.ToBuilder() - let inline check (map: HashMap<_, _>) = checkNotNull "map" map + let inline ofKeyComparer<'Key, 'Value> comparer = HashMapFactory.Create<'Key, 'Value>(comparer) + let inline ofComparers<'Key, 'Value> keyComparer valueComparer = HashMapFactory.Create<'Key, 'Value>(keyComparer, valueComparer) + + let inline singleton item = empty.Add(item) let inline isEmpty map = check map; map.IsEmpty + let inline length map = check map; map.Count let inline keyComparer map = check map; map.KeyComparer + let inline valueComparer map = check map; map.ValueComparer - let inline containsKey key map = check map; map.ContainsKey key + let inline containsKey key map = check map; map.ContainsKey key; let inline find key map = check map; map.[key] let inline tryFind key map = check map - let mutable value = Unchecked.defaultof<_> - if map.TryGetValue(key, &value) then Some value else None + match map.TryGetValue(key) with + | true, value -> Some value + | false, _ -> None + let inline vTryFind key map = + check map + match map.TryGetValue(key) with + | true, value -> ValueSome value + | false, _ -> ValueNone + + let inline pick chooser map = check map; map |> Seq.pick (fun kvp -> chooser kvp.Key kvp.Value) + let inline tryPick chooser map = check map; map |> Seq.tryPick (fun kvp -> chooser kvp.Key kvp.Value) + let inline vTryPick chooser map = + check map + match map |> Seq.tryPick (fun kvp -> chooser kvp.Key kvp.Value) with + | Some value -> ValueSome value + | None -> ValueNone let inline add key value map : HashMap<_,_> = check map; map.Add(key, value) let inline append map pairs : HashMap<_,_> = check map - checkNotNull "pairs" pairs + checkNotNull (nameof pairs) pairs map.AddRange pairs let inline remove key map : HashMap<_,_> = check map; map.Remove key @@ -58,16 +79,19 @@ module HashMap = let inline clear map: HashMap<_,_> = check map; map.Clear() - let inline toBuilder map : HashMapBuilder<_,_> = check map; map.ToBuilder() + let inline filter predicate map = + map |> Seq.filter (fun (kvp:KeyValuePair<_,_>) -> predicate kvp.Key kvp.Value) + let inline forall predicate map = + map |> Seq.forall (fun (kvp:KeyValuePair<_,_>) -> predicate kvp.Key kvp.Value) - // consider alternate implementation using range functions - let inline filter predicate map = - let builder = toBuilder map - for kvp in map do - if predicate kvp.Key kvp.Value then - builder.Add kvp - builder.ToImmutable() + let inline map mapping map' = + map' |> Seq.map (fun (kvp:KeyValuePair<_,_>) -> mapping kvp.Key kvp.Value) + + let inline where predicate map = + map |> Seq.where (fun (kvp:KeyValuePair<_,_>) -> predicate kvp.Key kvp.Value) |> empty.AddRange + + let inline count (map:HashMap<_,_>) = check map; map.Count type SortedMap<'Key, 'Value> = @@ -81,41 +105,68 @@ type internal SortedMapFactory = module SortedMap = let inline empty<'Key, 'Value> = SortedMapFactory.Create<'Key, 'Value>() - let inline ofSeq items = - checkNotNull "items" items - SortedMapFactory.CreateRange(items) - + let inline ofSeq items = SortedMapFactory.CreateRange(items) let inline ofSeqWith getId items = - checkNotNull "items" items + checkNotNull (nameof items) items items |> Seq.map (fun i -> KeyValuePair(getId i, i)) |> SortedMapFactory.CreateRange + let inline ofArray items = SortedMapFactory.CreateRange(items) + + let inline check (sortedMap: SortedMap<_, _>) = checkNotNull (nameof sortedMap) sortedMap let inline builder() = SortedMapFactory.CreateBuilder() + let inline builderWithKeyComparer comparer = SortedMapFactory.CreateBuilder(comparer) + let inline builderWithComparers keyComparer valueComparer = SortedMapFactory.CreateBuilder(keyComparer, valueComparer) - let inline ofBuilder (mapBuilder: SortedMapBuilder<_,_>) = - checkNotNull "sortedMapBuilder" mapBuilder - mapBuilder.ToImmutable() + let inline ofBuilder (sortedMapBuilder: SortedMapBuilder<_,_>) = + checkNotNull (nameof sortedMapBuilder) sortedMapBuilder + sortedMapBuilder.ToImmutable() - let inline check (map: SortedMap<_, _>) = checkNotNull "sortedMap" map + let inline toBuilder map : SortedMapBuilder<_,_> = check map; map.ToBuilder() + + let inline ofKeyComparer<'Key, 'Value> comparer = SortedMapFactory.Create<'Key, 'Value>(comparer) + let inline ofComparers<'Key, 'Value> keyComparer valueComparer = SortedMapFactory.Create<'Key, 'Value>(keyComparer, valueComparer) + + let inline singleton item = empty.Add(item) let inline isEmpty map = check map; map.IsEmpty + let inline length map = check map; map.Count let inline keyComparer map = check map; map.KeyComparer + let inline valueComparer map = check map; map.ValueComparer let inline containsKey key map = check map; map.ContainsKey key let inline find key map = check map; map.[key] let inline tryFind key map = check map - let mutable value = Unchecked.defaultof<_> - if map.TryGetValue(key, &value) then Some value else None + match map.TryGetValue(key) with + | true,value -> Some value + | false,_ -> None + let inline vTryFind key map = + check map + match map.TryGetValue(key) with + | true, value -> ValueSome value + | false, _ -> ValueNone + + let inline pick chooser map = check map; map |> Seq.pick (fun kvp -> chooser kvp.Key kvp.Value) + let inline tryPick chooser map = check map; map |> Seq.tryPick (fun kvp -> chooser kvp.Key kvp.Value) + let inline vTryPick chooser map = + check map + match map |> Seq.tryPick (fun kvp -> chooser kvp.Key kvp.Value) with + | Some value -> ValueSome value + | None -> ValueNone + + let inline iter action map = check map; map |> Seq.iter (fun kvp -> action kvp.Key kvp.Value) + + let inline exists predicate map = check map; map |> Seq.exists (fun kvp -> predicate kvp.Key kvp.Value) let inline add key value map : SortedMap<_,_> = check map; map.Add(key, value) let inline append map pairs : SortedMap<_,_> = check map - checkNotNull "pairs" pairs + checkNotNull (nameof pairs) pairs map.AddRange pairs let inline remove key map : SortedMap<_,_> = check map; map.Remove key @@ -123,12 +174,28 @@ module SortedMap = let inline clear map: SortedMap<_,_> = check map; map.Clear() - let inline toBuilder map : SortedMapBuilder<_,_> = check map; map.ToBuilder() + let inline findKey predicate map = + check map + match (map |> Seq.tryFind (fun kvp -> predicate kvp.Key kvp.Value)) with + | Some value -> value.Key + | None -> raise (new KeyNotFoundException()) + let inline tryFindKey predicate map = check map; map |> Seq.tryFind (fun kvp -> predicate kvp.Key kvp.Value) + let inline vTryFindKey predicate map = + check map + match (map |> Seq.tryFind (fun kvp -> predicate kvp.Key kvp.Value)) with + | Some value -> ValueSome value.Key + | None -> ValueNone - // consider alternate implementation using range functions let inline filter predicate map = - let builder = toBuilder map - for kvp in map do - if predicate kvp.Key kvp.Value then - builder.Add kvp - builder.ToImmutable() + map |> Seq.filter (fun (kvp:KeyValuePair<_,_>) -> predicate kvp.Key kvp.Value) + + let inline forall predicate map = + map |> Seq.forall (fun (kvp:KeyValuePair<_,_>) -> predicate kvp.Key kvp.Value) + + let inline map mapping map' = + map' |> Seq.map (fun (kvp:KeyValuePair<_,_>) -> mapping kvp.Key kvp.Value) + + let inline where predicate map = + map |> Seq.where (fun (kvp:KeyValuePair<_,_>) -> predicate kvp.Key kvp.Value) |> empty.AddRange + + let inline count (map:SortedMap<_,_>) = check map; map.Count From 177187c9cb052cee4a95e53f4f266f191221c07e Mon Sep 17 00:00:00 2001 From: Anthony Minchenko <65635298+anthony-mi@users.noreply.github.com> Date: Mon, 1 Mar 2021 16:55:21 +0200 Subject: [PATCH 04/17] Implemented `HashSet` and `SortedSet` functions --- src/FSharp.Collections.Immutable/sets.fs | 137 ++++++++++++++++++++++- 1 file changed, 136 insertions(+), 1 deletion(-) diff --git a/src/FSharp.Collections.Immutable/sets.fs b/src/FSharp.Collections.Immutable/sets.fs index b2f86e5..60da73d 100644 --- a/src/FSharp.Collections.Immutable/sets.fs +++ b/src/FSharp.Collections.Immutable/sets.fs @@ -2,6 +2,141 @@ type ISet<'T> = System.Collections.Immutable.IImmutableSet<'T> +type HashSet<'T> = System.Collections.Immutable.ImmutableHashSet<'T> + +type HashSetBuilder<'T> = HashSet<'T>.Builder + +type internal HashSetFactory = System.Collections.Immutable.ImmutableHashSet + +module HashSet = + let inline empty<'T> = HashSetFactory.Create<'T>() + + let inline ofBuilder (hashSetBuilder: HashSetBuilder<_>) = + checkNotNull (nameof hashSetBuilder) hashSetBuilder + hashSetBuilder.ToImmutable() + let inline ofComparer<'T> comparer = HashSetFactory.Create<'T>(equalityComparer = comparer) + let inline ofSeq items = + checkNotNull (nameof items) items + HashSetFactory.CreateRange(items) + let inline ofArray items = HashSetFactory.CreateRange(items) + + let inline check (set: HashSet<_>) = checkNotNull (nameof set) set + + let inline builder() = HashSetFactory.CreateBuilder() + let inline builderWithComparer comparer = HashSetFactory.CreateBuilder(comparer) + + let inline toBuilder set : HashSetBuilder<_> = check set; set.ToBuilder() + + let inline singleton item = empty.Add(item) + + let inline keyComparer set = check set; set.KeyComparer + + let inline isEmpty set = check set; set.IsEmpty + + let inline length set = check set; set.Count + + let inline contains value set = check set; set.Contains value + + let inline pick chooser set = check set; set |> Seq.pick chooser + let inline tryPick chooser set = check set; set |> Seq.tryPick chooser + let inline vTryPick chooser set = + check set + match set |> Seq.tryPick chooser with + | Some value -> ValueSome value + | None -> ValueNone + + let inline iter action map = check map; map |> Seq.iter action + + let inline exists predicate map = check map; map |> Seq.exists predicate + + let inline add value set : HashSet<_> = check set; set.Add(value) + let inline union set values : HashSet<_> = check set; values |> set.Union + + let inline remove value set : HashSet<_> = check set; set.Remove value + let inline difference values set : HashSet<_> = check set; values |> set.Except + + let inline clear set: HashSet<_> = check set; set.Clear() + + let inline filter predicate set = + set |> Seq.filter predicate |> empty.Union + + let inline where predicate set = + set |> Seq.where predicate |> empty.Union + + let inline map mapping set' = + set' |> Seq.map mapping + + let inline forall predicate set = + set |> Seq.forall predicate + + let inline count (set:HashSet<_>) = check set; set.Count + type SortedSet<'T> = System.Collections.Immutable.ImmutableSortedSet<'T> -type HashSet<'T> = System.Collections.Immutable.ImmutableHashSet<'T> +type SortedSetBuilder<'T> = SortedSet<'T>.Builder + +type internal SortedSetFactory = + System.Collections.Immutable.ImmutableSortedSet + +module SortedSet = + let inline empty<'T> = SortedSetFactory.Create<'T>() + + let inline ofBuilder (sortedSetBuilder: SortedSetBuilder<_>) = + checkNotNull (nameof sortedSetBuilder) sortedSetBuilder + sortedSetBuilder.ToImmutable() + let inline ofComparer<'T> comparer = SortedSetFactory.Create<'T>(comparer = comparer) + let inline ofSeq items = + checkNotNull (nameof items) items + SortedSetFactory.CreateRange(items) + let inline ofArray items = SortedSetFactory.CreateRange(items) + + let inline check (sortedSet: SortedSet<_>) = checkNotNull (nameof sortedSet) sortedSet + + let inline builder() = SortedSetFactory.CreateBuilder() + let inline builderWithComparer comparer = SortedSetFactory.CreateBuilder(comparer) + + let inline toBuilder set : SortedSetBuilder<_> = check set; set.ToBuilder() + + let inline singleton item = empty.Add(item) + + let inline keyComparer set = check set; set.KeyComparer + + let inline isEmpty set = check set; set.IsEmpty + + let inline length set = check set; set.Count + + let inline contains value set = check set; set.Contains value + + let inline pick chooser set = check set; set |> Seq.pick chooser + let inline tryPick chooser set = check set; set |> Seq.tryPick chooser + let inline vTryPick chooser set = + check set + match set |> Seq.tryPick chooser with + | Some value -> ValueSome value + | None -> ValueNone + + let inline iter action map = check map; map |> Seq.iter action + + let inline exists predicate map = check map; map |> Seq.exists predicate + + let inline add value set : SortedSet<_> = check set; set.Add(value) + let inline union set values : SortedSet<_> = check set; values |> set.Union + + let inline remove value set : SortedSet<_> = check set; set.Remove value + let inline difference values set : SortedSet<_> = check set; values |> set.Except + + let inline clear set: SortedSet<_> = check set; set.Clear() + + let inline filter predicate set = + set |> Seq.filter predicate |> empty.Union + + let inline where predicate set = + set |> Seq.where predicate |> empty.Union + + let inline map mapping set' = + set' |> Seq.map mapping + + let inline forall predicate set = + set |> Seq.forall predicate + + let inline count (set:SortedSet<_>) = check set; set.Count From 02cfef0a1dcec0993fd082c13000e1cd79b286ae Mon Sep 17 00:00:00 2001 From: Anthony Minchenko <65635298+anthony-mi@users.noreply.github.com> Date: Mon, 1 Mar 2021 17:05:41 +0200 Subject: [PATCH 05/17] Refactored all files to `nameof` --- src/FSharp.Collections.Immutable/flat-list.fs | 63 ++++++++++--------- .../immutable-list.fs | 10 +-- .../indexed-seq.fs | 2 +- src/FSharp.Collections.Immutable/queue.fs | 6 +- src/FSharp.Collections.Immutable/stack.fs | 2 +- 5 files changed, 43 insertions(+), 40 deletions(-) diff --git a/src/FSharp.Collections.Immutable/flat-list.fs b/src/FSharp.Collections.Immutable/flat-list.fs index 634fb87..6d17c05 100644 --- a/src/FSharp.Collections.Immutable/flat-list.fs +++ b/src/FSharp.Collections.Immutable/flat-list.fs @@ -22,10 +22,10 @@ module FlatList = ////////// Building ////////// let moveFromBuilder (builder : FlatList<_>.Builder) : FlatList<_> = - checkNotNull "builder" builder + checkNotNull (nameof builder) builder builder.MoveToImmutable() let ofBuilder (builder : FlatList<_>.Builder) : FlatList<_> = - checkNotNull "builder" builder + checkNotNull (nameof builder) builder builder.ToImmutable() let builder () : FlatList<'T>.Builder = FlatListFactory.CreateBuilder() @@ -35,7 +35,7 @@ module FlatList = let inline internal checkNotDefault argName (list : FlatList<'T>) = if list.IsDefault then invalidArg argName "Uninstantiated ImmutableArray/FlatList" - let inline internal check (list : FlatList<'T>) = checkNotDefault "list" list + let inline internal check (list : FlatList<'T>) = checkNotDefault (nameof list) list let inline internal indexNotFound() = raise (System.Collections.Generic.KeyNotFoundException()) @@ -44,8 +44,8 @@ module FlatList = let item index list = check list; list.[index] let append list1 list2 : FlatList<'T> = - checkNotDefault "list1" list1 - checkNotDefault "list2" list2 + checkNotDefault (nameof list1) list1 + checkNotDefault (nameof list2) list2 list1.AddRange(list2 : FlatList<_>) /// Searches for the specified object and returns the zero-based index of the first occurrence within the range @@ -107,7 +107,7 @@ module FlatList = let removeRange index (count: int) list: FlatList<_> = check list; list.RemoveRange(index, count) let blit source sourceIndex (destination: 'T[]) destinationIndex count = - checkNotDefault "source" source + checkNotDefault (nameof source) source try source.CopyTo(sourceIndex, destination, destinationIndex, count) with @@ -130,14 +130,14 @@ module FlatList = let inline private builderWithLengthOf list = builderWith <| length list module Builder = - let inline private check (builder: FlatList<'T>.Builder) = checkNotNull "builder" builder + let inline private check (builder: FlatList<'T>.Builder) = checkNotNull (nameof builder) builder let add item builder = check builder; builder.Add(item) ////////// Loop-based ////////// let init count initializer = - if count < 0 then invalidArg "count" ErrorStrings.InputMustBeNonNegative + if count < 0 then invalidArg (nameof count) ErrorStrings.InputMustBeNonNegative let builder = builderWith count for i = 0 to count - 1 do builder.Add <| initializer i @@ -191,11 +191,11 @@ module FlatList = action list.[i] let iter2 action list1 list2 = - checkNotDefault "list1" list1 - checkNotDefault "list2" list2 + checkNotDefault (nameof list1) list1 + checkNotDefault (nameof list2) list2 let f = OptimizedClosures.FSharpFunc<'T,'U, unit>.Adapt(action) let len = length list1 - if len <> length list2 then invalidArg "list2" ErrorStrings.ListsHaveDifferentLengths + if len <> length list2 then invalidArg (nameof list2) ErrorStrings.ListsHaveDifferentLengths for i = 0 to len - 1 do f.Invoke(list1.[i], list2.[i]) @@ -213,34 +213,37 @@ module FlatList = ofBuilder builder let map2 mapping list1 list2 = - checkNotDefault "list1" list1 - checkNotDefault "list2" list2 + checkNotDefault (nameof list1) list1 + checkNotDefault (nameof list2) list2 let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(mapping) let len1 = list1.Length - if len1 <> list2.Length then invalidArg "list2" ErrorStrings.ListsHaveDifferentLengths + if len1 <> list2.Length then invalidArg (nameof list2) ErrorStrings.ListsHaveDifferentLengths let res = builderWith len1 for i = 0 to len1 - 1 do res.Add <| f.Invoke(list1.[i], list2.[i]) moveFromBuilder res let map3 mapping list1 list2 list3 = - checkNotDefault "list1" list1 - checkNotDefault "list2" list2 - checkNotDefault "list3" list3 + checkNotDefault (nameof list1) list1 + checkNotDefault (nameof list2) list2 + checkNotDefault (nameof list3) list3 let f = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt(mapping) let len1 = list1.Length - if not (len1 = list2.Length && len1 = list3.Length) then invalidArg "" ErrorStrings.ListsHaveDifferentLengths + if not (len1 = list2.Length) + then invalidArg (nameof list2) ErrorStrings.ListsHaveDifferentLengths + if not (len1 = list3.Length) + then invalidArg (nameof list3) ErrorStrings.ListsHaveDifferentLengths let res = builderWith len1 for i = 0 to len1 - 1 do res.Add <| f.Invoke(list1.[i], list2.[i], list3.[i]) moveFromBuilder res let mapi2 mapping list1 list2 = - checkNotDefault "list1" list1 - checkNotDefault "list2" list2 + checkNotDefault (nameof list1) list1 + checkNotDefault (nameof list2) list2 let f = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt(mapping) let len1 = list1.Length - if len1 <> list2.Length then invalidArg "list2" ErrorStrings.ListsHaveDifferentLengths + if len1 <> list2.Length then invalidArg (nameof list2) ErrorStrings.ListsHaveDifferentLengths let res = builderWith len1 for i = 0 to len1 - 1 do res.Add <| f.Invoke(i,list1.[i], list2.[i]) @@ -254,11 +257,11 @@ module FlatList = f.Invoke(i, list.[i]) let iteri2 action list1 list2 = - checkNotDefault "list1" list1 - checkNotDefault "list2" list2 + checkNotDefault (nameof list1) list1 + checkNotDefault (nameof list2) list2 let f = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt(action) let len1 = list1.Length - if len1 <> list2.Length then invalidArg "list2" ErrorStrings.ListsHaveDifferentLengths + if len1 <> list2.Length then invalidArg (nameof list2) ErrorStrings.ListsHaveDifferentLengths for i = 0 to len1 - 1 do f.Invoke(i,list1.[i], list2.[i]) @@ -287,11 +290,11 @@ module FlatList = state let exists2 predicate list1 list2 = - checkNotDefault "list1" list1 - checkNotDefault "list2" list2 + checkNotDefault (nameof list1) list1 + checkNotDefault (nameof list2) list2 let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(predicate) let len1 = list1.Length - if len1 <> list2.Length then invalidArg "list2" ErrorStrings.ListsHaveDifferentLengths + if len1 <> list2.Length then invalidArg (nameof list2) ErrorStrings.ListsHaveDifferentLengths let rec loop i = i < len1 && (f.Invoke(list1.[i], list2.[i]) || loop (i+1)) loop 0 @@ -302,11 +305,11 @@ module FlatList = loop 0 let forall2 predicate list1 list2 = - checkNotDefault "list1" list1 - checkNotDefault "list2" list2 + checkNotDefault (nameof list1) list1 + checkNotDefault (nameof list2) list2 let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(predicate) let len1 = list1.Length - if len1 <> list2.Length then invalidArg "list2" ErrorStrings.ListsHaveDifferentLengths + if len1 <> list2.Length then invalidArg (nameof list2) ErrorStrings.ListsHaveDifferentLengths let rec loop i = i >= len1 || (f.Invoke(list1.[i], list2.[i]) && loop (i+1)) loop 0 diff --git a/src/FSharp.Collections.Immutable/immutable-list.fs b/src/FSharp.Collections.Immutable/immutable-list.fs index a4429a2..28550a2 100644 --- a/src/FSharp.Collections.Immutable/immutable-list.fs +++ b/src/FSharp.Collections.Immutable/immutable-list.fs @@ -1,4 +1,4 @@ -#if INTERACTIVE +#if INTERACTIVE namespace global #else namespace FSharp.Collections.Immutable @@ -11,13 +11,13 @@ module ImmutableList = ////////// Factory ////////// - let inline internal check (list: IImmutableList<_>) = checkNotNull "list" list + let inline internal check (list: IImmutableList<_>) = checkNotNull (nameof list) list let inline empty<'T> = ImmutableList.Create<'T>() let inline singleton<'T> (item : 'T) : ImmutableList<'T> = ImmutableList.Create<'T> (item) - let inline ofSeq (seq : 'T seq) = checkNotNull "seq" seq; ImmutableList.CreateRange seq + let inline ofSeq (seq : 'T seq) = checkNotNull (nameof seq) seq; ImmutableList.CreateRange seq let inline ofBuilder (builder : ImmutableList<_>.Builder) = builder.ToImmutable() @@ -183,7 +183,7 @@ module ImmutableList = ////////// Loop-based ////////// let concat lists = - checkNotNull "lists" lists + checkNotNull (nameof lists) lists build <| fun result -> for list in lists do result.AddRange list @@ -283,7 +283,7 @@ module ImmutableList = let forall predicate list = check list; Seq.forall predicate list let forall2 predicate (list1: IImmutableList<_>) (list2: IImmutableList<_>) = - checkNotNull "list1" list1; checkNotNull "list2" list2 + checkNotNull (nameof list1) list1; checkNotNull (nameof list2) list2 Seq.forall2 predicate list1 list2 let iter action list = check list; Seq.iter action list diff --git a/src/FSharp.Collections.Immutable/indexed-seq.fs b/src/FSharp.Collections.Immutable/indexed-seq.fs index 5b1731f..f7aeb55 100644 --- a/src/FSharp.Collections.Immutable/indexed-seq.fs +++ b/src/FSharp.Collections.Immutable/indexed-seq.fs @@ -3,7 +3,7 @@ type IIndexedSeq<'T> = System.Collections.Generic.IReadOnlyList<'T> module IndexedSeq = - let check (seq: IIndexedSeq<_>) = checkNotNull "seq" seq + let check (seq: IIndexedSeq<_>) = checkNotNull (nameof seq) seq let item index seq = check seq; seq.[index] let length seq = check seq; seq.Count diff --git a/src/FSharp.Collections.Immutable/queue.fs b/src/FSharp.Collections.Immutable/queue.fs index d44ad51..35cc450 100644 --- a/src/FSharp.Collections.Immutable/queue.fs +++ b/src/FSharp.Collections.Immutable/queue.fs @@ -9,7 +9,7 @@ module Queue = type internal QueueFactory = System.Collections.Immutable.ImmutableQueue - let inline private check (queue: IQueue<_>) = checkNotNull "queue" queue + let inline private check (queue: IQueue<_>) = checkNotNull (nameof queue) queue let inline empty<'T> : Queue<'T> = QueueFactory.Create<'T>() @@ -57,8 +57,8 @@ module Queue = let iter action queue = check queue; Seq.iter action queue let iteri action queue = check queue; Seq.iteri action queue let iter2 action (queue1: IQueue<_>) (queue2: IQueue<_>) = - checkNotNull "queue1" queue1 - checkNotNull "queue2" queue2 + checkNotNull (nameof queue1) queue1 + checkNotNull (nameof queue2) queue2 Seq.iter2 action queue1 queue2 let fold folder state queue = check queue; Seq.fold folder state queue diff --git a/src/FSharp.Collections.Immutable/stack.fs b/src/FSharp.Collections.Immutable/stack.fs index 107362f..1611961 100644 --- a/src/FSharp.Collections.Immutable/stack.fs +++ b/src/FSharp.Collections.Immutable/stack.fs @@ -8,7 +8,7 @@ type Stack<'T> = System.Collections.Immutable.ImmutableStack<'T> module Stack = type internal StackFactory = System.Collections.Immutable.ImmutableStack - let inline internal check (stack : IStack<_>) = checkNotNull "stack" stack + let inline internal check (stack : IStack<_>) = checkNotNull (nameof stack) stack let inline empty<'T> = StackFactory.Create<'T>() From daeb2e96b07f6293e9103395c4671d7ff5a89046 Mon Sep 17 00:00:00 2001 From: Anthony Minchenko <65635298+anthony-mi@users.noreply.github.com> Date: Mon, 1 Mar 2021 21:22:31 +0200 Subject: [PATCH 06/17] Implemented Set specific functions --- src/FSharp.Collections.Immutable/sets.fs | 83 +++++++++++++----------- 1 file changed, 46 insertions(+), 37 deletions(-) diff --git a/src/FSharp.Collections.Immutable/sets.fs b/src/FSharp.Collections.Immutable/sets.fs index 60da73d..54af7ad 100644 --- a/src/FSharp.Collections.Immutable/sets.fs +++ b/src/FSharp.Collections.Immutable/sets.fs @@ -18,6 +18,7 @@ module HashSet = let inline ofSeq items = checkNotNull (nameof items) items HashSetFactory.CreateRange(items) + let inline ofSeqWithComparer comparer items = HashSetFactory.Create(comparer, items = (items |> Array.ofSeq)) let inline ofArray items = HashSetFactory.CreateRange(items) let inline check (set: HashSet<_>) = checkNotNull (nameof set) set @@ -26,31 +27,27 @@ module HashSet = let inline builderWithComparer comparer = HashSetFactory.CreateBuilder(comparer) let inline toBuilder set : HashSetBuilder<_> = check set; set.ToBuilder() + let inline toSeq (set: HashSet<_>) = set :> seq<_> let inline singleton item = empty.Add(item) let inline keyComparer set = check set; set.KeyComparer - let inline isEmpty set = check set; set.IsEmpty - let inline length set = check set; set.Count + let inline isEmpty set = check set; set.IsEmpty let inline contains value set = check set; set.Contains value - - let inline pick chooser set = check set; set |> Seq.pick chooser - let inline tryPick chooser set = check set; set |> Seq.tryPick chooser - let inline vTryPick chooser set = - check set - match set |> Seq.tryPick chooser with - | Some value -> ValueSome value - | None -> ValueNone - - let inline iter action map = check map; map |> Seq.iter action - let inline exists predicate map = check map; map |> Seq.exists predicate + let inline isSubset (set1:HashSet<_>) set2 = check set1; set1.IsSubsetOf set2 + let inline isProperSubset (set1:HashSet<_>) set2 = check set1; set1.IsProperSubsetOf set2 + let inline isSuperset (set1:HashSet<_>) set2 = check set1; set1.IsSupersetOf set2 + let inline isProperSuperset (set1:HashSet<_>) set2 = check set1; set1.IsProperSupersetOf set2 let inline add value set : HashSet<_> = check set; set.Add(value) let inline union set values : HashSet<_> = check set; values |> set.Union + let inline unionMany (sets:HashSet<_> seq) = Seq.reduce union sets + let inline intersect (set1:HashSet<_>) set2 = check set1; set1.Intersect set2 + let inline intersectMany (sets:HashSet<_> seq) = Seq.reduce intersect sets let inline remove value set : HashSet<_> = check set; set.Remove value let inline difference values set : HashSet<_> = check set; values |> set.Except @@ -63,11 +60,19 @@ module HashSet = let inline where predicate set = set |> Seq.where predicate |> empty.Union - let inline map mapping set' = - set' |> Seq.map mapping + let inline pick chooser set = check set; set |> Seq.pick chooser + let inline tryPick chooser set = check set; set |> Seq.tryPick chooser + let inline vTryPick chooser set = + check set + match set |> Seq.tryPick chooser with + | Some value -> ValueSome value + | None -> ValueNone + + let inline map mapping (set: HashSet<_>) = set |> Seq.map mapping |> ofSeq - let inline forall predicate set = - set |> Seq.forall predicate + let inline forall predicate set = set |> Seq.forall predicate + + let inline iter action (set: HashSet<_>) = check set; set |> Seq.iter action let inline count (set:HashSet<_>) = check set; set.Count @@ -88,6 +93,7 @@ module SortedSet = let inline ofSeq items = checkNotNull (nameof items) items SortedSetFactory.CreateRange(items) + let inline ofSeqWithComparer comparer items = SortedSetFactory.Create(comparer, items = (items |> Array.ofSeq)) let inline ofArray items = SortedSetFactory.CreateRange(items) let inline check (sortedSet: SortedSet<_>) = checkNotNull (nameof sortedSet) sortedSet @@ -96,47 +102,50 @@ module SortedSet = let inline builderWithComparer comparer = SortedSetFactory.CreateBuilder(comparer) let inline toBuilder set : SortedSetBuilder<_> = check set; set.ToBuilder() + let inline toSeq (set: SortedSet<_>) = set :> seq<_> let inline singleton item = empty.Add(item) let inline keyComparer set = check set; set.KeyComparer - let inline isEmpty set = check set; set.IsEmpty let inline length set = check set; set.Count let inline contains value set = check set; set.Contains value - - let inline pick chooser set = check set; set |> Seq.pick chooser - let inline tryPick chooser set = check set; set |> Seq.tryPick chooser - let inline vTryPick chooser set = - check set - match set |> Seq.tryPick chooser with - | Some value -> ValueSome value - | None -> ValueNone - - let inline iter action map = check map; map |> Seq.iter action - + let inline isEmpty set = check set; set.IsEmpty let inline exists predicate map = check map; map |> Seq.exists predicate + let inline isSubset (set1:SortedSet<_>) set2 = check set1; set1.IsSubsetOf set2 + let inline isProperSubset (set1:SortedSet<_>) set2 = check set1; set1.IsProperSubsetOf set2 + let inline isSuperset (set1:SortedSet<_>) set2 = check set1; set1.IsSupersetOf set2 + let inline isProperSuperset (set1:SortedSet<_>) set2 = check set1; set1.IsProperSupersetOf set2 let inline add value set : SortedSet<_> = check set; set.Add(value) let inline union set values : SortedSet<_> = check set; values |> set.Union + let inline unionMany (sets:SortedSet<_> seq) = Seq.reduce union sets + let inline intersect (set1:SortedSet<_>) set2 = set1.Intersect set2 + let inline intersectMany (sets:SortedSet<_> seq) = Seq.reduce intersect sets let inline remove value set : SortedSet<_> = check set; set.Remove value let inline difference values set : SortedSet<_> = check set; values |> set.Except let inline clear set: SortedSet<_> = check set; set.Clear() - let inline filter predicate set = - set |> Seq.filter predicate |> empty.Union + let inline filter predicate set = set |> Seq.filter predicate |> empty.Union - let inline where predicate set = - set |> Seq.where predicate |> empty.Union + let inline where predicate set = set |> Seq.where predicate |> empty.Union + + let inline pick chooser set = check set; set |> Seq.pick chooser + let inline tryPick chooser set = check set; set |> Seq.tryPick chooser + let inline vTryPick chooser set = + check set + match set |> Seq.tryPick chooser with + | Some value -> ValueSome value + | None -> ValueNone + + let inline map mapping (set: SortedSet<_>) = set |> Seq.map mapping |> ofSeq - let inline map mapping set' = - set' |> Seq.map mapping + let inline forall predicate set = set |> Seq.forall predicate - let inline forall predicate set = - set |> Seq.forall predicate + let inline iter action (set: SortedSet<_>) = check set; set |> Seq.iter action let inline count (set:SortedSet<_>) = check set; set.Count From 9db8f7f32debf774b6c597a0481f2f2044526080 Mon Sep 17 00:00:00 2001 From: Anthony Minchenko <65635298+anthony-mi@users.noreply.github.com> Date: Mon, 1 Mar 2021 21:23:13 +0200 Subject: [PATCH 07/17] Implemented Map specific functions --- src/FSharp.Collections.Immutable/maps.fs | 35 ++++++++++++++++++------ 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/src/FSharp.Collections.Immutable/maps.fs b/src/FSharp.Collections.Immutable/maps.fs index 40cbadb..217cb40 100644 --- a/src/FSharp.Collections.Immutable/maps.fs +++ b/src/FSharp.Collections.Immutable/maps.fs @@ -15,10 +15,16 @@ module HashMap = let inline empty<'Key, 'Value> = HashMapFactory.Create<'Key, 'Value>() let inline ofSeq items = HashMapFactory.CreateRange(items) - let inline ofSeqWith getId items = + let inline ofSeqWith getKey items = checkNotNull (nameof items) items items - |> Seq.map (fun i -> KeyValuePair(getId i, i)) + |> Seq.map (fun i -> KeyValuePair(getKey i, i)) + |> HashMapFactory.CreateRange + let inline ofSeqGroupBy getKey items = + checkNotNull (nameof items) items + items + |> Seq.groupBy getKey + |> Seq.map (fun (key,value) -> KeyValuePair(key, value)) |> HashMapFactory.CreateRange let inline ofArray items = HashMapFactory.CreateRange(items) @@ -33,6 +39,7 @@ module HashMap = mapBuilder.ToImmutable() let inline toBuilder map : HashMapBuilder<_,_> = check map; map.ToBuilder() + let inline toSeq (map: HashMap<_,_>) = map :> seq<_> let inline ofKeyComparer<'Key, 'Value> comparer = HashMapFactory.Create<'Key, 'Value>(comparer) let inline ofComparers<'Key, 'Value> keyComparer valueComparer = HashMapFactory.Create<'Key, 'Value>(keyComparer, valueComparer) @@ -68,6 +75,11 @@ module HashMap = | Some value -> ValueSome value | None -> ValueNone + let inline iter action (map: HashMap<_,_>) = check map; map |> Seq.iter (fun kvp -> action kvp.Key kvp.Value) + + let inline exists predicate map = check map; map |> Seq.exists (fun kvp -> predicate kvp.Key kvp.Value) + + let inline add key value map : HashMap<_,_> = check map; map.Add(key, value) let inline append map pairs : HashMap<_,_> = check map @@ -86,7 +98,7 @@ module HashMap = map |> Seq.forall (fun (kvp:KeyValuePair<_,_>) -> predicate kvp.Key kvp.Value) let inline map mapping map' = - map' |> Seq.map (fun (kvp:KeyValuePair<_,_>) -> mapping kvp.Key kvp.Value) + map' |> Seq.map (fun (kvp:KeyValuePair<_,_>) -> mapping kvp.Key kvp.Value) |> ofSeq let inline where predicate map = map |> Seq.where (fun (kvp:KeyValuePair<_,_>) -> predicate kvp.Key kvp.Value) |> empty.AddRange @@ -106,10 +118,16 @@ module SortedMap = let inline empty<'Key, 'Value> = SortedMapFactory.Create<'Key, 'Value>() let inline ofSeq items = SortedMapFactory.CreateRange(items) - let inline ofSeqWith getId items = + let inline ofSeqWith getKey items = checkNotNull (nameof items) items items - |> Seq.map (fun i -> KeyValuePair(getId i, i)) + |> Seq.map (fun i -> KeyValuePair(getKey i, i)) + |> SortedMapFactory.CreateRange + let inline ofSeqGroupBy getKey items = + checkNotNull (nameof items) items + items + |> Seq.groupBy getKey + |> Seq.map (fun (key,value) -> KeyValuePair(key, value)) |> SortedMapFactory.CreateRange let inline ofArray items = SortedMapFactory.CreateRange(items) @@ -124,6 +142,7 @@ module SortedMap = sortedMapBuilder.ToImmutable() let inline toBuilder map : SortedMapBuilder<_,_> = check map; map.ToBuilder() + let inline toSeq (map: SortedMap<_,_>) = map :> seq<_> let inline ofKeyComparer<'Key, 'Value> comparer = SortedMapFactory.Create<'Key, 'Value>(comparer) let inline ofComparers<'Key, 'Value> keyComparer valueComparer = SortedMapFactory.Create<'Key, 'Value>(keyComparer, valueComparer) @@ -159,7 +178,7 @@ module SortedMap = | Some value -> ValueSome value | None -> ValueNone - let inline iter action map = check map; map |> Seq.iter (fun kvp -> action kvp.Key kvp.Value) + let inline iter action (map: SortedMap<_,_>) = check map; map |> Seq.iter (fun kvp -> action kvp.Key kvp.Value) let inline exists predicate map = check map; map |> Seq.exists (fun kvp -> predicate kvp.Key kvp.Value) @@ -192,8 +211,8 @@ module SortedMap = let inline forall predicate map = map |> Seq.forall (fun (kvp:KeyValuePair<_,_>) -> predicate kvp.Key kvp.Value) - let inline map mapping map' = - map' |> Seq.map (fun (kvp:KeyValuePair<_,_>) -> mapping kvp.Key kvp.Value) + let inline map mapping (map': SortedMap<_,_>) = + map' |> Seq.map (fun (kvp:KeyValuePair<_,_>) -> mapping kvp.Key kvp.Value) |> ofSeq let inline where predicate map = map |> Seq.where (fun (kvp:KeyValuePair<_,_>) -> predicate kvp.Key kvp.Value) |> empty.AddRange From d21f3f35749dc4a1cb02c16fee5cab71114717ba Mon Sep 17 00:00:00 2001 From: Anthony Minchenko <65635298+anthony-mi@users.noreply.github.com> Date: Mon, 1 Mar 2021 21:28:17 +0200 Subject: [PATCH 08/17] Added seq convertions --- .../FSharp.Collections.Immutable.fsproj | 1 + src/FSharp.Collections.Immutable/flat-list.fs | 1 + .../immutable-list.fs | 1 + src/FSharp.Collections.Immutable/queue.fs | 1 + src/FSharp.Collections.Immutable/seq.fs | 32 +++++++++++++++++++ src/FSharp.Collections.Immutable/stack.fs | 1 + 6 files changed, 37 insertions(+) create mode 100644 src/FSharp.Collections.Immutable/seq.fs diff --git a/src/FSharp.Collections.Immutable/FSharp.Collections.Immutable.fsproj b/src/FSharp.Collections.Immutable/FSharp.Collections.Immutable.fsproj index b408f24..9be61c5 100644 --- a/src/FSharp.Collections.Immutable/FSharp.Collections.Immutable.fsproj +++ b/src/FSharp.Collections.Immutable/FSharp.Collections.Immutable.fsproj @@ -25,6 +25,7 @@ + diff --git a/src/FSharp.Collections.Immutable/flat-list.fs b/src/FSharp.Collections.Immutable/flat-list.fs index 6d17c05..6ec532c 100644 --- a/src/FSharp.Collections.Immutable/flat-list.fs +++ b/src/FSharp.Collections.Immutable/flat-list.fs @@ -19,6 +19,7 @@ module FlatList = let inline ofSeq source: FlatList<'T> = FlatListFactory.CreateRange source + let inline toSeq (flatList: FlatList<_>) = flatList :> seq<_> ////////// Building ////////// let moveFromBuilder (builder : FlatList<_>.Builder) : FlatList<_> = diff --git a/src/FSharp.Collections.Immutable/immutable-list.fs b/src/FSharp.Collections.Immutable/immutable-list.fs index 28550a2..c8cbb88 100644 --- a/src/FSharp.Collections.Immutable/immutable-list.fs +++ b/src/FSharp.Collections.Immutable/immutable-list.fs @@ -174,6 +174,7 @@ module ImmutableList = let toBuilder (list: ImmutableList<_>) = check list; list.ToBuilder() + let inline toSeq (immutableList: ImmutableList<_>) = immutableList :> seq<_> let inline update f list = let builder = toBuilder list diff --git a/src/FSharp.Collections.Immutable/queue.fs b/src/FSharp.Collections.Immutable/queue.fs index 35cc450..08b6f28 100644 --- a/src/FSharp.Collections.Immutable/queue.fs +++ b/src/FSharp.Collections.Immutable/queue.fs @@ -17,6 +17,7 @@ module Queue = let inline ofSeq(source : 'T seq) : Queue<'T> = QueueFactory.CreateRange source + let inline toSeq (queue: Queue<_>) = queue :> seq<_> let isEmpty queue = check queue; queue.IsEmpty let clear queue : IQueue<_> = check queue; queue.Clear() diff --git a/src/FSharp.Collections.Immutable/seq.fs b/src/FSharp.Collections.Immutable/seq.fs new file mode 100644 index 0000000..d9826b1 --- /dev/null +++ b/src/FSharp.Collections.Immutable/seq.fs @@ -0,0 +1,32 @@ +#if INTERACTIVE +namespace global +#else +namespace FSharp.Collections.Immutable +#endif + +[] +module Seq = + + let inline ofFlatList flatList = FlatList.toSeq flatList + let inline toFlatList seq = FlatList.ofSeq seq + + let inline ofStack stack = Stack.toSeq stack + let inline toStack seq = Stack.ofSeq seq + + let inline ofImmutableList immutableList = ImmutableList.toSeq immutableList + let inline toImmutableList seq = ImmutableList.ofSeq seq + + let inline ofQueue queue = Queue.toSeq queue + let inline toQueue queue = Queue.ofSeq queue + + let inline ofHashMap hashMap = HashMap.toSeq hashMap + let inline toHashMap hashMap = HashMap.ofSeq hashMap + + let inline ofSortedMap sortedHashMap = SortedMap.toSeq sortedHashMap + let inline toSortedMap sortedHashMap = SortedMap.ofSeq sortedHashMap + + let inline ofHashSet hashSet = HashSet.toSeq hashSet + let inline toHashSet hashSet = HashSet.ofSeq hashSet + + let inline ofSortedSet sortedSet = SortedSet.toSeq sortedSet + let inline toSortedSet sortedSet = SortedSet.ofSeq sortedSet diff --git a/src/FSharp.Collections.Immutable/stack.fs b/src/FSharp.Collections.Immutable/stack.fs index 1611961..6e51f9b 100644 --- a/src/FSharp.Collections.Immutable/stack.fs +++ b/src/FSharp.Collections.Immutable/stack.fs @@ -16,6 +16,7 @@ module Stack = let inline ofArray (array : 'T []) : Stack<'T> = ofSeq array + let inline toSeq (stack: IStack<_>) = stack :> seq<_> let push head stack : IStack<'T> = check stack stack.Push head From 7b953993e4fbd9460d3b17861c2857a7974e5d3e Mon Sep 17 00:00:00 2001 From: Anthony Minchenko <65635298+anthony-mi@users.noreply.github.com> Date: Mon, 1 Mar 2021 21:29:41 +0200 Subject: [PATCH 09/17] Added missing attributes that changes compiled names of modules --- src/FSharp.Collections.Immutable/flat-list.fs | 3 ++- src/FSharp.Collections.Immutable/maps.fs | 2 ++ src/FSharp.Collections.Immutable/queue.fs | 3 ++- src/FSharp.Collections.Immutable/sets.fs | 2 ++ src/FSharp.Collections.Immutable/stack.fs | 3 ++- 5 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/FSharp.Collections.Immutable/flat-list.fs b/src/FSharp.Collections.Immutable/flat-list.fs index 6ec532c..d051e0a 100644 --- a/src/FSharp.Collections.Immutable/flat-list.fs +++ b/src/FSharp.Collections.Immutable/flat-list.fs @@ -8,7 +8,7 @@ namespace FSharp.Collections.Immutable type FlatList<'T> = System.Collections.Immutable.ImmutableArray<'T> // based on the F# Array module source -[] +[] module FlatList = type internal FlatListFactory = System.Collections.Immutable.ImmutableArray @@ -20,6 +20,7 @@ module FlatList = let inline ofSeq source: FlatList<'T> = FlatListFactory.CreateRange source let inline toSeq (flatList: FlatList<_>) = flatList :> seq<_> + ////////// Building ////////// let moveFromBuilder (builder : FlatList<_>.Builder) : FlatList<_> = diff --git a/src/FSharp.Collections.Immutable/maps.fs b/src/FSharp.Collections.Immutable/maps.fs index 217cb40..2276708 100644 --- a/src/FSharp.Collections.Immutable/maps.fs +++ b/src/FSharp.Collections.Immutable/maps.fs @@ -11,6 +11,7 @@ type HashMapBuilder<'Key, 'Value> = HashMap<'Key, 'Value>.Builder type internal HashMapFactory = System.Collections.Immutable.ImmutableDictionary +[] module HashMap = let inline empty<'Key, 'Value> = HashMapFactory.Create<'Key, 'Value>() @@ -114,6 +115,7 @@ type SortedMapBuilder<'Key, 'Value> = SortedMap<'Key, 'Value>.Builder type internal SortedMapFactory = System.Collections.Immutable.ImmutableSortedDictionary +[] module SortedMap = let inline empty<'Key, 'Value> = SortedMapFactory.Create<'Key, 'Value>() diff --git a/src/FSharp.Collections.Immutable/queue.fs b/src/FSharp.Collections.Immutable/queue.fs index 08b6f28..d255608 100644 --- a/src/FSharp.Collections.Immutable/queue.fs +++ b/src/FSharp.Collections.Immutable/queue.fs @@ -4,7 +4,7 @@ type IQueue<'T> = System.Collections.Immutable.IImmutableQueue<'T> type Queue<'T> = System.Collections.Immutable.ImmutableQueue<'T> -[] +[] module Queue = type internal QueueFactory = System.Collections.Immutable.ImmutableQueue @@ -18,6 +18,7 @@ module Queue = let inline ofSeq(source : 'T seq) : Queue<'T> = QueueFactory.CreateRange source let inline toSeq (queue: Queue<_>) = queue :> seq<_> + let isEmpty queue = check queue; queue.IsEmpty let clear queue : IQueue<_> = check queue; queue.Clear() diff --git a/src/FSharp.Collections.Immutable/sets.fs b/src/FSharp.Collections.Immutable/sets.fs index 54af7ad..aac4e34 100644 --- a/src/FSharp.Collections.Immutable/sets.fs +++ b/src/FSharp.Collections.Immutable/sets.fs @@ -8,6 +8,7 @@ type HashSetBuilder<'T> = HashSet<'T>.Builder type internal HashSetFactory = System.Collections.Immutable.ImmutableHashSet +[] module HashSet = let inline empty<'T> = HashSetFactory.Create<'T>() @@ -83,6 +84,7 @@ type SortedSetBuilder<'T> = SortedSet<'T>.Builder type internal SortedSetFactory = System.Collections.Immutable.ImmutableSortedSet +[] module SortedSet = let inline empty<'T> = SortedSetFactory.Create<'T>() diff --git a/src/FSharp.Collections.Immutable/stack.fs b/src/FSharp.Collections.Immutable/stack.fs index 6e51f9b..7fe7e57 100644 --- a/src/FSharp.Collections.Immutable/stack.fs +++ b/src/FSharp.Collections.Immutable/stack.fs @@ -4,7 +4,7 @@ type IStack<'T> = System.Collections.Immutable.IImmutableStack<'T> type Stack<'T> = System.Collections.Immutable.ImmutableStack<'T> -[] +[] module Stack = type internal StackFactory = System.Collections.Immutable.ImmutableStack @@ -17,6 +17,7 @@ module Stack = let inline ofArray (array : 'T []) : Stack<'T> = ofSeq array let inline toSeq (stack: IStack<_>) = stack :> seq<_> + let push head stack : IStack<'T> = check stack stack.Push head From 2e45df6ef0317cc6b37d2b3fbb6b53b7e704b9f0 Mon Sep 17 00:00:00 2001 From: Andrii Chebukin Date: Thu, 11 Mar 2021 23:30:05 +0200 Subject: [PATCH 10/17] Reorganized modules, removed count functions, added ofArray and fixed ofArray signatures --- src/FSharp.Collections.Immutable/flat-list.fs | 52 ++++++++-------- .../immutable-list.fs | 39 ++++++------ src/FSharp.Collections.Immutable/maps.fs | 61 +++++++++---------- src/FSharp.Collections.Immutable/sets.fs | 57 +++++++++-------- 4 files changed, 100 insertions(+), 109 deletions(-) diff --git a/src/FSharp.Collections.Immutable/flat-list.fs b/src/FSharp.Collections.Immutable/flat-list.fs index d051e0a..e7ee567 100644 --- a/src/FSharp.Collections.Immutable/flat-list.fs +++ b/src/FSharp.Collections.Immutable/flat-list.fs @@ -13,11 +13,17 @@ module FlatList = type internal FlatListFactory = System.Collections.Immutable.ImmutableArray - let inline empty<'T> : FlatList<_> = FlatListFactory.Create<'T>() + let inline internal checkNotDefault argName (list : FlatList<'T>) = + if list.IsDefault then invalidArg argName "Uninstantiated ImmutableArray/FlatList" + let inline internal check (list : FlatList<'T>) = checkNotDefault (nameof list) list + + ////////// Creating ////////// + let inline empty<'T> : FlatList<_> = FlatListFactory.Create<'T>() let inline singleton<'T> (item : 'T) : FlatList<'T> = FlatListFactory.Create<'T> (item) - let inline ofSeq source: FlatList<'T> = FlatListFactory.CreateRange source + let inline ofSeq source = FlatListFactory.CreateRange source + let inline ofArray (source : _ array) = FlatListFactory.CreateRange source let inline toSeq (flatList: FlatList<_>) = flatList :> seq<_> @@ -30,16 +36,23 @@ module FlatList = checkNotNull (nameof builder) builder builder.ToImmutable() - let builder () : FlatList<'T>.Builder = FlatListFactory.CreateBuilder() + let inline builder () : FlatList<'T>.Builder = FlatListFactory.CreateBuilder() + let inline builderWith capacity : FlatList<'T>.Builder = FlatListFactory.CreateBuilder(capacity) - let builderWith capacity : FlatList<'T>.Builder = FlatListFactory.CreateBuilder(capacity) + let toBuilder list: FlatList<_>.Builder = check list; list.ToBuilder() - let inline internal checkNotDefault argName (list : FlatList<'T>) = - if list.IsDefault then invalidArg argName "Uninstantiated ImmutableArray/FlatList" + module Builder = + let inline private check (builder: FlatList<'T>.Builder) = checkNotNull (nameof builder) builder - let inline internal check (list : FlatList<'T>) = checkNotDefault (nameof list) list + let add item builder = check builder; builder.Add(item) + + let inline internal indexNotFound() = raise <| System.Collections.Generic.KeyNotFoundException() + + let isEmpty (list: FlatList<_>) = list.IsEmpty + let isDefault (list: FlatList<_>) = list.IsDefault + let isDefaultOrEmpty (list: FlatList<_>) = list.IsDefaultOrEmpty - let inline internal indexNotFound() = raise (System.Collections.Generic.KeyNotFoundException()) + ////////// IReadOnly* ////////// let length list = check list; list.Length @@ -82,12 +95,6 @@ module FlatList = lastIndexFromWith comparer (length list - 1) item list let lastIndex item list = lastIndexWith HashIdentity.Structural item list - let isEmpty (list: FlatList<_>) = list.IsEmpty - - let isDefault (list: FlatList<_>) = list.IsDefault - - let isDefaultOrEmpty (list: FlatList<_>) = list.IsDefaultOrEmpty - /// Removes the specified objects from the list with the given comparer. let removeAllWith (comparer: System.Collections.Generic.IEqualityComparer<_>) items list: FlatList<_> = check list @@ -110,10 +117,8 @@ module FlatList = let blit source sourceIndex (destination: 'T[]) destinationIndex count = checkNotDefault (nameof source) source - try - source.CopyTo(sourceIndex, destination, destinationIndex, count) - with - |exn -> raise exn // throw same exception with the correct stack trace. Update exception code + try source.CopyTo(sourceIndex, destination, destinationIndex, count) + with exn -> raise exn // throw same exception with the correct stack trace. Update exception code let sortRangeWithComparer comparer index count list = check list @@ -125,19 +130,10 @@ module FlatList = let sortWith comparer list = sortWithComparer (ComparisonIdentity.FromFunction comparer) list let sort list = check list; list.Sort() - ////////// Building ////////// - - let toBuilder list: FlatList<_>.Builder = check list; list.ToBuilder() + ////////// Loop-based ////////// let inline private builderWithLengthOf list = builderWith <| length list - module Builder = - let inline private check (builder: FlatList<'T>.Builder) = checkNotNull (nameof builder) builder - - let add item builder = check builder; builder.Add(item) - - ////////// Loop-based ////////// - let init count initializer = if count < 0 then invalidArg (nameof count) ErrorStrings.InputMustBeNonNegative let builder = builderWith count diff --git a/src/FSharp.Collections.Immutable/immutable-list.fs b/src/FSharp.Collections.Immutable/immutable-list.fs index c8cbb88..441ba2f 100644 --- a/src/FSharp.Collections.Immutable/immutable-list.fs +++ b/src/FSharp.Collections.Immutable/immutable-list.fs @@ -14,14 +14,29 @@ module ImmutableList = let inline internal check (list: IImmutableList<_>) = checkNotNull (nameof list) list let inline empty<'T> = ImmutableList.Create<'T>() - let inline singleton<'T> (item : 'T) : ImmutableList<'T> = ImmutableList.Create<'T> (item) - let inline ofSeq (seq : 'T seq) = checkNotNull (nameof seq) seq; ImmutableList.CreateRange seq + let inline ofSeq source = checkNotNull (nameof source) source; ImmutableList.CreateRange source + let inline ofArray (source : _ array) = checkNotNull (nameof source) source; ImmutableList.CreateRange source + + ////////// Building ////////// let inline ofBuilder (builder : ImmutableList<_>.Builder) = builder.ToImmutable() - let inline builder() = ImmutableList.CreateBuilder() + let inline builder () = ImmutableList.CreateBuilder() + + let toBuilder (list: ImmutableList<_>) = check list; list.ToBuilder() + + let inline build f = + let builder = builder() + f builder + builder.ToImmutable() + + let inline update f list = + let builder = toBuilder list + f builder + builder.ToImmutable() + open System.Collections.Generic open System @@ -81,7 +96,6 @@ module ImmutableList = let remove item list = removeWith HashIdentity.Structural item list - /// Removes the specified objects from the list with the given comparer. let exceptWith (comparer: IEqualityComparer<_>) items list = check list @@ -136,7 +150,6 @@ module ImmutableList = lastIndexFromWith comparer (length list - 1) item list let lastIndex item list = lastIndexWith HashIdentity.Structural item list - ////////// Filter-based ////////// let filterFold (predicate: 'State -> 'T -> bool * 'State) initial list = @@ -165,22 +178,6 @@ module ImmutableList = else true) list let takeUntil predicate list = takeWhile (not << predicate) list - ////////// Building ////////// - - let inline build f = - let builder = builder() - f builder - builder.ToImmutable() - - let toBuilder (list: ImmutableList<_>) = check list; list.ToBuilder() - - let inline toSeq (immutableList: ImmutableList<_>) = immutableList :> seq<_> - - let inline update f list = - let builder = toBuilder list - f builder - builder.ToImmutable() - ////////// Loop-based ////////// let concat lists = diff --git a/src/FSharp.Collections.Immutable/maps.fs b/src/FSharp.Collections.Immutable/maps.fs index 2276708..f6a32d4 100644 --- a/src/FSharp.Collections.Immutable/maps.fs +++ b/src/FSharp.Collections.Immutable/maps.fs @@ -9,27 +9,31 @@ type HashMap<'Key, 'Value> = type HashMapBuilder<'Key, 'Value> = HashMap<'Key, 'Value>.Builder -type internal HashMapFactory = System.Collections.Immutable.ImmutableDictionary - [] module HashMap = + + type internal HashMapFactory = System.Collections.Immutable.ImmutableDictionary + + let inline check (map: HashMap<_, _>) = checkNotNull (nameof map) map + + ////////// Creating ////////// + let inline empty<'Key, 'Value> = HashMapFactory.Create<'Key, 'Value>() + let inline singleton item = empty.Add(item) - let inline ofSeq items = HashMapFactory.CreateRange(items) - let inline ofSeqWith getKey items = - checkNotNull (nameof items) items - items + let inline ofSeq source = HashMapFactory.CreateRange(source) + let inline ofSeqWith getKey source = + source |> Seq.map (fun i -> KeyValuePair(getKey i, i)) |> HashMapFactory.CreateRange - let inline ofSeqGroupBy getKey items = - checkNotNull (nameof items) items - items + let inline ofSeqGroupBy getKey source = + source |> Seq.groupBy getKey |> Seq.map (fun (key,value) -> KeyValuePair(key, value)) |> HashMapFactory.CreateRange - let inline ofArray items = HashMapFactory.CreateRange(items) + let inline ofArray (source : _ array) = HashMapFactory.CreateRange(source) - let inline check (map: HashMap<_, _>) = checkNotNull (nameof map) map + ////////// Building ////////// let inline builder() = HashMapFactory.CreateBuilder() let inline builderWithKeyComparer comparer = HashMapFactory.CreateBuilder(comparer) @@ -45,7 +49,6 @@ module HashMap = let inline ofKeyComparer<'Key, 'Value> comparer = HashMapFactory.Create<'Key, 'Value>(comparer) let inline ofComparers<'Key, 'Value> keyComparer valueComparer = HashMapFactory.Create<'Key, 'Value>(keyComparer, valueComparer) - let inline singleton item = empty.Add(item) let inline isEmpty map = check map; map.IsEmpty @@ -80,7 +83,6 @@ module HashMap = let inline exists predicate map = check map; map |> Seq.exists (fun kvp -> predicate kvp.Key kvp.Value) - let inline add key value map : HashMap<_,_> = check map; map.Add(key, value) let inline append map pairs : HashMap<_,_> = check map @@ -104,36 +106,36 @@ module HashMap = let inline where predicate map = map |> Seq.where (fun (kvp:KeyValuePair<_,_>) -> predicate kvp.Key kvp.Value) |> empty.AddRange - let inline count (map:HashMap<_,_>) = check map; map.Count - type SortedMap<'Key, 'Value> = System.Collections.Immutable.ImmutableSortedDictionary<'Key, 'Value> type SortedMapBuilder<'Key, 'Value> = SortedMap<'Key, 'Value>.Builder -type internal SortedMapFactory = - System.Collections.Immutable.ImmutableSortedDictionary - [] module SortedMap = + + type internal SortedMapFactory = System.Collections.Immutable.ImmutableSortedDictionary + + let inline check (sortedMap: SortedMap<_, _>) = checkNotNull (nameof sortedMap) sortedMap + + ////////// Creating ////////// + let inline empty<'Key, 'Value> = SortedMapFactory.Create<'Key, 'Value>() + let inline singleton item = SortedMapFactory.Create(item) - let inline ofSeq items = SortedMapFactory.CreateRange(items) - let inline ofSeqWith getKey items = - checkNotNull (nameof items) items - items + let inline ofSeq source = SortedMapFactory.CreateRange(source) + let inline ofSeqWith getKey source = + source |> Seq.map (fun i -> KeyValuePair(getKey i, i)) |> SortedMapFactory.CreateRange - let inline ofSeqGroupBy getKey items = - checkNotNull (nameof items) items - items + let inline ofSeqGroupBy getKey source = + source |> Seq.groupBy getKey |> Seq.map (fun (key,value) -> KeyValuePair(key, value)) - |> SortedMapFactory.CreateRange - let inline ofArray items = SortedMapFactory.CreateRange(items) + let inline ofArray (source : _ array) = SortedMapFactory.CreateRange(source) - let inline check (sortedMap: SortedMap<_, _>) = checkNotNull (nameof sortedMap) sortedMap + ////////// Building ////////// let inline builder() = SortedMapFactory.CreateBuilder() let inline builderWithKeyComparer comparer = SortedMapFactory.CreateBuilder(comparer) @@ -149,7 +151,6 @@ module SortedMap = let inline ofKeyComparer<'Key, 'Value> comparer = SortedMapFactory.Create<'Key, 'Value>(comparer) let inline ofComparers<'Key, 'Value> keyComparer valueComparer = SortedMapFactory.Create<'Key, 'Value>(keyComparer, valueComparer) - let inline singleton item = empty.Add(item) let inline isEmpty map = check map; map.IsEmpty @@ -218,5 +219,3 @@ module SortedMap = let inline where predicate map = map |> Seq.where (fun (kvp:KeyValuePair<_,_>) -> predicate kvp.Key kvp.Value) |> empty.AddRange - - let inline count (map:SortedMap<_,_>) = check map; map.Count diff --git a/src/FSharp.Collections.Immutable/sets.fs b/src/FSharp.Collections.Immutable/sets.fs index aac4e34..8e79686 100644 --- a/src/FSharp.Collections.Immutable/sets.fs +++ b/src/FSharp.Collections.Immutable/sets.fs @@ -3,35 +3,37 @@ type ISet<'T> = System.Collections.Immutable.IImmutableSet<'T> type HashSet<'T> = System.Collections.Immutable.ImmutableHashSet<'T> - type HashSetBuilder<'T> = HashSet<'T>.Builder -type internal HashSetFactory = System.Collections.Immutable.ImmutableHashSet - [] module HashSet = + + type internal HashSetFactory = System.Collections.Immutable.ImmutableHashSet + + let inline check (set: HashSet<_>) = checkNotNull (nameof set) set + + ////////// Creating ////////// + let inline empty<'T> = HashSetFactory.Create<'T>() + let inline singleton<'T> (item : 'T) = HashSetFactory.Create<'T>(item) + let inline ofSeq source = HashSetFactory.CreateRange(source) + let inline ofSeqWithComparer comparer source = HashSetFactory.Create(comparer, items = (source |> Array.ofSeq)) + let inline ofArray (source : _ array) = HashSetFactory.CreateRange(source) let inline ofBuilder (hashSetBuilder: HashSetBuilder<_>) = - checkNotNull (nameof hashSetBuilder) hashSetBuilder + checkNotNull (nameof hashSetBuilder) hashSetBuilder hashSetBuilder.ToImmutable() let inline ofComparer<'T> comparer = HashSetFactory.Create<'T>(equalityComparer = comparer) - let inline ofSeq items = - checkNotNull (nameof items) items - HashSetFactory.CreateRange(items) - let inline ofSeqWithComparer comparer items = HashSetFactory.Create(comparer, items = (items |> Array.ofSeq)) - let inline ofArray items = HashSetFactory.CreateRange(items) - let inline check (set: HashSet<_>) = checkNotNull (nameof set) set + ////////// Building ////////// let inline builder() = HashSetFactory.CreateBuilder() + let inline builderWith capacity : HashSet<'T>.Builder = HashSetFactory.CreateBuilder(capacity) let inline builderWithComparer comparer = HashSetFactory.CreateBuilder(comparer) let inline toBuilder set : HashSetBuilder<_> = check set; set.ToBuilder() let inline toSeq (set: HashSet<_>) = set :> seq<_> - let inline singleton item = empty.Add(item) - let inline keyComparer set = check set; set.KeyComparer let inline length set = check set; set.Count @@ -75,39 +77,38 @@ module HashSet = let inline iter action (set: HashSet<_>) = check set; set |> Seq.iter action - let inline count (set:HashSet<_>) = check set; set.Count - type SortedSet<'T> = System.Collections.Immutable.ImmutableSortedSet<'T> - type SortedSetBuilder<'T> = SortedSet<'T>.Builder -type internal SortedSetFactory = - System.Collections.Immutable.ImmutableSortedSet - [] module SortedSet = + + type internal SortedSetFactory = System.Collections.Immutable.ImmutableSortedSet + + let inline check (sortedSet: SortedSet<_>) = checkNotNull (nameof sortedSet) sortedSet + + ////////// Creating ////////// + let inline empty<'T> = SortedSetFactory.Create<'T>() + let inline singleton<'T> (item : 'T) = SortedSetFactory.Create<'T>(item) + let inline ofSeq source = SortedSetFactory.CreateRange(source) + let inline ofSeqWithComparer comparer source = SortedSetFactory.Create(comparer, items = (source |> Array.ofSeq)) + let inline ofArray (source : _ array) = SortedSetFactory.CreateRange(source) let inline ofBuilder (sortedSetBuilder: SortedSetBuilder<_>) = - checkNotNull (nameof sortedSetBuilder) sortedSetBuilder + checkNotNull (nameof sortedSetBuilder) sortedSetBuilder sortedSetBuilder.ToImmutable() let inline ofComparer<'T> comparer = SortedSetFactory.Create<'T>(comparer = comparer) - let inline ofSeq items = - checkNotNull (nameof items) items - SortedSetFactory.CreateRange(items) - let inline ofSeqWithComparer comparer items = SortedSetFactory.Create(comparer, items = (items |> Array.ofSeq)) - let inline ofArray items = SortedSetFactory.CreateRange(items) - let inline check (sortedSet: SortedSet<_>) = checkNotNull (nameof sortedSet) sortedSet + ////////// Building ////////// let inline builder() = SortedSetFactory.CreateBuilder() + let inline builderWith capacity : SortedSet<'T>.Builder = SortedSetFactory.CreateBuilder(capacity) let inline builderWithComparer comparer = SortedSetFactory.CreateBuilder(comparer) let inline toBuilder set : SortedSetBuilder<_> = check set; set.ToBuilder() let inline toSeq (set: SortedSet<_>) = set :> seq<_> - let inline singleton item = empty.Add(item) - let inline keyComparer set = check set; set.KeyComparer @@ -149,5 +150,3 @@ module SortedSet = let inline forall predicate set = set |> Seq.forall predicate let inline iter action (set: SortedSet<_>) = check set; set |> Seq.iter action - - let inline count (set:SortedSet<_>) = check set; set.Count From 2088689cab90a2a8ca5d50c0613ff01962032e14 Mon Sep 17 00:00:00 2001 From: Andrii Chebukin Date: Thu, 11 Mar 2021 23:30:59 +0200 Subject: [PATCH 11/17] Added @anthony-mi as author, bumped package version to 2.0.0 --- .../FSharp.Collections.Immutable.fsproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/FSharp.Collections.Immutable/FSharp.Collections.Immutable.fsproj b/src/FSharp.Collections.Immutable/FSharp.Collections.Immutable.fsproj index 9be61c5..2fab4ca 100644 --- a/src/FSharp.Collections.Immutable/FSharp.Collections.Immutable.fsproj +++ b/src/FSharp.Collections.Immutable/FSharp.Collections.Immutable.fsproj @@ -7,8 +7,8 @@ FSharp.Collections.Immutable XperiAndri FSharp.Collections.Immutable - 1.0.0 - XperiAndri;EventHelix;vilinski + 2.0.0 + XperiAndri;EventHelix;vilinski;anthony-mi true FSharp.Collections.Immutable System;Immutable;Collections;FSharp;F# From 9c9a998f2ab1ec8a9891827e8c1e201d164e7483 Mon Sep 17 00:00:00 2001 From: Andrii Chebukin Date: Thu, 11 Mar 2021 23:36:29 +0200 Subject: [PATCH 12/17] Added toArray functions --- src/FSharp.Collections.Immutable/flat-list.fs | 1 + .../immutable-list.fs | 15 ++++----------- src/FSharp.Collections.Immutable/maps.fs | 8 ++++++-- src/FSharp.Collections.Immutable/sets.fs | 8 ++++++-- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/FSharp.Collections.Immutable/flat-list.fs b/src/FSharp.Collections.Immutable/flat-list.fs index e7ee567..5f86c40 100644 --- a/src/FSharp.Collections.Immutable/flat-list.fs +++ b/src/FSharp.Collections.Immutable/flat-list.fs @@ -26,6 +26,7 @@ module FlatList = let inline ofArray (source : _ array) = FlatListFactory.CreateRange source let inline toSeq (flatList: FlatList<_>) = flatList :> seq<_> + let inline toArray (list : FlatList<_>) = check list; Seq.toArray list ////////// Building ////////// diff --git a/src/FSharp.Collections.Immutable/immutable-list.fs b/src/FSharp.Collections.Immutable/immutable-list.fs index 441ba2f..7586d64 100644 --- a/src/FSharp.Collections.Immutable/immutable-list.fs +++ b/src/FSharp.Collections.Immutable/immutable-list.fs @@ -18,6 +18,10 @@ module ImmutableList = let inline ofSeq source = checkNotNull (nameof source) source; ImmutableList.CreateRange source let inline ofArray (source : _ array) = checkNotNull (nameof source) source; ImmutableList.CreateRange source + let inline ofList (list : _ list) = ofSeq list + + let inline toSeq (list : ImmutableList<_>) = list :> seq<_> + let inline toArray (list : ImmutableList<_>) = check list; Seq.toArray list ////////// Building ////////// @@ -230,21 +234,12 @@ module ImmutableList = let tryTail list = if isEmpty list then None else Some <| tail list - let collect mapping list = concat <| map mapping list let cons head list = insert 0 head list - - - - - let ofList list = ofSeq list - //let ofArray (array: 'T array) = ImmutableList.Create<'T>(items = [||]) - - let init count initializer = if count < 0 then // throw the same exception @@ -285,5 +280,3 @@ module ImmutableList = Seq.forall2 predicate list1 list2 let iter action list = check list; Seq.iter action list - - let toArray list = check list; Seq.toArray list diff --git a/src/FSharp.Collections.Immutable/maps.fs b/src/FSharp.Collections.Immutable/maps.fs index f6a32d4..01233f2 100644 --- a/src/FSharp.Collections.Immutable/maps.fs +++ b/src/FSharp.Collections.Immutable/maps.fs @@ -33,6 +33,9 @@ module HashMap = |> HashMapFactory.CreateRange let inline ofArray (source : _ array) = HashMapFactory.CreateRange(source) + let inline toSeq (map: HashMap<_,_>) = map :> seq<_> + let inline toArray (map : HashMap<_,_>) = check map; Seq.toArray map + ////////// Building ////////// let inline builder() = HashMapFactory.CreateBuilder() @@ -44,7 +47,6 @@ module HashMap = mapBuilder.ToImmutable() let inline toBuilder map : HashMapBuilder<_,_> = check map; map.ToBuilder() - let inline toSeq (map: HashMap<_,_>) = map :> seq<_> let inline ofKeyComparer<'Key, 'Value> comparer = HashMapFactory.Create<'Key, 'Value>(comparer) let inline ofComparers<'Key, 'Value> keyComparer valueComparer = HashMapFactory.Create<'Key, 'Value>(keyComparer, valueComparer) @@ -135,6 +137,9 @@ module SortedMap = |> Seq.map (fun (key,value) -> KeyValuePair(key, value)) let inline ofArray (source : _ array) = SortedMapFactory.CreateRange(source) + let inline toSeq (map: SortedMap<_,_>) = map :> seq<_> + let inline toArray (map : SortedMap<_,_>) = check map; Seq.toArray map + ////////// Building ////////// let inline builder() = SortedMapFactory.CreateBuilder() @@ -146,7 +151,6 @@ module SortedMap = sortedMapBuilder.ToImmutable() let inline toBuilder map : SortedMapBuilder<_,_> = check map; map.ToBuilder() - let inline toSeq (map: SortedMap<_,_>) = map :> seq<_> let inline ofKeyComparer<'Key, 'Value> comparer = SortedMapFactory.Create<'Key, 'Value>(comparer) let inline ofComparers<'Key, 'Value> keyComparer valueComparer = SortedMapFactory.Create<'Key, 'Value>(keyComparer, valueComparer) diff --git a/src/FSharp.Collections.Immutable/sets.fs b/src/FSharp.Collections.Immutable/sets.fs index 8e79686..3b091b1 100644 --- a/src/FSharp.Collections.Immutable/sets.fs +++ b/src/FSharp.Collections.Immutable/sets.fs @@ -25,6 +25,9 @@ module HashSet = hashSetBuilder.ToImmutable() let inline ofComparer<'T> comparer = HashSetFactory.Create<'T>(equalityComparer = comparer) + let inline toSeq (set : HashSet<_>) = set :> seq<_> + let inline toArray (set : HashSet<_>) = check set; Seq.toArray set + ////////// Building ////////// let inline builder() = HashSetFactory.CreateBuilder() @@ -32,7 +35,6 @@ module HashSet = let inline builderWithComparer comparer = HashSetFactory.CreateBuilder(comparer) let inline toBuilder set : HashSetBuilder<_> = check set; set.ToBuilder() - let inline toSeq (set: HashSet<_>) = set :> seq<_> let inline keyComparer set = check set; set.KeyComparer @@ -100,6 +102,9 @@ module SortedSet = sortedSetBuilder.ToImmutable() let inline ofComparer<'T> comparer = SortedSetFactory.Create<'T>(comparer = comparer) + let inline toSeq (set: SortedSet<_>) = set :> seq<_> + let inline toArray (set : SortedSet<_>) = check set; Seq.toArray set + ////////// Building ////////// let inline builder() = SortedSetFactory.CreateBuilder() @@ -107,7 +112,6 @@ module SortedSet = let inline builderWithComparer comparer = SortedSetFactory.CreateBuilder(comparer) let inline toBuilder set : SortedSetBuilder<_> = check set; set.ToBuilder() - let inline toSeq (set: SortedSet<_>) = set :> seq<_> let inline keyComparer set = check set; set.KeyComparer From 422192f00d69dac1ad0d1f30f1ed542007619044 Mon Sep 17 00:00:00 2001 From: Andrii Chebukin Date: Tue, 18 May 2021 16:03:25 +0300 Subject: [PATCH 13/17] Added maintainers to README.md and NuGet and MyGet badges --- README.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1ec1d40..d2bc569 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,19 @@ -# FSharp.Collections.Immutable +# FSharp.Collections.Immutable [![NuGet Status](http://img.shields.io/nuget/v/FSharp.Collections.Immutable.svg?style=flat)](https://www.nuget.org/packages/FSharp.Collections.Immutable/) [![MyGet Status](https://img.shields.io/myget/fsharp-collections-immutable/v/fsharp.collections.immutable.svg?style=flat)](https://www.myget.org/feed/Packages/fsharp-collections-immutable) F# bindings for System.Collections.Immutable -![.NET Core](https://github.com/fsprojects/FSharp.Collections.Immutable/workflows/.NET%20Core/badge.svg) +![Build status](https://github.com/fsprojects/FSharp.Collections.Immutable/workflows/.NET%20Core/badge.svg) + +**FSharp.Collections.Immutable** is a collection of F# bindings for System.Collections.Immutable. + +Please contribute to this project. Don't ask for permission, just fork the repository and send pull requests. + +Please also join the [F# Open Source Group](http://fsharp.github.com) + +# Maintainer(s) + +- [@xperiandri](https://github.com/xperiandri) +- [@eventhelix](https://github.com/eventhelix) + + +The default maintainer account for projects under "fsprojects" is [@fsprojectsgit](https://github.com/fsprojectsgit) - F# Community Project Incubation Space (repo management) \ No newline at end of file From fdb5ff40ba30858cc0a3f72a2fb8305264d05dbb Mon Sep 17 00:00:00 2001 From: Andrii Chebukin Date: Tue, 18 May 2021 17:11:09 +0300 Subject: [PATCH 14/17] Added .editorconfig --- .editorconfig | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..31577aa --- /dev/null +++ b/.editorconfig @@ -0,0 +1,56 @@ +# To learn more about .editorconfig see https://aka.ms/editorconfigdocs +############################### +# Core EditorConfig Options # +############################### +# All files +[*] +end_of_line = crlf +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true +# Code files +[*.{cs,csx,fs,fsx,vb,vbx}] +indent_size = 4 +charset = utf-8-bom +# Project files +[*.{csproj,fsproj,vbproj,shproj,projitems}] +indent_size = 2 +charset = utf-8-bom +############################### +# F# Coding Conventions # +############################### +[*.{fs,fsx}] +max_line_length = 120 +fsharp_semicolon_at_end_of_line = false +fsharp_space_before_parameter = true +fsharp_space_before_lowercase_invocation = true +fsharp_space_before_uppercase_invocation = true +fsharp_space_before_class_constructor = true +fsharp_space_before_member = true +fsharp_space_before_colon = true +fsharp_space_after_comma = true +fsharp_space_before_semicolon = false +fsharp_space_after_semicolon = true +fsharp_indent_on_try_with = false +fsharp_space_around_delimiter = true +fsharp_max_if_then_else_short_width = 80 +fsharp_max_infix_operator_expression = 80 +fsharp_max_record_width = 80 +fsharp_max_record_number_of_items = 1 +fsharp_record_multiline_formatter = character_width +fsharp_max_array_or_list_width = 80 +fsharp_max_array_or_list_number_of_items = 10 +fsharp_array_or_list_multiline_formatter = character_width +fsharp_max_value_binding_width = 80 +fsharp_max_function_binding_width = 80 +fsharp_max_dot_get_expression_width = 40 +fsharp_multiline_block_brackets_on_same_column = false +fsharp_newline_between_type_definition_and_members = false +fsharp_keep_if_then_in_same_line = false +fsharp_max_elmish_width = 80 +fsharp_single_argument_web_mode = false +fsharp_align_function_signature_to_indentation = false +fsharp_alternative_long_member_definitions = false +fsharp_multi_line_lambda_closing_newline = false +fsharp_disable_elmish_syntax = false +fsharp_strict_mode = false From b5e2a8f6146910c066525de089dd17629a5f3b37 Mon Sep 17 00:00:00 2001 From: dim-37 Date: Tue, 18 May 2021 16:35:49 +0300 Subject: [PATCH 15/17] Added SourceLink --- .../FSharp.Collections.Immutable.fsproj | 68 +++++++++++-------- 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/src/FSharp.Collections.Immutable/FSharp.Collections.Immutable.fsproj b/src/FSharp.Collections.Immutable/FSharp.Collections.Immutable.fsproj index 2fab4ca..2b3fbfb 100644 --- a/src/FSharp.Collections.Immutable/FSharp.Collections.Immutable.fsproj +++ b/src/FSharp.Collections.Immutable/FSharp.Collections.Immutable.fsproj @@ -1,35 +1,45 @@  - - netstandard2.0 - F# bindings for System.Collections.Immutable - Copyright © XperiAndri 2016 - FSharp.Collections.Immutable - XperiAndri - FSharp.Collections.Immutable - 2.0.0 - XperiAndri;EventHelix;vilinski;anthony-mi - true - FSharp.Collections.Immutable - System;Immutable;Collections;FSharp;F# - git - https://github.com/fsprojects/FSharp.Collections.Immutable/ - + + netstandard2.0 + $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb + F# bindings for System.Collections.Immutable + Copyright © XperiAndri 2016 + FSharp.Collections.Immutable + XperiAndri + FSharp.Collections.Immutable + 2.0.0 + XperiAndri;EventHelix;vilinski;anthony-mi;dim-37 + true + FSharp.Collections.Immutable + System;Immutable;Collections;FSharp;F# + git + embedded + https://github.com/fsprojects/FSharp.Collections.Immutable/ + https://github.com/fsprojects/FSharp.Collections.Immutable/ + true + true + - - - - - - - - - - - + + + + + + + + + + + - - - + + true + + + + + + From d42073c0e086d09effccffe52ab0b490a84ced82 Mon Sep 17 00:00:00 2001 From: Andrii Chebukin Date: Tue, 3 Jun 2025 02:07:17 +0400 Subject: [PATCH 16/17] feat: release automation with FAKE and minimal documentation * Added build and release automation * Updated tools * Added a logo and corrected packaging settings * Updated NuGet packages * Added Copilot instructions * Fixed documentation * Migrated test coverage to TRX * Set .NET SDK to `9.x` in pipelines * Added `dotnet tool update` and fixed `dotnet tool restore` * Migrated to `slnx` --- .config/dotnet-tools.json | 34 + .devcontainer/Dockerfile | 17 + .devcontainer/devcontainer.json | 73 ++ .editorconfig | 332 ++++++-- .fantomasignore | 2 + .git-blame-ignore-revs | 6 + .gitattributes | 4 +- .github/ISSUE_TEMPLATE.md | 31 + .github/ISSUE_TEMPLATE/bug_report.md | 35 + .github/ISSUE_TEMPLATE/feature_request.md | 17 + .github/PULL_REQUEST_TEMPLATE.md | 25 + .github/copilot-instructions.md | 57 ++ .github/workflows/build.yml | 60 +- .github/workflows/fsdocs-gh-pages.yml | 61 ++ .github/workflows/publish_ci.yml | 70 +- .github/workflows/publish_release.yml | 52 +- .gitignore | 244 +++++- .vscode/extensions.json | 9 + .vscode/settings.json | 7 + CHANGELOG.md | 24 + Directory.Build.props | 49 ++ Directory.Build.targets | 47 ++ Directory.Packages.props | 34 + FSharp.Collections.Immutable.sln | 34 - FSharp.Collections.Immutable.slnf | 9 + FSharp.Collections.Immutable.slnx | 14 + README.md | 111 ++- build.cmd | 1 + build.sh | 6 + build/Changelog.fs | 233 ++++++ build/FsDocs.fs | 224 ++++++ build/Properties/launchSettings.json | 24 + build/build.fs | 731 ++++++++++++++++++ build/build.fsproj | 40 + docsSrc/Explanations/Background.md | 39 + docsSrc/How_Tos/Doing_A_Thing.md | 14 + docsSrc/How_Tos/Doing_Another_Thing.md | 9 + docsSrc/Tutorials/Getting_Started.md | 41 + docsSrc/_menu-item_template.html | 1 + docsSrc/_menu_template.html | 9 + docsSrc/_template.html | 166 ++++ docsSrc/content/fsdocs-custom.css | 15 + docsSrc/content/fsdocs-dark.css | 50 ++ docsSrc/content/fsdocs-light.css | 43 ++ docsSrc/content/fsdocs-main.css | 604 +++++++++++++++ docsSrc/content/logo.pdn | Bin 0 -> 8637 bytes docsSrc/content/logo.png | Bin 0 -> 1904 bytes docsSrc/content/logo.svg | 57 ++ docsSrc/content/navbar-fixed-left.css | 91 +++ docsSrc/content/theme-toggle.js | 68 ++ docsSrc/index.md | 79 ++ global.json | 6 + .../FSharp.Collections.Immutable.fsproj | 74 +- .../{flat-list.fs => FlatList.fs} | 367 ++++++--- ...ion-util.fs => ImmutableCollectionUtil.fs} | 10 +- .../{immutable-list.fs => ImmutableList.fs} | 255 +++--- .../IndexedSeq.fs | 17 + src/FSharp.Collections.Immutable/Maps.fs | 339 ++++++++ src/FSharp.Collections.Immutable/Queue.fs | 132 ++++ .../{seq.fs => Seq.fs} | 0 src/FSharp.Collections.Immutable/Sets.fs | 266 +++++++ .../{stack.fs => Stack.fs} | 23 +- .../indexed-seq.fs | 10 - src/FSharp.Collections.Immutable/maps.fs | 225 ------ src/FSharp.Collections.Immutable/queue.fs | 80 -- src/FSharp.Collections.Immutable/sets.fs | 156 ---- tests/Directory.Build.props | 7 + .../Attributes.fs | 7 + .../FSharp.Collections.Immutable.Tests.fsproj | 32 + .../FlatList.fs | 10 + .../ImmutableList.fs | 10 + .../IndexedSeq.fs | 10 + .../Maps.fs | 16 + .../Queue.fs | 10 + .../Sets.fs | 16 + .../Stack.fs | 10 + 76 files changed, 5188 insertions(+), 903 deletions(-) create mode 100644 .config/dotnet-tools.json create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/devcontainer.json create mode 100644 .fantomasignore create mode 100644 .git-blame-ignore-revs create mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/copilot-instructions.md create mode 100644 .github/workflows/fsdocs-gh-pages.yml create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json create mode 100644 CHANGELOG.md create mode 100644 Directory.Build.props create mode 100644 Directory.Build.targets create mode 100644 Directory.Packages.props delete mode 100644 FSharp.Collections.Immutable.sln create mode 100644 FSharp.Collections.Immutable.slnf create mode 100644 FSharp.Collections.Immutable.slnx create mode 100644 build.cmd create mode 100644 build.sh create mode 100644 build/Changelog.fs create mode 100644 build/FsDocs.fs create mode 100644 build/Properties/launchSettings.json create mode 100644 build/build.fs create mode 100644 build/build.fsproj create mode 100644 docsSrc/Explanations/Background.md create mode 100644 docsSrc/How_Tos/Doing_A_Thing.md create mode 100644 docsSrc/How_Tos/Doing_Another_Thing.md create mode 100644 docsSrc/Tutorials/Getting_Started.md create mode 100644 docsSrc/_menu-item_template.html create mode 100644 docsSrc/_menu_template.html create mode 100644 docsSrc/_template.html create mode 100644 docsSrc/content/fsdocs-custom.css create mode 100644 docsSrc/content/fsdocs-dark.css create mode 100644 docsSrc/content/fsdocs-light.css create mode 100644 docsSrc/content/fsdocs-main.css create mode 100644 docsSrc/content/logo.pdn create mode 100644 docsSrc/content/logo.png create mode 100644 docsSrc/content/logo.svg create mode 100644 docsSrc/content/navbar-fixed-left.css create mode 100644 docsSrc/content/theme-toggle.js create mode 100644 docsSrc/index.md create mode 100644 global.json rename src/FSharp.Collections.Immutable/{flat-list.fs => FlatList.fs} (58%) rename src/FSharp.Collections.Immutable/{immutable-collection-util.fs => ImmutableCollectionUtil.fs} (73%) rename src/FSharp.Collections.Immutable/{immutable-list.fs => ImmutableList.fs} (50%) create mode 100644 src/FSharp.Collections.Immutable/IndexedSeq.fs create mode 100644 src/FSharp.Collections.Immutable/Maps.fs create mode 100644 src/FSharp.Collections.Immutable/Queue.fs rename src/FSharp.Collections.Immutable/{seq.fs => Seq.fs} (100%) create mode 100644 src/FSharp.Collections.Immutable/Sets.fs rename src/FSharp.Collections.Immutable/{stack.fs => Stack.fs} (62%) delete mode 100644 src/FSharp.Collections.Immutable/indexed-seq.fs delete mode 100644 src/FSharp.Collections.Immutable/maps.fs delete mode 100644 src/FSharp.Collections.Immutable/queue.fs delete mode 100644 src/FSharp.Collections.Immutable/sets.fs create mode 100644 tests/Directory.Build.props create mode 100644 tests/FSharp.Collections.Immutable.Tests/Attributes.fs create mode 100644 tests/FSharp.Collections.Immutable.Tests/FSharp.Collections.Immutable.Tests.fsproj create mode 100644 tests/FSharp.Collections.Immutable.Tests/FlatList.fs create mode 100644 tests/FSharp.Collections.Immutable.Tests/ImmutableList.fs create mode 100644 tests/FSharp.Collections.Immutable.Tests/IndexedSeq.fs create mode 100644 tests/FSharp.Collections.Immutable.Tests/Maps.fs create mode 100644 tests/FSharp.Collections.Immutable.Tests/Queue.fs create mode 100644 tests/FSharp.Collections.Immutable.Tests/Sets.fs create mode 100644 tests/FSharp.Collections.Immutable.Tests/Stack.fs diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json new file mode 100644 index 0000000..3c0225f --- /dev/null +++ b/.config/dotnet-tools.json @@ -0,0 +1,34 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "dotnet-reportgenerator-globaltool": { + "version": "5.4.7", + "commands": [ + "reportgenerator" + ], + "rollForward": false + }, + "fsharp-analyzers": { + "version": "0.31.0", + "commands": [ + "fsharp-analyzers" + ], + "rollForward": false + }, + "fantomas": { + "version": "7.0.2", + "commands": [ + "fantomas" + ], + "rollForward": false + }, + "fsdocs-tool": { + "version": "20.0.1", + "commands": [ + "fsdocs" + ], + "rollForward": false + } + } +} \ No newline at end of file diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..96c07a3 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,17 @@ +# [Choice] Debian version (use bullseye on local arm64/Apple Silicon): bookworm, bullseye, buster +ARG VARIANT="bookworm" +FROM buildpack-deps:${VARIANT}-curl + + +ENV \ + # Enable detection of running in a container + DOTNET_RUNNING_IN_CONTAINER=true \ + DOTNET_ROOT=/usr/share/dotnet/ \ + DOTNET_NOLOGO=true \ + DOTNET_CLI_TELEMETRY_OPTOUT=false\ + DOTNET_USE_POLLING_FILE_WATCHER=true + + +# [Optional] Uncomment this section to install additional OS packages. +# RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ +# && apt-get -y install --no-install-recommends diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..5b1e8df --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,73 @@ +{ + "name": "dotnet", + // Set the build context one level higher so we can grab metadata like global.json + "context": "..", + "dockerFile": "Dockerfile", + "forwardPorts": [ + 0 + ], + "features": { + // https://github.com/devcontainers/features/blob/main/src/common-utils/README.md + "ghcr.io/devcontainers/features/common-utils:2": { + "installZsh": true, + "installOhMyZshConfig": true, + "configureZshAsDefaultShell": true, + "username": "vscode", + "userUid": "1000", + "userGid": "1000", + "upgradePackages": true + }, + // https://github.com/devcontainers/features/blob/main/src/github-cli/README.md + "ghcr.io/devcontainers/features/github-cli:1": {}, + // https://github.com/devcontainers-contrib/features/blob/main/src/starship/README.md + "ghcr.io/devcontainers-contrib/features/starship:1": {}, + // https://github.com/devcontainers/features/blob/main/src/dotnet/README.md + "ghcr.io/devcontainers/features/dotnet:2": { + "version": "9.0", + "additionalVersions": "8.0" + } + }, + "overrideFeatureInstallOrder": [ + "ghcr.io/devcontainers/features/common-utils", + "ghcr.io/devcontainers/features/github-cli", + "ghcr.io/devcontainers-contrib/features/starship", + "ghcr.io/devcontainers/features/dotnet" + ], + "customizations": { + "vscode": { + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "ms-dotnettools.csharp", + "Ionide.Ionide-fsharp", + "tintoy.msbuild-project-tools", + "ionide.ionide-paket", + "usernamehw.errorlens", + "alefragnani.Bookmarks", + "oderwat.indent-rainbow", + "vscode-icons-team.vscode-icons", + "EditorConfig.EditorConfig", + "ms-azuretools.vscode-docker", + "GitHub.vscode-pull-request-github", + "github.vscode-github-actions" + ], + "settings": { + "terminal.integrated.defaultProfile.linux": "zsh", + "csharp.suppressDotnetInstallWarning": true + } + } + }, + "remoteUser": "vscode", + "containerUser": "vscode", + "containerEnv": { + // Expose the local environment variable to the container + // They are used for releasing and publishing from the container + "GITHUB_TOKEN": "${localEnv:GITHUB_TOKEN}" + }, + "onCreateCommand": { + "enable-starship": "echo 'eval \"$(starship init zsh)\"' >> ~/.zshrc" + }, + "postAttachCommand": { + "restore": "dotnet tool restore && dotnet restore" + }, + "waitFor": "updateContentCommand" +} diff --git a/.editorconfig b/.editorconfig index 31577aa..869005a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,56 +1,296 @@ -# To learn more about .editorconfig see https://aka.ms/editorconfigdocs +# EditorConfig is awesome: +http://EditorConfig.org + +# top-most EditorConfig file +root = true + ############################### # Core EditorConfig Options # ############################### # All files -[*] -end_of_line = crlf +[*] # Do not apply to all files not to break something +guidelines = 120 dashed, 130 +# Either crlf | lf, default is system-dependent (when not specified at all) +# end_of_line=crlf +# Remove whitespace at the end of any line + +# Visual Studio Solution Files +[*.sln] +indent_style = tab + +# Code files +[*.{cs,csx,fs,fsi,fsx}] +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = space # default=space +indent_size = 4 # default=4 +charset = utf-8 + +# Project files and app specific XML files +[*.{csproj,fsproj,shproj,sfproj,projitems,props,xaml,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = space +indent_size = 2 + +# XML configuration files +[{app.config,nuget.config,packages.config,web.config}] +trim_trailing_whitespace = true +insert_final_newline = true +indent_style = space +indent_size = 2 + +# XML files +[*.xml] +trim_trailing_whitespace = false # do not trim as it affects CData +insert_final_newline = true indent_style = space +indent_size = 2 + +# JSON and YAML files +[*.{json,yml,yaml}] +trim_trailing_whitespace = true insert_final_newline = true +indent_style = space +indent_size = 2 + +# Proto files +[*.proto] trim_trailing_whitespace = true -# Code files -[*.{cs,csx,fs,fsx,vb,vbx}] -indent_size = 4 -charset = utf-8-bom -# Project files -[*.{csproj,fsproj,vbproj,shproj,projitems}] -indent_size = 2 -charset = utf-8-bom +insert_final_newline = true +indent_style = space +indent_size = 4 + +# Markdown Files +[*.{md,mdx}] +trim_trailing_whitespace = false + +# Bash Files +[*.{sh}] +end_of_line = lf + +# Batch Files +[*.{cmd,bat}] +end_of_line = crlf + +# Powershell Files +[*.{ps1, psm1}] +end_of_line = crlf + +# Paket files +[paket.*] +trim_trailing_whitespace = true +indent_size = 2 + +[*.paket.references] +trim_trailing_whitespace = true +indent_size = 2 + ############################### # F# Coding Conventions # ############################### -[*.{fs,fsx}] -max_line_length = 120 -fsharp_semicolon_at_end_of_line = false -fsharp_space_before_parameter = true -fsharp_space_before_lowercase_invocation = true -fsharp_space_before_uppercase_invocation = true -fsharp_space_before_class_constructor = true -fsharp_space_before_member = true -fsharp_space_before_colon = true -fsharp_space_after_comma = true -fsharp_space_before_semicolon = false -fsharp_space_after_semicolon = true -fsharp_indent_on_try_with = false -fsharp_space_around_delimiter = true -fsharp_max_if_then_else_short_width = 80 -fsharp_max_infix_operator_expression = 80 -fsharp_max_record_width = 80 -fsharp_max_record_number_of_items = 1 -fsharp_record_multiline_formatter = character_width -fsharp_max_array_or_list_width = 80 -fsharp_max_array_or_list_number_of_items = 10 -fsharp_array_or_list_multiline_formatter = character_width -fsharp_max_value_binding_width = 80 -fsharp_max_function_binding_width = 80 -fsharp_max_dot_get_expression_width = 40 -fsharp_multiline_block_brackets_on_same_column = false -fsharp_newline_between_type_definition_and_members = false -fsharp_keep_if_then_in_same_line = false -fsharp_max_elmish_width = 80 -fsharp_single_argument_web_mode = false -fsharp_align_function_signature_to_indentation = false -fsharp_alternative_long_member_definitions = false -fsharp_multi_line_lambda_closing_newline = false -fsharp_disable_elmish_syntax = false -fsharp_strict_mode = false +# https://fsprojects.github.io/fantomas/docs/end-users/Configuration.html + +# filetypes that need to be formatted by Fantomas: +[*.{fs,fsi,fsx}] + +# files to be ignored for Fantomas may go into this file, if present: +# .fantomasignore + +# indentation size, default=4 +indent_size=4 + +# line length before it gets broken down into multiple lines +# default 120 +max_line_length=130 + +# Either crlf | lf, default is system-dependent (when not specified at all) +# end_of_line=crlf + +# Whether end-of-file has a newline, default=true +insert_final_newline=true + +# false: someLineOfCode +# true: someLineOfCode; +# default false +fsharp_semicolon_at_end_of_line=false + +# false: f(1,2) +# true: f(1, 2) +# default true +fsharp_space_before_parameter=true + +# false: Option.map(fun x -> x) +# true: Option.map (fun x -> x) +# default true +fsharp_space_before_lowercase_invocation=true + +# false: x.ToString() +# true: x.ToString () +# default false +fsharp_space_before_uppercase_invocation=true + +# false: new Ship(withBeans) +# true: new Ship (withBeans) +# default false +fsharp_space_before_class_constructor=true + +# false: __.member Foo(x) = x +# true: __.member Foo (x) = x +# default false +fsharp_space_before_member=true + +# false: type Point = { x: int; y: int } +# true: type Point = { x : int; y : int } +# default false +fsharp_space_before_colon=true + +# false: (a,b,c) +# true: (a, b, c) +# default true +fsharp_space_after_comma=true + +# false: [a; b; 42] +# true: [a ; b ; 42] +# default false +fsharp_space_before_semicolon=false + +# false: [a;b;42] +# true: [a; b; 42] +# default true +fsharp_space_after_semicolon=true + +# false: let a = [1;2;3] +# true: let a = [ 1;2;3 ] +# default true +fsharp_space_around_delimiter=true + +# breaks an if-then-else in smaller parts if it is on one line +# default 40 +fsharp_max_if_then_else_short_width=60 + +# breaks an infix operator expression if it is on one line +# infix: a + b + c +# default 50 +fsharp_max_infix_operator_expression=60 + +# breaks a single-line record declaration +# i.e. if this gets too wide: { X = 10; Y = 12 } +# default 40 +fsharp_max_record_width=80 + +# breaks a record into one item per line if items exceed this number +# i.e. if set to 1, this will be on three lines: { X = 10; Y = 12 } +# requires fsharp_record_multiline_formatter=number_of_items to take effect +# default 1 +fsharp_max_record_number_of_items=1 + +# whether to use line-length (by counting chars) or items (by counting fields) +# for the record settings above +# either number_of_items or character_width +# default character_width +fsharp_record_multiline_formatter=character_width + +# breaks a single line array or list if it exceeds this size +# default 40 +fsharp_max_array_or_list_width=100 + +# breaks an array or list into one item per line if items exceeds this number +# i.e. if set to 1, this will be shown on three lines [1; 2; 3] +# requires fsharp_array_or_list_multiline_formatter=number_of_items to take effect +# default 1 +fsharp_max_array_or_list_number_of_items=1 + +# whether to use line-length (by counting chars) or items (by counting fields) +# for the list and array settings above +# either number_of_items or character_width +# default character_width +fsharp_array_or_list_multiline_formatter=character_width + +# maximum with of a value binding, does not include keyword "let" +# default 80 +fsharp_max_value_binding_width=100 + +# maximum width for function and member binding (rh-side) +# default 40 +fsharp_max_function_binding_width=80 + +# maximum width for expressions like X.DoY().GetZ(10).Help() +# default 50 +fsharp_max_dot_get_expression_width=80 + +# whether open/close brackets go on the same column +# cramped: type Range = +# { From: float +# To: float } +# aligned: type Range = +# { +# From: float +# To: float +# } +# stroustrup: type Range = { +# From: float +# To: float +# } +# default cramped +fsharp_multiline_bracket_style=stroustrup + +# whether to move the beginning of compuitation expression to the new line +# true: let x = +# computation { +# ... +# } +# false: let x = computation { +# .. +# } +fsharp_newline_before_multiline_computation_expression=false + +# whether a newline should be placed before members +# false: type Range = +# { From: float } +# member this.Length = this.To - this.From +# true: type Range = +# { From: float } +# +# member this.Length = this.To - this.From +# default false +fsharp_newline_between_type_definition_and_members=true + +# if a function sign exceeds max_line_length, then: +# false: do not place the equal-sign on a single line +# true: place the equal-sign on a single line +# default false +fsharp_align_function_signature_to_indentation=false + +# see docs: https://github.com/fsprojects/fantomas/blob/master/docs/Documentation.md#fsharp_alternative_long_member_definitions +# default false +fsharp_alternative_long_member_definitions=true + +# places closing paren in lambda on a newline in multiline lambdas +# default false +fsharp_multi_line_lambda_closing_newline=true + +# allows the 'else'-branch to be aligned at same level as 'else' if the ret type allows it +# false: match x with +# | null -> () +# | _ -> () +# true: match x with +# | null -> () +# | _ -> +# () +# default false +fsharp_keep_indent_in_branch=true + +# whether a bar is placed before DU +# false: type MyDU = Short of int +# true: type MyDU = | Short of int +# default false +fsharp_bar_before_discriminated_union_declaration=false + +# multiline, nested expressions must be surrounded by blank lines +# default true +fsharp_blank_lines_around_nested_multiline_expressions=false + +# set maximal number of consecutive blank lines to keep from original source +# it doesn't change number of new blank lines generated by Fantomas +fsharp_keep_max_number_of_blank_lines=2 diff --git a/.fantomasignore b/.fantomasignore new file mode 100644 index 0000000..d9f2aa7 --- /dev/null +++ b/.fantomasignore @@ -0,0 +1,2 @@ +# Ignore AssemblyInfo files +AssemblyInfo.fs diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 0000000..9c8817e --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,6 @@ +# This file contains a list of git hashes of revisions to be ignored by git +# These revisions are considered "unimportant" in +# that they are unlikely to be what you are interested in when blaming. +# Like formatting with Fantomas +# https://docs.github.com/en/repositories/working-with-files/using-files/viewing-a-file#ignore-commits-in-the-blame-view +# Add formatting commits here diff --git a/.gitattributes b/.gitattributes index 206349c..cb6f883 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,8 +1,9 @@ # Auto detect text files -* text=auto +* text=auto # Custom for Visual Studio *.cs diff=csharp text=auto eol=lf +*.vb diff=csharp text=auto eol=lf *.fs diff=csharp text=auto eol=lf *.fsi diff=csharp text=auto eol=lf *.fsx diff=csharp text=auto eol=lf @@ -11,6 +12,7 @@ *.vbproj merge=union *.fsproj merge=union *.dbproj merge=union +*.sh text eol=lf # Standard to msysgit *.doc diff=astextplain diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..02ca9be --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,31 @@ +## Description + +Please insert a description of your problem or question. + +## Error messages, screenshots + +Please add any error logs or screenshots if available. + +## Failing test, failing GitHub repo, or reproduction steps + +Please add either a failing test, a GitHub repo of the problem or detailed reproduction steps. + +## Expected Behavior + +Please define what you would expect the behavior to be like. + +## Known workarounds + +Please provide a description of any known workarounds. + +## Other information + +* Operating System: + - [ ] windows [insert version here] + - [ ] macOs [insert version] + - [ ] linux [insert flavor/version here] +* Platform + - [ ] dotnet core + - [ ] dotnet full + - [ ] mono +* Branch or release version: diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..b735373 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,35 @@ +--- +name: Bug report +about: Create a report to help us improve + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: [e.g. iOS] + - Browser [e.g. chrome, safari] + - Version [e.g. 22] + +**Smartphone (please complete the following information):** + - Device: [e.g. iPhone6] + - OS: [e.g. iOS8.1] + - Browser [e.g. stock browser, safari] + - Version [e.g. 22] + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000..066b2d9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,17 @@ +--- +name: Feature request +about: Suggest an idea for this project + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..ab249a8 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,25 @@ +## Proposed Changes + +Describe the big picture of your changes here to communicate to the maintainers why we should accept this pull request. If it fixes a bug or resolves a feature request, be sure to link to that issue. + +## Types of changes + +What types of changes does your code introduce to FSharp.Azure.Cosmos? +_Put an `x` in the boxes that apply_ + +- [ ] Bugfix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) + + +## Checklist + +_Put an `x` in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code._ + +- [ ] Build and tests pass locally +- [ ] I have added tests that prove my fix is effective or that my feature works (if appropriate) +- [ ] I have added necessary documentation (if appropriate) + +## Further comments + +If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did and what alternatives you considered, etc... diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..8690c43 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,57 @@ +We prefer the latest F# 9 features over the old syntax + +Prefer `voption` over `option` + +Prefer `task` CE over `async` CE + +This is how you define a non-default F# class constructor: +```fsharp +type DerivedClass = + inherit BaseClass + + new (``arguments here``) as ``created object`` + = + // create any objects used in the base class constructor + let fieldValue = "" + { + inherit + BaseClass (``arguments here``) + } + then + ``created object``.otherField <- fieldValue + + [] + val mutable otherField : FieldType +``` + +Always prefer F# class initializers over property assignment! **You absolutely must use F# class initializers instead of property assignment**! + +Class declaration: +``` F# +type MyClass (someConstructorParam : string) = + member ReadOnlyProperty = someConstructorParam + + member val MutableProperty1 = "" with get, set + member val MutableProperty2 = "" with get, set +``` + +Wrong: +``` F# +let myClass = MyClass("some value") +myClass.MutableProperty1 <- "new value" +myClass.MutableProperty2 <- "new value" +``` + +Right: +``` F# +let myClass = + MyClass( + // constructor parameters go first without names + "some value", + // then mutable properties go next with names + MutableProperty1 = "new value", + MutableProperty2 = + // operations must be placed into parentheses + (5 |> string) + ) +``` diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a45ad74..31c54a8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,21 +1,57 @@ -name: .NET Core +name: Build main on: push: - branches-ignore: - - master - - develop + branches: + - main + pull_request: + branches: + - main jobs: build: + strategy: + matrix: + configuration: [Debug, Release] + os: [ubuntu-latest, windows-latest, macOS-latest] + runs-on: ${{ matrix.os }} - runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Setup necessary dotnet SDKs + uses: actions/setup-dotnet@v3 + with: + global-json-file: global.json + dotnet-version: | + 9.x + 8.x + - name: Build via Bash + if: runner.os != 'Windows' + run: | + chmod +x ./build.sh + ./build.sh + env: + CI: true + CONFIGURATION: ${{ matrix.configuration }} + ENABLE_COVERAGE: true + - name: Build via Windows + if: runner.os == 'Windows' + run: ./build.cmd + env: + CI: true + CONFIGURATION: ${{ matrix.configuration }} + ENABLE_COVERAGE: true + # Builds the project in a dev container + build-devcontainer: + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: Setup .NET Core - uses: actions/setup-dotnet@v1 - - name: Build with dotnet - run: | - DOTNET_CLI_TELEMETRY_OPTOUT=1 - dotnet build --nologo --configuration Release + + - uses: actions/checkout@v3 + + - name: Build and run dev container task + uses: devcontainers/ci@v0.3 + with: + runCmd: | + chmod +x ./build.sh + ./build.sh diff --git a/.github/workflows/fsdocs-gh-pages.yml b/.github/workflows/fsdocs-gh-pages.yml new file mode 100644 index 0000000..0ebb9ec --- /dev/null +++ b/.github/workflows/fsdocs-gh-pages.yml @@ -0,0 +1,61 @@ +name: Deploy Docs + +on: + # Runs on pushes targeting the default branch + push: + branches: ["main"] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + # Build job + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Pages + uses: actions/configure-pages@v4 + + - name: Setup necessary dotnet SDKs + uses: actions/setup-dotnet@v4 + with: + global-json-file: global.json + dotnet-version: | + 9.x + + - name: Build Docs + run: | + chmod +x ./build.sh + ./build.sh builddocs + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: docs/ + + # Deployment job + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/publish_ci.yml b/.github/workflows/publish_ci.yml index b63bbb6..9a0f45b 100644 --- a/.github/workflows/publish_ci.yml +++ b/.github/workflows/publish_ci.yml @@ -1,25 +1,65 @@ -name: publish to MyGet +name: Publish to GitHub on: push: branches: - - develop + - main + +env: + CONFIGURATION: Release jobs: build: - + # Sets permissions of the GITHUB_TOKEN to allow release creating + permissions: + packages: write + environment: + name: nuget runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: Setup .NET Core - uses: actions/setup-dotnet@v1 - - name: Build with dotnet - run: | - sed -i "s|\(.*\)|\1-ci-$GITHUB_RUN_ID|" src/FSharp.Collections.Immutable/FSharp.Collections.Immutable.fsproj - dotnet pack --nologo --configuration Release -o nuget - - name: MyGet push - run: | - source=https://www.myget.org/F/fsharp-collections-immutable/api/v3/index.json - key=${{secrets.MyGet_Key}} - dotnet nuget push -s $source -k $key nuget/*.nupkg + - uses: actions/checkout@v3 + + - name: Setup necessary dotnet SDKs + uses: actions/setup-dotnet@v3 + with: + global-json-file: global.json + dotnet-version: | + 9.x + 8.x + + - name: Add the GitHub source + run: dotnet nuget add source --name "github.com" "https://nuget.pkg.github.com/fsprojects/index.json" + + - name: Ensure NuGet package source mapping + shell: pwsh + run: | + $nugetConfigPath = "$HOME/.nuget/NuGet/NuGet.Config" + [xml]$nugetConfig = Get-Content $nugetConfigPath + + $packageSourceMapping = $nugetConfig.configuration.packageSourceMapping + if ($packageSourceMapping -ne $null) { + $packageSourceMapping.RemoveAll() + } else { + $packageSourceMapping = $nugetConfig.CreateElement("packageSourceMapping") + $nugetConfig.configuration.AppendChild($packageSourceMapping) + } + + $nugetSource = $nugetConfig.CreateElement("packageSource") + $nugetSource.SetAttribute("key", "nuget.org") + $nugetPattern = $nugetConfig.CreateElement("package") + $nugetPattern.SetAttribute("pattern", "*") + $nugetSource.AppendChild($nugetPattern) + $packageSourceMapping.AppendChild($nugetSource) + + $nugetConfig.Save($nugetConfigPath) + + - name: Publish to GitHub + env: + NUGET_TOKEN: ${{ secrets.NUGET_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + FAKE_DETAILED_ERRORS: true + ENABLE_COVERAGE: false # AltCover doesn't work with Release builds, reports lower coverage than actual + run: | + chmod +x ./build.sh + ./build.sh "PublishToGitHub" diff --git a/.github/workflows/publish_release.yml b/.github/workflows/publish_release.yml index acd6a0f..d92d34f 100644 --- a/.github/workflows/publish_release.yml +++ b/.github/workflows/publish_release.yml @@ -1,32 +1,36 @@ -name: publish to NuGet +name: Publish to NuGet on: push: - branches: - - master + tags: + - 'releases/*' +env: + CONFIGURATION: Release jobs: - publish: - + build: + # Sets permissions of the GITHUB_TOKEN to allow release creating + permissions: + contents: write + environment: + name: nuget runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - # Required for a specific dotnet version that doesn't come with ubuntu-latest / windows-latest - # Visit bit.ly/2synnZl to see the list of SDKs that are pre-installed with ubuntu-latest / windows-latest - # - name: Setup dotnet - # uses: actions/setup-dotnet@v1 - # with: - # dotnet-version: 3.1.100 - - # Publish - - name: publish on version change - uses: rohith/publish-nuget@v2 + - uses: actions/checkout@v3 + - name: Setup necessary dotnet SDKs + uses: actions/setup-dotnet@v3 with: - PROJECT_FILE_PATH: src/FSharp.Collections.Immutable/FSharp.Collections.Immutable.fsproj # Relative to repository root - # VERSION_FILE_PATH: Directory.Build.props # Filepath with version info, relative to repository root. Defaults to project file - # VERSION_REGEX: (.*)<\/Version> # Regex pattern to extract version info in a capturing group - # TAG_COMMIT: true # Flag to enable / disalge git tagging - # TAG_FORMAT: v* # Format of the git tag, [*] gets replaced with version - NUGET_KEY: ${{secrets.NuGet_Key}} + global-json-file: global.json + dotnet-version: | + 9.x + 8.x + + - name: Publish to NuGet + env: + NUGET_TOKEN: ${{ secrets.NUGET_TOKEN }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + FAKE_DETAILED_ERRORS: true + ENABLE_COVERAGE: false # AltCover doesn't work with Release builds, reports lower coverage than actual + run: | + chmod +x ./build.sh + ./build.sh Publish diff --git a/.gitignore b/.gitignore index 98a4281..99fd3b7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,10 @@ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore # User-specific files +*.rsuser *.suo *.user *.userosscache @@ -10,6 +13,9 @@ # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs +# Mono auto generated files +mono_crash.* + # Build results [Dd]ebug/ [Dd]ebugPublic/ @@ -17,39 +23,62 @@ [Rr]eleases/ x64/ x86/ -build/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ bld/ [Bb]in/ [Oo]bj/ +[Ll]og/ +[Ll]ogs/ -# Visual Studio 2015 cache/options directory +# Visual Studio 2015/2017 cache/options directory .vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* -# NUNIT +# NUnit *.VisualState.xml TestResult.xml +nunit-*.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c -# DNX +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core project.lock.json +project.fragment.lock.json artifacts/ +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio *_i.c *_p.c -*_i.h +*_h.h *.ilk *.meta *.obj +*.iobj *.pch *.pdb +*.ipdb *.pgc *.pgd *.rsp @@ -59,7 +88,9 @@ artifacts/ *.tlh *.tmp *.tmp_proj +*_wpftmp.csproj *.log +*.tlog *.vspscc *.vssscc .builds @@ -74,14 +105,21 @@ _Chutzpah* ipch/ *.aps *.ncb +*.opendb *.opensdf *.sdf *.cachefile +*.VC.db +*.VC.VC.opendb # Visual Studio profiler *.psess *.vsp *.vspx +*.sap + +# Visual Studio Trace Files +*.e2e # TFS 2012 Local Workspace $tf/ @@ -89,9 +127,6 @@ $tf/ # Guidance Automation Toolkit *.gpState -# CodeRush is a .NET coding add-in -.cr/ - # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper @@ -106,9 +141,23 @@ _TeamCity* # DotCover is a Code Coverage Tool *.dotCover +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + # NCrunch _NCrunch_* .*crunch*.local.xml +nCrunchTemp_* # MightyMoose *.mm.* @@ -136,49 +185,72 @@ publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml -## TODO: Comment the next line if you want to checkin your -## web deploy settings but do note that will include unencrypted -## passwords -#*.pubxml - +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml *.publishproj +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + # NuGet Packages *.nupkg +# NuGet Symbol Packages +*.snupkg # The packages folder can be ignored because of Package Restore -**/packages/* -# project.json output for .csproj and .fsproj projects can be ignored because of Package Restore -*.nuget.targets +**/[Pp]ackages/* # except build/, which is used as an MSBuild target. -!**/packages/build/ +!**/[Pp]ackages/build/ # Uncomment if necessary however generally it will be regenerated when needed -#!**/packages/repositories.config +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets -# Windows Azure Build Output +# Microsoft Azure Build Output csx/ *.build.csdef -# Windows Store app package directory +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache -!*.[Cc]ache/ +!?*.[Cc]ache/ # Others ClientBin/ -[Ss]tyle[Cc]op.* ~$* *~ *.dbmdl *.dbproj.schemaview +*.jfm *.pfx *.publishsettings -node_modules/ orleans.codegen.cs +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + # RIA/Silverlight projects Generated_Code/ @@ -189,21 +261,32 @@ _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak # SQL Server files *.mdf *.ldf +*.ndf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl # Microsoft Fakes FakesAssemblies/ +# GhostDoc plugin setting file +*.GhostDoc.xml + # Node.js Tools for Visual Studio .ntvs_analysis.dat +node_modules/ # Visual Studio 6 build log *.plg @@ -211,9 +294,114 @@ FakesAssemblies/ # Visual Studio 6 workspace options file *.opt -# LightSwitch generated files -GeneratedArtifacts/ -_Pvt_Extensions/ -ModelManifest.xml +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder .ionide/ -.idea/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml + +# fsdocs generated +tmp/ +temp/ +.fsdocs +docs/ diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..d566ef1 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,9 @@ +{ + "recommendations": [ + "ionide.ionide-paket", + "ionide.ionide-fsharp", + "ionide.ionide-fake", + "ms-dotnettools.csharp", + "editorConfig.editorConfig" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..b98926a --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "FSharp.fsacRuntime":"netcore", + "FSharp.enableAnalyzers": false, + "FSharp.analyzersPath": [ + "./packages/analyzers" + ] +} diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..e3f2456 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,24 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [1.0.0] - 2020-02-23 + +First release + +### Implemented type abbreviations and modules with functions for: +* `FlatList` (`ImmutableArray`) +* `ImmutableList` +* `Stack` (`ImmutableStack`) +* `Queue` (`ImmutableQueue`) +* `HashMap` (`ImmutableDictionary`) +* `SortedMap` (`ImmutableSortedDictionary`) +* `HashSet` (`ImmutableHashSet`) +* `SortedSet` (`ImmutableSortedSet`) +* `IIndexedSeq` (`IReadOnlyList`) + +[Unreleased]: https://github.com/fsprojects/FSharp.Collections.Immutable/compare/releases/1.0.0...HEAD +[1.0.0]: https://github.com/fsprojects/FSharp.Collections.Immutable/releases/tag/releases/1.0.0 diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 0000000..d14b42f --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,49 @@ + + + + + F#;FSharp;Collections;Immutable + https://github.com/fsprojects/FSharp.Collections.Immutable + false + LICENSE + README.md + logo.png + + git + fsprojects, EventHelix;vilinski;anthony-mi;dim-37 + https://github.com/fsprojects/FSharp.Collections.Immutable + + true + + true + snupkg + true + + + + FSharp.Collections.Immutable + 9.0 + enable + true + false + true + + + + + + + + + + + + + + diff --git a/Directory.Build.targets b/Directory.Build.targets new file mode 100644 index 0000000..484ac5a --- /dev/null +++ b/Directory.Build.targets @@ -0,0 +1,47 @@ + + + + + <_BuildProjBaseIntermediateOutputPath>$(MSBuildThisFileDirectory)build/obj/ + <_DotnetToolManifestFile>$(MSBuildThisFileDirectory).config/dotnet-tools.json + <_DotnetToolRestoreOutputFile>$(_BuildProjBaseIntermediateOutputPath)/dotnet-tool-restore-$(NETCoreSdkVersion)-$(OS) + <_DotnetFantomasOutputFile>$(BaseIntermediateOutputPath)dotnet-fantomas-msbuild-$(NETCoreSdkVersion)-$(OS) + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Directory.Packages.props b/Directory.Packages.props new file mode 100644 index 0000000..b822078 --- /dev/null +++ b/Directory.Packages.props @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FSharp.Collections.Immutable.sln b/FSharp.Collections.Immutable.sln deleted file mode 100644 index a9324bb..0000000 --- a/FSharp.Collections.Immutable.sln +++ /dev/null @@ -1,34 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29021.104 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "FSharp.Collections.Immutable", "src\FSharp.Collections.Immutable\FSharp.Collections.Immutable.fsproj", "{9805E74C-D028-4D05-9256-5C2FDC9B6EA8}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{9BE8C74B-E5EF-4A0E-8E77-CDCD967B6E88}" - ProjectSection(SolutionItems) = preProject - .github\workflows\build.yml = .github\workflows\build.yml - .github\workflows\publish_ci.yml = .github\workflows\publish_ci.yml - .github\workflows\publish_release.yml = .github\workflows\publish_release.yml - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {9805E74C-D028-4D05-9256-5C2FDC9B6EA8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9805E74C-D028-4D05-9256-5C2FDC9B6EA8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9805E74C-D028-4D05-9256-5C2FDC9B6EA8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9805E74C-D028-4D05-9256-5C2FDC9B6EA8}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {5A4E44BA-0D9F-4E81-A35E-83A38C3E43CF} - EndGlobalSection - GlobalSection(CodealikeProperties) = postSolution - SolutionGuid = f92c102d-027e-479b-995c-b971032fea8c - EndGlobalSection -EndGlobal diff --git a/FSharp.Collections.Immutable.slnf b/FSharp.Collections.Immutable.slnf new file mode 100644 index 0000000..097e0fa --- /dev/null +++ b/FSharp.Collections.Immutable.slnf @@ -0,0 +1,9 @@ +{ + "solution": { + "path": "FSharp.Collections.Immutable.slnx", + "projects": [ + "src\\FSharp.Collections.Immutable\\FSharp.Collections.Immutable.fsproj", + "tests\\FSharp.Collections.Immutable.Tests\\FSharp.Collections.Immutable.Tests.fsproj" + ] + } +} \ No newline at end of file diff --git a/FSharp.Collections.Immutable.slnx b/FSharp.Collections.Immutable.slnx new file mode 100644 index 0000000..e0ade1a --- /dev/null +++ b/FSharp.Collections.Immutable.slnx @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/README.md b/README.md index d2bc569..7819e3f 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,122 @@ -# FSharp.Collections.Immutable [![NuGet Status](http://img.shields.io/nuget/v/FSharp.Collections.Immutable.svg?style=flat)](https://www.nuget.org/packages/FSharp.Collections.Immutable/) [![MyGet Status](https://img.shields.io/myget/fsharp-collections-immutable/v/fsharp.collections.immutable.svg?style=flat)](https://www.myget.org/feed/Packages/fsharp-collections-immutable) +# FSharp.Collections.Immutable [![NuGet Status](http://img.shields.io/nuget/v/FSharp.Collections.Immutable.svg?style=flat)](https://www.nuget.org/packages/FSharp.Collections.Immutable/) [![GitHub Actions](https://github.com/fsprojects/FSharp.Collections.Immutable/workflows/Build%20main/badge.svg)](https://github.com/fsprojects/FSharp.Collections.Immutable/actions?query=branch%3Amain) F# bindings for System.Collections.Immutable ![Build status](https://github.com/fsprojects/FSharp.Collections.Immutable/workflows/.NET%20Core/badge.svg) -**FSharp.Collections.Immutable** is a collection of F# bindings for System.Collections.Immutable. +**FSharp.Collections.Immutable** is a collection of F# bindings for [System.Collections.Immutable](https://learn.microsoft.com/en-us/dotnet/api/system.collections.immutable). Please contribute to this project. Don't ask for permission, just fork the repository and send pull requests. Please also join the [F# Open Source Group](http://fsharp.github.com) +## Features + +* `FlatList` (`ImmutableArray`) +* `ImmutableList` +* `Stack` (`ImmutableStack`) +* `Queue` (`ImmutableQueue`) +* `HashMap` (`ImmutableDictionary`) +* `SortedMap` (`ImmutableSortedDictionary`) +* `HashSet` (`ImmutableHashSet`) +* `SortedSet` (`ImmutableSortedSet`) +* `IIndexedSeq` (`IReadOnlyList`) + +[Documentation](https://fsprojects.github.io/FSharp.Collections.Immutable/) + +--- + +## Builds + +GitHub Actions | +:---: | +[![GitHub Actions](https://github.com/fsprojects/FSharp.Collections.Immutable/workflows/Build%20main/badge.svg)](https://github.com/fsprojects/FSharp.Collections.Immutable/actions?query=branch%3Amain) | + +## NuGet + +Package | Stable | Prerelease +--- | --- | --- +FSharp.Collections.Immutable | [![NuGet Badge](https://img.shields.io/nuget/v/FSharp.Collections.Immutable.svg)](https://www.nuget.org/packages/FSharp.Collections.Immutable/) | [![NuGet Badge](https://img.shields.io/nuget/vpre/FSharp.Collections.Immutable.svg)](https://www.nuget.org/packages/FSharp.Collections.Immutable/) + +--- + +### Developing + +Make sure the following **requirements** are installed on your system: + +- [dotnet SDK](https://www.microsoft.com/net/download/core) 8.0 or higher + +or + +- [VSCode Dev Container](https://code.visualstudio.com/docs/remote/containers) + + +--- + +### Environment Variables + +- `CONFIGURATION` will set the [configuration](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-build?tabs=netcore2x#options) of the dotnet commands. If not set, it will default to Release. + - `CONFIGURATION=Debug ./build.sh` will result in `-c` additions to commands such as in `dotnet build -c Debug` +- `ENABLE_COVERAGE` Will enable running code coverage metrics. AltCover can have [severe performance degradation](https://github.com/SteveGilham/altcover/issues/57) so code coverage evaluation are disabled by default to speed up the feedback loop. + - `ENABLE_COVERAGE=1 ./build.sh` will enable code coverage evaluation + + +--- + +### Building +> build.cmd // on windows + +> ./build.sh // on unix +--- + +### Build Targets + +- `Clean` - Cleans artifact and temp directories. +- `DotnetRestore` - Runs [dotnet restore](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-restore?tabs=netcore2x) on the [solution file](https://docs.microsoft.com/en-us/visualstudio/extensibility/internals/solution-dot-sln-file?view=vs-2019). +- [`DotnetBuild`](#Building) - Runs [dotnet build](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-build?tabs=netcore2x) on the [solution file](https://docs.microsoft.com/en-us/visualstudio/extensibility/internals/solution-dot-sln-file?view=vs-2019). +- `FSharpAnalyzers` - Runs [BinaryDefense.FSharp.Analyzers](https://github.com/BinaryDefense/BinaryDefense.FSharp.Analyzers). +- `DotnetTest` - Runs [dotnet test](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-test?tabs=netcore21) on the [solution file](https://docs.microsoft.com/en-us/visualstudio/extensibility/internals/solution-dot-sln-file?view=vs-2019). +- `GenerateCoverageReport` - Code coverage is run during `DotnetTest` and this generates a report via [ReportGenerator](https://github.com/danielpalme/ReportGenerator). +- `ShowCoverageReport` - Shows the report generated in `GenerateCoverageReport`. +- `WatchTests` - Runs [dotnet watch](https://docs.microsoft.com/en-us/aspnet/core/tutorials/dotnet-watch?view=aspnetcore-3.0) with the test projects. Useful for rapid feedback loops. +- `GenerateAssemblyInfo` - Generates [AssemblyInfo](https://docs.microsoft.com/en-us/dotnet/api/microsoft.visualbasic.applicationservices.assemblyinfo?view=netframework-4.8) for libraries. +- `DotnetPack` - Runs [dotnet pack](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-pack). This includes running [Source Link](https://github.com/dotnet/sourcelink). +- `SourceLinkTest` - Runs a Source Link test tool to verify Source Links were properly generated. +- `PublishToNuGet` - Publishes the NuGet packages generated in `DotnetPack` to NuGet via [paket push](https://fsprojects.github.io/Paket/paket-push.html). Runs only from `Github Actions`. +- `GitRelease` - Creates a commit message with the [Release Notes](https://fake.build/apidocs/v5/fake-core-releasenotes.html) and a git tag via the version in the `Release Notes`. +- `GitHubRelease` - Publishes a [GitHub Release](https://help.github.com/en/articles/creating-releases) with the Release Notes and any NuGet packages. Runs only from `Github Actions`. +- `FormatCode` - Runs [Fantomas](https://github.com/fsprojects/fantomas) on the solution file. +- `CheckFormatCode` - Runs [Fantomas --check](https://fsprojects.github.io/fantomas/docs/end-users/FormattingCheck.html) on the solution file. +- `BuildDocs` - Generates [Documentation](https://fsprojects.github.io/FSharp.Formatting) from `docsSrc` and the [XML Documentation Comments](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/xmldoc/) from your libraries in `src`. +- `WatchDocs` - Generates documentation and starts a webserver locally. It will rebuild and hot reload if it detects any changes made to `docsSrc` files, or libraries in `src`. + +--- + + +### Releasing + +- [Start a git repo with a remote](https://help.github.com/articles/adding-an-existing-project-to-github-using-the-command-line/) +git init +git add . +git commit -m "Scaffold" +git branch -M main +git remote add origin https://github.com/fsprojects/FSharp.Collections.Immutable.git +git push -u origin main +- [Create an Environment](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#creating-an-environment) on your repository named `nuget`. +- [Create a NuGet API key](https://learn.microsoft.com/en-us/nuget/nuget-org/publish-a-package#create-an-api-key) +- Add your `NUGET_TOKEN` to the [Environment Secrets](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#environment-secrets) of your newly created environment. +- Then update the `CHANGELOG.md` with an "Unreleased" section containing release notes for this version, in [KeepAChangelog](https://keepachangelog.com/en/1.1.0/) format. + +NOTE: Its highly recommend to add a link to the Pull Request next to the release note that it affects. The reason for this is when the `RELEASE` target is run, it will add these new notes into the body of git commit. GitHub will notice the links and will update the Pull Request with what commit referenced it saying ["added a commit that referenced this pull request"](https://github.com/TheAngryByrd/MiniScaffold/pull/179#ref-commit-837ad59). Since the build script automates the commit message, it will say "Bump Version to x.y.z". The benefit of this is when users goto a Pull Request, it will be clear when and which version those code changes released. Also when reading the `CHANGELOG`, if someone is curious about how or why those changes were made, they can easily discover the work and discussions. + +### Releasing Documentation + +- Set Source for "Build and deployment" on [GitHub Pages](https://github.com/fsprojects/FSharp.Collections.Immutable/settings/pages) to `GitHub Actions`. +- Documentation is auto-deployed via [GitHub Action](https://github.com/fsprojects/FSharp.Collections.Immutable/blob/main/.github/workflows/fsdocs-gh-pages.yml) to [Your GitHub Page](https://fsprojects.github.io/FSharp.Collections.Immutable/) + # Maintainer(s) - [@xperiandri](https://github.com/xperiandri) - [@eventhelix](https://github.com/eventhelix) - -The default maintainer account for projects under "fsprojects" is [@fsprojectsgit](https://github.com/fsprojectsgit) - F# Community Project Incubation Space (repo management) \ No newline at end of file +The default maintainer account for projects under "fsprojects" is [@fsprojectsgit](https://github.com/fsprojectsgit) - F# Community Project Incubation Space (repo management) diff --git a/build.cmd b/build.cmd new file mode 100644 index 0000000..b9f6df4 --- /dev/null +++ b/build.cmd @@ -0,0 +1 @@ +dotnet run --project ./build/build.fsproj -- -t %* diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..0783d63 --- /dev/null +++ b/build.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +set -eu +set -o pipefail + +FAKE_DETAILED_ERRORS=true dotnet run --project ./build/build.fsproj -- -t "$@" diff --git a/build/Changelog.fs b/build/Changelog.fs new file mode 100644 index 0000000..27ceada --- /dev/null +++ b/build/Changelog.fs @@ -0,0 +1,233 @@ +module Changelog + +open System +open Fake.Core +open Fake.IO + +let isEmptyChange = + function + | Changelog.Change.Added s + | Changelog.Change.Changed s + | Changelog.Change.Deprecated s + | Changelog.Change.Fixed s + | Changelog.Change.Removed s + | Changelog.Change.Security s + | Changelog.Change.Custom (_, s) -> String.IsNullOrWhiteSpace s.CleanedText + +let tagFromVersionNumber versionNumber = sprintf "releases/%s" versionNumber + +let failOnEmptyChangelog (latestEntry : Changelog.ChangelogEntry) = + let isEmpty = + (latestEntry.Changes |> Seq.forall isEmptyChange) + || latestEntry.Changes |> Seq.isEmpty + + if isEmpty then + failwith "No changes in CHANGELOG. Please add your changes under a heading specified in https://keepachangelog.com/" + +let mkLinkReference (newVersion : SemVerInfo) (changelog : Changelog.Changelog) (gitHubRepoUrl : string) = + if changelog.Entries |> List.isEmpty then + // No actual changelog entries yet: link reference will just point to the Git tag + sprintf "[%s]: %s/releases/tag/%s" newVersion.AsString gitHubRepoUrl (tagFromVersionNumber newVersion.AsString) + else + let versionTuple version = (version.Major, version.Minor, version.Patch) + // Changelog entries come already sorted, most-recent first, by the Changelog module + let prevEntry = + changelog.Entries + |> List.skipWhile (fun entry -> + entry.SemVer.PreRelease.IsSome + || versionTuple entry.SemVer = versionTuple newVersion + ) + |> List.tryHead + + let linkTarget = + match prevEntry with + | Some entry -> + sprintf + "%s/compare/%s...%s" + gitHubRepoUrl + (tagFromVersionNumber entry.SemVer.AsString) + (tagFromVersionNumber newVersion.AsString) + | None -> sprintf "%s/releases/tag/%s" gitHubRepoUrl (tagFromVersionNumber newVersion.AsString) + + sprintf "[%s]: %s" newVersion.AsString linkTarget + +let mkReleaseNotes changelog (latestEntry : Changelog.ChangelogEntry) gitHubRepoUrl = + let linkReference = mkLinkReference latestEntry.SemVer changelog gitHubRepoUrl + + if String.isNullOrEmpty linkReference then + latestEntry.ToString () + else + // Add link reference target to description before building release notes, since in main changelog file it's at the bottom of the file + let description = + match latestEntry.Description with + | None -> linkReference + | Some desc when desc.Contains (linkReference) -> desc + | Some desc -> sprintf "%s\n\n%s" (desc.Trim ()) linkReference + + { latestEntry with Description = Some description }.ToString () + +let getVersionNumber envVarName ctx = + let args = ctx.Context.Arguments + + let verArg = + args + |> List.tryHead + |> Option.defaultWith (fun () -> Environment.environVarOrDefault envVarName "") + + if SemVer.isValid verArg then + verArg + elif verArg.StartsWith ("v") && SemVer.isValid verArg.[1..] then + let target = ctx.Context.FinalTarget + + Trace.traceImportantfn + "Please specify a version number without leading 'v' next time, e.g. \"./build.sh %s %s\" rather than \"./build.sh %s %s\"" + target + verArg.[1..] + target + verArg + + verArg.[1..] + elif String.isNullOrEmpty verArg then + let target = ctx.Context.FinalTarget + + Trace.traceErrorfn + "Please specify a version number, either at the command line (\"./build.sh %s 1.0.0\") or in the %s environment variable" + target + envVarName + + failwith "No version number found" + else + Trace.traceErrorfn "Please specify a valid version number: %A could not be recognized as a version number" verArg + + failwith "Invalid version number" + +let mutable changelogBackupFilename = "" + +let updateChangelog changelogPath (changelog : Fake.Core.Changelog.Changelog) gitHubRepoUrl ctx = + + let verStr = ctx |> getVersionNumber "RELEASE_VERSION" + + let description, unreleasedChanges = + match changelog.Unreleased with + | None -> None, [] + | Some u -> u.Description, u.Changes + + let newVersion = SemVer.parse verStr + + changelog.Entries + |> List.tryFind (fun entry -> entry.SemVer = newVersion) + |> Option.iter (fun entry -> + Trace.traceErrorfn + "Version %s already exists in %s, released on %s" + verStr + changelogPath + (if entry.Date.IsSome then + entry.Date.Value.ToString ("yyyy-MM-dd") + else + "(no date specified)") + + failwith "Can't release with a duplicate version number" + ) + + changelog.Entries + |> List.tryFind (fun entry -> entry.SemVer > newVersion) + |> Option.iter (fun entry -> + Trace.traceErrorfn + "You're trying to release version %s, but a later version %s already exists, released on %s" + verStr + entry.SemVer.AsString + (if entry.Date.IsSome then + entry.Date.Value.ToString ("yyyy-MM-dd") + else + "(no date specified)") + + failwith "Can't release with a version number older than an existing release" + ) + + let versionTuple version = (version.Major, version.Minor, version.Patch) + + let prereleaseEntries = + changelog.Entries + |> List.filter (fun entry -> + entry.SemVer.PreRelease.IsSome + && versionTuple entry.SemVer = versionTuple newVersion + ) + + let prereleaseChanges = + prereleaseEntries + |> List.collect (fun entry -> entry.Changes |> List.filter (not << isEmptyChange)) + |> List.distinct + + let assemblyVersion, nugetVersion = Changelog.parseVersions newVersion.AsString + + let newEntry = + Changelog.ChangelogEntry.New ( + assemblyVersion.Value, + nugetVersion.Value, + Some System.DateTime.Today, + description, + unreleasedChanges @ prereleaseChanges, + false + ) + + let newChangelog = + Changelog.Changelog.New (changelog.Header, changelog.Description, None, newEntry :: changelog.Entries) + + // Save changelog to temporary file before making any edits + changelogBackupFilename <- System.IO.Path.GetTempFileName () + + changelogPath |> Shell.copyFile changelogBackupFilename + + Target.activateFinal "DeleteChangelogBackupFile" + + newChangelog |> Changelog.save changelogPath + + // Now update the link references at the end of the file + let linkReferenceForLatestEntry = mkLinkReference newVersion changelog gitHubRepoUrl + + let linkReferenceForUnreleased = + sprintf "[Unreleased]: %s/compare/%s...%s" gitHubRepoUrl (tagFromVersionNumber newVersion.AsString) "HEAD" + + let tailLines = File.read changelogPath |> List.ofSeq |> List.rev + + let isRef (line : string) = + System.Text.RegularExpressions.Regex.IsMatch (line, @"^\[.+?\]:\s?[a-z]+://.*$") + + let linkReferenceTargets = + tailLines + |> List.skipWhile String.isNullOrWhiteSpace + |> List.takeWhile isRef + |> List.rev // Now most recent entry is at the head of the list + + let newLinkReferenceTargets = + match linkReferenceTargets with + | [] -> [ linkReferenceForUnreleased; linkReferenceForLatestEntry ] + | first :: rest when first |> String.startsWith "[Unreleased]:" -> + linkReferenceForUnreleased + :: linkReferenceForLatestEntry + :: rest + | first :: rest -> + linkReferenceForUnreleased + :: linkReferenceForLatestEntry + :: first + :: rest + + let blankLineCount = + tailLines + |> Seq.takeWhile String.isNullOrWhiteSpace + |> Seq.length + + let linkRefCount = linkReferenceTargets |> List.length + + let skipCount = blankLineCount + linkRefCount + + let updatedLines = + List.rev (tailLines |> List.skip skipCount) + @ newLinkReferenceTargets + + File.write false changelogPath updatedLines + + // If build fails after this point but before we commit changes, undo our modifications + Target.activateBuildFailure "RevertChangelog" + + newEntry diff --git a/build/FsDocs.fs b/build/FsDocs.fs new file mode 100644 index 0000000..8c16481 --- /dev/null +++ b/build/FsDocs.fs @@ -0,0 +1,224 @@ +namespace Fake.DotNet + +open Fake.Core +open Fake.IO +open Fake.IO.FileSystemOperators + +/// +/// Contains tasks to interact with fsdocs tool to +/// process F# script files, markdown and for generating API documentation. +/// +[] +module Fsdocs = + + /// + /// Fsdocs build command parameters and options + /// + type BuildCommandParams = { + /// Input directory of content (default: docs) + Input : string option + + /// Project files to build API docs for outputs, defaults to all packable projects + Projects : seq option + + /// Output Directory (default output for build and tmp/watch for watch) + Output : string option + + /// Disable generation of API docs + NoApiDocs : bool option + + /// Evaluate F# fragments in scripts + Eval : bool option + + /// Save images referenced in docs + SaveImages : bool option + + /// Add line numbers + LineNumbers : bool option + + /// Additional substitution parameters for templates + Parameters : seq option + + /// Disable project cracking. + IgnoreProjects : bool option + + /// In API doc generation qualify the output by the collection name, e.g. 'reference/FSharp.Core/...' instead of 'reference/...' . + Qualify : bool option + + /// The tool will also generate documentation for non-public members + NoPublic : bool option + + /// Do not copy default content styles, javascript or use default templates + NoDefaultContent : bool option + + /// Clean the output directory + Clean : bool option + + /// Display version information + Version : bool option + + /// Provide properties to dotnet msbuild, e.g. --properties Configuration=Release Version=3.4 + Properties : string option + + /// Additional arguments passed down as otherflags to the F# compiler when the API is being generated. + /// Note that these arguments are trimmed, this is to overcome a limitation in the command line argument + /// processing. A typical use-case would be to pass an addition assembly reference. + /// Example --fscoptions " -r:MyAssembly.dll" + FscOptions : string option + + /// Fail if docs are missing or can't be generated + Strict : bool option + + /// Source folder at time of component build (<FsDocsSourceFolder>) + SourceFolder : string option + + /// Source repository for github links (<FsDocsSourceRepository>) + SourceRepository : string option + + /// Assume comments in F# code are markdown (<UsesMarkdownComments>) + MdComments : bool option + } with + + /// Parameter default values. + static member Default = { + Input = None + Projects = None + Output = None + NoApiDocs = None + Eval = None + SaveImages = None + LineNumbers = None + Parameters = None + IgnoreProjects = None + Qualify = None + NoPublic = None + NoDefaultContent = None + Clean = None + Version = None + Properties = None + FscOptions = None + Strict = None + SourceFolder = None + SourceRepository = None + MdComments = None + } + + /// + /// Fsdocs watch command parameters and options + /// + type WatchCommandParams = { + /// Do not serve content when watching. + NoServer : bool option + + /// Do not launch a browser window. + NoLaunch : bool option + + /// URL extension to launch http://localhost:/%s. + Open : string option + + /// Port to serve content for http://localhost serving. + Port : int option + + /// Build Commands + BuildCommandParams : BuildCommandParams option + } with + + /// Parameter default values. + static member Default = { + NoServer = None + NoLaunch = None + Open = None + Port = None + BuildCommandParams = None + } + + let internal buildBuildCommandParams (buildParams : BuildCommandParams) = + let buildSubstitutionParameters (subParameters : seq) = + seq { + yield "--parameters" + for (key, value) in subParameters do + yield key + yield value + } + |> String.concat " " + + System.Text.StringBuilder () + |> StringBuilder.appendIfSome buildParams.Input (sprintf "--input %s") + |> StringBuilder.appendIfSome buildParams.Projects (fun projects -> $"""--projects %s{projects |> String.concat " "}""") + |> StringBuilder.appendIfSome buildParams.Output (sprintf "--output %s") + |> StringBuilder.appendIfSome buildParams.NoApiDocs (fun _ -> "--noapidocs") + |> StringBuilder.appendIfSome buildParams.Eval (fun _ -> "--eval") + |> StringBuilder.appendIfSome buildParams.SaveImages (fun _ -> "--saveimages") + |> StringBuilder.appendIfSome buildParams.LineNumbers (fun _ -> "--linenumbers") + |> StringBuilder.appendIfSome buildParams.Parameters (fun parameters -> buildSubstitutionParameters parameters) + |> StringBuilder.appendIfSome buildParams.IgnoreProjects (fun _ -> "--ignoreprojects") + |> StringBuilder.appendIfSome buildParams.Qualify (fun _ -> "--qualify") + |> StringBuilder.appendIfSome buildParams.NoPublic (fun _ -> "--nonpublic") + |> StringBuilder.appendIfSome buildParams.NoDefaultContent (fun _ -> "--nodefaultcontent") + |> StringBuilder.appendIfSome buildParams.Clean (fun _ -> "--clean") + |> StringBuilder.appendIfSome buildParams.Version (fun _ -> "--version") + |> StringBuilder.appendIfSome buildParams.Properties (sprintf "--properties %s") + |> StringBuilder.appendIfSome buildParams.FscOptions (sprintf "--fscoptions %s") + |> StringBuilder.appendIfSome buildParams.Strict (fun _ -> "--strict") + |> StringBuilder.appendIfSome buildParams.SourceFolder (sprintf "--sourcefolder %s") + |> StringBuilder.appendIfSome buildParams.SourceRepository (sprintf "--sourcerepo %s") + |> StringBuilder.appendIfSome buildParams.MdComments (fun _ -> "--mdcomments") + |> StringBuilder.toText + |> String.trim + + let internal buildWatchCommandParams (watchParams : WatchCommandParams) = + System.Text.StringBuilder () + |> StringBuilder.appendIfSome watchParams.NoServer (fun _ -> "--noserver") + |> StringBuilder.appendIfSome watchParams.NoLaunch (fun _ -> "--nolaunch") + |> StringBuilder.appendIfSome watchParams.Open (sprintf "--open %s") + |> StringBuilder.appendIfSome watchParams.Port (sprintf "--port %i") + |> StringBuilder.appendIfSome watchParams.BuildCommandParams buildBuildCommandParams + |> StringBuilder.toText + |> String.trim + + + let cleanCache (workingDirectory) = Shell.cleanDirs [ workingDirectory ".fsdocs" ] + + /// + /// Build documentation using fsdocs build command + /// + /// + /// Function used to overwrite the dotnetOptions. + /// Function used to overwrite the build command default parameters. + /// + /// + /// + /// Fsdocs.build (fun p -> { p with Clean = Some(true); Strict = Some(true) }) + /// + /// + let build dotnetOptions setBuildParams = + let buildParams = setBuildParams BuildCommandParams.Default + let formattedParameters = buildBuildCommandParams buildParams + + // let dotnetOptions = (fun (buildOptions: DotNet.Options) -> buildOptions) + let result = DotNet.exec dotnetOptions "fsdocs build" formattedParameters + + if 0 <> result.ExitCode then + failwithf "fsdocs build failed with exit code '%d'" result.ExitCode + + /// + /// Watch documentation using fsdocs watch command + /// + /// + /// Function used to overwrite the dotnetOptions. + /// Function used to overwrite the watch command default parameters. + /// + /// + /// + /// Fsdocs.watch (fun p -> { p with Port = Some(3005) }) + /// + /// + let watch dotnetOptions setWatchParams = + let watchParams = setWatchParams WatchCommandParams.Default + let formattedParameters = buildWatchCommandParams watchParams + + // let dotnetOptions = (fun (buildOptions: DotNet.Options) -> buildOptions) + let result = DotNet.exec dotnetOptions "fsdocs watch" formattedParameters + + if 0 <> result.ExitCode then + failwithf "fsdocs watch failed with exit code '%d'" result.ExitCode diff --git a/build/Properties/launchSettings.json b/build/Properties/launchSettings.json new file mode 100644 index 0000000..f0c59e8 --- /dev/null +++ b/build/Properties/launchSettings.json @@ -0,0 +1,24 @@ +{ + "profiles": { + "BuildAndTest": { + "commandName": "Project", + "commandLineArgs": "--target DotnetTest" + }, + "Publish": { + "commandName": "Project", + "commandLineArgs": "--target Publish" + }, + "PublishToGitHub": { + "commandName": "Project", + "commandLineArgs": "--target PublishToGitHub" + }, + "BuildDocs": { + "commandName": "Project", + "commandLineArgs": "--target BuildDocs" + }, + "Release": { + "commandName": "Project", + "commandLineArgs": "--target Release 1.0.0" + } + } +} diff --git a/build/build.fs b/build/build.fs new file mode 100644 index 0000000..c28e99c --- /dev/null +++ b/build/build.fs @@ -0,0 +1,731 @@ +open System +open Fake.Core +open Fake.DotNet +open Fake.Tools +open Fake.IO +open Fake.IO.FileSystemOperators +open Fake.IO.Globbing.Operators +open Fake.Core.TargetOperators +open Fake.Api +open Fake.BuildServer +open Argu + +let environVarAsBoolOrDefault varName defaultValue = + let truthyConsts = [ "1"; "Y"; "YES"; "T"; "TRUE" ] + Environment.environVar varName + |> ValueOption.ofObj + |> ValueOption.map (fun envvar -> + truthyConsts + |> List.exists (fun ``const`` -> String.Equals (``const``, envvar, StringComparison.InvariantCultureIgnoreCase)) + ) + |> ValueOption.defaultValue defaultValue + +//----------------------------------------------------------------------------- +// Metadata and Configuration +//----------------------------------------------------------------------------- + +let rootDirectory = __SOURCE_DIRECTORY__ ".." + +let productName = "FSharp.Collections.Immutable" + +let sln = rootDirectory "FSharp.Collections.Immutable.slnf" + +let srcCodeGlob = + !!(rootDirectory "src/**/*.fs") + ++ (rootDirectory "src/**/*.fsx") + -- (rootDirectory "src/**/obj/**/*.fs") + +let testsCodeGlob = + !!(rootDirectory "tests/**/*.fs") + ++ (rootDirectory "tests/**/*.fsx") + -- (rootDirectory "tests/**/obj/**/*.fs") + +let srcGlob = rootDirectory "src/**/*.??proj" + +let testsGlob = rootDirectory "tests/**/*.??proj" + +let srcAndTest = !!srcGlob ++ testsGlob + +let distDir = rootDirectory "dist" + +let distGlob = distDir "*.nupkg" + +let testResultsDir = rootDirectory "TestResults" + +let coverageReportDir = rootDirectory "docs" "coverage" + +let docsDir = rootDirectory "docs" + +let docsSrcDir = rootDirectory "docsSrc" + +let temp = rootDirectory "temp" + +let watchDocsDir = temp "watch-docs" + +let gitOwner = "fsprojects" +let gitRepoName = "FSharp.Collections.Immutable" + +let gitHubRepoUrl = $"https://github.com/%s{gitOwner}/%s{gitRepoName}" + +let documentationRootUrl = $"https://%s{gitOwner}.github.io/%s{gitRepoName}" + +let releaseBranch = "main" +let readme = "README.md" +let changelogFile = "CHANGELOG.md" + +let READMElink = Uri (Uri (gitHubRepoUrl), $"blob/{releaseBranch}/{readme}") +let CHANGELOGlink = Uri (Uri (gitHubRepoUrl), $"blob/{releaseBranch}/{changelogFile}") + +let changelogPath = rootDirectory changelogFile + +let changelog = Fake.Core.Changelog.load changelogPath + +let mutable latestEntry = + if Seq.isEmpty changelog.Entries then + Changelog.ChangelogEntry.New ("0.0.1", "0.0.1-alpha.1", Some DateTime.Today, None, [], false) + else + changelog.LatestEntry + +let mutable changelogBackupFilename = "" + +let publishUrl = "https://www.nuget.org" + +let enableCodeCoverage = environVarAsBoolOrDefault "ENABLE_COVERAGE" false + +let githubToken = Environment.environVarOrNone "GITHUB_TOKEN" + +let nugetToken = Environment.environVarOrNone "NUGET_TOKEN" + +//----------------------------------------------------------------------------- +// Helpers +//----------------------------------------------------------------------------- + + +let isRelease (targets : Target list) = + targets + |> Seq.map (fun t -> t.Name) + |> Seq.exists ((=) "PublishToNuGet") + +let invokeAsync f = async { f () } + +let configuration (targets : Target list) = + let defaultVal = if isRelease targets then "Release" else "Debug" + + match Environment.environVarOrDefault "CONFIGURATION" defaultVal with + | "Debug" -> DotNet.BuildConfiguration.Debug + | "Release" -> DotNet.BuildConfiguration.Release + | config -> DotNet.BuildConfiguration.Custom config + +let failOnBadExitAndPrint (p : ProcessResult) = + if p.ExitCode <> 0 then + p.Errors |> Seq.iter Trace.traceError + + failwithf "failed with exitcode %d" p.ExitCode + +let isPublishToGitHub ctx = ctx.Context.FinalTarget = "PublishToGitHub" + +let isCI = lazy environVarAsBoolOrDefault "CI" false + +// CI Servers can have bizarre failures that have nothing to do with your code +let rec retryIfInCI times fn = + match isCI.Value with + | true -> + if times > 1 then + try + fn () + with _ -> + retryIfInCI (times - 1) fn + else + fn () + | _ -> fn () + +let failOnWrongBranch () = + if Git.Information.getBranchName "" <> releaseBranch then + failwithf "Not on %s. If you want to release please switch to this branch." releaseBranch + + +module dotnet = + let watch cmdParam program args = DotNet.exec cmdParam (sprintf "watch %s" program) args + + let run cmdParam args = DotNet.exec cmdParam "run" args + + let tool optionConfig command args = + DotNet.exec optionConfig (sprintf "%s" command) args + |> failOnBadExitAndPrint + + let reportgenerator optionConfig args = tool optionConfig "reportgenerator" args + + let sourcelink optionConfig args = tool optionConfig "sourcelink" args + + let fcswatch optionConfig args = tool optionConfig "fcswatch" args + + let fsharpAnalyzer optionConfig args = tool optionConfig "fsharp-analyzers" args + + let fantomas args = DotNet.exec id "fantomas" args + +module FSharpAnalyzers = + type Arguments = + | Project of string + | Analyzers_Path of string + | Fail_On_Warnings of string list + | Ignore_Files of string list + | Verbose + + interface IArgParserTemplate with + member s.Usage = "" + + +module DocsTool = + let quoted s = $"\"%s{s}\"" + + let fsDocsDotnetOptions (o : DotNet.Options) = { o with WorkingDirectory = rootDirectory } + + let fsDocsBuildParams configuration (p : Fsdocs.BuildCommandParams) = { + p with + Clean = Some true + Input = Some (quoted docsSrcDir) + Output = Some (quoted docsDir) + Eval = Some true + Projects = Some (Seq.map quoted (!!srcGlob)) + Properties = Some ($"Configuration=%s{configuration}") + Parameters = + Some [ + // https://fsprojects.github.io/FSharp.Formatting/content.html#Templates-and-Substitutions + "root", quoted $"{documentationRootUrl}/" + "fsdocs-collection-name", quoted productName + "fsdocs-repository-branch", quoted releaseBranch + "fsdocs-package-version", quoted latestEntry.NuGetVersion + "fsdocs-readme-link", quoted (READMElink.ToString ()) + "fsdocs-release-notes-link", quoted (CHANGELOGlink.ToString ()) + "fsdocs-logo-src", + quoted ( + "https://raw.githubusercontent.com/fsprojects/FSharp.Collections.Immutable/refs/heads/main/docsSrc/content/logo.png" + ) + ] + Strict = Some true + } + + let cleanDocsCache () = Fsdocs.cleanCache rootDirectory + + let build (configuration) = Fsdocs.build fsDocsDotnetOptions (fsDocsBuildParams configuration) + + + let watch (configuration) = + let buildParams bp = + let bp = + Option.defaultValue Fsdocs.BuildCommandParams.Default bp + |> fsDocsBuildParams configuration + + { bp with Output = Some watchDocsDir; Strict = None } + + Fsdocs.watch fsDocsDotnetOptions (fun p -> { p with BuildCommandParams = Some (buildParams p.BuildCommandParams) }) + +let allReleaseChecks () = failOnWrongBranch () +//Changelog.failOnEmptyChangelog latestEntry + + +let failOnLocalBuild () = + if not isCI.Value then + failwith "Not on CI. If you want to publish, please use CI." + +let failOnCIBuild () = + if isCI.Value then + failwith "On CI. If you want to run this target, please use a local build." + +let allPublishChecks () = failOnLocalBuild () +//Changelog.failOnEmptyChangelog latestEntry + +//----------------------------------------------------------------------------- +// Target Implementations +//----------------------------------------------------------------------------- + +/// So we don't require always being on the latest MSBuild.StructuredLogger +let disableBinLog (p : MSBuild.CliArguments) = { p with DisableInternalBinLog = true } + +let clean _ = + [ "bin"; "temp"; distDir; coverageReportDir; testResultsDir ] + |> Shell.cleanDirs + + !!srcGlob ++ testsGlob + |> Seq.collect (fun p -> + [ "bin"; "obj" ] + |> Seq.map (fun sp -> IO.Path.GetDirectoryName p sp) + ) + |> Shell.cleanDirs + +let dotnetRestore _ = + [ sln ] + |> Seq.map (fun dir -> + fun () -> + let args = [] |> String.concat " " + + DotNet.restore + (fun c -> { + c with + MSBuildParams = disableBinLog c.MSBuildParams + Common = c.Common |> DotNet.Options.withCustomParams (Some (args)) + }) + dir + ) + |> Seq.iter (retryIfInCI 10) + +let dotnetToolRestore _ = + let result = + fun () -> DotNet.exec id "tool" "restore" + |> (retryIfInCI 10) + + + if not result.OK then + failwithf "Failed to restore .NET tools: %A" result.Errors + +let updateChangelog ctx = + latestEntry <- + if not <| isPublishToGitHub ctx then + Changelog.updateChangelog changelogPath changelog gitHubRepoUrl ctx + elif Seq.isEmpty changelog.Entries then + latestEntry + else + let latest = changelog.LatestEntry + let semVer = { + latest.SemVer with + Original = None + Patch = latest.SemVer.Patch + 1u + PreRelease = PreRelease.TryParse "ci" + } + { + latest with + SemVer = semVer + NuGetVersion = semVer.AsString + AssemblyVersion = semVer.AsString + } + +let revertChangelog _ = + if String.isNotNullOrEmpty Changelog.changelogBackupFilename then + Changelog.changelogBackupFilename + |> Shell.copyFile changelogPath + +let deleteChangelogBackupFile _ = + if String.isNotNullOrEmpty Changelog.changelogBackupFilename then + Shell.rm Changelog.changelogBackupFilename + +let getPackageVersionProperty publishToGitHub = + if publishToGitHub then + let runId = Environment.environVar "GITHUB_RUN_ID" + $"/p:PackageVersion=%s{latestEntry.NuGetVersion}-%s{runId}" + else + $"/p:PackageVersion=%s{latestEntry.NuGetVersion}" + +let dotnetBuild ctx = + + let publishToGitHub = isPublishToGitHub ctx + + let args = [ getPackageVersionProperty publishToGitHub; "--no-restore" ] + + DotNet.build + (fun c -> { + c with + Configuration = configuration (ctx.Context.AllExecutingTargets) + Common = c.Common |> DotNet.Options.withAdditionalArgs args + MSBuildParams = { + (disableBinLog c.MSBuildParams) with + Properties = [ + if publishToGitHub then + ("DebugType", "embedded") + ("EmbedAllSources", "true") + ] + } + }) + sln + +let fsharpAnalyzers _ = + let argParser = ArgumentParser.Create (programName = "fsharp-analyzers") + + !!srcGlob + |> Seq.iter (fun proj -> + let args = + [ + FSharpAnalyzers.Analyzers_Path (rootDirectory "packages/analyzers") + FSharpAnalyzers.Arguments.Project proj + FSharpAnalyzers.Arguments.Fail_On_Warnings [ "BDH0002" ] + FSharpAnalyzers.Arguments.Ignore_Files [ "*AssemblyInfo.fs" ] + FSharpAnalyzers.Verbose + ] + |> argParser.PrintCommandLineArgumentsFlat + + dotnet.fsharpAnalyzer id args + ) + +let dotnetTest ctx = + // Create test results directory if it doesn't exist + Directory.create testResultsDir + + let args = [ + "--no-build" + if enableCodeCoverage then + "--collect:\"Code Coverage\"" + "--results-directory" + testResultsDir + "--logger:trx" // Enable TRX report generation + ] + + DotNet.test + (fun c -> { + c with + MSBuildParams = disableBinLog c.MSBuildParams + Configuration = configuration (ctx.Context.AllExecutingTargets) + Common = c.Common |> DotNet.Options.withAdditionalArgs args + }) + sln + +let generateCoverageReport _ = + + let coverageFiles = !!(testResultsDir "*/coverage.cobertura.xml") + + let sourceDirs = !!srcGlob |> Seq.map Path.getDirectory |> String.concat ";" + + let independentArgs = [ + sprintf "-reports:\"%s\"" (coverageFiles |> String.concat ";") + sprintf "-targetdir:\"%s\"" coverageReportDir + // Add source dir + sprintf "-sourcedirs:\"%s\"" sourceDirs + // Ignore test assemblies + sprintf "-assemblyfilters:\"%s\"" "-*.Tests" + // Generate HTML and Cobertura reports + sprintf "-reporttypes:%s" "Html;Cobertura" + ] + + let args = independentArgs |> String.concat " " + + dotnet.reportgenerator id args + +let showCoverageReport _ = + failOnCIBuild () + + coverageReportDir "index.html" + |> Command.ShellCommand + |> CreateProcess.fromCommand + |> Proc.start + |> ignore + + +let watchTests _ = + !!testsGlob + |> Seq.map (fun proj -> + fun () -> + dotnet.watch + (fun opt -> + opt + |> DotNet.Options.withWorkingDirectory (IO.Path.GetDirectoryName proj) + ) + "test" + "" + |> ignore + ) + |> Seq.iter (invokeAsync >> Async.Catch >> Async.Ignore >> Async.Start) + + printfn "Press Ctrl+C (or Ctrl+Break) to stop..." + + let cancelEvent = + Console.CancelKeyPress + |> Async.AwaitEvent + |> Async.RunSynchronously + + cancelEvent.Cancel <- true + +let generateAssemblyInfo _ = + + let (|Fsproj|Csproj|Vbproj|) (projFileName : string) = + match projFileName with + | f when f.EndsWith ("fsproj") -> Fsproj + | f when f.EndsWith ("csproj") -> Csproj + | f when f.EndsWith ("vbproj") -> Vbproj + | _ -> failwith (sprintf "Project file %s not supported. Unknown project type." projFileName) + + let releaseChannel = + match latestEntry.SemVer.PreRelease with + | Some pr -> pr.Name + | _ -> "release" + + let getAssemblyInfoAttributes projectName = [ + AssemblyInfo.Title (projectName) + AssemblyInfo.Product productName + AssemblyInfo.Version latestEntry.AssemblyVersion + AssemblyInfo.Metadata ("ReleaseDate", latestEntry.Date.Value.ToString ("o")) + AssemblyInfo.FileVersion latestEntry.AssemblyVersion + AssemblyInfo.InformationalVersion latestEntry.AssemblyVersion + AssemblyInfo.Metadata ("ReleaseChannel", releaseChannel) + AssemblyInfo.Metadata ("GitHash", Git.Information.getCurrentSHA1 (null)) + ] + + let getProjectDetails (projectPath : string) = + let projectName = IO.Path.GetFileNameWithoutExtension (projectPath) + + (projectPath, projectName, IO.Path.GetDirectoryName (projectPath), (getAssemblyInfoAttributes projectName)) + + !!srcGlob + |> Seq.map getProjectDetails + |> Seq.iter (fun (projFileName, _, folderName, attributes) -> + match projFileName with + | Fsproj -> AssemblyInfoFile.createFSharp (folderName "AssemblyInfo.fs") attributes + | Csproj -> AssemblyInfoFile.createCSharp ((folderName "Properties") "AssemblyInfo.cs") attributes + | Vbproj -> AssemblyInfoFile.createVisualBasic ((folderName "My Project") "AssemblyInfo.vb") attributes + ) + +let dotnetPack ctx = + // Get release notes with properly-linked version number + let releaseNotes = Changelog.mkReleaseNotes changelog latestEntry gitHubRepoUrl + + let args = [ getPackageVersionProperty (isPublishToGitHub ctx); $"/p:PackageReleaseNotes=\"{releaseNotes}\"" ] + + DotNet.pack + (fun c -> { + c with + MSBuildParams = disableBinLog c.MSBuildParams + Configuration = configuration (ctx.Context.AllExecutingTargets) + OutputPath = Some distDir + Common = c.Common |> DotNet.Options.withAdditionalArgs args + }) + sln + +let sourceLinkTest _ = + !!distGlob + |> Seq.iter (fun nupkg -> dotnet.sourcelink id $"test %s{nupkg}") + +type PushSource = + | NuGet + | GitHub + +let publishTo (source : PushSource) _ = + allPublishChecks () + + distGlob + |> DotNet.nugetPush (fun o -> { + o with + Common = { + o.Common with + WorkingDirectory = "dist" + CustomParams = Some "--skip-duplicate" + } + PushParams = { + o.PushParams with + // TODO: Uncomment when migrated to F# 9 + //NoSymbols = source.IsGitHub + Source = + match source with + | NuGet -> Some "nuget.org" + | GitHub -> Some "github.com" + ApiKey = + match source with + | NuGet -> nugetToken + | GitHub -> githubToken + } + }) + +let gitRelease _ = + allReleaseChecks () + + let releaseNotesGitCommitFormat = latestEntry.ToString () + + Git.Staging.stageFile "" (rootDirectory "CHANGELOG.md") + |> ignore + + !!(rootDirectory "src/**/AssemblyInfo.fs") + ++ (rootDirectory "tests/**/AssemblyInfo.fs") + |> Seq.iter (Git.Staging.stageFile "" >> ignore) + + let msg = $"Bump version to `%s{latestEntry.NuGetVersion}`\n\n%s{releaseNotesGitCommitFormat}" + + Git.Commit.exec "" msg + + Target.deactivateBuildFailure "RevertChangelog" + + Git.Branches.push "" + + let tag = Changelog.tagFromVersionNumber latestEntry.NuGetVersion + + Git.Branches.tag "" tag + Git.Branches.pushTag "" "origin" tag + +let githubRelease _ = + allPublishChecks () + + let token = + match githubToken with + | Some s -> s + | _ -> failwith "please set the `GITHUB_TOKEN` environment variable to a github personal access token with repo access." + + let files = !!distGlob + // Get release notes with properly-linked version number + let releaseNotes = Changelog.mkReleaseNotes changelog latestEntry gitHubRepoUrl + + GitHub.createClientWithToken token + |> GitHub.draftNewRelease + gitOwner + gitRepoName + (Changelog.tagFromVersionNumber latestEntry.NuGetVersion) + (latestEntry.SemVer.PreRelease <> None) + (releaseNotes |> Seq.singleton) + |> GitHub.uploadFiles files + |> GitHub.publishDraft + |> Async.RunSynchronously + +let formatCode _ = + let result = dotnet.fantomas $"{rootDirectory}" + + if not result.OK then + printfn "Errors while formatting all files: %A" result.Messages + +let checkFormatCode ctx = + let result = dotnet.fantomas $"{rootDirectory} --check" + + if result.ExitCode = 0 then + Trace.log "No files need formatting" + elif result.ExitCode = 99 then + failwith "Some files need formatting, check output for more info" + else + Trace.logf "Errors while formatting: %A" result.Errors + + +let cleanDocsCache _ = DocsTool.cleanDocsCache () + +let buildDocs ctx = + let configuration = configuration (ctx.Context.AllExecutingTargets) + DocsTool.build (string configuration) + +let watchDocs ctx = + let configuration = configuration (ctx.Context.AllExecutingTargets) + DocsTool.watch (string configuration) + + +let initTargets (ctx : Context.FakeExecutionContext) = + BuildServer.install [ GitHubActions.Installer ] + + let isPublishToGitHub = + ctx.Arguments + |> Seq.pairwise + |> Seq.exists (fun (arg, value) -> + (String.Equals (arg, "-t", StringComparison.OrdinalIgnoreCase) + || String.Equals (arg, "--target", StringComparison.OrdinalIgnoreCase)) + && String.Equals (value, "PublishToGitHub", StringComparison.OrdinalIgnoreCase) + ) + + /// Defines a dependency - y is dependent on x. Finishes the chain. + let (==>!) x y = x ==> y |> ignore + + /// Defines a soft dependency. x must run before y, if it is present, but y does not require x to be run. Finishes the chain. + let (?=>!) x y = x ?=> y |> ignore + //----------------------------------------------------------------------------- + // Hide Secrets in Logger + //----------------------------------------------------------------------------- + Option.iter (TraceSecrets.register "") githubToken + Option.iter (TraceSecrets.register "") nugetToken + //----------------------------------------------------------------------------- + // Target Declaration + //----------------------------------------------------------------------------- + + Target.create "Clean" clean + Target.create "DotnetRestore" dotnetRestore + Target.create "DotnetToolRestore" dotnetToolRestore + Target.create "UpdateChangelog" updateChangelog + Target.createBuildFailure "RevertChangelog" revertChangelog // Do NOT put this in the dependency chain + Target.createFinal "DeleteChangelogBackupFile" deleteChangelogBackupFile // Do NOT put this in the dependency chain + Target.create "DotnetBuild" dotnetBuild + Target.create "FSharpAnalyzers" fsharpAnalyzers + Target.create "DotnetTest" dotnetTest + Target.create "GenerateCoverageReport" generateCoverageReport + Target.create "ShowCoverageReport" showCoverageReport + Target.create "WatchTests" watchTests + Target.create "GenerateAssemblyInfo" generateAssemblyInfo + Target.create "DotnetPack" dotnetPack + Target.create "SourceLinkTest" sourceLinkTest + Target.create "PublishToNuGet" (publishTo NuGet) + Target.create "PublishToGitHub" (publishTo GitHub) + Target.create "GitRelease" gitRelease + Target.create "GitHubRelease" githubRelease + Target.create "FormatCode" formatCode + Target.create "CheckFormatCode" checkFormatCode + Target.create "Release" ignore // For local + Target.create "Publish" ignore //For CI + Target.create "CleanDocsCache" cleanDocsCache + Target.create "BuildDocs" buildDocs + Target.create "WatchDocs" watchDocs + + //----------------------------------------------------------------------------- + // Target Dependencies + //----------------------------------------------------------------------------- + + + // Only call Clean if DotnetPack was in the call chain + // Ensure Clean is called before DotnetRestore + "Clean" ?=>! "DotnetRestore" + + "Clean" ==>! "DotnetPack" + + // Only call GenerateAssemblyInfo if GitRelease was in the call chain + // Ensure GenerateAssemblyInfo is called after DotnetRestore and before DotnetBuild + "DotnetRestore" ?=>! "GenerateAssemblyInfo" + + "GenerateAssemblyInfo" ?=>! "DotnetBuild" + + // Ensure UpdateChangelog is called after DotnetRestore + "DotnetRestore" ?=>! "UpdateChangelog" + + "UpdateChangelog" ?=>! "GenerateAssemblyInfo" + + "CleanDocsCache" ==>! "BuildDocs" + + "DotnetBuild" ?=>! "BuildDocs" + + "DotnetBuild" ==>! "BuildDocs" + + + "DotnetBuild" ==>! "WatchDocs" + + "DotnetTest" ==> "GenerateCoverageReport" + ==>! "ShowCoverageReport" + + "UpdateChangelog" + ==> "GenerateAssemblyInfo" + ==> "GitRelease" + ==>! "Release" + + + "DotnetRestore" =?> ("CheckFormatCode", isCI.Value) + ==> "DotnetBuild" + ==> "DotnetTest" + ==> "DotnetPack" + ==> "PublishToNuGet" + ==> "GitHubRelease" + ==>! "Publish" + + "DotnetRestore" + =?> ("CheckFormatCode", isCI.Value) + =?> ("GenerateAssemblyInfo", isPublishToGitHub) + ==> "DotnetBuild" + ==> "DotnetTest" + ==> "DotnetPack" + ==>! "PublishToGitHub" + + "DotnetRestore" ==>! "WatchTests" + + //"DotnetToolRestore" ?=>! "DotnetRestore" + "DotnetToolRestore" ==>! "BuildDocs" + "DotnetToolRestore" ?=>! "CheckFormatCode" + "DotnetToolRestore" ?=>! "FormatCode" + +//----------------------------------------------------------------------------- +// Target Start +//----------------------------------------------------------------------------- +[] +let main argv = + + let ctx = + argv + |> Array.toList + |> Context.FakeExecutionContext.Create false "build.fsx" + + Context.setExecutionContext (Context.RuntimeContext.Fake ctx) + initTargets ctx + Target.runOrDefaultWithArguments "DotnetPack" + + 0 // return an integer exit code diff --git a/build/build.fsproj b/build/build.fsproj new file mode 100644 index 0000000..a12452d --- /dev/null +++ b/build/build.fsproj @@ -0,0 +1,40 @@ + + + Exe + net8.0 + 3390;$(WarnOn) + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docsSrc/Explanations/Background.md b/docsSrc/Explanations/Background.md new file mode 100644 index 0000000..a1525b3 --- /dev/null +++ b/docsSrc/Explanations/Background.md @@ -0,0 +1,39 @@ +--- +title: Background +category: Explanations +categoryindex: 3 +index: 1 +--- + +# Background + +## System.Collections.Immutable and F# + +[System.Collections.Immutable](https://learn.microsoft.com/en-us/dotnet/api/system.collections.immutable) is a high-performance .NET library providing a suite of immutable collection types, such as arrays, lists, stacks, queues, dictionaries, and sets. These collections are designed for scenarios where data structures need to be shared safely across threads or require non-destructive updates, making them ideal for functional programming patterns. + +While F# has its own built-in immutable collections, System.Collections.Immutable collections are engineered for performance and scalability, especially in concurrent and multi-threaded environments. They use advanced algorithms to minimize memory allocations and maximize efficiency when creating modified copies of collections. + +**FSharp.Collections.Immutable** provides idiomatic F# bindings for these .NET collections, allowing F# developers to leverage their performance and safety benefits with a familiar F#-style API. + +## Why Use System.Collections.Immutable in F#? + +- **Performance**: Optimized for fast structural sharing and minimal memory overhead compared to standard F# collections in certain scenarios. +- **Thread Safety**: Immutable by design, making them safe for concurrent access without locks. +- **Rich API**: Feature-rich and consistent with .NET ecosystem standards. +- **Interoperability**: Seamless integration with C# and other .NET languages. + +## Available Collections + +- `FlatList` (`ImmutableArray`) +- `ImmutableList` +- `Stack` (`ImmutableStack`) +- `Queue` (`ImmutableQueue`) +- `HashMap` (`ImmutableDictionary`) +- `SortedMap` (`ImmutableSortedDictionary`) +- `HashSet` (`ImmutableHashSet`) +- `SortedSet` (`ImmutableSortedSet`) +- `IIndexedSeq` (`IReadOnlyList`) + +--- + +FSharp.Collections.Immutable enables F# developers to use these performant, thread-safe, and feature-rich immutable collections in a natural and idiomatic way. diff --git a/docsSrc/How_Tos/Doing_A_Thing.md b/docsSrc/How_Tos/Doing_A_Thing.md new file mode 100644 index 0000000..071e5c1 --- /dev/null +++ b/docsSrc/How_Tos/Doing_A_Thing.md @@ -0,0 +1,14 @@ +--- +title: How To do a first thing +category: How To Guides +categoryindex: 2 +index: 1 +--- + +# How To do a first thing + +The best way to use IObservable is to use one .Subscribe()-method which will take function parameters (which will be "injected" to the right place). + +Use Rx (or R3) when you need async events to communicate with each other, e.g.: +- Events, WebServices, Threads, Timers, AutoComplete, Drag & Drop, ... + diff --git a/docsSrc/How_Tos/Doing_Another_Thing.md b/docsSrc/How_Tos/Doing_Another_Thing.md new file mode 100644 index 0000000..03064b3 --- /dev/null +++ b/docsSrc/How_Tos/Doing_Another_Thing.md @@ -0,0 +1,9 @@ +--- +title: How To do a second thing +category: How To Guides +categoryindex: 2 +index: 2 +--- + +# How To do a second thing + diff --git a/docsSrc/Tutorials/Getting_Started.md b/docsSrc/Tutorials/Getting_Started.md new file mode 100644 index 0000000..eea423e --- /dev/null +++ b/docsSrc/Tutorials/Getting_Started.md @@ -0,0 +1,41 @@ +--- +title: Getting Started +category: Tutorials +categoryindex: 1 +index: 1 +--- + +# Getting Started + +## Installation + +First, add the NuGet package to your project: +``` +dotnet add package FSharp.Collections.Immutable +``` +## Basic Setup + +Here's a minimal example to get started: +``` F# +open FSharp.Collections.Immutable +``` + +``` F# +// Create an immutable list +let list1 = ImmutableList.ofSeq [1; 2; 3] + +// Create an immutable hash set +let set1 = HashSet.ofSeq ["a"; "b"] + +// Create an immutable dictionary +let dict1 = HashMap.ofSeq [KeyValuePair ("key1", 42); KeyValuePair ("key2", 100)] + + +printfn "List: %A" (list1 |> Seq.toList) +printfn "Set: %A" (set1 |> Seq.toList) +printfn "Dict: %A" (dict1 |> Seq.toList) +## Next Steps + +- Check out the [How-To Guides](../How_Tos/Doing_A_Thing.html) for common scenarios +- Read the [Background](../Explanations/Background.html) for deeper understanding +- Browse the [API Reference](../reference/index.html) for detailed documentation diff --git a/docsSrc/_menu-item_template.html b/docsSrc/_menu-item_template.html new file mode 100644 index 0000000..dc1b656 --- /dev/null +++ b/docsSrc/_menu-item_template.html @@ -0,0 +1 @@ +
  • {{fsdocs-menu-item-content}}
  • \ No newline at end of file diff --git a/docsSrc/_menu_template.html b/docsSrc/_menu_template.html new file mode 100644 index 0000000..066716c --- /dev/null +++ b/docsSrc/_menu_template.html @@ -0,0 +1,9 @@ + \ No newline at end of file diff --git a/docsSrc/_template.html b/docsSrc/_template.html new file mode 100644 index 0000000..2e69546 --- /dev/null +++ b/docsSrc/_template.html @@ -0,0 +1,166 @@ + + + + + + {{fsdocs-page-title}} + + + + + + + + + + + + + + + + {{fsdocs-watch-script}} + + + + + + +
    + {{fsdocs-content}} + {{fsdocs-tooltips}} +
    + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docsSrc/content/fsdocs-custom.css b/docsSrc/content/fsdocs-custom.css new file mode 100644 index 0000000..62b2801 --- /dev/null +++ b/docsSrc/content/fsdocs-custom.css @@ -0,0 +1,15 @@ +.fsharp-icon-logo { + width: 25px; + margin-top: -2px; + -webkit-filter: grayscale(100%) brightness(1) invert(1); /* Safari 6.0 - 9.0 */ + filter: grayscale(100%) brightness(1) invert(1); +} + + +body .navbar .dropdown-menu .active .bi { + display: block !important; +} + +nav.navbar .dropdown-item img.fsharp-icon-logo { + margin-right: 0px; +} diff --git a/docsSrc/content/fsdocs-dark.css b/docsSrc/content/fsdocs-dark.css new file mode 100644 index 0000000..001b653 --- /dev/null +++ b/docsSrc/content/fsdocs-dark.css @@ -0,0 +1,50 @@ +@import url('https://raw.githubusercontent.com/tonsky/FiraCode/fixed/distr/fira_code.css'); +@import url('https://fonts.googleapis.com/css2?family=Hind+Vadodara&family=Roboto+Mono&display=swap'); +/*-------------------------------------------------------------------------- + Formatting for page & standard document content +/*--------------------------------------------------------------------------*/ + +:root { + --fsdocs-text-color:#d1d1d1; + --fsdocs-pre-border-color: #000000; + --fsdocs-pre-border-color-top: #070707; + --fsdocs-pre-background-color: #1E1E1E; + --fsdocs-pre-color: #e2e2e2; + --fsdocs-table-pre-background-color: #1d1d1d; + --fsdocs-table-pre-color: #c9c9c9; + + --fsdocs-code-strings-color: #ea9a75; + --fsdocs-code-printf-color: #E0C57F; + --fsdocs-code-escaped-color: #EA8675; + --fsdocs-code-identifiers-color: var(--fsdocs-text-color); + --fsdocs-code-module-color: #43AEC6; + --fsdocs-code-reference-color: #6a8dd8; + --fsdocs-code-value-color: #43AEC6; + --fsdocs-code-interface-color: #43AEC6; + --fsdocs-code-typearg-color: #43AEC6; + --fsdocs-code-disposable-color: #2f798a; + --fsdocs-code-property-color: #43AEC6; + --fsdocs-code-punctuation-color: #43AEC6; + --fsdocs-code-punctuation2-color: #e1e1e1; + --fsdocs-code-function-color: #e1e1e1; + --fsdocs-code-function2-color: #43AEC6; + --fsdocs-code-activepattern-color: #4ec9b0; + --fsdocs-code-unioncase-color: #4ec9b0; + --fsdocs-code-enumeration-color: #4ec9b0; + --fsdocs-code-keywords-color: #2248c4; + --fsdocs-code-comment-color: #329215; + --fsdocs-code-operators-color: #af75c1; + --fsdocs-code-numbers-color: #96C71D; + --fsdocs-code-linenumbers-color: #80b0b0; + --fsdocs-code-mutable-color: #997f0c; + --fsdocs-code-inactive-color: #808080; + --fsdocs-code-preprocessor-color: #af75c1; + --fsdocs-code-fsioutput-color: #808080; + --fsdocs-code-tooltip-color: #d1d1d1; +} + + +.fsdocs-source-link img { + -webkit-filter: grayscale(100%) brightness(1) invert(1); /* Safari 6.0 - 9.0 */ + filter: grayscale(100%) brightness(1) invert(1); +} \ No newline at end of file diff --git a/docsSrc/content/fsdocs-light.css b/docsSrc/content/fsdocs-light.css new file mode 100644 index 0000000..318ccd9 --- /dev/null +++ b/docsSrc/content/fsdocs-light.css @@ -0,0 +1,43 @@ +@import url('https://fonts.googleapis.com/css2?family=Hind+Vadodara&family=Roboto+Mono&display=swap'); +/*-------------------------------------------------------------------------- + Formatting for page & standard document content +/*--------------------------------------------------------------------------*/ + +:root { + --fsdocs-text-color:#262626; + --fsdocs-pre-border-color: #d8d8d8; + --fsdocs-pre-border-color-top: #e3e3e3; + --fsdocs-pre-background-color: #f3f4f7; + --fsdocs-pre-color: #8e0e2b; + --fsdocs-table-pre-background-color: #fff7ed; + --fsdocs-table-pre-color: #837b79; + + --fsdocs-code-strings-color: #dd1144; + --fsdocs-code-printf-color: #E0C57F; + --fsdocs-code-escaped-color: #EA8675; + --fsdocs-code-identifiers-color: var(--fsdocs-text-color); + --fsdocs-code-module-color: #009999; + --fsdocs-code-reference-color: #4974D1; + --fsdocs-code-value-color: #43AEC6; + --fsdocs-code-interface-color: #43AEC6; + --fsdocs-code-typearg-color: #43AEC6; + --fsdocs-code-disposable-color: #43AEC6; + --fsdocs-code-property-color: #43AEC6; + --fsdocs-code-punctuation-color: #43AEC6; + --fsdocs-code-punctuation2-color: #var(--fsdocs-text-color); + --fsdocs-code-function-color: #e1e1e1; + --fsdocs-code-function2-color: #990000; + --fsdocs-code-activepattern-color: #4ec9b0; + --fsdocs-code-unioncase-color: #4ec9b0; + --fsdocs-code-enumeration-color: #4ec9b0; + --fsdocs-code-keywords-color: #b68015; + --fsdocs-code-comment-color: #808080; + --fsdocs-code-operators-color: #af75c1; + --fsdocs-code-numbers-color: #009999; + --fsdocs-code-linenumbers-color: #80b0b0; + --fsdocs-code-mutable-color: #d1d1d1; + --fsdocs-code-inactive-color: #808080; + --fsdocs-code-preprocessor-color: #af75c1; + --fsdocs-code-fsioutput-color: #808080; + --fsdocs-code-tooltip-color: #d1d1d1; +} diff --git a/docsSrc/content/fsdocs-main.css b/docsSrc/content/fsdocs-main.css new file mode 100644 index 0000000..2ad1582 --- /dev/null +++ b/docsSrc/content/fsdocs-main.css @@ -0,0 +1,604 @@ +@import url('https://fonts.googleapis.com/css2?family=Hind+Vadodara&family=Roboto+Mono&display=swap'); +/*-------------------------------------------------------------------------- + Formatting for page & standard document content +/*--------------------------------------------------------------------------*/ + +body { + font-family: 'Hind Vadodara', sans-serif; + /* padding-top: 0px; + padding-bottom: 40px; +*/ +} + +blockquote { + margin: 0 1em 0 0.25em; + margin-top: 0px; + margin-right: 1em; + margin-bottom: 0px; + margin-left: 0.25em; + padding: 0 .75em 0 1em; + border-left: 1px solid #777; + border-right: 0px solid #777; +} + +/* Format the heading - nicer spacing etc. */ +.masthead { + overflow: hidden; +} + + .masthead .muted a { + text-decoration: none; + color: #999999; + } + + .masthead ul, .masthead li { + margin-bottom: 0px; + } + + .masthead .nav li { + margin-top: 15px; + font-size: 110%; + } + + .masthead h3 { + margin-top: 15px; + margin-bottom: 5px; + font-size: 170%; + } + +/*-------------------------------------------------------------------------- + Formatting fsdocs-content +/*--------------------------------------------------------------------------*/ + +/* Change font sizes for headings etc. */ +#fsdocs-content h1 { + margin: 30px 0px 15px 0px; + /* font-weight: 400; */ + font-size: 2rem; + letter-spacing: 1.78px; + line-height: 2.5rem; + font-weight: 400; +} + +#fsdocs-content h2 { + font-size: 1.6rem; + margin: 20px 0px 10px 0px; + font-weight: 400; +} + +#fsdocs-content h3 { + font-size: 1.2rem; + margin: 15px 0px 10px 0px; + font-weight: 400; +} + +#fsdocs-content hr { + margin: 0px 0px 20px 0px; +} + +#fsdocs-content li { + font-size: 1.0rem; + line-height: 1.375rem; + letter-spacing: 0.01px; + font-weight: 500; + margin: 0px 0px 15px 0px; +} + +#fsdocs-content p { + font-size: 1.0rem; + line-height: 1.375rem; + letter-spacing: 0.01px; + font-weight: 500; + color: var(--fsdocs-text-color);; +} + +#fsdocs-content a:not(.btn) { + color: #4974D1; +} +/* remove the default bootstrap bold on dt elements */ +#fsdocs-content dt { + font-weight: normal; +} + + + +/*-------------------------------------------------------------------------- + Formatting tables in fsdocs-content, using learn.microsoft.com tables +/*--------------------------------------------------------------------------*/ + +#fsdocs-content .table { + table-layout: auto; + width: 100%; + font-size: 0.875rem; +} + + #fsdocs-content .table caption { + font-size: 0.8rem; + font-weight: 600; + letter-spacing: 2px; + text-transform: uppercase; + padding: 1.125rem; + border-width: 0 0 1px; + border-style: solid; + border-color: #e3e3e3; + text-align: right; + } + + #fsdocs-content .table td, + #fsdocs-content .table th { + display: table-cell; + word-wrap: break-word; + padding: 0.75rem 1rem 0.75rem 0rem; + line-height: 1.5; + vertical-align: top; + border-top: 1px solid #e3e3e3; + border-right: 0; + border-left: 0; + border-bottom: 0; + border-style: solid; + } + + /* suppress the top line on inner lists such as tables of exceptions */ + #fsdocs-content .table .fsdocs-exception-list td, + #fsdocs-content .table .fsdocs-exception-list th { + border-top: 0 + } + + #fsdocs-content .table td p:first-child, + #fsdocs-content .table th p:first-child { + margin-top: 0; + } + + #fsdocs-content .table td.nowrap, + #fsdocs-content .table th.nowrap { + white-space: nowrap; + } + + #fsdocs-content .table td.is-narrow, + #fsdocs-content .table th.is-narrow { + width: 15%; + } + + #fsdocs-content .table th:not([scope='row']) { + border-top: 0; + border-bottom: 1px; + } + + #fsdocs-content .table > caption + thead > tr:first-child > td, + #fsdocs-content .table > colgroup + thead > tr:first-child > td, + #fsdocs-content .table > thead:first-child > tr:first-child > td { + border-top: 0; + } + + #fsdocs-content .table table-striped > tbody > tr:nth-of-type(odd) { + background-color: var(--box-shadow-light); + } + + #fsdocs-content .table.min { + width: unset; + } + + #fsdocs-content .table.is-left-aligned td:first-child, + #fsdocs-content .table.is-left-aligned th:first-child { + padding-left: 0; + } + + #fsdocs-content .table.is-left-aligned td:first-child a, + #fsdocs-content .table.is-left-aligned th:first-child a { + outline-offset: -0.125rem; + } + +@media screen and (max-width: 767px), screen and (min-resolution: 120dpi) and (max-width: 767.9px) { + #fsdocs-content .table.is-stacked-mobile td:nth-child(1) { + display: block; + width: 100%; + padding: 1rem 0; + } + + #fsdocs-content .table.is-stacked-mobile td:not(:nth-child(1)) { + display: block; + border-width: 0; + padding: 0 0 1rem; + } +} + +#fsdocs-content .table.has-inner-borders th, +#fsdocs-content .table.has-inner-borders td { + border-right: 1px solid #e3e3e3; +} + + #fsdocs-content .table.has-inner-borders th:last-child, + #fsdocs-content .table.has-inner-borders td:last-child { + border-right: none; + } + +.fsdocs-entity-list .fsdocs-entity-name { + width: 25%; + font-weight: bold; +} + +.fsdocs-member-list .fsdocs-member-usage { + width: 35%; +} + +/*-------------------------------------------------------------------------- + Formatting xmldoc sections in fsdocs-content +/*--------------------------------------------------------------------------*/ + +.fsdocs-xmldoc, .fsdocs-entity-xmldoc, .fsdocs-member-xmldoc { + font-size: 1.0rem; + line-height: 1.375rem; + letter-spacing: 0.01px; + font-weight: 500; + color: var(--fsdocs-text-color);; +} + +.fsdocs-xmldoc h1 { + font-size: 1.2rem; + margin: 10px 0px 0px 0px; +} + +.fsdocs-xmldoc h2 { + font-size: 1.2rem; + margin: 10px 0px 0px 0px; +} + +.fsdocs-xmldoc h3 { + font-size: 1.1rem; + margin: 10px 0px 0px 0px; +} + +/* #fsdocs-nav .searchbox { + margin-top: 30px; + margin-bottom: 30px; +} */ + +#fsdocs-nav img.logo{ + width:90%; + /* height:140px; */ + /* margin:10px 0px 0px 20px; */ + margin-top:40px; + border-style:none; +} + +#fsdocs-nav input{ + /* margin-left: 20px; */ + margin-right: 20px; + margin-top: 20px; + margin-bottom: 20px; + width: 93%; + -webkit-border-radius: 0; + border-radius: 0; +} + +#fsdocs-nav { + /* margin-left: -5px; */ + /* width: 90%; */ + font-size:0.95rem; +} + +#fsdocs-nav li.nav-header{ + /* margin-left: -5px; */ + /* width: 90%; */ + padding-left: 0; + color: var(--fsdocs-text-color);; + text-transform: none; + font-size:16px; + margin-top: 9px; + font-weight: bold; +} + +#fsdocs-nav a{ + padding-left: 0; + color: #6c6c6d; + /* margin-left: 5px; */ + /* width: 90%; */ +} + +/*-------------------------------------------------------------------------- + Formatting pre and code sections in fsdocs-content (code highlighting is + further below) +/*--------------------------------------------------------------------------*/ + +#fsdocs-content code { + /* font-size: 0.83rem; */ + font: 0.85rem 'Roboto Mono', monospace; + background-color: #f7f7f900; + border: 0px; + padding: 0px; + /* word-wrap: break-word; */ + /* white-space: pre; */ +} + +/* omitted */ +#fsdocs-content span.omitted { + background: #3c4e52; + border-radius: 5px; + color: #808080; + padding: 0px 0px 1px 0px; +} + +#fsdocs-content pre .fssnip code { + font: 0.86rem 'Roboto Mono', monospace; +} + +#fsdocs-content table.pre, +#fsdocs-content pre.fssnip, +#fsdocs-content pre { + line-height: 13pt; + border: 0px solid var(--fsdocs-pre-border-color); + border-top: 0px solid var(--fsdocs-pre-border-color-top); + border-collapse: separate; + white-space: pre; + font: 0.86rem 'Roboto Mono', monospace; + width: 100%; + margin: 10px 0px 20px 0px; + background-color: var(--fsdocs-pre-background-color); + padding: 10px; + border-radius: 5px; + color: var(--fsdocs-pre-color); + max-width: none; + box-sizing: border-box; +} + +#fsdocs-content pre.fssnip code { + font: 0.86rem 'Roboto Mono', monospace; + font-weight: 600; +} + +#fsdocs-content table.pre { + background-color: var(--fsdocs-table-pre-background-color);; +} + +#fsdocs-content table.pre pre { + padding: 0px; + margin: 0px; + border-radius: 0px; + width: 100%; + background-color: var(--fsdocs-table-pre-background-color); + color: var(--fsdocs-table-pre-color); +} + +#fsdocs-content table.pre td { + padding: 0px; + white-space: normal; + margin: 0px; + width: 100%; +} + +#fsdocs-content table.pre td.lines { + width: 30px; +} + + +#fsdocs-content pre { + word-wrap: inherit; +} + +.fsdocs-example-header { + font-size: 1.0rem; + line-height: 1.375rem; + letter-spacing: 0.01px; + font-weight: 700; + color: var(--fsdocs-text-color);; +} + +/*-------------------------------------------------------------------------- + Formatting github source links +/*--------------------------------------------------------------------------*/ + +.fsdocs-source-link { + float: right; + text-decoration: none; +} + + .fsdocs-source-link img { + border-style: none; + margin-left: 10px; + width: auto; + height: 1.4em; + } + + .fsdocs-source-link .hover { + display: none; + } + + .fsdocs-source-link:hover .hover { + display: block; + } + + .fsdocs-source-link .normal { + display: block; + } + + .fsdocs-source-link:hover .normal { + display: none; + } + +/*-------------------------------------------------------------------------- + Formatting logo +/*--------------------------------------------------------------------------*/ + +#fsdocs-logo { + width:40px; + height:40px; + margin:10px 0px 0px 0px; + border-style:none; +} + +/*-------------------------------------------------------------------------- + +/*--------------------------------------------------------------------------*/ + +#fsdocs-content table.pre pre { + padding: 0px; + margin: 0px; + border: none; +} + +/*-------------------------------------------------------------------------- + Remove formatting from links +/*--------------------------------------------------------------------------*/ + +#fsdocs-content h1 a, +#fsdocs-content h1 a:hover, +#fsdocs-content h1 a:focus, +#fsdocs-content h2 a, +#fsdocs-content h2 a:hover, +#fsdocs-content h2 a:focus, +#fsdocs-content h3 a, +#fsdocs-content h3 a:hover, +#fsdocs-content h3 a:focus, +#fsdocs-content h4 a, +#fsdocs-content h4 a:hover, #fsdocs-content +#fsdocs-content h4 a:focus, +#fsdocs-content h5 a, +#fsdocs-content h5 a:hover, +#fsdocs-content h5 a:focus, +#fsdocs-content h6 a, +#fsdocs-content h6 a:hover, +#fsdocs-content h6 a:focus { + color: var(--fsdocs-text-color);; + text-decoration: none; + text-decoration-style: none; + /* outline: none */ +} + +/*-------------------------------------------------------------------------- + Formatting for F# code snippets +/*--------------------------------------------------------------------------*/ + +.fsdocs-param-name, +.fsdocs-return-name, +.fsdocs-param { + font-weight: 900; + font-size: 0.85rem; + font-family: 'Roboto Mono', monospace; +} +/* strings --- and stlyes for other string related formats */ +#fsdocs-content span.s { + color: var(--fsdocs-code-strings-color); +} +/* printf formatters */ +#fsdocs-content span.pf { + color: var(--fsdocs-code-printf-color); +} +/* escaped chars */ +#fsdocs-content span.e { + color: var(--fsdocs-code-escaped-color); +} + +/* identifiers --- and styles for more specific identifier types */ +#fsdocs-content span.id { + color: var(--fsdocs-identifiers-color);; +} +/* module */ +#fsdocs-content span.m { + color:var(--fsdocs-code-module-color); +} +/* reference type */ +#fsdocs-content span.rt { + color: var(--fsdocs-code-reference-color); +} +/* value type */ +#fsdocs-content span.vt { + color: var(--fsdocs-code-value-color); +} +/* interface */ +#fsdocs-content span.if { + color: var(--fsdocs-code-interface-color); +} +/* type argument */ +#fsdocs-content span.ta { + color: var(--fsdocs-code-typearg-color); +} +/* disposable */ +#fsdocs-content span.d { + color: var(--fsdocs-code-disposable-color); +} +/* property */ +#fsdocs-content span.prop { + color: var(--fsdocs-code-property-color); +} +/* punctuation */ +#fsdocs-content span.p { + color: var(--fsdocs-code-punctuation-color); +} +#fsdocs-content span.pn { + color: var(--fsdocs-code-punctuation2-color); +} +/* function */ +#fsdocs-content span.f { + color: var(--fsdocs-code-function-color); +} +#fsdocs-content span.fn { + color: var(--fsdocs-code-function2-color); +} +/* active pattern */ +#fsdocs-content span.pat { + color: var(--fsdocs-code-activepattern-color); +} +/* union case */ +#fsdocs-content span.u { + color: var(--fsdocs-code-unioncase-color); +} +/* enumeration */ +#fsdocs-content span.e { + color: var(--fsdocs-code-enumeration-color); +} +/* keywords */ +#fsdocs-content span.k { + color: var(--fsdocs-code-keywords-color); + /* font-weight: bold; */ +} +/* comment */ +#fsdocs-content span.c { + color: var(--fsdocs-code-comment-color); + font-weight: 400; + font-style: italic; +} +/* operators */ +#fsdocs-content span.o { + color: var(--fsdocs-code-operators-color); +} +/* numbers */ +#fsdocs-content span.n { + color: var(--fsdocs-code-numbers-color); +} +/* line number */ +#fsdocs-content span.l { + color: var(--fsdocs-code-linenumbers-color); +} +/* mutable var or ref cell */ +#fsdocs-content span.v { + color: var(--fsdocs-code-mutable-color); + font-weight: bold; +} +/* inactive code */ +#fsdocs-content span.inactive { + color: var(--fsdocs-code-inactive-color); +} +/* preprocessor */ +#fsdocs-content span.prep { + color: var(--fsdocs-code-preprocessor-color); +} +/* fsi output */ +#fsdocs-content span.fsi { + color: var(--fsdocs-code-fsioutput-color); +} + +/* tool tip */ +div.fsdocs-tip { + background: #475b5f; + border-radius: 4px; + font: 0.85rem 'Roboto Mono', monospace; + padding: 6px 8px 6px 8px; + display: none; + color: var(--fsdocs-code-tooltip-color); + pointer-events: none; +} + + div.fsdocs-tip code { + color: var(--fsdocs-code-tooltip-color); + font: 0.85rem 'Roboto Mono', monospace; + } diff --git a/docsSrc/content/logo.pdn b/docsSrc/content/logo.pdn new file mode 100644 index 0000000000000000000000000000000000000000..c1ffec090291db78b4d4662b0ac7e3988cf39415 GIT binary patch literal 8637 zcmeHL3zQVqnVyDug6v3q&m@^~#?{?4nSQ?v%vz7G?&^1SP4#rQB2-sbS5;ScS9N#w zYse%dF=3-l#?f<(nixO{YKVf00*WT6L3X1NP*D)#$$|o+5EUF96!umR$Y7F9vd2AV z&oR}fZ{5d#zyIF<|L%Y9tq>Y8HJ{TkS5D^eEX}dq6(Onc^LmVWeNQ*f3LLMTDrD#y zTPV)!G4*s8=`x!f6cj!JY6K|g{qF6ts1S^YjP%TD)fMOz@3lFP}mF_hAmm;repEaPrJ<1yQG28eg2QYj@8 zhY4FP=8MCa+f_vfy$8x7gG8h{BymiQ2$>3s&Kh;$hBRftoqBVLgTon<%}(nQ_>dUz zrS&PwkSC!8PN%(92y=?E>=#j*@d_mZ4&!-OX#n!!L0&Jxk~AO+Oo|<}NkRQ!0fV$z zgs@TwmC$MJ=_H=_4GLUz0FzP@M3D%uND?MW9@Ie$3Ve{1s}4u1l(vSwya)GkW&?~1 zR<<;lG7{xbDk1CL`T-1LvnWx~W0D9X`6`9Uh&_lAn3IbUgWgI4cfyrCB5|acNwV5p zLDuEdL4kv67|wcO)K^YN*pM%&&l!>_i9kG+JgiPColj&4jvC-8p8)3_+H%Sl(3=d& zfGShXd#aEj=u1;W#sDM`G;fyzVcaE_OI3&|!9=N=(7FoYwANux`1J82E8`)Q3>)Ia zAc@#nZJADHla87(g%}+rSsl?>IU3U%Eg3qE0_)`StfiVG2 zn?0P{$;)I?&C5d6WzQrPn=Z~`Mmm+r!WkS+M@6%k3wq5-rs%2yFKTTGL&}^-dCcd7 zie$iSb=%P55NphZYN@KDj0hw}r3Jzth3)pF7$TF}R1MEM?PkOj$zxEp=;ep>IR~7v z1U+!oP|8tW2rwK~qPd`>!b#CV41&c3uPxY|GRlxB7h(fa01O5}!Ds>z+#<4k)sf-@ z25YqDs*oZESMvxA%$&{V0~Uk?+~HO3(7p&uI18vmdZB!viU<9X>YzZO-muFpa9#n} zgU<&7a)uzq2=J>@;t+(+1wkK|M0??SA4qG~p%Uy38{IVyb6ThY#2d3^lxhOU+=vu) z0;&b`3dZmh(95WLt@%o%=5?a+YCe^A`mL$bP%S+euw?VroT$&zDN!3`xIh@zv8hC^ zhJ*%GBW&>#VFzm$TzNZz zyW}FMW79!|OU6LQLBBvo4G1R%tr#Rb(=kf4P}#WC&ax(wp$q!lfDf+WE-vJ;+Z|ea zK^qDHr|?y)%^H{VrUVXAgJv;G;BGk{3kZnhAxSgCrc)eUv!@b?N_HTjEfN^vA>BT~ z>^0T~ZRH{nAY-H-2Ek124>k~j2@DZ&XE5#-0W(mO#iA9tP>L>!-f%F2Fy%C7j2Q}6 zRI31Y)KIfNO=!zLR2;|Xk@hMCfanwe!%X`7PCg|c~j*+FGtDy;B%!Y9H*ISYh~z8IwTuA#-W zP|!0j(MLeBtP~-`B_fJ)6cNA?!G~cUPZ6%gGAKk63g;0LxKTvRX)cG=U>O=Dogl7f zFq@9i`m&G}BL}LC&Vx}X35k5B-UlNFRV>m)!5+j2<`jqYoCl8s{`+Dug^7QIEJdMu z)^CW?DI?g`2&#fsG1LfUAuld#Ik*akp^%db;ocZz7BW@{bz)AZE)1DDnR5$Xw+QRWxznFf+Th!%1RDk%Y0=|gFS zp3{B$LDxsX0|fq)dio6mXd-_PN*`TM(E& zFz5)KDX{>qu+Vt*)u%*Br6AQShSV+)RAaYK zsVE9V?3bpL%aixQMgae3{XFRlHEmP5(AEMHbrkAw8dasAaZ`O93;c9iDl{+f3pw=# zmxN5RZ9$kV3+f#dbOP>eZB<28sAtY^Xo&o@p`k^^tkb&QvhNGw@Wv0p68>ULRVC4M zk*zhA)upP@G`E3@8JDqDA=RhQoVj@hD5G=La<`BKUn=yLp6(2YL_G#;Pq$K&S@3zn6f}t|pVHM^2-D z=`2)R^Ld{|1w;B*r@^Wf3Z8LIxdjKFcfo@P}Qj!0@S*ek@B>^~*49bm{Pn`n=Hd=VH zp{NZ=g)E&pRa7TYpU9=EPIV%G&Mqo-&f3JAi(n5;vQ0&X&gns8BM97Qx!liYr9utP zNQ|f&RsEmdxVk}fZ|hMJRZIPKTdS05%+Xo)PtOZ2>ec~fe2!3rX-4D$EHVK;BG#Zus4f#{1(zK|CuAgVr_w+BuCa+Ox zp;}*~vOqQI8G~q4|JK`7cb?rgb8_2K<-v)t>xR~Prm^9jrww4wZk?{b|I7E@@hYv+ zWVb(O{l)*^XSAjE$sd0=IcGJP)}QI*lnL#6FiSxfUq{^0z2dwXJ(tT}3Ntu<@50ME zM|U3k@J8jmRWF}p$KMzqmvpDQfA;yulRKXjhvkP~tlZz8D^EOd zY}50B*B|L$zw_YZJ6dduUhtpz=-rts4^B4@U$wG*%Tdkk{oRk>*Z%NpE88EQJAB(4 z2cMo3>`K*^ZfM`L)1~HC4gd7Sky~a>EcSKXbXKnyTauq&u40ciT?cMc+5-d!&)>A!XD zJ?+DDgkaZ1^dEwMr+MCW9RKi@JD+_0m7$4yTdI43T|0qUuP9F(K6bYM4(zo8=pWws zW*TpX_!J?~7*>esf zy}x{Zu@yVEP29Klj?tNKcD%azK!2fkwdJYs2+xE8;(geoh7F_F_AY(tn;Z2nU1v=l z8|(b&8~48;_UG(eqVwV7TU+n{$u?}P-wdxxJxcr%h%VT%@vCbFmyO&teDul?!u|wo&i>Hn6-Pk@Nw?Wz64_xs?apNm{ zKKW!h7QOM;)+hZh>{&Ol-?OgEWx07ryYR&PLsvf3|Kkj!duUAAeNo5q>pHS;3)kKH za)voFZDiwl!(WLly>Qp7Gjq@U62mqqod-`W+5f?c*>U-xb^CDF%GJZBq|~u|r6;@b zZS3P~d)Ci3ecN$wqI31;qhr6aJv94$Uk!P~ij9wrE}#9BW$We@{qH?^SEu3q%F`VJ zQ|S8Wwy}}hUS3bkdc?45^qZNHkdMhecer;c()-+wg`LicE&HzriZ@>%t{q7X?<-=~ z#Lo_TEW5F7{qJqCJhgCS9kFqApx5@^@saVj`aBc2&+{Fs zUDd0T7HAJIJ@SF&jSn9A`EUBSzq@+cYkypKd z7Gu|s&))rm@&9_jw|C_HcaTosHo5mVK&oioCtm{|&=g5si{ps&@e9db7 z&~eF5EFQe!+EC=4aPQJtyRY7NXfyTEs{iPi|Jc}f7Hw~Sp1*JGUh89zkDnO6pfoGC z?!u0?+|$PsxBooVyK7-v+I-inTld{O()j4RSKc2K=Oa75zGm#mqW#tLU*0^jVOitM z^uEU`AKz(>KC~E2&;9IiZ|61fKVb00fsYq-e(h_oy5H?z3(cHi39oI>ZoPTh$oYrv ze*7mwRmSu$86O_&8CKpL-oECNk>?I0opUxlgQbpbyZ!sW{jQHs7P{`d{ReZlZow`; zwtUvD8MOEA<6E0W{hBdiSV{fip`Pg-m+W?NzrRAOtQ>=e`R`f2v2DxF{wp7rcP{Q7 z`RUttn_j$WmSgLdZT)LEUARZwx3Fv1!ru;!eEF@t!f)<}&MWjTIGQ_h<@^2Wf%o%# Q7JvWvMNruPO*L5kH{P=V$^ZZW literal 0 HcmV?d00001 diff --git a/docsSrc/content/logo.png b/docsSrc/content/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..1d43c1f56ea6c56db841128aab35592a7bf34664 GIT binary patch literal 1904 zcmeAS@N?(olHy`uVBq!ia0vp^CqS5k8A#4*i(3Pv7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$jZRL%n;xc;+mQ`J1q%_=47PI%}$?}lewTEXHik!;^O=zC51~XN|slZuV}1W z+uX3ewP}54+oqn*Exlb^r%c>AZOZN$Q}@i8zIXP_eRF2+n>Xjc!g&W5EjYAv@sZ_A zj;>gGY}NAPt5=>_v+Crg4QID+y|823g+042@85g%!2WB84qiWY^wx>vw@;nCbLQ0D zE0-Q!x%~L*mB%-4JiB}6<%9dL|Ns9Fbnqw`4FOt*!1j4nHb6T#3p^r=85sBugD~Uq z{1qucL5ULAh?3y^w370~qEv>0#LT=By}Z;C1rt33J>#Bd(*uB+=&GlSV@O5Z+uPN_ zmjeWjJycL&x+fa)fvZE@q2vDl!!x(tp5$BhS3;(5=69_ow`Slgzwwzx|Zsk+ehr`pEkyvy?kn+!q-x>lWU!wH+e?&@h#a` zr<84UrL08p>sjtdQTwMa96xz%S7@maN9|{?Yi{daZ%`<$RapJ_TJenuA13WP z+;}DbiKwBmjNFpEdHl1V7AQ8VE_?iE!>Voisqc5K5V~Es))L6+Odf*TXH8yQ#KxMbeTBC+QviRWcAIZuU^0Vb8Df^ z6dR9Ho#^*pir4P{n^!j}ca@*~*>$-xCl9;IJ#jF*mwDITeww$8hrn@J6|*CSe`Y** z{xhhPvry*ppKH+?8x=a&Z1zqWRgFTKkMAm&CYkUlcs`Msa-;9{@^10A)6;5JtdhOCQ}4sv&C8ZlI-9)b zzClTc0GLiLRboHDhYj5{M_gxuFFzjVG-ljq}IHNm8> zZwdFzM-|`iZB>=^SaN$aSC*%V%FM;OffGvlrY+%}`3WectE%g9x9#$7L)kiB8O)}jW_yqCd^D>ER@Mq=uP1(>@UCU zubkd_A= zjRPySS-~nYLcsp3nOlp5pb-}0kVJCN-}#|e + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docsSrc/content/navbar-fixed-left.css b/docsSrc/content/navbar-fixed-left.css new file mode 100644 index 0000000..28e4c57 --- /dev/null +++ b/docsSrc/content/navbar-fixed-left.css @@ -0,0 +1,91 @@ +/* CSS for Bootstrap 5 Fixed Left Sidebar Navigation */ + + + +@media (min-width: 992px){ + + body { + padding-left: 300px; + padding-right: 60px; + } + + #fsdocs-logo { + width:140px; + height:140px; + margin:10px 0px 0px 0px; + border-style:none; + } + + + nav.navbar { + position: fixed; + left: 0; + width: 300px; + bottom: 0; + top: 0; + overflow-y: auto; + overflow-x: hidden; + display: block; + border-right: 1px solid #cecece; + } + + nav.navbar>.container { + flex-direction: column; + padding: 0; + } + + nav.navbar .navbar-nav { + flex-direction: column; + } + nav.navbar .navbar-collapse { + width: 100%; + } + + nav.navbar .navbar-nav { + width: 100%; + } + + nav.navbar .navbar-nav .dropdown-menu { + position: static; + display: block; + } + + nav.navbar .dropdown { + margin-bottom: 5px; + font-size: 14px; + } + + nav.navbar .dropdown-item { + white-space: normal; + font-size: 14px; + vertical-align: middle; + } + + nav.navbar .dropdown-item img { + margin-right: 5px; + } + + nav.navbar .dropdown-toggle { + cursor: default; + } + + nav.navbar .dropdown-menu { + border-radius: 0; + border-left: 0; + border-right: 0; + } + + nav.navbar .dropdown-toggle:not(#bd-theme)::after { + display: none; + } + + .dropdown-menu[data-bs-popper] { + top: auto; + left: auto; + margin-top: auto; + } + + .nav-link:focus, .nav-link:hover { + color: auto; + } +} \ No newline at end of file diff --git a/docsSrc/content/theme-toggle.js b/docsSrc/content/theme-toggle.js new file mode 100644 index 0000000..c208c08 --- /dev/null +++ b/docsSrc/content/theme-toggle.js @@ -0,0 +1,68 @@ +/*! + * Color mode toggler for Bootstrap's docs (https://getbootstrap.com/) + * Copyright 2011-2022 The Bootstrap Authors + * Licensed under the Creative Commons Attribution 3.0 Unported License. + */ + +(() => { + 'use strict' + + const storedTheme = localStorage.getItem('theme') + + const getPreferredTheme = () => { + if (storedTheme) { + return storedTheme + } + + return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' + } + + const setTheme = function (theme) { + const fsdocsTheme = document.getElementById("fsdocs-theme") + const re = /fsdocs-.*.css/ + if (theme === 'auto' && window.matchMedia('(prefers-color-scheme: dark)').matches) { + document.documentElement.setAttribute('data-bs-theme', 'dark') + fsdocsTheme.setAttribute("href", fsdocsTheme.getAttribute("href").replace(re,"fsdocs-dark.css")) + + } else { + document.documentElement.setAttribute('data-bs-theme', theme) + + fsdocsTheme.setAttribute("href", fsdocsTheme.getAttribute("href").replace(re,`fsdocs-${theme}.css`)) + } + } + + setTheme(getPreferredTheme()) + + const showActiveTheme = theme => { + const activeThemeIcon = document.getElementById('theme-icon-active') + const btnToActive = document.querySelector(`[data-bs-theme-value="${theme}"]`) + const svgOfActiveBtn = btnToActive.querySelector('i').getAttribute('class') + + document.querySelectorAll('[data-bs-theme-value]').forEach(element => { + element.classList.remove('active') + }) + + btnToActive.classList.add('active') + activeThemeIcon.setAttribute('class', svgOfActiveBtn) + } + + window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { + if (storedTheme !== 'light' || storedTheme !== 'dark') { + setTheme(getPreferredTheme()) + } + }) + + window.addEventListener('DOMContentLoaded', () => { + showActiveTheme(getPreferredTheme()) + + document.querySelectorAll('[data-bs-theme-value]') + .forEach(toggle => { + toggle.addEventListener('click', () => { + const theme = toggle.getAttribute('data-bs-theme-value') + localStorage.setItem('theme', theme) + setTheme(theme) + showActiveTheme(theme) + }) + }) + }) +})() \ No newline at end of file diff --git a/docsSrc/index.md b/docsSrc/index.md new file mode 100644 index 0000000..a58115a --- /dev/null +++ b/docsSrc/index.md @@ -0,0 +1,79 @@ +# FSharp.Collections.Immutable + +F# bindings for [System.Collections.Immutable](https://learn.microsoft.com/en-us/dotnet/api/system.collections.immutable). + +**FSharp.Collections.Immutable** provides idiomatic F# wrappers for the .NET immutable collections, making it easy to use persistent data structures in F# code. + +## Key Features + +- `FlatList` (`ImmutableArray`) +- `ImmutableList` +- `Stack` (`ImmutableStack`) +- `Queue` (`ImmutableQueue`) +- `HashMap` (`ImmutableDictionary`) +- `SortedMap` (`ImmutableSortedDictionary`) +- `HashSet` (`ImmutableHashSet`) +- `SortedSet` (`ImmutableSortedSet`) +- `IIndexedSeq` (`IReadOnlyList`) + +--- + +
    +
    +
    +
    + The FSharp.Collections.Immutable library can be installed from NuGet: +
    PM> Install-Package FSharp.Collections.Immutable
    +
    +
    +
    +
    + +--- + +
    +
    +
    +
    +
    Tutorials
    +

    Step-by-step guide to get started with FSharp.Collections.Immutable.

    +
    + +
    +
    +
    +
    +
    +
    How-To Guides
    +

    Guides you through the steps involved in addressing key problems and use-cases.

    +
    + +
    +
    +
    +
    +
    +
    Explanations
    +

    Discusses key topics and concepts at a fairly high level and provide useful background information and explanation.

    +
    + +
    +
    +
    +
    +
    +
    Api Reference
    +

    Contain technical reference for APIs.

    +
    + +
    +
    +
    diff --git a/global.json b/global.json new file mode 100644 index 0000000..ccbe73c --- /dev/null +++ b/global.json @@ -0,0 +1,6 @@ +{ + "sdk": { + "version": "9.0.300", + "rollForward": "latestMinor" + } +} diff --git a/src/FSharp.Collections.Immutable/FSharp.Collections.Immutable.fsproj b/src/FSharp.Collections.Immutable/FSharp.Collections.Immutable.fsproj index 2b3fbfb..9f5941f 100644 --- a/src/FSharp.Collections.Immutable/FSharp.Collections.Immutable.fsproj +++ b/src/FSharp.Collections.Immutable/FSharp.Collections.Immutable.fsproj @@ -1,45 +1,43 @@  - - netstandard2.0 - $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb - F# bindings for System.Collections.Immutable - Copyright © XperiAndri 2016 - FSharp.Collections.Immutable - XperiAndri - FSharp.Collections.Immutable - 2.0.0 - XperiAndri;EventHelix;vilinski;anthony-mi;dim-37 - true - FSharp.Collections.Immutable - System;Immutable;Collections;FSharp;F# - git - embedded - https://github.com/fsprojects/FSharp.Collections.Immutable/ - https://github.com/fsprojects/FSharp.Collections.Immutable/ - true - true - + + net8.0 + $(AssemblyBaseName) + true + true + True + - - - - - - - - - - - + + FSharp.Collections.Immutable + FSharp.Collections.Immutable + F# API for using Microsoft Azure Cosmos DB service via NoSQL API + Provides extension methods for the FeedIterator and computation expressions to build operations + - - true - + + true + true + - - - - + + + + + + + + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + diff --git a/src/FSharp.Collections.Immutable/flat-list.fs b/src/FSharp.Collections.Immutable/FlatList.fs similarity index 58% rename from src/FSharp.Collections.Immutable/flat-list.fs rename to src/FSharp.Collections.Immutable/FlatList.fs index 5f86c40..82bcce7 100644 --- a/src/FSharp.Collections.Immutable/flat-list.fs +++ b/src/FSharp.Collections.Immutable/FlatList.fs @@ -1,4 +1,4 @@ -#if INTERACTIVE +#if INTERACTIVE namespace global #else namespace FSharp.Collections.Immutable @@ -8,76 +8,89 @@ namespace FSharp.Collections.Immutable type FlatList<'T> = System.Collections.Immutable.ImmutableArray<'T> // based on the F# Array module source -[] +[] module FlatList = type internal FlatListFactory = System.Collections.Immutable.ImmutableArray let inline internal checkNotDefault argName (list : FlatList<'T>) = - if list.IsDefault then invalidArg argName "Uninstantiated ImmutableArray/FlatList" + if list.IsDefault then + invalidArg argName "Uninstantiated ImmutableArray/FlatList" + let inline internal check (list : FlatList<'T>) = checkNotDefault (nameof list) list ////////// Creating ////////// - let inline empty<'T> : FlatList<_> = FlatListFactory.Create<'T>() + let inline empty<'T> : FlatList<_> = FlatListFactory.Create<'T> () let inline singleton<'T> (item : 'T) : FlatList<'T> = FlatListFactory.Create<'T> (item) let inline ofSeq source = FlatListFactory.CreateRange source let inline ofArray (source : _ array) = FlatListFactory.CreateRange source - let inline toSeq (flatList: FlatList<_>) = flatList :> seq<_> - let inline toArray (list : FlatList<_>) = check list; Seq.toArray list + let inline toSeq (flatList : FlatList<_>) = flatList :> seq<_> + + let inline toArray (list : FlatList<_>) = + check list + Seq.toArray list ////////// Building ////////// let moveFromBuilder (builder : FlatList<_>.Builder) : FlatList<_> = checkNotNull (nameof builder) builder - builder.MoveToImmutable() + builder.MoveToImmutable () + let ofBuilder (builder : FlatList<_>.Builder) : FlatList<_> = checkNotNull (nameof builder) builder - builder.ToImmutable() + builder.ToImmutable () - let inline builder () : FlatList<'T>.Builder = FlatListFactory.CreateBuilder() - let inline builderWith capacity : FlatList<'T>.Builder = FlatListFactory.CreateBuilder(capacity) + let inline builder () : FlatList<'T>.Builder = FlatListFactory.CreateBuilder () + let inline builderWith capacity : FlatList<'T>.Builder = FlatListFactory.CreateBuilder (capacity) - let toBuilder list: FlatList<_>.Builder = check list; list.ToBuilder() + let toBuilder list : FlatList<_>.Builder = + check list + list.ToBuilder () module Builder = - let inline private check (builder: FlatList<'T>.Builder) = checkNotNull (nameof builder) builder + let inline private check (builder : FlatList<'T>.Builder) = checkNotNull (nameof builder) builder - let add item builder = check builder; builder.Add(item) + let add item builder = + check builder + builder.Add (item) - let inline internal indexNotFound() = raise <| System.Collections.Generic.KeyNotFoundException() + let inline internal indexNotFound () = raise <| System.Collections.Generic.KeyNotFoundException () - let isEmpty (list: FlatList<_>) = list.IsEmpty - let isDefault (list: FlatList<_>) = list.IsDefault - let isDefaultOrEmpty (list: FlatList<_>) = list.IsDefaultOrEmpty + let isEmpty (list : FlatList<_>) = list.IsEmpty + let isDefault (list : FlatList<_>) = list.IsDefault + let isDefaultOrEmpty (list : FlatList<_>) = list.IsDefaultOrEmpty ////////// IReadOnly* ////////// - let length list = check list; list.Length + let length list = + check list + list.Length - let item index list = check list; list.[index] + let item index list = + check list + list.[index] let append list1 list2 : FlatList<'T> = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 - list1.AddRange(list2 : FlatList<_>) + list1.AddRange (list2 : FlatList<_>) /// Searches for the specified object and returns the zero-based index of the first occurrence within the range /// of elements in the list that starts at the specified index and /// contains the specified number of elements. let indexRangeWith comparer index count item list = check list - list.IndexOf(item, index, count, comparer) - let indexRange index count item list = - indexRangeWith HashIdentity.Structural index count item list - let indexFromWith comparer index item list = - indexRangeWith comparer index (length list - index) item - let indexFrom index item list = - indexFromWith HashIdentity.Structural index item list - let indexWith comparer item list = - indexFromWith comparer 0 item list + list.IndexOf (item, index, count, comparer) + + let indexRange index count item list = indexRangeWith HashIdentity.Structural index count item list + let indexFromWith comparer index item list = indexRangeWith comparer index (length list - index) item + let indexFrom index item list = indexFromWith HashIdentity.Structural index item list + let indexWith comparer item list = indexFromWith comparer 0 item list let index item list = indexWith HashIdentity.Structural item list /// Searches for the specified object and returns the zero-based index of the last occurrence within the @@ -85,126 +98,159 @@ module FlatList = /// of elements and ends at the specified index. let lastIndexRangeWith comparer index count item list = check list - list.LastIndexOf(item, index, count, comparer) - let lastIndexRange index count item list = - lastIndexRangeWith HashIdentity.Structural index count item list - let lastIndexFromWith comparer index item list = - lastIndexRangeWith comparer index (index + 1) item list - let lastIndexFrom index item list = - lastIndexFromWith HashIdentity.Structural index item list - let lastIndexWith comparer item list = - lastIndexFromWith comparer (length list - 1) item list + list.LastIndexOf (item, index, count, comparer) + + let lastIndexRange index count item list = lastIndexRangeWith HashIdentity.Structural index count item list + let lastIndexFromWith comparer index item list = lastIndexRangeWith comparer index (index + 1) item list + let lastIndexFrom index item list = lastIndexFromWith HashIdentity.Structural index item list + let lastIndexWith comparer item list = lastIndexFromWith comparer (length list - 1) item list let lastIndex item list = lastIndexWith HashIdentity.Structural item list /// Removes the specified objects from the list with the given comparer. - let removeAllWith (comparer: System.Collections.Generic.IEqualityComparer<_>) items list: FlatList<_> = + let removeAllWith (comparer : System.Collections.Generic.IEqualityComparer<'T>) (items : 'T seq) list : FlatList<_> = check list - list.RemoveRange(items, comparer) + list.RemoveRange (items, comparer) /// Removes the specified objects from the list. let removeAll items list = removeAllWith HashIdentity.Structural items list /// Removes all the elements that do not match the conditions defined by the specified predicate. - let filter predicate list: FlatList<_> = + let filter predicate list : FlatList<_> = check list - System.Predicate(not << predicate) - |> list.RemoveAll + System.Predicate (not << predicate) |> list.RemoveAll /// Removes all the elements that do not match the conditions defined by the specified predicate. let where predicate list = filter predicate list /// Removes a range of elements from the list. - let removeRange index (count: int) list: FlatList<_> = check list; list.RemoveRange(index, count) + let removeRange index (count : int) list : FlatList<_> = + check list + list.RemoveRange (index, count) - let blit source sourceIndex (destination: 'T[]) destinationIndex count = + let blit source sourceIndex (destination : 'T[]) destinationIndex count = checkNotDefault (nameof source) source - try source.CopyTo(sourceIndex, destination, destinationIndex, count) - with exn -> raise exn // throw same exception with the correct stack trace. Update exception code + + try + source.CopyTo (sourceIndex, destination, destinationIndex, count) + with exn -> + raise exn // throw same exception with the correct stack trace. Update exception code let sortRangeWithComparer comparer index count list = check list - list.Sort(index, count, comparer) + list.Sort (index, count, comparer) + let sortRangeWith comparer index count list = sortRangeWithComparer (ComparisonIdentity.FromFunction comparer) index count list + let sortRange index count list = sortRangeWithComparer ComparisonIdentity.Structural index count list - let sortWithComparer (comparer : System.Collections.Generic.IComparer<_>) list = check list; list.Sort(comparer) + + let sortWithComparer (comparer : System.Collections.Generic.IComparer<_>) list = + check list + list.Sort (comparer) + let sortWith comparer list = sortWithComparer (ComparisonIdentity.FromFunction comparer) list - let sort list = check list; list.Sort() + + let sort list = + check list + list.Sort () ////////// Loop-based ////////// let inline private builderWithLengthOf list = builderWith <| length list let init count initializer = - if count < 0 then invalidArg (nameof count) ErrorStrings.InputMustBeNonNegative + if count < 0 then + invalidArg (nameof count) ErrorStrings.InputMustBeNonNegative + let builder = builderWith count + for i = 0 to count - 1 do builder.Add <| initializer i + moveFromBuilder builder - let rec private concatAddLengths (arrs: FlatList>) i acc = - if i >= length arrs then acc - else concatAddLengths arrs (i+1) (acc + arrs.[i].Length) + let rec private concatAddLengths (arrs : FlatList>) i acc = + if i >= length arrs then + acc + else + concatAddLengths arrs (i + 1) (acc + arrs.[i].Length) let concat (arrs : FlatList>) = // consider generalizing - let result: FlatList<'T>.Builder = builderWith <| concatAddLengths arrs 0 0 + let result : FlatList<'T>.Builder = builderWith <| concatAddLengths arrs 0 0 + for i = 0 to length arrs - 1 do - result.AddRange(arrs.[i]: FlatList<'T>) + result.AddRange (arrs.[i] : FlatList<'T>) + moveFromBuilder result let inline map mapping list = check list let builder = builderWithLengthOf list + for i = 0 to length list - 1 do - builder.Add(mapping list.[i]) + builder.Add (mapping list.[i]) + moveFromBuilder builder let countBy projection list = check list // need struct box optimization - let dict = new System.Collections.Generic.Dictionary<'Key, int>(HashIdentity.Structural) + let dict = new System.Collections.Generic.Dictionary<'Key, int> (HashIdentity.Structural) // Build the groupings for v in list do let key = projection v let mutable prev = Unchecked.defaultof<_> - if dict.TryGetValue(key, &prev) then dict.[key] <- prev + 1 else dict.[key] <- 1 + + if dict.TryGetValue (key, &prev) then + dict.[key] <- prev + 1 + else + dict.[key] <- 1 let res = builderWith dict.Count let mutable i = 0 + for group in dict do - res.Add(group.Key, group.Value) + res.Add (group.Key, group.Value) i <- i + 1 + moveFromBuilder res let indexed list = check list let builder = builderWithLengthOf list + for i = 0 to length list - 1 do - builder.Add(i, list.[i]) + builder.Add (i, list.[i]) + moveFromBuilder builder let inline iter action list = check list + for i = 0 to length list - 1 do action list.[i] let iter2 action list1 list2 = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 - let f = OptimizedClosures.FSharpFunc<'T,'U, unit>.Adapt(action) + let f = OptimizedClosures.FSharpFunc<'T, 'U, unit>.Adapt (action) let len = length list1 - if len <> length list2 then invalidArg (nameof list2) ErrorStrings.ListsHaveDifferentLengths + + if len <> length list2 then + invalidArg (nameof list2) ErrorStrings.ListsHaveDifferentLengths + for i = 0 to len - 1 do - f.Invoke(list1.[i], list2.[i]) + f.Invoke (list1.[i], list2.[i]) - let distinctBy projection (list: FlatList<'T>) = - let builder: FlatList<'T>.Builder = builderWith <| length list - let set = System.Collections.Generic.HashSet<'Key>(HashIdentity.Structural) + let distinctBy projection (list : FlatList<'T>) = + let builder : FlatList<'T>.Builder = builderWith <| length list + let set = System.Collections.Generic.HashSet<'Key> (HashIdentity.Structural) let mutable outputIndex = 0 for i = 0 to length list - 1 do let item = list.[i] + if set.Add <| projection item then outputIndex <- outputIndex + 1 Builder.add item builder @@ -214,204 +260,272 @@ module FlatList = let map2 mapping list1 list2 = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(mapping) + let f = OptimizedClosures.FSharpFunc<_, _, _>.Adapt (mapping) let len1 = list1.Length - if len1 <> list2.Length then invalidArg (nameof list2) ErrorStrings.ListsHaveDifferentLengths + + if len1 <> list2.Length then + invalidArg (nameof list2) ErrorStrings.ListsHaveDifferentLengths + let res = builderWith len1 + for i = 0 to len1 - 1 do - res.Add <| f.Invoke(list1.[i], list2.[i]) + res.Add <| f.Invoke (list1.[i], list2.[i]) + moveFromBuilder res let map3 mapping list1 list2 list3 = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 checkNotDefault (nameof list3) list3 - let f = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt(mapping) + let f = OptimizedClosures.FSharpFunc<_, _, _, _>.Adapt (mapping) let len1 = list1.Length - if not (len1 = list2.Length) - then invalidArg (nameof list2) ErrorStrings.ListsHaveDifferentLengths - if not (len1 = list3.Length) - then invalidArg (nameof list3) ErrorStrings.ListsHaveDifferentLengths + + if not (len1 = list2.Length) then + invalidArg (nameof list2) ErrorStrings.ListsHaveDifferentLengths + + if not (len1 = list3.Length) then + invalidArg (nameof list3) ErrorStrings.ListsHaveDifferentLengths let res = builderWith len1 + for i = 0 to len1 - 1 do - res.Add <| f.Invoke(list1.[i], list2.[i], list3.[i]) + res.Add <| f.Invoke (list1.[i], list2.[i], list3.[i]) + moveFromBuilder res + let mapi2 mapping list1 list2 = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 - let f = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt(mapping) + let f = OptimizedClosures.FSharpFunc<_, _, _, _>.Adapt (mapping) let len1 = list1.Length - if len1 <> list2.Length then invalidArg (nameof list2) ErrorStrings.ListsHaveDifferentLengths + + if len1 <> list2.Length then + invalidArg (nameof list2) ErrorStrings.ListsHaveDifferentLengths + let res = builderWith len1 + for i = 0 to len1 - 1 do - res.Add <| f.Invoke(i,list1.[i], list2.[i]) + res.Add <| f.Invoke (i, list1.[i], list2.[i]) + moveFromBuilder res let iteri action list = check list - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(action) + let f = OptimizedClosures.FSharpFunc<_, _, _>.Adapt (action) let len = list.Length + for i = 0 to len - 1 do - f.Invoke(i, list.[i]) + f.Invoke (i, list.[i]) let iteri2 action list1 list2 = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 - let f = OptimizedClosures.FSharpFunc<_,_,_,_>.Adapt(action) + let f = OptimizedClosures.FSharpFunc<_, _, _, _>.Adapt (action) let len1 = list1.Length - if len1 <> list2.Length then invalidArg (nameof list2) ErrorStrings.ListsHaveDifferentLengths + + if len1 <> list2.Length then + invalidArg (nameof list2) ErrorStrings.ListsHaveDifferentLengths + for i = 0 to len1 - 1 do - f.Invoke(i,list1.[i], list2.[i]) + f.Invoke (i, list1.[i], list2.[i]) let mapi mapping list = check list - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(mapping) + let f = OptimizedClosures.FSharpFunc<_, _, _>.Adapt (mapping) let len = list.Length let res = builderWithLengthOf list + for i = 0 to len - 1 do - res.Add <| f.Invoke(i,list.[i]) + res.Add <| f.Invoke (i, list.[i]) + moveFromBuilder res let exists predicate list = check list let len = list.Length - let rec loop i = i < len && (predicate list.[i] || loop (i+1)) + let rec loop i = i < len && (predicate list.[i] || loop (i + 1)) loop 0 let inline contains e list = check list let mutable state = false let mutable i = 0 + while (not state && i < list.Length) do state <- e = list.[i] i <- i + 1 + state let exists2 predicate list1 list2 = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(predicate) + let f = OptimizedClosures.FSharpFunc<_, _, _>.Adapt (predicate) let len1 = list1.Length - if len1 <> list2.Length then invalidArg (nameof list2) ErrorStrings.ListsHaveDifferentLengths - let rec loop i = i < len1 && (f.Invoke(list1.[i], list2.[i]) || loop (i+1)) + + if len1 <> list2.Length then + invalidArg (nameof list2) ErrorStrings.ListsHaveDifferentLengths + + let rec loop i = + i < len1 + && (f.Invoke (list1.[i], list2.[i]) || loop (i + 1)) + loop 0 let forall predicate list = check list let len = list.Length - let rec loop i = i >= len || (predicate list.[i] && loop (i+1)) + let rec loop i = i >= len || (predicate list.[i] && loop (i + 1)) loop 0 let forall2 predicate list1 list2 = checkNotDefault (nameof list1) list1 checkNotDefault (nameof list2) list2 - let f = OptimizedClosures.FSharpFunc<_,_,_>.Adapt(predicate) + let f = OptimizedClosures.FSharpFunc<_, _, _>.Adapt (predicate) let len1 = list1.Length - if len1 <> list2.Length then invalidArg (nameof list2) ErrorStrings.ListsHaveDifferentLengths - let rec loop i = i >= len1 || (f.Invoke(list1.[i], list2.[i]) && loop (i+1)) + + if len1 <> list2.Length then + invalidArg (nameof list2) ErrorStrings.ListsHaveDifferentLengths + + let rec loop i = + i >= len1 + || (f.Invoke (list1.[i], list2.[i]) && loop (i + 1)) + loop 0 let groupBy projection list = check list - let dict = new System.Collections.Generic.Dictionary<'Key,ResizeArray<'T>>(HashIdentity.Structural) + let dict = new System.Collections.Generic.Dictionary<'Key, ResizeArray<'T>> (HashIdentity.Structural) // Build the groupings for i = 0 to (list.Length - 1) do let v = list.[i] let key = projection v - let ok, prev = dict.TryGetValue(key) + let ok, prev = dict.TryGetValue (key) + if ok then - prev.Add(v) + prev.Add (v) else - let prev = new ResizeArray<'T>(1) + let prev = new ResizeArray<'T> (1) dict.[key] <- prev - prev.Add(v) + prev.Add (v) // Return the list-of-lists. let result = builderWith dict.Count let mutable i = 0 + for group in dict do - result.Add(group.Key, ofSeq group.Value) + result.Add (group.Key, ofSeq group.Value) i <- i + 1 moveFromBuilder result let pick chooser list = check list + let rec loop i = if i >= list.Length then - indexNotFound() + indexNotFound () else match chooser list.[i] with - | None -> loop(i+1) + | None -> loop (i + 1) | Some res -> res + loop 0 let tryPick chooser list = check list + let rec loop i = - if i >= list.Length then None else - match chooser list.[i] with - | None -> loop(i+1) - | res -> res + if i >= list.Length then + None + else + match chooser list.[i] with + | None -> loop (i + 1) + | res -> res + loop 0 let choose chooser list = check list let res = builderWith list.Length + for i = 0 to list.Length - 1 do match chooser list.[i] with | None -> () - | Some b -> res.Add(b) + | Some b -> res.Add (b) + ofBuilder res let partition predicate list = check list let res1 = builderWith list.Length let res2 = builderWith list.Length + for i = 0 to list.Length - 1 do let x = list.[i] - if predicate x then res1.Add(x) else res2.Add(x) + if predicate x then res1.Add (x) else res2.Add (x) + ofBuilder res1, ofBuilder res2 let find predicate list = check list + let rec loop i = - if i >= list.Length then indexNotFound() else - if predicate list.[i] then list.[i] else loop (i+1) + if i >= list.Length then indexNotFound () + else if predicate list.[i] then list.[i] + else loop (i + 1) + loop 0 + let tryFind predicate list = check list + let rec loop i = - if i >= list.Length then None else - if predicate list.[i] then Some list.[i] else loop (i+1) + if i >= list.Length then None + else if predicate list.[i] then Some list.[i] + else loop (i + 1) + loop 0 + let findBack predicate list = check list + let rec loop i = - if i < 0 then indexNotFound() else - if predicate list.[i] then list.[i] else loop (i - 1) + if i < 0 then indexNotFound () + else if predicate list.[i] then list.[i] + else loop (i - 1) + loop <| length list - 1 + let tryFindBack predicate list = check list + let rec loop i = - if i < 0 then None else - if predicate list.[i] then Some list.[i] else loop (i+1) + if i < 0 then None + else if predicate list.[i] then Some list.[i] + else loop (i + 1) + loop <| length list - 1 let findIndexBack predicate list = check list + let rec loop i = - if i < 0 then indexNotFound() else - if predicate list.[i] then i else loop (i - 1) + if i < 0 then indexNotFound () + else if predicate list.[i] then i + else loop (i - 1) + loop <| length list - 1 let tryFindIndexBack predicate list = check list + let rec loop i = - if i < 0 then None else - if predicate list.[i] then Some i else loop (i - 1) + if i < 0 then None + else if predicate list.[i] then Some i + else loop (i - 1) + loop <| length list - 1 // TODO: windowed @@ -422,9 +536,12 @@ module FlatList = let inline private lengthWhile predicate list = check list let mutable count = 0 + while count < list.Length && predicate list.[count] do count <- count + 1 + count + let takeWhile predicate list = take (lengthWhile predicate list) list let skip index list = removeRange 0 index list @@ -440,8 +557,10 @@ module FlatList = let head list = item 0 list let tryItem index list = - if index >= length list || index < 0 then None - else Some(list.[index]) + if index >= length list || index < 0 then + None + else + Some (list.[index]) let tryHead list = tryItem 0 list @@ -460,7 +579,7 @@ module FlatList = let collect mapping list = concat <| map mapping list let inline build f = - let builder = builder() + let builder = builder () f builder moveFromBuilder builder @@ -469,6 +588,6 @@ module FlatList = f builder moveFromBuilder builder - ////////// +////////// module ImmutableArray = FlatList diff --git a/src/FSharp.Collections.Immutable/immutable-collection-util.fs b/src/FSharp.Collections.Immutable/ImmutableCollectionUtil.fs similarity index 73% rename from src/FSharp.Collections.Immutable/immutable-collection-util.fs rename to src/FSharp.Collections.Immutable/ImmutableCollectionUtil.fs index af62e58..608fe4f 100644 --- a/src/FSharp.Collections.Immutable/immutable-collection-util.fs +++ b/src/FSharp.Collections.Immutable/ImmutableCollectionUtil.fs @@ -1,4 +1,4 @@ -#if INTERACTIVE +#if INTERACTIVE namespace global #else namespace FSharp.Collections.Immutable @@ -6,14 +6,14 @@ namespace FSharp.Collections.Immutable [] module internal ImmutableCollectionUtil = - let inline checkNotNull name arg = + let inline checkNotNull name (arg : _ | null) = match arg with - |null -> nullArg name - |_ -> () + | null -> nullArg name + | _ -> () module internal ErrorStrings = [] let InputMustBeNonNegative = "The input must be non-negative." [] - let ListsHaveDifferentLengths = "The lists have different lengths." \ No newline at end of file + let ListsHaveDifferentLengths = "The lists have different lengths." diff --git a/src/FSharp.Collections.Immutable/immutable-list.fs b/src/FSharp.Collections.Immutable/ImmutableList.fs similarity index 50% rename from src/FSharp.Collections.Immutable/immutable-list.fs rename to src/FSharp.Collections.Immutable/ImmutableList.fs index 7586d64..48ced7c 100644 --- a/src/FSharp.Collections.Immutable/immutable-list.fs +++ b/src/FSharp.Collections.Immutable/ImmutableList.fs @@ -2,6 +2,7 @@ namespace global #else namespace FSharp.Collections.Immutable + open FSharp.Collections.Immutable.ImmutableCollectionUtil #endif open System.Collections.Immutable @@ -11,35 +12,46 @@ module ImmutableList = ////////// Factory ////////// - let inline internal check (list: IImmutableList<_>) = checkNotNull (nameof list) list + let inline internal check (list : IImmutableList<_>) = checkNotNull (nameof list) list - let inline empty<'T> = ImmutableList.Create<'T>() + let inline empty<'T> = ImmutableList.Create<'T> () let inline singleton<'T> (item : 'T) : ImmutableList<'T> = ImmutableList.Create<'T> (item) - let inline ofSeq source = checkNotNull (nameof source) source; ImmutableList.CreateRange source - let inline ofArray (source : _ array) = checkNotNull (nameof source) source; ImmutableList.CreateRange source + let inline ofSeq source = + checkNotNull (nameof source) source + ImmutableList.CreateRange source + + let inline ofArray (source : _ array) = + checkNotNull (nameof source) source + ImmutableList.CreateRange source + let inline ofList (list : _ list) = ofSeq list let inline toSeq (list : ImmutableList<_>) = list :> seq<_> - let inline toArray (list : ImmutableList<_>) = check list; Seq.toArray list + + let inline toArray (list : ImmutableList<_>) = + check list + Seq.toArray list ////////// Building ////////// - let inline ofBuilder (builder : ImmutableList<_>.Builder) = builder.ToImmutable() + let inline ofBuilder (builder : ImmutableList<_>.Builder) = builder.ToImmutable () - let inline builder () = ImmutableList.CreateBuilder() + let inline builder () = ImmutableList.CreateBuilder () - let toBuilder (list: ImmutableList<_>) = check list; list.ToBuilder() + let toBuilder (list : ImmutableList<_>) = + check list + list.ToBuilder () let inline build f = - let builder = builder() + let builder = builder () f builder - builder.ToImmutable() + builder.ToImmutable () let inline update f list = let builder = toBuilder list f builder - builder.ToImmutable() + builder.ToImmutable () open System.Collections.Generic @@ -47,63 +59,80 @@ module ImmutableList = ////////// IReadOnly* ////////// - let length list = check list; list.Count + let length list = + check list + list.Count - let item index list = check list; list.[index] + let item index list = + check list + list.[index] ////////// ImmutableList ////////// - let contains item (list : ImmutableList<_>) = list.Contains(item) + let contains item (list : ImmutableList<_>) = list.Contains (item) - let reverse (list : ImmutableList<_>) = list.Reverse() + let reverse (list : ImmutableList<_>) = list.Reverse () - let reverseRange (index, count) (list : ImmutableList<_>) = list.Reverse(index, count) + let reverseRange (index, count) (list : ImmutableList<_>) = list.Reverse (index, count) ////////// IImmutableList ////////// /// Replaces an element in the list at a given position with the specified element. - let withItem index value list = check list; list.SetItem(index, value) + let withItem index value list = + check list + list.SetItem (index, value) /// Returns a new list with the first matching element in the list replaced with the specified element with /// the given comparer. let replaceWith comparer oldValue value list = check list - list.Replace(oldValue, value, comparer) + list.Replace (oldValue, value, comparer) /// Returns a new list with the first matching element in the list replaced with the specified element. - let replace oldValue value list = - replaceWith HashIdentity.Structural oldValue value list + let replace oldValue value list = replaceWith HashIdentity.Structural oldValue value list /// Creates a list with all the items removed, but with the same sorting and ordering semantics as /// this list. - let clear list = check list; list.Clear() + let clear list = + check list + list.Clear () /// Makes a copy of the list, and adds the specified object to the end of the copied list. - let add item list = check list; list.Add item + let add item list = + check list + list.Add item /// Makes a copy of the list and adds the specified objects to the end of the copied list. - let append list items = check list; list.AddRange items + let append list items = + check list + list.AddRange items /// Inserts the specified element at the specified index in a immutable list. - let insert index item list = check list; list.Insert(index, item) + let insert index item list = + check list + list.Insert (index, item) /// Inserts the specified elements at the specified index in the immutable list. - let insertRange index items list = check list; list.InsertRange(index, items) // TODO: rename + let insertRange index items list = + check list + list.InsertRange (index, items) // TODO: rename /// Removes the first occurrence of a specified object from this immutable list using the given comparer. - let removeWith comparer item list = check list; list.Remove(item, comparer) + let removeWith comparer item list = + check list + list.Remove (item, comparer) /// Removes the first occurrence of a specified object from this immutable list. let remove item list = removeWith HashIdentity.Structural item list /// Removes the specified objects from the list with the given comparer. - let exceptWith (comparer: IEqualityComparer<_>) items list = + let exceptWith (comparer : IEqualityComparer<_>) items list = check list - list.RemoveRange(items, comparer) + list.RemoveRange (items, comparer) /// Removes the specified objects from the list. let except items list = exceptWith HashIdentity.Structural items list @@ -112,29 +141,29 @@ module ImmutableList = /// Removes all the elements that do not match the conditions defined by the specified predicate. let filter predicate list = check list - Predicate(not << predicate) - |> list.RemoveAll + Predicate (not << predicate) |> list.RemoveAll /// Removes a range of elements from the System.Collections.Immutable.IImmutableList`1. - let removeRange index (count: int) list = check list; list.RemoveRange(index, count) + let removeRange index (count : int) list = + check list + list.RemoveRange (index, count) /// Removes the element at the specified index of the immutable list. - let removeAt index list = check list; list.RemoveAt index + let removeAt index list = + check list + list.RemoveAt index /// Searches for the specified object and returns the zero-based index of the first occurrence within the range /// of elements in the list that starts at the specified index and /// contains the specified number of elements. let indexRangeWith comparer index count item list = - check list; - list.IndexOf(item, index, count, comparer) - let indexRange index count item list = - indexRangeWith HashIdentity.Structural index count item list - let indexFromWith comparer index item list = - indexRangeWith comparer index (length list - index) item - let indexFrom index item list = - indexFromWith HashIdentity.Structural index item list - let indexWith comparer item list = - indexFromWith comparer 0 item list + check list + list.IndexOf (item, index, count, comparer) + + let indexRange index count item list = indexRangeWith HashIdentity.Structural index count item list + let indexFromWith comparer index item list = indexRangeWith comparer index (length list - index) item + let indexFrom index item list = indexFromWith HashIdentity.Structural index item list + let indexWith comparer item list = indexFromWith comparer 0 item list let index item list = indexWith HashIdentity.Structural item list @@ -143,74 +172,92 @@ module ImmutableList = /// of elements and ends at the specified index. let lastIndexRangeWith comparer index count item list = check list - list.LastIndexOf(item, index, count, comparer) - let lastIndexRange index count item list = - lastIndexRangeWith HashIdentity.Structural index count item list - let lastIndexFromWith comparer index item list = - lastIndexRangeWith comparer index (index + 1) item list - let lastIndexFrom index item list = - lastIndexFromWith HashIdentity.Structural index item list - let lastIndexWith comparer item list = - lastIndexFromWith comparer (length list - 1) item list + list.LastIndexOf (item, index, count, comparer) + + let lastIndexRange index count item list = lastIndexRangeWith HashIdentity.Structural index count item list + let lastIndexFromWith comparer index item list = lastIndexRangeWith comparer index (index + 1) item list + let lastIndexFrom index item list = lastIndexFromWith HashIdentity.Structural index item list + let lastIndexWith comparer item list = lastIndexFromWith comparer (length list - 1) item list let lastIndex item list = lastIndexWith HashIdentity.Structural item list ////////// Filter-based ////////// - let filterFold (predicate: 'State -> 'T -> bool * 'State) initial list = + let filterFold (predicate : 'State -> 'T -> bool * 'State) initial list = let state = ref initial - filter (fun item -> - let condition, state' = predicate !state item - state := state' - condition) list, !state + + filter + (fun item -> + let condition, state' = predicate !state item + state := state' + condition + ) + list, + !state let skipWhile predicate list = let condition = ref true - filter (fun item -> - if !condition then - condition := !condition && predicate item - !condition - else false) list + + filter + (fun item -> + if !condition then + condition := !condition && predicate item + !condition + else + false + ) + list let skipUntil predicate list = skipWhile (not << predicate) list let takeWhile predicate list = let condition = ref true - filter (fun item -> - if !condition then - condition := !condition && predicate item - not !condition - else true) list + + filter + (fun item -> + if !condition then + condition := !condition && predicate item + not !condition + else + true + ) + list + let takeUntil predicate list = takeWhile (not << predicate) list ////////// Loop-based ////////// let concat lists = checkNotNull (nameof lists) lists - build <| fun result -> + + build + <| fun result -> for list in lists do result.AddRange list let map mapping list = check list - build <| fun builder -> + + build + <| fun builder -> for item in list do - builder.Add(mapping item) + builder.Add (mapping item) let choose chooser list = check list - build <| fun builder -> + + build + <| fun builder -> for item in list do match chooser item with - |Some item -> builder.Add item - |None -> () + | Some item -> builder.Add item + | None -> () ////////// Based on other operations ////////// let isEmpty list = length list = 0 - let take count list = - removeRange count (length list - count) list + let take count list = removeRange count (length list - count) list let skip index list = removeRange 0 index list @@ -225,8 +272,10 @@ module ImmutableList = let tail list = removeAt 0 list let tryItem index list = - if index >= length list || index < 0 then None - else Some(list.[index]) + if index >= length list || index < 0 then + None + else + Some (list.[index]) let tryHead list = tryItem 0 list @@ -245,38 +294,60 @@ module ImmutableList = // throw the same exception try Seq.init count initializer |> ignore - with - |exn -> raise exn // get the right stack trace - build <| fun builder -> + with exn -> + raise exn // get the right stack trace + + build + <| fun builder -> for i = 0 to count - 1 do builder.Add <| initializer i let unfold generator state = - let rec unfoldLoop state (builder: ImmutableList<_>.Builder) = + let rec unfoldLoop state (builder : ImmutableList<_>.Builder) = match generator state with - |Some(state, item) -> builder.Add(item); unfoldLoop state builder - |None -> () + | Some (state, item) -> + builder.Add (item) + unfoldLoop state builder + | None -> () + build <| unfoldLoop state ////////// Seq-based ////////// - let find predicate list = check list; Seq.find predicate list + let find predicate list = + check list + Seq.find predicate list - let tryFind predicate list = check list; Seq.tryFind predicate list + let tryFind predicate list = + check list + Seq.tryFind predicate list - let findIndex predicate list = check list; Seq.findIndex predicate list + let findIndex predicate list = + check list + Seq.findIndex predicate list - let tryFindIndex predicate list = check list; Seq.tryFindIndex predicate list + let tryFindIndex predicate list = + check list + Seq.tryFindIndex predicate list - let pick chooser list = check list; Seq.pick chooser list + let pick chooser list = + check list + Seq.pick chooser list - let fold folder state list = check list; Seq.fold folder state list + let fold folder state list = + check list + Seq.fold folder state list - let forall predicate list = check list; Seq.forall predicate list + let forall predicate list = + check list + Seq.forall predicate list - let forall2 predicate (list1: IImmutableList<_>) (list2: IImmutableList<_>) = - checkNotNull (nameof list1) list1; checkNotNull (nameof list2) list2 + let forall2 predicate (list1 : IImmutableList<_>) (list2 : IImmutableList<_>) = + checkNotNull (nameof list1) list1 + checkNotNull (nameof list2) list2 Seq.forall2 predicate list1 list2 - let iter action list = check list; Seq.iter action list + let iter action list = + check list + Seq.iter action list diff --git a/src/FSharp.Collections.Immutable/IndexedSeq.fs b/src/FSharp.Collections.Immutable/IndexedSeq.fs new file mode 100644 index 0000000..7d388b4 --- /dev/null +++ b/src/FSharp.Collections.Immutable/IndexedSeq.fs @@ -0,0 +1,17 @@ +namespace FSharp.Collections.Immutable + +type IIndexedSeq<'T> = System.Collections.Generic.IReadOnlyList<'T> + +module IndexedSeq = + + let check (seq : IIndexedSeq<_>) = checkNotNull (nameof seq) seq + + let item index seq = + check seq + seq.[index] + + let length seq = + check seq + seq.Count + +module ReadOnlyList = IndexedSeq diff --git a/src/FSharp.Collections.Immutable/Maps.fs b/src/FSharp.Collections.Immutable/Maps.fs new file mode 100644 index 0000000..12f5d63 --- /dev/null +++ b/src/FSharp.Collections.Immutable/Maps.fs @@ -0,0 +1,339 @@ +namespace FSharp.Collections.Immutable + +open System.Collections.Generic + +type IMap<'Key, 'Value> = System.Collections.Immutable.IImmutableDictionary<'Key, 'Value> + +type HashMap<'Key, 'Value when 'Key : not null> = System.Collections.Immutable.ImmutableDictionary<'Key, 'Value> + +type HashMapBuilder<'Key, 'Value when 'Key : not null> = HashMap<'Key, 'Value>.Builder + +[] +module HashMap = + + type internal HashMapFactory = System.Collections.Immutable.ImmutableDictionary + + let inline check (map : HashMap<_, _>) = checkNotNull (nameof map) map + + ////////// Creating ////////// + + let inline empty<'Key, 'Value when 'Key : not null> = HashMapFactory.Create<'Key, 'Value> () + let inline singleton item = empty.Add (item) + + let inline ofSeq source = HashMapFactory.CreateRange (source) + + let inline ofSeqWith getKey source = + source + |> Seq.map (fun i -> KeyValuePair (getKey i, i)) + |> HashMapFactory.CreateRange + + let inline ofSeqGroupBy getKey source = + source + |> Seq.groupBy getKey + |> Seq.map (fun (key, value) -> KeyValuePair (key, value)) + |> HashMapFactory.CreateRange + + let inline ofArray (source : _ array) = HashMapFactory.CreateRange (source) + + let inline toSeq (map : HashMap<_, _>) = map :> seq<_> + + let inline toArray (map : HashMap<_, _>) = + check map + Seq.toArray map + + ////////// Building ////////// + + let inline builder () = HashMapFactory.CreateBuilder () + let inline builderWithKeyComparer comparer = HashMapFactory.CreateBuilder (comparer) + let inline builderWithComparers keyComparer valueComparer = HashMapFactory.CreateBuilder (keyComparer, valueComparer) + + let inline ofBuilder (mapBuilder : HashMapBuilder<_, _>) = + checkNotNull (nameof mapBuilder) mapBuilder + mapBuilder.ToImmutable () + + let inline toBuilder map : HashMapBuilder<_, _> = + check map + map.ToBuilder () + + let inline ofKeyComparer<'Key, 'Value when 'Key : not null> comparer = HashMapFactory.Create<'Key, 'Value> (comparer) + let inline ofComparers<'Key, 'Value when 'Key : not null> keyComparer valueComparer = + HashMapFactory.Create<'Key, 'Value> (keyComparer, valueComparer) + + + let inline isEmpty map = + check map + map.IsEmpty + + let inline length map = + check map + map.Count + + let inline keyComparer map = + check map + map.KeyComparer + + let inline valueComparer map = + check map + map.ValueComparer + + let inline containsKey key map = + check map + map.ContainsKey key + + let inline find key map = + check map + map.[key] + + let inline tryFind key map = + check map + + match map.TryGetValue (key) with + | true, value -> Some value + | false, _ -> None + + let inline vTryFind key map = + check map + + match map.TryGetValue (key) with + | true, value -> ValueSome value + | false, _ -> ValueNone + + let inline pick chooser map = + check map + map |> Seq.pick (fun kvp -> chooser kvp.Key kvp.Value) + + let inline tryPick chooser map = + check map + map |> Seq.tryPick (fun kvp -> chooser kvp.Key kvp.Value) + + let inline vTryPick chooser map = + check map + + match map |> Seq.tryPick (fun kvp -> chooser kvp.Key kvp.Value) with + | Some value -> ValueSome value + | None -> ValueNone + + let inline iter action (map : HashMap<_, _>) = + check map + map |> Seq.iter (fun kvp -> action kvp.Key kvp.Value) + + let inline exists predicate map = + check map + map |> Seq.exists (fun kvp -> predicate kvp.Key kvp.Value) + + let inline add key value map : HashMap<_, _> = + check map + map.Add (key, value) + + let inline append map pairs : HashMap<_, _> = + check map + checkNotNull (nameof pairs) pairs + map.AddRange pairs + + let inline remove key map : HashMap<_, _> = + check map + map.Remove key + + let inline except keys map : HashMap<_, _> = + check map + map.RemoveRange keys + + let inline clear map : HashMap<_, _> = + check map + map.Clear () + + let inline filter predicate map = + map + |> Seq.filter (fun (kvp : KeyValuePair<_, _>) -> predicate kvp.Key kvp.Value) + + let inline forall predicate map = + map + |> Seq.forall (fun (kvp : KeyValuePair<_, _>) -> predicate kvp.Key kvp.Value) + + let inline map mapping map' = + map' + |> Seq.map (fun (kvp : KeyValuePair<_, _>) -> mapping kvp.Key kvp.Value) + |> ofSeq + + let inline where predicate map = + map + |> Seq.where (fun (kvp : KeyValuePair<_, _>) -> predicate kvp.Key kvp.Value) + |> empty.AddRange + + +type SortedMap<'Key, 'Value when 'Key : not null> = System.Collections.Immutable.ImmutableSortedDictionary<'Key, 'Value> + +type SortedMapBuilder<'Key, 'Value when 'Key : not null> = SortedMap<'Key, 'Value>.Builder + +[] +module SortedMap = + + type internal SortedMapFactory = System.Collections.Immutable.ImmutableSortedDictionary + + let inline check (sortedMap : SortedMap<_, _>) = checkNotNull (nameof sortedMap) sortedMap + + ////////// Creating ////////// + + let inline empty<'Key, 'Value when 'Key : not null> = SortedMapFactory.Create<'Key, 'Value> () + let inline singleton item = SortedMapFactory.Create (item) + + let inline ofSeq source = SortedMapFactory.CreateRange (source) + + let inline ofSeqWith getKey source = + source + |> Seq.map (fun i -> KeyValuePair (getKey i, i)) + |> SortedMapFactory.CreateRange + + let inline ofSeqGroupBy getKey source = + source + |> Seq.groupBy getKey + |> Seq.map (fun (key, value) -> KeyValuePair (key, value)) + + let inline ofArray (source : _ array) = SortedMapFactory.CreateRange (source) + + let inline toSeq (map : SortedMap<_, _>) = map :> seq<_> + + let inline toArray (map : SortedMap<_, _>) = + check map + Seq.toArray map + + ////////// Building ////////// + + let inline builder () = SortedMapFactory.CreateBuilder () + let inline builderWithKeyComparer comparer = SortedMapFactory.CreateBuilder (comparer) + let inline builderWithComparers keyComparer valueComparer = SortedMapFactory.CreateBuilder (keyComparer, valueComparer) + + let inline ofBuilder (sortedMapBuilder : SortedMapBuilder<_, _>) = + checkNotNull (nameof sortedMapBuilder) sortedMapBuilder + sortedMapBuilder.ToImmutable () + + let inline toBuilder map : SortedMapBuilder<_, _> = + check map + map.ToBuilder () + + let inline ofKeyComparer<'Key, 'Value when 'Key : not null> comparer = SortedMapFactory.Create<'Key, 'Value> (comparer) + let inline ofComparers<'Key, 'Value when 'Key : not null> keyComparer valueComparer = + SortedMapFactory.Create<'Key, 'Value> (keyComparer, valueComparer) + + + let inline isEmpty map = + check map + map.IsEmpty + + let inline length map = + check map + map.Count + + let inline keyComparer map = + check map + map.KeyComparer + + let inline valueComparer map = + check map + map.ValueComparer + + let inline containsKey key map = + check map + map.ContainsKey key + + let inline find key map = + check map + map.[key] + + let inline tryFind key map = + check map + + match map.TryGetValue (key) with + | true, value -> Some value + | false, _ -> None + + let inline vTryFind key map = + check map + + match map.TryGetValue (key) with + | true, value -> ValueSome value + | false, _ -> ValueNone + + let inline pick chooser map = + check map + map |> Seq.pick (fun kvp -> chooser kvp.Key kvp.Value) + + let inline tryPick chooser map = + check map + map |> Seq.tryPick (fun kvp -> chooser kvp.Key kvp.Value) + + let inline vTryPick chooser map = + check map + + match map |> Seq.tryPick (fun kvp -> chooser kvp.Key kvp.Value) with + | Some value -> ValueSome value + | None -> ValueNone + + let inline iter action (map : SortedMap<_, _>) = + check map + map |> Seq.iter (fun kvp -> action kvp.Key kvp.Value) + + let inline exists predicate map = + check map + map |> Seq.exists (fun kvp -> predicate kvp.Key kvp.Value) + + let inline add key value map : SortedMap<_, _> = + check map + map.Add (key, value) + + let inline append map pairs : SortedMap<_, _> = + check map + checkNotNull (nameof pairs) pairs + map.AddRange pairs + + let inline remove key map : SortedMap<_, _> = + check map + map.Remove key + + let inline except keys map : SortedMap<_, _> = + check map + map.RemoveRange keys + + let inline clear map : SortedMap<_, _> = + check map + map.Clear () + + let inline findKey predicate map = + check map + + match (map |> Seq.tryFind (fun kvp -> predicate kvp.Key kvp.Value)) with + | Some value -> value.Key + | None -> raise (new KeyNotFoundException ()) + + let inline tryFindKey predicate map = + check map + map |> Seq.tryFind (fun kvp -> predicate kvp.Key kvp.Value) + + let inline vTryFindKey predicate map = + check map + + match (map |> Seq.tryFind (fun kvp -> predicate kvp.Key kvp.Value)) with + | Some value -> ValueSome value.Key + | None -> ValueNone + + let inline filter predicate map = + map + |> Seq.filter (fun (kvp : KeyValuePair<_, _>) -> predicate kvp.Key kvp.Value) + + let inline forall predicate map = + map + |> Seq.forall (fun (kvp : KeyValuePair<_, _>) -> predicate kvp.Key kvp.Value) + + let inline map mapping (map' : SortedMap<_, _>) = + map' + |> Seq.map (fun (kvp : KeyValuePair<_, _>) -> mapping kvp.Key kvp.Value) + |> ofSeq + + let inline where predicate map = + map + |> Seq.where (fun (kvp : KeyValuePair<_, _>) -> predicate kvp.Key kvp.Value) + |> empty.AddRange diff --git a/src/FSharp.Collections.Immutable/Queue.fs b/src/FSharp.Collections.Immutable/Queue.fs new file mode 100644 index 0000000..dd8d64f --- /dev/null +++ b/src/FSharp.Collections.Immutable/Queue.fs @@ -0,0 +1,132 @@ +namespace FSharp.Collections.Immutable + +type IQueue<'T> = System.Collections.Immutable.IImmutableQueue<'T> + +type Queue<'T> = System.Collections.Immutable.ImmutableQueue<'T> + +[] +module Queue = + + type internal QueueFactory = System.Collections.Immutable.ImmutableQueue + + let inline private check (queue : IQueue<_>) = checkNotNull (nameof queue) queue + + let inline empty<'T> : Queue<'T> = QueueFactory.Create<'T> () + + let inline singleton<'T> (item : 'T) : Queue<'T> = QueueFactory.Create<'T> (item) + + let inline ofSeq (source : 'T seq) : Queue<'T> = QueueFactory.CreateRange source + + let inline toSeq (queue : Queue<_>) = queue :> seq<_> + + let isEmpty queue = + check queue + queue.IsEmpty + + let clear queue : IQueue<_> = + check queue + queue.Clear () + + let enqueue item queue : IQueue<_> = + check queue + queue.Enqueue item + + let head queue = + check queue + queue.Peek () + + let tail queue : IQueue<_> = + check queue + queue.Dequeue () + + ////////// + + let (|Cons|Nil|) queue = // consider renaming + if isEmpty queue then Nil else Cons (head queue, tail queue) + + ////////// Predicate based ////////// + + let filter predicate queue = + let rec loop queue result = + match queue with + | Cons (head, tail) -> + loop tail + <| if predicate head then enqueue head result else result + | Nil -> result + + loop queue <| clear queue + + ////////// Seq-based ////////// + + let find predicate queue = + check queue + Seq.find predicate queue + + let tryFind predicate queue = + check queue + Seq.tryFind predicate queue + + let findIndex predicate queue = + check queue + Seq.findIndex predicate queue + + let tryFindIndex predicate queue = + check queue + Seq.tryFindIndex predicate queue + + let pick chooser queue = + check queue + Seq.pick chooser queue + + let tryPick chooser queue = + check queue + Seq.tryPick chooser queue + + let iter action queue = + check queue + Seq.iter action queue + + let iteri action queue = + check queue + Seq.iteri action queue + + let iter2 action (queue1 : IQueue<_>) (queue2 : IQueue<_>) = + checkNotNull (nameof queue1) queue1 + checkNotNull (nameof queue2) queue2 + Seq.iter2 action queue1 queue2 + + let fold folder state queue = + check queue + Seq.fold folder state queue + + let forall predicate queue = + check queue + Seq.forall predicate + + let exists predicate queue = + check queue + Seq.exists predicate queue + + let reduce reduction queue = + check queue + Seq.reduce reduction queue + + let inline sum queue = + check queue + Seq.sum queue + + let inline sumBy projection queue = + check queue + Seq.sumBy projection queue + + let inline average queue = + check queue + Seq.average queue + + let inline averageBy projection queue = + check queue + Seq.averageBy projection + +module ImmutableQueue = Queue diff --git a/src/FSharp.Collections.Immutable/seq.fs b/src/FSharp.Collections.Immutable/Seq.fs similarity index 100% rename from src/FSharp.Collections.Immutable/seq.fs rename to src/FSharp.Collections.Immutable/Seq.fs diff --git a/src/FSharp.Collections.Immutable/Sets.fs b/src/FSharp.Collections.Immutable/Sets.fs new file mode 100644 index 0000000..cbdba22 --- /dev/null +++ b/src/FSharp.Collections.Immutable/Sets.fs @@ -0,0 +1,266 @@ +namespace FSharp.Collections.Immutable + +type ISet<'T> = System.Collections.Immutable.IImmutableSet<'T> + +type HashSet<'T> = System.Collections.Immutable.ImmutableHashSet<'T> +type HashSetBuilder<'T> = HashSet<'T>.Builder + +[] +module HashSet = + + type internal HashSetFactory = System.Collections.Immutable.ImmutableHashSet + + let inline check (set : HashSet<_>) = checkNotNull (nameof set) set + + ////////// Creating ////////// + + let inline empty<'T> = HashSetFactory.Create<'T> () + let inline singleton<'T> (item : 'T) = HashSetFactory.Create<'T> (item) + let inline ofSeq source = HashSetFactory.CreateRange (source) + let inline ofSeqWithComparer comparer source = HashSetFactory.Create (comparer, items = (source |> Array.ofSeq)) + let inline ofArray (source : _ array) = HashSetFactory.CreateRange (source) + + let inline ofBuilder (hashSetBuilder : HashSetBuilder<_>) = + checkNotNull (nameof hashSetBuilder) hashSetBuilder + hashSetBuilder.ToImmutable () + + let inline ofComparer<'T> comparer = HashSetFactory.Create<'T> (equalityComparer = comparer) + + let inline toSeq (set : HashSet<_>) = set :> seq<_> + + let inline toArray (set : HashSet<_>) = + check set + Seq.toArray set + + ////////// Building ////////// + + let inline builder () = HashSetFactory.CreateBuilder () + let inline builderWith capacity : HashSet<'T>.Builder = HashSetFactory.CreateBuilder (capacity) + let inline builderWithComparer comparer = HashSetFactory.CreateBuilder (comparer) + + let inline toBuilder set : HashSetBuilder<_> = + check set + set.ToBuilder () + + let inline keyComparer set = + check set + set.KeyComparer + + let inline length set = + check set + set.Count + + let inline isEmpty set = + check set + set.IsEmpty + + let inline contains value set = + check set + set.Contains value + + let inline exists predicate map = + check map + map |> Seq.exists predicate + + let inline isSubset (set1 : HashSet<_>) set2 = + check set1 + set1.IsSubsetOf set2 + + let inline isProperSubset (set1 : HashSet<_>) set2 = + check set1 + set1.IsProperSubsetOf set2 + + let inline isSuperset (set1 : HashSet<_>) set2 = + check set1 + set1.IsSupersetOf set2 + + let inline isProperSuperset (set1 : HashSet<_>) set2 = + check set1 + set1.IsProperSupersetOf set2 + + let inline add value set : HashSet<_> = + check set + set.Add (value) + + let inline union set values : HashSet<_> = + check set + values |> set.Union + + let inline unionMany (sets : HashSet<_> seq) = Seq.reduce union sets + + let inline intersect (set1 : HashSet<_>) set2 = + check set1 + set1.Intersect set2 + + let inline intersectMany (sets : HashSet<_> seq) = Seq.reduce intersect sets + + let inline remove value set : HashSet<_> = + check set + set.Remove value + + let inline difference values set : HashSet<_> = + check set + values |> set.Except + + let inline clear set : HashSet<_> = + check set + set.Clear () + + let inline filter predicate set = set |> Seq.filter predicate |> empty.Union + + let inline where predicate set = set |> Seq.where predicate |> empty.Union + + let inline pick chooser set = + check set + set |> Seq.pick chooser + + let inline tryPick chooser set = + check set + set |> Seq.tryPick chooser + + let inline vTryPick chooser set = + check set + + match set |> Seq.tryPick chooser with + | Some value -> ValueSome value + | None -> ValueNone + + let inline map mapping (set : HashSet<_>) = set |> Seq.map mapping |> ofSeq + + let inline forall predicate set = set |> Seq.forall predicate + + let inline iter action (set : HashSet<_>) = + check set + set |> Seq.iter action + +type SortedSet<'T> = System.Collections.Immutable.ImmutableSortedSet<'T> +type SortedSetBuilder<'T> = SortedSet<'T>.Builder + +[] +module SortedSet = + + type internal SortedSetFactory = System.Collections.Immutable.ImmutableSortedSet + + let inline check (sortedSet : SortedSet<_>) = checkNotNull (nameof sortedSet) sortedSet + + ////////// Creating ////////// + + let inline empty<'T> = SortedSetFactory.Create<'T> () + let inline singleton<'T> (item : 'T) = SortedSetFactory.Create<'T> (item) + let inline ofSeq source = SortedSetFactory.CreateRange (source) + let inline ofSeqWithComparer comparer source = SortedSetFactory.Create (comparer, items = (source |> Array.ofSeq)) + let inline ofArray (source : _ array) = SortedSetFactory.CreateRange (source) + + let inline ofBuilder (sortedSetBuilder : SortedSetBuilder<_>) = + checkNotNull (nameof sortedSetBuilder) sortedSetBuilder + sortedSetBuilder.ToImmutable () + + let inline ofComparer<'T> comparer = SortedSetFactory.Create<'T> (comparer = comparer) + + let inline toSeq (set : SortedSet<_>) = set :> seq<_> + + let inline toArray (set : SortedSet<_>) = + check set + Seq.toArray set + + ////////// Building ////////// + + let inline builder () = SortedSetFactory.CreateBuilder () + let inline builderWith capacity : SortedSet<'T>.Builder = SortedSetFactory.CreateBuilder (capacity) + let inline builderWithComparer comparer = SortedSetFactory.CreateBuilder (comparer) + + let inline toBuilder set : SortedSetBuilder<_> = + check set + set.ToBuilder () + + let inline keyComparer set = + check set + set.KeyComparer + + + let inline length set = + check set + set.Count + + let inline contains value set = + check set + set.Contains value + + let inline isEmpty set = + check set + set.IsEmpty + + let inline exists predicate map = + check map + map |> Seq.exists predicate + + let inline isSubset (set1 : SortedSet<_>) set2 = + check set1 + set1.IsSubsetOf set2 + + let inline isProperSubset (set1 : SortedSet<_>) set2 = + check set1 + set1.IsProperSubsetOf set2 + + let inline isSuperset (set1 : SortedSet<_>) set2 = + check set1 + set1.IsSupersetOf set2 + + let inline isProperSuperset (set1 : SortedSet<_>) set2 = + check set1 + set1.IsProperSupersetOf set2 + + let inline add value set : SortedSet<_> = + check set + set.Add (value) + + let inline union set values : SortedSet<_> = + check set + values |> set.Union + + let inline unionMany (sets : SortedSet<_> seq) = Seq.reduce union sets + let inline intersect (set1 : SortedSet<_>) set2 = set1.Intersect set2 + let inline intersectMany (sets : SortedSet<_> seq) = Seq.reduce intersect sets + + let inline remove value set : SortedSet<_> = + check set + set.Remove value + + let inline difference values set : SortedSet<_> = + check set + values |> set.Except + + let inline clear set : SortedSet<_> = + check set + set.Clear () + + let inline filter predicate set = set |> Seq.filter predicate |> empty.Union + + let inline where predicate set = set |> Seq.where predicate |> empty.Union + + let inline pick chooser set = + check set + set |> Seq.pick chooser + + let inline tryPick chooser set = + check set + set |> Seq.tryPick chooser + + let inline vTryPick chooser set = + check set + + match set |> Seq.tryPick chooser with + | Some value -> ValueSome value + | None -> ValueNone + + let inline map mapping (set : SortedSet<_>) = set |> Seq.map mapping |> ofSeq + + let inline forall predicate set = set |> Seq.forall predicate + + let inline iter action (set : SortedSet<_>) = + check set + set |> Seq.iter action diff --git a/src/FSharp.Collections.Immutable/stack.fs b/src/FSharp.Collections.Immutable/Stack.fs similarity index 62% rename from src/FSharp.Collections.Immutable/stack.fs rename to src/FSharp.Collections.Immutable/Stack.fs index 7fe7e57..a9502e5 100644 --- a/src/FSharp.Collections.Immutable/stack.fs +++ b/src/FSharp.Collections.Immutable/Stack.fs @@ -4,19 +4,21 @@ type IStack<'T> = System.Collections.Immutable.IImmutableStack<'T> type Stack<'T> = System.Collections.Immutable.ImmutableStack<'T> -[] +[] module Stack = type internal StackFactory = System.Collections.Immutable.ImmutableStack let inline internal check (stack : IStack<_>) = checkNotNull (nameof stack) stack - let inline empty<'T> = StackFactory.Create<'T>() + let inline empty<'T> = StackFactory.Create<'T> () let inline ofSeq source = StackFactory.CreateRange source - let inline ofArray (array : 'T []) : Stack<'T> = ofSeq array + let inline ofArray (array : 'T[]) : Stack<'T> = ofSeq array - let inline toSeq (stack: IStack<_>) = stack :> seq<_> + let inline toSeq (stack : IStack<_>) = stack :> seq<_> let push head stack : IStack<'T> = check stack @@ -26,22 +28,25 @@ module Stack = let peek stack = check stack - stack.Peek() + stack.Peek () let head stack = peek stack let tail stack : IStack<_> = check stack - stack.Pop() + stack.Pop () let pop stack = check stack - stack.Peek(), tail stack + stack.Peek (), tail stack let (|Cons|Nil|) stack = check stack - if stack.IsEmpty then Nil - else Cons(stack.Peek(), stack.Pop()) + + if stack.IsEmpty then + Nil + else + Cons (stack.Peek (), stack.Pop ()) ///////////// module ImmutableStack = Stack diff --git a/src/FSharp.Collections.Immutable/indexed-seq.fs b/src/FSharp.Collections.Immutable/indexed-seq.fs deleted file mode 100644 index f7aeb55..0000000 --- a/src/FSharp.Collections.Immutable/indexed-seq.fs +++ /dev/null @@ -1,10 +0,0 @@ -namespace FSharp.Collections.Immutable - -type IIndexedSeq<'T> = System.Collections.Generic.IReadOnlyList<'T> - -module IndexedSeq = - let check (seq: IIndexedSeq<_>) = checkNotNull (nameof seq) seq - let item index seq = check seq; seq.[index] - let length seq = check seq; seq.Count - -module ReadOnlyList = IndexedSeq diff --git a/src/FSharp.Collections.Immutable/maps.fs b/src/FSharp.Collections.Immutable/maps.fs deleted file mode 100644 index 01233f2..0000000 --- a/src/FSharp.Collections.Immutable/maps.fs +++ /dev/null @@ -1,225 +0,0 @@ -namespace FSharp.Collections.Immutable - -open System.Collections.Generic - -type IMap<'Key, 'Value> = System.Collections.Immutable.IImmutableDictionary<'Key, 'Value> - -type HashMap<'Key, 'Value> = - System.Collections.Immutable.ImmutableDictionary<'Key, 'Value> - -type HashMapBuilder<'Key, 'Value> = HashMap<'Key, 'Value>.Builder - -[] -module HashMap = - - type internal HashMapFactory = System.Collections.Immutable.ImmutableDictionary - - let inline check (map: HashMap<_, _>) = checkNotNull (nameof map) map - - ////////// Creating ////////// - - let inline empty<'Key, 'Value> = HashMapFactory.Create<'Key, 'Value>() - let inline singleton item = empty.Add(item) - - let inline ofSeq source = HashMapFactory.CreateRange(source) - let inline ofSeqWith getKey source = - source - |> Seq.map (fun i -> KeyValuePair(getKey i, i)) - |> HashMapFactory.CreateRange - let inline ofSeqGroupBy getKey source = - source - |> Seq.groupBy getKey - |> Seq.map (fun (key,value) -> KeyValuePair(key, value)) - |> HashMapFactory.CreateRange - let inline ofArray (source : _ array) = HashMapFactory.CreateRange(source) - - let inline toSeq (map: HashMap<_,_>) = map :> seq<_> - let inline toArray (map : HashMap<_,_>) = check map; Seq.toArray map - - ////////// Building ////////// - - let inline builder() = HashMapFactory.CreateBuilder() - let inline builderWithKeyComparer comparer = HashMapFactory.CreateBuilder(comparer) - let inline builderWithComparers keyComparer valueComparer = HashMapFactory.CreateBuilder(keyComparer, valueComparer) - - let inline ofBuilder (mapBuilder: HashMapBuilder<_,_>) = - checkNotNull (nameof mapBuilder) mapBuilder - mapBuilder.ToImmutable() - - let inline toBuilder map : HashMapBuilder<_,_> = check map; map.ToBuilder() - - let inline ofKeyComparer<'Key, 'Value> comparer = HashMapFactory.Create<'Key, 'Value>(comparer) - let inline ofComparers<'Key, 'Value> keyComparer valueComparer = HashMapFactory.Create<'Key, 'Value>(keyComparer, valueComparer) - - - let inline isEmpty map = check map; map.IsEmpty - - let inline length map = check map; map.Count - - let inline keyComparer map = check map; map.KeyComparer - let inline valueComparer map = check map; map.ValueComparer - - let inline containsKey key map = check map; map.ContainsKey key; - - let inline find key map = check map; map.[key] - let inline tryFind key map = - check map - match map.TryGetValue(key) with - | true, value -> Some value - | false, _ -> None - let inline vTryFind key map = - check map - match map.TryGetValue(key) with - | true, value -> ValueSome value - | false, _ -> ValueNone - - let inline pick chooser map = check map; map |> Seq.pick (fun kvp -> chooser kvp.Key kvp.Value) - let inline tryPick chooser map = check map; map |> Seq.tryPick (fun kvp -> chooser kvp.Key kvp.Value) - let inline vTryPick chooser map = - check map - match map |> Seq.tryPick (fun kvp -> chooser kvp.Key kvp.Value) with - | Some value -> ValueSome value - | None -> ValueNone - - let inline iter action (map: HashMap<_,_>) = check map; map |> Seq.iter (fun kvp -> action kvp.Key kvp.Value) - - let inline exists predicate map = check map; map |> Seq.exists (fun kvp -> predicate kvp.Key kvp.Value) - - let inline add key value map : HashMap<_,_> = check map; map.Add(key, value) - let inline append map pairs : HashMap<_,_> = - check map - checkNotNull (nameof pairs) pairs - map.AddRange pairs - - let inline remove key map : HashMap<_,_> = check map; map.Remove key - let inline except keys map : HashMap<_,_> = check map; map.RemoveRange keys - - let inline clear map: HashMap<_,_> = check map; map.Clear() - - let inline filter predicate map = - map |> Seq.filter (fun (kvp:KeyValuePair<_,_>) -> predicate kvp.Key kvp.Value) - - let inline forall predicate map = - map |> Seq.forall (fun (kvp:KeyValuePair<_,_>) -> predicate kvp.Key kvp.Value) - - let inline map mapping map' = - map' |> Seq.map (fun (kvp:KeyValuePair<_,_>) -> mapping kvp.Key kvp.Value) |> ofSeq - - let inline where predicate map = - map |> Seq.where (fun (kvp:KeyValuePair<_,_>) -> predicate kvp.Key kvp.Value) |> empty.AddRange - - -type SortedMap<'Key, 'Value> = - System.Collections.Immutable.ImmutableSortedDictionary<'Key, 'Value> - -type SortedMapBuilder<'Key, 'Value> = SortedMap<'Key, 'Value>.Builder - -[] -module SortedMap = - - type internal SortedMapFactory = System.Collections.Immutable.ImmutableSortedDictionary - - let inline check (sortedMap: SortedMap<_, _>) = checkNotNull (nameof sortedMap) sortedMap - - ////////// Creating ////////// - - let inline empty<'Key, 'Value> = SortedMapFactory.Create<'Key, 'Value>() - let inline singleton item = SortedMapFactory.Create(item) - - let inline ofSeq source = SortedMapFactory.CreateRange(source) - let inline ofSeqWith getKey source = - source - |> Seq.map (fun i -> KeyValuePair(getKey i, i)) - |> SortedMapFactory.CreateRange - let inline ofSeqGroupBy getKey source = - source - |> Seq.groupBy getKey - |> Seq.map (fun (key,value) -> KeyValuePair(key, value)) - let inline ofArray (source : _ array) = SortedMapFactory.CreateRange(source) - - let inline toSeq (map: SortedMap<_,_>) = map :> seq<_> - let inline toArray (map : SortedMap<_,_>) = check map; Seq.toArray map - - ////////// Building ////////// - - let inline builder() = SortedMapFactory.CreateBuilder() - let inline builderWithKeyComparer comparer = SortedMapFactory.CreateBuilder(comparer) - let inline builderWithComparers keyComparer valueComparer = SortedMapFactory.CreateBuilder(keyComparer, valueComparer) - - let inline ofBuilder (sortedMapBuilder: SortedMapBuilder<_,_>) = - checkNotNull (nameof sortedMapBuilder) sortedMapBuilder - sortedMapBuilder.ToImmutable() - - let inline toBuilder map : SortedMapBuilder<_,_> = check map; map.ToBuilder() - - let inline ofKeyComparer<'Key, 'Value> comparer = SortedMapFactory.Create<'Key, 'Value>(comparer) - let inline ofComparers<'Key, 'Value> keyComparer valueComparer = SortedMapFactory.Create<'Key, 'Value>(keyComparer, valueComparer) - - - let inline isEmpty map = check map; map.IsEmpty - - let inline length map = check map; map.Count - - let inline keyComparer map = check map; map.KeyComparer - let inline valueComparer map = check map; map.ValueComparer - - let inline containsKey key map = check map; map.ContainsKey key - - let inline find key map = check map; map.[key] - let inline tryFind key map = - check map - match map.TryGetValue(key) with - | true,value -> Some value - | false,_ -> None - let inline vTryFind key map = - check map - match map.TryGetValue(key) with - | true, value -> ValueSome value - | false, _ -> ValueNone - - let inline pick chooser map = check map; map |> Seq.pick (fun kvp -> chooser kvp.Key kvp.Value) - let inline tryPick chooser map = check map; map |> Seq.tryPick (fun kvp -> chooser kvp.Key kvp.Value) - let inline vTryPick chooser map = - check map - match map |> Seq.tryPick (fun kvp -> chooser kvp.Key kvp.Value) with - | Some value -> ValueSome value - | None -> ValueNone - - let inline iter action (map: SortedMap<_,_>) = check map; map |> Seq.iter (fun kvp -> action kvp.Key kvp.Value) - - let inline exists predicate map = check map; map |> Seq.exists (fun kvp -> predicate kvp.Key kvp.Value) - - let inline add key value map : SortedMap<_,_> = check map; map.Add(key, value) - let inline append map pairs : SortedMap<_,_> = - check map - checkNotNull (nameof pairs) pairs - map.AddRange pairs - - let inline remove key map : SortedMap<_,_> = check map; map.Remove key - let inline except keys map : SortedMap<_,_> = check map; map.RemoveRange keys - - let inline clear map: SortedMap<_,_> = check map; map.Clear() - - let inline findKey predicate map = - check map - match (map |> Seq.tryFind (fun kvp -> predicate kvp.Key kvp.Value)) with - | Some value -> value.Key - | None -> raise (new KeyNotFoundException()) - let inline tryFindKey predicate map = check map; map |> Seq.tryFind (fun kvp -> predicate kvp.Key kvp.Value) - let inline vTryFindKey predicate map = - check map - match (map |> Seq.tryFind (fun kvp -> predicate kvp.Key kvp.Value)) with - | Some value -> ValueSome value.Key - | None -> ValueNone - - let inline filter predicate map = - map |> Seq.filter (fun (kvp:KeyValuePair<_,_>) -> predicate kvp.Key kvp.Value) - - let inline forall predicate map = - map |> Seq.forall (fun (kvp:KeyValuePair<_,_>) -> predicate kvp.Key kvp.Value) - - let inline map mapping (map': SortedMap<_,_>) = - map' |> Seq.map (fun (kvp:KeyValuePair<_,_>) -> mapping kvp.Key kvp.Value) |> ofSeq - - let inline where predicate map = - map |> Seq.where (fun (kvp:KeyValuePair<_,_>) -> predicate kvp.Key kvp.Value) |> empty.AddRange diff --git a/src/FSharp.Collections.Immutable/queue.fs b/src/FSharp.Collections.Immutable/queue.fs deleted file mode 100644 index d255608..0000000 --- a/src/FSharp.Collections.Immutable/queue.fs +++ /dev/null @@ -1,80 +0,0 @@ -namespace FSharp.Collections.Immutable - -type IQueue<'T> = System.Collections.Immutable.IImmutableQueue<'T> - -type Queue<'T> = System.Collections.Immutable.ImmutableQueue<'T> - -[] -module Queue = - - type internal QueueFactory = System.Collections.Immutable.ImmutableQueue - - let inline private check (queue: IQueue<_>) = checkNotNull (nameof queue) queue - - let inline empty<'T> : Queue<'T> = QueueFactory.Create<'T>() - - let inline singleton<'T> (item : 'T) : Queue<'T> = QueueFactory.Create<'T> (item) - - let inline ofSeq(source : 'T seq) : Queue<'T> = QueueFactory.CreateRange source - - let inline toSeq (queue: Queue<_>) = queue :> seq<_> - - let isEmpty queue = check queue; queue.IsEmpty - - let clear queue : IQueue<_> = check queue; queue.Clear() - - let enqueue item queue : IQueue<_> = check queue; queue.Enqueue item - - let head queue = check queue; queue.Peek() - - let tail queue : IQueue<_> = check queue; queue.Dequeue() - - ////////// - - let (|Cons|Nil|) queue = // consider renaming - if isEmpty queue then Nil else Cons(head queue, tail queue) - - ////////// Predicate based ////////// - - let filter predicate queue = - let rec loop queue result = - match queue with - |Cons(head, tail) -> - loop tail <| if predicate head then enqueue head result else result - |Nil -> result - - loop queue <| clear queue - - ////////// Seq-based ////////// - - let find predicate queue = check queue; Seq.find predicate queue - let tryFind predicate queue = check queue; Seq.tryFind predicate queue - - let findIndex predicate queue = check queue; Seq.findIndex predicate queue - let tryFindIndex predicate queue = check queue; Seq.tryFindIndex predicate queue - - let pick chooser queue = check queue; Seq.pick chooser queue - let tryPick chooser queue = check queue; Seq.tryPick chooser queue - - let iter action queue = check queue; Seq.iter action queue - let iteri action queue = check queue; Seq.iteri action queue - let iter2 action (queue1: IQueue<_>) (queue2: IQueue<_>) = - checkNotNull (nameof queue1) queue1 - checkNotNull (nameof queue2) queue2 - Seq.iter2 action queue1 queue2 - - let fold folder state queue = check queue; Seq.fold folder state queue - - let forall predicate queue = check queue; Seq.forall predicate - - let exists predicate queue = check queue; Seq.exists predicate queue - - let reduce reduction queue = check queue; Seq.reduce reduction queue - - let inline sum queue = check queue; Seq.sum queue - let inline sumBy projection queue = check queue; Seq.sumBy projection queue - - let inline average queue = check queue; Seq.average queue - let inline averageBy projection queue = check queue; Seq.averageBy projection - -module ImmutableQueue = Queue diff --git a/src/FSharp.Collections.Immutable/sets.fs b/src/FSharp.Collections.Immutable/sets.fs deleted file mode 100644 index 3b091b1..0000000 --- a/src/FSharp.Collections.Immutable/sets.fs +++ /dev/null @@ -1,156 +0,0 @@ -namespace FSharp.Collections.Immutable - -type ISet<'T> = System.Collections.Immutable.IImmutableSet<'T> - -type HashSet<'T> = System.Collections.Immutable.ImmutableHashSet<'T> -type HashSetBuilder<'T> = HashSet<'T>.Builder - -[] -module HashSet = - - type internal HashSetFactory = System.Collections.Immutable.ImmutableHashSet - - let inline check (set: HashSet<_>) = checkNotNull (nameof set) set - - ////////// Creating ////////// - - let inline empty<'T> = HashSetFactory.Create<'T>() - let inline singleton<'T> (item : 'T) = HashSetFactory.Create<'T>(item) - let inline ofSeq source = HashSetFactory.CreateRange(source) - let inline ofSeqWithComparer comparer source = HashSetFactory.Create(comparer, items = (source |> Array.ofSeq)) - let inline ofArray (source : _ array) = HashSetFactory.CreateRange(source) - - let inline ofBuilder (hashSetBuilder: HashSetBuilder<_>) = - checkNotNull (nameof hashSetBuilder) hashSetBuilder - hashSetBuilder.ToImmutable() - let inline ofComparer<'T> comparer = HashSetFactory.Create<'T>(equalityComparer = comparer) - - let inline toSeq (set : HashSet<_>) = set :> seq<_> - let inline toArray (set : HashSet<_>) = check set; Seq.toArray set - - ////////// Building ////////// - - let inline builder() = HashSetFactory.CreateBuilder() - let inline builderWith capacity : HashSet<'T>.Builder = HashSetFactory.CreateBuilder(capacity) - let inline builderWithComparer comparer = HashSetFactory.CreateBuilder(comparer) - - let inline toBuilder set : HashSetBuilder<_> = check set; set.ToBuilder() - - let inline keyComparer set = check set; set.KeyComparer - - let inline length set = check set; set.Count - - let inline isEmpty set = check set; set.IsEmpty - let inline contains value set = check set; set.Contains value - let inline exists predicate map = check map; map |> Seq.exists predicate - let inline isSubset (set1:HashSet<_>) set2 = check set1; set1.IsSubsetOf set2 - let inline isProperSubset (set1:HashSet<_>) set2 = check set1; set1.IsProperSubsetOf set2 - let inline isSuperset (set1:HashSet<_>) set2 = check set1; set1.IsSupersetOf set2 - let inline isProperSuperset (set1:HashSet<_>) set2 = check set1; set1.IsProperSupersetOf set2 - - let inline add value set : HashSet<_> = check set; set.Add(value) - let inline union set values : HashSet<_> = check set; values |> set.Union - let inline unionMany (sets:HashSet<_> seq) = Seq.reduce union sets - let inline intersect (set1:HashSet<_>) set2 = check set1; set1.Intersect set2 - let inline intersectMany (sets:HashSet<_> seq) = Seq.reduce intersect sets - - let inline remove value set : HashSet<_> = check set; set.Remove value - let inline difference values set : HashSet<_> = check set; values |> set.Except - - let inline clear set: HashSet<_> = check set; set.Clear() - - let inline filter predicate set = - set |> Seq.filter predicate |> empty.Union - - let inline where predicate set = - set |> Seq.where predicate |> empty.Union - - let inline pick chooser set = check set; set |> Seq.pick chooser - let inline tryPick chooser set = check set; set |> Seq.tryPick chooser - let inline vTryPick chooser set = - check set - match set |> Seq.tryPick chooser with - | Some value -> ValueSome value - | None -> ValueNone - - let inline map mapping (set: HashSet<_>) = set |> Seq.map mapping |> ofSeq - - let inline forall predicate set = set |> Seq.forall predicate - - let inline iter action (set: HashSet<_>) = check set; set |> Seq.iter action - -type SortedSet<'T> = System.Collections.Immutable.ImmutableSortedSet<'T> -type SortedSetBuilder<'T> = SortedSet<'T>.Builder - -[] -module SortedSet = - - type internal SortedSetFactory = System.Collections.Immutable.ImmutableSortedSet - - let inline check (sortedSet: SortedSet<_>) = checkNotNull (nameof sortedSet) sortedSet - - ////////// Creating ////////// - - let inline empty<'T> = SortedSetFactory.Create<'T>() - let inline singleton<'T> (item : 'T) = SortedSetFactory.Create<'T>(item) - let inline ofSeq source = SortedSetFactory.CreateRange(source) - let inline ofSeqWithComparer comparer source = SortedSetFactory.Create(comparer, items = (source |> Array.ofSeq)) - let inline ofArray (source : _ array) = SortedSetFactory.CreateRange(source) - - let inline ofBuilder (sortedSetBuilder: SortedSetBuilder<_>) = - checkNotNull (nameof sortedSetBuilder) sortedSetBuilder - sortedSetBuilder.ToImmutable() - let inline ofComparer<'T> comparer = SortedSetFactory.Create<'T>(comparer = comparer) - - let inline toSeq (set: SortedSet<_>) = set :> seq<_> - let inline toArray (set : SortedSet<_>) = check set; Seq.toArray set - - ////////// Building ////////// - - let inline builder() = SortedSetFactory.CreateBuilder() - let inline builderWith capacity : SortedSet<'T>.Builder = SortedSetFactory.CreateBuilder(capacity) - let inline builderWithComparer comparer = SortedSetFactory.CreateBuilder(comparer) - - let inline toBuilder set : SortedSetBuilder<_> = check set; set.ToBuilder() - - let inline keyComparer set = check set; set.KeyComparer - - - let inline length set = check set; set.Count - - let inline contains value set = check set; set.Contains value - let inline isEmpty set = check set; set.IsEmpty - let inline exists predicate map = check map; map |> Seq.exists predicate - let inline isSubset (set1:SortedSet<_>) set2 = check set1; set1.IsSubsetOf set2 - let inline isProperSubset (set1:SortedSet<_>) set2 = check set1; set1.IsProperSubsetOf set2 - let inline isSuperset (set1:SortedSet<_>) set2 = check set1; set1.IsSupersetOf set2 - let inline isProperSuperset (set1:SortedSet<_>) set2 = check set1; set1.IsProperSupersetOf set2 - - let inline add value set : SortedSet<_> = check set; set.Add(value) - let inline union set values : SortedSet<_> = check set; values |> set.Union - let inline unionMany (sets:SortedSet<_> seq) = Seq.reduce union sets - let inline intersect (set1:SortedSet<_>) set2 = set1.Intersect set2 - let inline intersectMany (sets:SortedSet<_> seq) = Seq.reduce intersect sets - - let inline remove value set : SortedSet<_> = check set; set.Remove value - let inline difference values set : SortedSet<_> = check set; values |> set.Except - - let inline clear set: SortedSet<_> = check set; set.Clear() - - let inline filter predicate set = set |> Seq.filter predicate |> empty.Union - - let inline where predicate set = set |> Seq.where predicate |> empty.Union - - let inline pick chooser set = check set; set |> Seq.pick chooser - let inline tryPick chooser set = check set; set |> Seq.tryPick chooser - let inline vTryPick chooser set = - check set - match set |> Seq.tryPick chooser with - | Some value -> ValueSome value - | None -> ValueNone - - let inline map mapping (set: SortedSet<_>) = set |> Seq.map mapping |> ofSeq - - let inline forall predicate set = set |> Seq.forall predicate - - let inline iter action (set: SortedSet<_>) = check set; set |> Seq.iter action diff --git a/tests/Directory.Build.props b/tests/Directory.Build.props new file mode 100644 index 0000000..e7a7266 --- /dev/null +++ b/tests/Directory.Build.props @@ -0,0 +1,7 @@ + + + + false + true + + diff --git a/tests/FSharp.Collections.Immutable.Tests/Attributes.fs b/tests/FSharp.Collections.Immutable.Tests/Attributes.fs new file mode 100644 index 0000000..923f313 --- /dev/null +++ b/tests/FSharp.Collections.Immutable.Tests/Attributes.fs @@ -0,0 +1,7 @@ +namespace FSharp.Collections.Immutable + +open Microsoft.VisualStudio.TestTools.UnitTesting + +[] + +do () diff --git a/tests/FSharp.Collections.Immutable.Tests/FSharp.Collections.Immutable.Tests.fsproj b/tests/FSharp.Collections.Immutable.Tests/FSharp.Collections.Immutable.Tests.fsproj new file mode 100644 index 0000000..407a068 --- /dev/null +++ b/tests/FSharp.Collections.Immutable.Tests/FSharp.Collections.Immutable.Tests.fsproj @@ -0,0 +1,32 @@ + + + + net8.0 + $(AssemblyBaseName).Tests + + Exe + true + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/FSharp.Collections.Immutable.Tests/FlatList.fs b/tests/FSharp.Collections.Immutable.Tests/FlatList.fs new file mode 100644 index 0000000..351bac9 --- /dev/null +++ b/tests/FSharp.Collections.Immutable.Tests/FlatList.fs @@ -0,0 +1,10 @@ +namespace FSharp.Collections.Immutable.Tests + +open System +open Microsoft.VisualStudio.TestTools.UnitTesting + +[] +type FlatListTests () = + + [] + member this.TestMethodPassing () = Assert.IsTrue (true) diff --git a/tests/FSharp.Collections.Immutable.Tests/ImmutableList.fs b/tests/FSharp.Collections.Immutable.Tests/ImmutableList.fs new file mode 100644 index 0000000..452167f --- /dev/null +++ b/tests/FSharp.Collections.Immutable.Tests/ImmutableList.fs @@ -0,0 +1,10 @@ +namespace FSharp.Collections.Immutable.Tests + +open System +open Microsoft.VisualStudio.TestTools.UnitTesting + +[] +type ImmutableListTests () = + + [] + member this.TestMethodPassing () = Assert.IsTrue (true) diff --git a/tests/FSharp.Collections.Immutable.Tests/IndexedSeq.fs b/tests/FSharp.Collections.Immutable.Tests/IndexedSeq.fs new file mode 100644 index 0000000..17294a9 --- /dev/null +++ b/tests/FSharp.Collections.Immutable.Tests/IndexedSeq.fs @@ -0,0 +1,10 @@ +namespace FSharp.Collections.Immutable.Tests + +open System +open Microsoft.VisualStudio.TestTools.UnitTesting + +[] +type IndexedSeqTests () = + + [] + member this.TestMethodPassing () = Assert.IsTrue (true) diff --git a/tests/FSharp.Collections.Immutable.Tests/Maps.fs b/tests/FSharp.Collections.Immutable.Tests/Maps.fs new file mode 100644 index 0000000..84f2fde --- /dev/null +++ b/tests/FSharp.Collections.Immutable.Tests/Maps.fs @@ -0,0 +1,16 @@ +namespace FSharp.Collections.Immutable.Tests + +open System +open Microsoft.VisualStudio.TestTools.UnitTesting + +[] +type HashMapTests () = + + [] + member this.TestMethodPassing () = Assert.IsTrue (true) + +[] +type SortedMapTests () = + + [] + member this.TestMethodPassing () = Assert.IsTrue (true) diff --git a/tests/FSharp.Collections.Immutable.Tests/Queue.fs b/tests/FSharp.Collections.Immutable.Tests/Queue.fs new file mode 100644 index 0000000..826a1cb --- /dev/null +++ b/tests/FSharp.Collections.Immutable.Tests/Queue.fs @@ -0,0 +1,10 @@ +namespace FSharp.Collections.Immutable.Tests + +open System +open Microsoft.VisualStudio.TestTools.UnitTesting + +[] +type QueueTests () = + + [] + member this.TestMethodPassing () = Assert.IsTrue (true) diff --git a/tests/FSharp.Collections.Immutable.Tests/Sets.fs b/tests/FSharp.Collections.Immutable.Tests/Sets.fs new file mode 100644 index 0000000..b170420 --- /dev/null +++ b/tests/FSharp.Collections.Immutable.Tests/Sets.fs @@ -0,0 +1,16 @@ +namespace FSharp.Collections.Immutable.Tests + +open System +open Microsoft.VisualStudio.TestTools.UnitTesting + +[] +type HashSetTests () = + + [] + member this.TestMethodPassing () = Assert.IsTrue (true) + +[] +type SortedSetTests () = + + [] + member this.TestMethodPassing () = Assert.IsTrue (true) diff --git a/tests/FSharp.Collections.Immutable.Tests/Stack.fs b/tests/FSharp.Collections.Immutable.Tests/Stack.fs new file mode 100644 index 0000000..2674f68 --- /dev/null +++ b/tests/FSharp.Collections.Immutable.Tests/Stack.fs @@ -0,0 +1,10 @@ +namespace FSharp.Collections.Immutable.Tests + +open System +open Microsoft.VisualStudio.TestTools.UnitTesting + +[] +type StackTests () = + + [] + member this.TestMethodPassing () = Assert.IsTrue (true) From b4ffe2df749c3cf47d4625b9e624a271aff713db Mon Sep 17 00:00:00 2001 From: Andrii Chebukin Date: Tue, 3 Jun 2025 02:38:51 +0400 Subject: [PATCH 17/17] fixup! feat: release automation with FAKE and minimal documentation --- .devcontainer/devcontainer.json | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 5b1e8df..c7955dd 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -19,8 +19,6 @@ }, // https://github.com/devcontainers/features/blob/main/src/github-cli/README.md "ghcr.io/devcontainers/features/github-cli:1": {}, - // https://github.com/devcontainers-contrib/features/blob/main/src/starship/README.md - "ghcr.io/devcontainers-contrib/features/starship:1": {}, // https://github.com/devcontainers/features/blob/main/src/dotnet/README.md "ghcr.io/devcontainers/features/dotnet:2": { "version": "9.0", @@ -30,7 +28,6 @@ "overrideFeatureInstallOrder": [ "ghcr.io/devcontainers/features/common-utils", "ghcr.io/devcontainers/features/github-cli", - "ghcr.io/devcontainers-contrib/features/starship", "ghcr.io/devcontainers/features/dotnet" ], "customizations": { @@ -63,9 +60,6 @@ // They are used for releasing and publishing from the container "GITHUB_TOKEN": "${localEnv:GITHUB_TOKEN}" }, - "onCreateCommand": { - "enable-starship": "echo 'eval \"$(starship init zsh)\"' >> ~/.zshrc" - }, "postAttachCommand": { "restore": "dotnet tool restore && dotnet restore" },