From aa63838591e12a7c138e5a430ba1ab358606e2d9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 10 Mar 2026 13:06:01 +0000 Subject: [PATCH 01/14] feat: add map, filter, iter, exists, forall, toList, toArray to Queue and Deque modules Adds commonly needed collection functions to Queue and Deque that were present in F# List but missing from these modules. Addresses part of #152 (Align Collection Module functions with FSharp.Collections). New functions for both Queue and Deque: - map : transform each element, returning the same collection type - filter : keep elements matching a predicate - iter : apply a side-effecting function to each element (FIFO order) - exists : test whether any element satisfies a predicate - forall : test whether all elements satisfy a predicate - toList : convert to list in FIFO order - toArray : convert to array in FIFO order All seven functions are O(n) and preserve FIFO element order. 21 new tests added (QueueTest and DequeTest), all passing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/FSharpx.Collections/Deque.fs | 29 +++++ src/FSharpx.Collections/Deque.fsi | 107 +++++++++++-------- src/FSharpx.Collections/Queue.fs | 49 +++++++++ src/FSharpx.Collections/Queue.fsi | 73 ++++++++----- tests/FSharpx.Collections.Tests/DequeTest.fs | 62 ++++++++++- tests/FSharpx.Collections.Tests/QueueTest.fs | 67 +++++++++++- 6 files changed, 316 insertions(+), 71 deletions(-) diff --git a/src/FSharpx.Collections/Deque.fs b/src/FSharpx.Collections/Deque.fs index 2a056164..d6f852a8 100644 --- a/src/FSharpx.Collections/Deque.fs +++ b/src/FSharpx.Collections/Deque.fs @@ -244,5 +244,34 @@ module Deque = let inline toSeq(q: Deque<'T>) = q :> seq<'T> + ///O(n). Returns a list of the deque elements in FIFO order. + let toList(q: Deque<'T>) : 'T list = + q.front @ List.rev q.rBack + + ///O(n). Returns an array of the deque elements in FIFO order. + let toArray(q: Deque<'T>) : 'T[] = + Array.ofSeq q + + ///O(n). Returns a new deque whose elements are the results of applying the given function to each element. + let map (f: 'T -> 'U) (q: Deque<'T>) : Deque<'U> = + Deque<'U>(List.map f q.front, List.map f q.rBack) + + ///O(n). Returns a new deque containing only the elements of the original for which the given predicate returns true. + let filter (predicate: 'T -> bool) (q: Deque<'T>) : Deque<'T> = + Deque<'T>(List.filter predicate q.front, List.filter predicate q.rBack) + + ///O(n). Applies the given function to each element of the deque. + let iter (f: 'T -> unit) (q: Deque<'T>) = + List.iter f q.front + List.iter f (List.rev q.rBack) + + ///O(n). Returns true if any element of the deque satisfies the given predicate. + let exists (predicate: 'T -> bool) (q: Deque<'T>) : bool = + List.exists predicate q.front || List.exists predicate q.rBack + + ///O(n). Returns true if all elements of the deque satisfy the given predicate. + let forall (predicate: 'T -> bool) (q: Deque<'T>) : bool = + List.forall predicate q.front && List.forall predicate q.rBack + let inline tryUnconj(q: Deque<'T>) = q.TryUnconj diff --git a/src/FSharpx.Collections/Deque.fsi b/src/FSharpx.Collections/Deque.fsi index 6a3da772..cfa70b4b 100644 --- a/src/FSharpx.Collections/Deque.fsi +++ b/src/FSharpx.Collections/Deque.fsi @@ -12,136 +12,157 @@ type Deque<'T> = interface System.Collections.Generic.IReadOnlyCollection<'T> ///O(1). Returns a new deque with the element added to the end. - member Conj : 'T -> Deque<'T> + member Conj: 'T -> Deque<'T> ///O(1). Returns a new deque with the element added to the beginning. - member Cons : 'T -> Deque<'T> + member Cons: 'T -> Deque<'T> ///O(1) amortized, O(n), worst case. Returns the first element. - member Head : 'T + member Head: 'T ///O(1) amortized, O(n), worst case. Returns option first element. - member TryHead : 'T option + member TryHead: 'T option ///O(1) amortized, O(n), worst case. Returns a new deque of the elements before the last element. - member Initial : Deque<'T> + member Initial: Deque<'T> ///O(1) amortized, O(n), worst case. Returns a new deque of the elements before the last element. - member TryInitial : Deque<'T> option + member TryInitial: Deque<'T> option ///O(1). Returns true if the deque has no elements. - member IsEmpty : bool + member IsEmpty: bool ///O(1) amortized, O(n), worst case. Returns the last element. - member Last : 'T + member Last: 'T ///O(1) amortized, O(n), worst case. Returns option last element. - member TryLast : 'T option + member TryLast: 'T option ///O(1). Returns the count of elememts. - member Length : int + member Length: int ///O(1). Returns deque reversed. - member Rev : Deque<'T> + member Rev: Deque<'T> ///O(1) amortized, O(n), worst case. Returns a new deque of the elements trailing the first element. - member Tail : Deque<'T> + member Tail: Deque<'T> ///O(1) amortized, O(n), worst case. Returns option deque of the elements trailing the first element. - member TryTail : Deque<'T> option + member TryTail: Deque<'T> option ///O(1) amortized, O(n), worst case. Returns init and the last element. - member Unconj : Deque<'T> * 'T + member Unconj: Deque<'T> * 'T ///O(1) amortized, O(n), worst case. Returns option init and the last element. - member TryUnconj : (Deque<'T> * 'T) option + member TryUnconj: (Deque<'T> * 'T) option ///O(1) amortized, O(n), worst case. Returns the first element and tail. - member Uncons : 'T * Deque<'T> + member Uncons: 'T * Deque<'T> ///O(1) amortized, O(n), worst case. Returns option first element and tail. - member TryUncons : ('T * Deque<'T>) option + member TryUncons: ('T * Deque<'T>) option [] module Deque = //pattern discriminators - val (|Cons|Nil|) : Deque<'T> -> Choice<('T * Deque<'T>),unit> + val (|Cons|Nil|): Deque<'T> -> Choice<('T * Deque<'T>), unit> - val (|Conj|Nil|) : Deque<'T> -> Choice<(Deque<'T> * 'T),unit> + val (|Conj|Nil|): Deque<'T> -> Choice<(Deque<'T> * 'T), unit> ///O(1). Returns a new deque with the element added to the end. - val inline conj : 'T -> Deque<'T> -> Deque<'T> + val inline conj: 'T -> Deque<'T> -> Deque<'T> ///O(1). Returns a new deque with the element added to the beginning. - val inline cons : 'T -> Deque<'T> -> Deque<'T> + val inline cons: 'T -> Deque<'T> -> Deque<'T> ///O(1). Returns deque of no elements. [] val empty<'T> : Deque<'T> ///O(n). Applies a function to each element of the deque, threading an accumulator argument through the computation, left to right - val fold : ('State -> 'T -> 'State) -> 'State -> Deque<'T> -> 'State + val fold: ('State -> 'T -> 'State) -> 'State -> Deque<'T> -> 'State ///O(n). Applies a function to each element of the deque, threading an accumulator argument through the computation, right to left - val foldBack : ('T -> 'State -> 'State) -> Deque<'T> -> 'State -> 'State + val foldBack: ('T -> 'State -> 'State) -> Deque<'T> -> 'State -> 'State ///O(1) amortized, O(n), worst case. Returns the first element. - val inline head : Deque<'T> -> 'T + val inline head: Deque<'T> -> 'T ///O(1) amortized, O(n), worst case. Returns option first element. - val inline tryHead : Deque<'T> -> 'T option + val inline tryHead: Deque<'T> -> 'T option ///O(1) amortized, O(n), worst case. Returns a new deque of the elements before the last element. - val inline initial : Deque<'T> -> Deque<'T> + val inline initial: Deque<'T> -> Deque<'T> ///O(1) amortized, O(n), worst case. Returns option deque of the elements before the last element. - val inline tryInitial : Deque<'T> -> Deque<'T> option + val inline tryInitial: Deque<'T> -> Deque<'T> option ///O(1). Returns true if the deque has no elements. - val inline isEmpty : Deque<'T> -> bool + val inline isEmpty: Deque<'T> -> bool ///O(1) amortized, O(n), worst case. Returns the last element. - val inline last : Deque<'T> -> 'T + val inline last: Deque<'T> -> 'T ///O(1) amortized, O(n), worst case. Returns option last element. - val inline tryLast : Deque<'T> -> 'T option + val inline tryLast: Deque<'T> -> 'T option ///O(1). Returns the count of elememts. - val inline length : Deque<'T> -> int + val inline length: Deque<'T> -> int ///O(n), worst case. Returns a deque of the two lists concatenated. - val ofCatLists : 'T list -> 'T list -> Deque<'T> + val ofCatLists: 'T list -> 'T list -> Deque<'T> ///O(n), worst case. Returns a deque of the list. - val ofList : 'T list -> Deque<'T> + val ofList: 'T list -> Deque<'T> ///O(n), worst case. Returns a deque of the seq. - val ofSeq : seq<'T> -> Deque<'T> + val ofSeq: seq<'T> -> Deque<'T> ///O(1). Returns deque reversed. - val inline rev : Deque<'T> -> Deque<'T> + val inline rev: Deque<'T> -> Deque<'T> ///O(1). Returns a deque of one element. - val singleton : 'T -> Deque<'T> + val singleton: 'T -> Deque<'T> ///O(1) amortized, O(n), worst case. Returns a new deque of the elements trailing the first element. - val inline tail : Deque<'T> -> Deque<'T> + val inline tail: Deque<'T> -> Deque<'T> ///O(1) amortized, O(n), worst case. Returns option deque of the elements trailing the first element. - val inline tryTail : Deque<'T> -> Deque<'T> option + val inline tryTail: Deque<'T> -> Deque<'T> option ///O(1) amortized, O(n), worst case. Returns init and the last element. - val inline unconj : Deque<'T> -> Deque<'T> * 'T + val inline unconj: Deque<'T> -> Deque<'T> * 'T ///O(1) amortized, O(n), worst case. Returns option init and the last element. - val inline tryUnconj : Deque<'T> -> (Deque<'T> * 'T) option + val inline tryUnconj: Deque<'T> -> (Deque<'T> * 'T) option ///O(1) amortized, O(n), worst case. Returns the first element and tail. - val inline uncons : Deque<'T> -> 'T * Deque<'T> + val inline uncons: Deque<'T> -> 'T * Deque<'T> ///O(n). Views the given deque as a sequence. - val inline toSeq : Deque<'T> -> seq<'T> + val inline toSeq: Deque<'T> -> seq<'T> + + ///O(n). Returns a list of the deque elements in FIFO order. + val toList: Deque<'T> -> 'T list + + ///O(n). Returns an array of the deque elements in FIFO order. + val toArray: Deque<'T> -> 'T[] + + ///O(n). Returns a new deque whose elements are the results of applying the given function to each element. + val map: ('T -> 'U) -> Deque<'T> -> Deque<'U> + + ///O(n). Returns a new deque containing only the elements for which the given predicate returns true. + val filter: ('T -> bool) -> Deque<'T> -> Deque<'T> + + ///O(n). Applies the given function to each element of the deque. + val iter: ('T -> unit) -> Deque<'T> -> unit + + ///O(n). Returns true if any element of the deque satisfies the given predicate. + val exists: ('T -> bool) -> Deque<'T> -> bool + + ///O(n). Returns true if all elements of the deque satisfy the given predicate. + val forall: ('T -> bool) -> Deque<'T> -> bool ///O(1) amortized, O(n), worst case. Returns option first element and tail. - val inline tryUncons : Deque<'T> -> ('T * Deque<'T>) option + val inline tryUncons: Deque<'T> -> ('T * Deque<'T>) option diff --git a/src/FSharpx.Collections/Queue.fs b/src/FSharpx.Collections/Queue.fs index c4a5b218..f1bba106 100644 --- a/src/FSharpx.Collections/Queue.fs +++ b/src/FSharpx.Collections/Queue.fs @@ -148,6 +148,55 @@ module Queue = let inline toSeq(q: Queue<'T>) = q :> seq<'T> + ///O(n). Returns a list of the queue elements in FIFO order. + let toList(q: Queue<'T>) : 'T list = + q.front @ List.rev q.rBack + + ///O(n). Returns an array of the queue elements in FIFO order. + let toArray(q: Queue<'T>) : 'T[] = + let arr = Array.zeroCreate q.Length + let mutable i = 0 + + List.iter + (fun x -> + arr.[i] <- x + i <- i + 1) + q.front + + List.iter + (fun x -> + arr.[i] <- x + i <- i + 1) + (List.rev q.rBack) + + arr + + ///O(n). Returns a new queue whose elements are the results of applying the given function to each element. + let map (f: 'T -> 'U) (q: Queue<'T>) : Queue<'U> = + Queue<'U>(List.map f q.front, List.map f q.rBack) + + ///O(n). Returns a new queue containing only the elements of the original for which the given predicate returns true. + let filter (predicate: 'T -> bool) (q: Queue<'T>) : Queue<'T> = + let f = List.filter predicate q.front + let r = List.filter predicate q.rBack + + match f with + | [] -> Queue<'T>(List.rev r, []) + | _ -> Queue<'T>(f, r) + + ///O(n). Applies the given function to each element of the queue. + let iter (f: 'T -> unit) (q: Queue<'T>) = + List.iter f q.front + List.iter f (List.rev q.rBack) + + ///O(n). Returns true if any element of the queue satisfies the given predicate. + let exists (predicate: 'T -> bool) (q: Queue<'T>) : bool = + List.exists predicate q.front || List.exists predicate q.rBack + + ///O(n). Returns true if all elements of the queue satisfy the given predicate. + let forall (predicate: 'T -> bool) (q: Queue<'T>) : bool = + List.forall predicate q.front && List.forall predicate q.rBack + let inline uncons(q: Queue<'T>) = q.Uncons let inline tryUncons(q: Queue<'T>) = diff --git a/src/FSharpx.Collections/Queue.fsi b/src/FSharpx.Collections/Queue.fsi index f5d05014..649e43d3 100644 --- a/src/FSharpx.Collections/Queue.fsi +++ b/src/FSharpx.Collections/Queue.fsi @@ -14,85 +14,106 @@ type Queue<'T> = interface System.Collections.Generic.IReadOnlyCollection<'T> ///O(1). Returns a new queue with the element added to the end. (Enqueue) - member Conj : 'T -> Queue<'T> + member Conj: 'T -> Queue<'T> ///O(1). Returns the first element. (Peek) - member Head : 'T + member Head: 'T ///O(1). Returns option first element - member TryHead : 'T option + member TryHead: 'T option ///O(1). Returns true if the queue has no elements. - member IsEmpty : bool + member IsEmpty: bool ///O(1). Returns the count of elememts. - member Length : int + member Length: int ///O(n). Returns queue reversed. - member Rev : unit -> Queue<'T> + member Rev: unit -> Queue<'T> ///O(1) amortized, O(n) worst-case. Returns a new queue of the elements trailing the first element. (Dequeue) - member Tail : Queue<'T> + member Tail: Queue<'T> ///O(1) amortized, O(n) worst-case. Returns option queue of the elements trailing the first element. - member TryTail : Queue<'T> option + member TryTail: Queue<'T> option ///O(1) amortized, O(n) worst-case. Returns the first element and tail. - member Uncons : 'T * Queue<'T> + member Uncons: 'T * Queue<'T> ///O(1) amortized, O(n) worst-case. Returns option first element and tail. - member TryUncons : ('T * Queue<'T>) option + member TryUncons: ('T * Queue<'T>) option [] module Queue = //pattern discriminators (active pattern) - val (|Cons|Nil|) : Queue<'T> -> Choice<('T * Queue<'T>),unit> + val (|Cons|Nil|): Queue<'T> -> Choice<('T * Queue<'T>), unit> ///O(1). Returns a new queue with the element added to the end. (enqueue) - val inline conj : 'T -> Queue<'T> -> Queue<'T> + val inline conj: 'T -> Queue<'T> -> Queue<'T> ///O(1). Returns queue of no elements. [] val empty<'T> : Queue<'T> ///O(n). Applies a function to each element of the queue, threading an accumulator argument through the computation, left to right. - val fold : ('State -> 'T -> 'State) -> 'State -> Queue<'T> -> 'State + val fold: ('State -> 'T -> 'State) -> 'State -> Queue<'T> -> 'State ///O(n). Applies a function to each element of the queue, threading an accumulator argument through the computation, right to left. - val foldBack : ('T -> 'State -> 'State) -> Queue<'T> -> 'State -> 'State + val foldBack: ('T -> 'State -> 'State) -> Queue<'T> -> 'State -> 'State ///O(1). Returns the first element. (peek) - val inline head : Queue<'T> -> 'T + val inline head: Queue<'T> -> 'T ///O(1). Returns option first element. - val inline tryHead : Queue<'T> -> 'T option + val inline tryHead: Queue<'T> -> 'T option ///O(1). Returns true if the queue has no elements. - val inline isEmpty : Queue<'T> -> bool + val inline isEmpty: Queue<'T> -> bool ///O(1). Returns the count of elememts. - val inline length : Queue<'T> -> int + val inline length: Queue<'T> -> int ///O(1). Returns a queue of the list - val ofList : list<'T> -> Queue<'T> + val ofList: list<'T> -> Queue<'T> ///O(n). Returns a queue of the seq. - val ofSeq : seq<'T> -> Queue<'T> + val ofSeq: seq<'T> -> Queue<'T> ///O(n). Returns queue reversed. - val inline rev : Queue<'T> -> Queue<'T> + val inline rev: Queue<'T> -> Queue<'T> ///O(1) amortized, O(n) worst-case. Returns a new queue of the elements trailing the first element. (dequeue) - val inline tail : Queue<'T> -> Queue<'T> + val inline tail: Queue<'T> -> Queue<'T> ///O(1) amortized, O(n) worst-case. Returns option queue of the elements trailing the first element - val inline tryTail : Queue<'T> -> Queue<'T> option + val inline tryTail: Queue<'T> -> Queue<'T> option ///O(n). Views the given queue as a sequence. - val inline toSeq : Queue<'T> -> seq<'T> + val inline toSeq: Queue<'T> -> seq<'T> + + ///O(n). Returns a list of the queue elements in FIFO order. + val toList: Queue<'T> -> 'T list + + ///O(n). Returns an array of the queue elements in FIFO order. + val toArray: Queue<'T> -> 'T[] + + ///O(n). Returns a new queue whose elements are the results of applying the given function to each element. + val map: ('T -> 'U) -> Queue<'T> -> Queue<'U> + + ///O(n). Returns a new queue containing only the elements for which the given predicate returns true. + val filter: ('T -> bool) -> Queue<'T> -> Queue<'T> + + ///O(n). Applies the given function to each element of the queue. + val iter: ('T -> unit) -> Queue<'T> -> unit + + ///O(n). Returns true if any element of the queue satisfies the given predicate. + val exists: ('T -> bool) -> Queue<'T> -> bool + + ///O(n). Returns true if all elements of the queue satisfy the given predicate. + val forall: ('T -> bool) -> Queue<'T> -> bool ///O(1) amortized, O(n) worst-case. Returns the first element and tail. - val inline uncons : Queue<'T> -> 'T * Queue<'T> + val inline uncons: Queue<'T> -> 'T * Queue<'T> ///O(1) amortized, O(n) worst-case. Returns option first element and tail. - val inline tryUncons : Queue<'T> -> ('T * Queue<'T>) option + val inline tryUncons: Queue<'T> -> ('T * Queue<'T>) option diff --git a/tests/FSharpx.Collections.Tests/DequeTest.fs b/tests/FSharpx.Collections.Tests/DequeTest.fs index 153366db..4ad06670 100644 --- a/tests/FSharpx.Collections.Tests/DequeTest.fs +++ b/tests/FSharpx.Collections.Tests/DequeTest.fs @@ -1221,4 +1221,64 @@ module DequeTests = config10k "get Deque.initial from deque safely 2" (Prop.forAll(Arb.fromGen intGensStart2.[2]) - <| fun (q, l) -> List.ofSeq q.TryInitial.Value = (List.rev l |> List.tail |> List.rev)) ] + <| fun (q, l) -> List.ofSeq q.TryInitial.Value = (List.rev l |> List.tail |> List.rev)) + + test "toList preserves FIFO order" { + let q = Deque.ofSeq [ 1; 2; 3; 4; 5 ] + Expect.equal "toList" [ 1; 2; 3; 4; 5 ] (Deque.toList q) + } + + test "toList empty deque" { Expect.equal "toList empty" [] (Deque.toList Deque.empty) } + + test "toArray preserves FIFO order" { + let q = Deque.ofSeq [ 1; 2; 3 ] + Expect.equal "toArray" [| 1; 2; 3 |] (Deque.toArray q) + } + + test "map transforms elements" { + let q = Deque.ofSeq [ 1; 2; 3 ] + Expect.equal "map" [ 2; 4; 6 ] (Deque.map ((*) 2) q |> Deque.toList) + } + + test "map preserves FIFO order" { + let q = Deque.ofSeq [ "a"; "b"; "c" ] |> Deque.conj "d" |> Deque.conj "e" + + Expect.equal "map order" [ "A"; "B"; "C"; "D"; "E" ] (Deque.map (fun (s: string) -> s.ToUpper()) q |> Deque.toList) + } + + test "filter keeps matching elements" { + let q = Deque.ofSeq [ 1; 2; 3; 4; 5; 6 ] + Expect.equal "filter even" [ 2; 4; 6 ] (Deque.filter (fun x -> x % 2 = 0) q |> Deque.toList) + } + + test "filter preserves order" { + let q = Deque.ofSeq [ 1; 2; 3; 4; 5 ] + Expect.equal "filter order" [ 1; 3; 5 ] (Deque.filter (fun x -> x % 2 <> 0) q |> Deque.toList) + } + + test "iter visits each element in FIFO order" { + let q = Deque.ofSeq [ 1; 2; 3 ] + let result = System.Collections.Generic.List() + Deque.iter result.Add q + Expect.equal "iter order" [ 1; 2; 3 ] (List.ofSeq result) + } + + test "exists returns true when element satisfies predicate" { + let q = Deque.ofSeq [ 1; 2; 3 ] + Expect.isTrue "exists" (Deque.exists ((=) 2) q) + } + + test "exists returns false when no element satisfies predicate" { + let q = Deque.ofSeq [ 1; 2; 3 ] + Expect.isFalse "exists false" (Deque.exists ((=) 99) q) + } + + test "forall returns true when all elements satisfy predicate" { + let q = Deque.ofSeq [ 2; 4; 6 ] + Expect.isTrue "forall" (Deque.forall (fun x -> x % 2 = 0) q) + } + + test "forall returns false when some elements do not" { + let q = Deque.ofSeq [ 2; 3; 6 ] + Expect.isFalse "forall false" (Deque.forall (fun x -> x % 2 = 0) q) + } ] diff --git a/tests/FSharpx.Collections.Tests/QueueTest.fs b/tests/FSharpx.Collections.Tests/QueueTest.fs index b942dfd3..f7f4acba 100644 --- a/tests/FSharpx.Collections.Tests/QueueTest.fs +++ b/tests/FSharpx.Collections.Tests/QueueTest.fs @@ -316,4 +316,69 @@ module QueueTests = config10k "ofList build and serialize" (Prop.forAll(Arb.fromGen queueOfListGen) - <| fun (q, l) -> q |> Seq.toList = l) ] + <| fun (q, l) -> q |> Seq.toList = l) + + test "toList preserves FIFO order" { + let q = Queue.ofSeq [ 1; 2; 3; 4; 5 ] + Expect.equal "toList" [ 1; 2; 3; 4; 5 ] (Queue.toList q) + } + + test "toList empty queue" { Expect.equal "toList empty" [] (Queue.toList Queue.empty) } + + test "toArray preserves FIFO order" { + let q = Queue.ofSeq [ 1; 2; 3 ] + Expect.equal "toArray" [| 1; 2; 3 |] (Queue.toArray q) + } + + test "map transforms elements" { + let q = Queue.ofSeq [ 1; 2; 3 ] + Expect.equal "map" [ 2; 4; 6 ] (Queue.map ((*) 2) q |> Queue.toList) + } + + test "map preserves FIFO order across front/rBack boundary" { + let q = Queue.ofSeq [ "a"; "b"; "c" ] |> Queue.conj "d" |> Queue.conj "e" + + Expect.equal "map order" [ "A"; "B"; "C"; "D"; "E" ] (Queue.map (fun (s: string) -> s.ToUpper()) q |> Queue.toList) + } + + test "filter keeps matching elements" { + let q = Queue.ofSeq [ 1; 2; 3; 4; 5; 6 ] + Expect.equal "filter even" [ 2; 4; 6 ] (Queue.filter (fun x -> x % 2 = 0) q |> Queue.toList) + } + + test "filter preserves order" { + let q = Queue.ofSeq [ 1; 2; 3; 4; 5 ] + Expect.equal "filter preserves order" [ 1; 3; 5 ] (Queue.filter (fun x -> x % 2 <> 0) q |> Queue.toList) + } + + test "filter all out gives empty" { + let q = Queue.ofSeq [ 1; 2; 3 ] + Expect.isTrue "filter all out" (Queue.filter (fun _ -> false) q |> Queue.isEmpty) + } + + test "iter visits each element in FIFO order" { + let q = Queue.ofSeq [ 1; 2; 3 ] + let result = System.Collections.Generic.List() + Queue.iter result.Add q + Expect.equal "iter order" [ 1; 2; 3 ] (List.ofSeq result) + } + + test "exists returns true when element satisfies predicate" { + let q = Queue.ofSeq [ 1; 2; 3 ] + Expect.isTrue "exists" (Queue.exists ((=) 2) q) + } + + test "exists returns false when no element satisfies predicate" { + let q = Queue.ofSeq [ 1; 2; 3 ] + Expect.isFalse "exists false" (Queue.exists ((=) 99) q) + } + + test "forall returns true when all elements satisfy predicate" { + let q = Queue.ofSeq [ 2; 4; 6 ] + Expect.isTrue "forall" (Queue.forall (fun x -> x % 2 = 0) q) + } + + test "forall returns false when some elements do not satisfy predicate" { + let q = Queue.ofSeq [ 2; 3; 6 ] + Expect.isFalse "forall false" (Queue.forall (fun x -> x % 2 = 0) q) + } ] From c4220d3d13cc7676f2800cdc60efe6a8c09032ee Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 10 Mar 2026 13:12:24 +0000 Subject: [PATCH 02/14] ci: trigger checks From f5697532e9c79b9618c101513595cac469762290 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 12 Apr 2026 16:19:18 +0000 Subject: [PATCH 03/14] docs: clarify that exists/forall check elements in non-FIFO order Agent-Logs-Url: https://github.com/fsprojects/FSharpx.Collections/sessions/5505841c-0090-46f8-9556-d78eba3c714b Co-authored-by: gdziadkiewicz <8547855+gdziadkiewicz@users.noreply.github.com> --- src/FSharpx.Collections/Deque.fs | 2 ++ src/FSharpx.Collections/Deque.fsi | 2 ++ src/FSharpx.Collections/Queue.fs | 2 ++ src/FSharpx.Collections/Queue.fsi | 2 ++ 4 files changed, 8 insertions(+) diff --git a/src/FSharpx.Collections/Deque.fs b/src/FSharpx.Collections/Deque.fs index d6f852a8..14a86982 100644 --- a/src/FSharpx.Collections/Deque.fs +++ b/src/FSharpx.Collections/Deque.fs @@ -266,10 +266,12 @@ module Deque = List.iter f (List.rev q.rBack) ///O(n). Returns true if any element of the deque satisfies the given predicate. + ///Note: elements are not necessarily checked in FIFO order; the internal rear list is checked in reverse (LIFO) order. let exists (predicate: 'T -> bool) (q: Deque<'T>) : bool = List.exists predicate q.front || List.exists predicate q.rBack ///O(n). Returns true if all elements of the deque satisfy the given predicate. + ///Note: elements are not necessarily checked in FIFO order; the internal rear list is checked in reverse (LIFO) order. let forall (predicate: 'T -> bool) (q: Deque<'T>) : bool = List.forall predicate q.front && List.forall predicate q.rBack diff --git a/src/FSharpx.Collections/Deque.fsi b/src/FSharpx.Collections/Deque.fsi index cfa70b4b..560bad2b 100644 --- a/src/FSharpx.Collections/Deque.fsi +++ b/src/FSharpx.Collections/Deque.fsi @@ -159,9 +159,11 @@ module Deque = val iter: ('T -> unit) -> Deque<'T> -> unit ///O(n). Returns true if any element of the deque satisfies the given predicate. + ///Note: elements are not necessarily checked in FIFO order; the internal rear list is checked in reverse (LIFO) order. val exists: ('T -> bool) -> Deque<'T> -> bool ///O(n). Returns true if all elements of the deque satisfy the given predicate. + ///Note: elements are not necessarily checked in FIFO order; the internal rear list is checked in reverse (LIFO) order. val forall: ('T -> bool) -> Deque<'T> -> bool ///O(1) amortized, O(n), worst case. Returns option first element and tail. diff --git a/src/FSharpx.Collections/Queue.fs b/src/FSharpx.Collections/Queue.fs index f1bba106..6d36ea23 100644 --- a/src/FSharpx.Collections/Queue.fs +++ b/src/FSharpx.Collections/Queue.fs @@ -190,10 +190,12 @@ module Queue = List.iter f (List.rev q.rBack) ///O(n). Returns true if any element of the queue satisfies the given predicate. + ///Note: elements are not necessarily checked in FIFO order; the internal rear list is checked in reverse (LIFO) order. let exists (predicate: 'T -> bool) (q: Queue<'T>) : bool = List.exists predicate q.front || List.exists predicate q.rBack ///O(n). Returns true if all elements of the queue satisfy the given predicate. + ///Note: elements are not necessarily checked in FIFO order; the internal rear list is checked in reverse (LIFO) order. let forall (predicate: 'T -> bool) (q: Queue<'T>) : bool = List.forall predicate q.front && List.forall predicate q.rBack diff --git a/src/FSharpx.Collections/Queue.fsi b/src/FSharpx.Collections/Queue.fsi index 649e43d3..be7c6959 100644 --- a/src/FSharpx.Collections/Queue.fsi +++ b/src/FSharpx.Collections/Queue.fsi @@ -107,9 +107,11 @@ module Queue = val iter: ('T -> unit) -> Queue<'T> -> unit ///O(n). Returns true if any element of the queue satisfies the given predicate. + ///Note: elements are not necessarily checked in FIFO order; the internal rear list is checked in reverse (LIFO) order. val exists: ('T -> bool) -> Queue<'T> -> bool ///O(n). Returns true if all elements of the queue satisfy the given predicate. + ///Note: elements are not necessarily checked in FIFO order; the internal rear list is checked in reverse (LIFO) order. val forall: ('T -> bool) -> Queue<'T> -> bool ///O(1) amortized, O(n) worst-case. Returns the first element and tail. From 1b1c880456bb1129ed28e62007a2940b1ba23d8e Mon Sep 17 00:00:00 2001 From: Grzegorz Dziadkiewicz Date: Sun, 19 Apr 2026 14:22:17 +0200 Subject: [PATCH 04/14] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/FSharpx.Collections/Deque.fs | 4 ++-- src/FSharpx.Collections/Deque.fsi | 8 ++++---- tests/FSharpx.Collections.Tests/DequeTest.fs | 4 ++-- tests/FSharpx.Collections.Tests/QueueTest.fs | 6 ++++++ 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/src/FSharpx.Collections/Deque.fs b/src/FSharpx.Collections/Deque.fs index 14a86982..18fd46d6 100644 --- a/src/FSharpx.Collections/Deque.fs +++ b/src/FSharpx.Collections/Deque.fs @@ -244,11 +244,11 @@ module Deque = let inline toSeq(q: Deque<'T>) = q :> seq<'T> - ///O(n). Returns a list of the deque elements in FIFO order. + ///O(n). Returns a list of the deque elements in front-to-back (head-to-last) order. let toList(q: Deque<'T>) : 'T list = q.front @ List.rev q.rBack - ///O(n). Returns an array of the deque elements in FIFO order. + ///O(n). Returns an array of the deque elements in front-to-back (head-to-last) order. let toArray(q: Deque<'T>) : 'T[] = Array.ofSeq q diff --git a/src/FSharpx.Collections/Deque.fsi b/src/FSharpx.Collections/Deque.fsi index 560bad2b..2b67848f 100644 --- a/src/FSharpx.Collections/Deque.fsi +++ b/src/FSharpx.Collections/Deque.fsi @@ -143,10 +143,10 @@ module Deque = ///O(n). Views the given deque as a sequence. val inline toSeq: Deque<'T> -> seq<'T> - ///O(n). Returns a list of the deque elements in FIFO order. + ///O(n). Returns a list of the deque elements in front-to-back (head-to-last) order. val toList: Deque<'T> -> 'T list - ///O(n). Returns an array of the deque elements in FIFO order. + ///O(n). Returns an array of the deque elements in front-to-back (head-to-last) order. val toArray: Deque<'T> -> 'T[] ///O(n). Returns a new deque whose elements are the results of applying the given function to each element. @@ -159,11 +159,11 @@ module Deque = val iter: ('T -> unit) -> Deque<'T> -> unit ///O(n). Returns true if any element of the deque satisfies the given predicate. - ///Note: elements are not necessarily checked in FIFO order; the internal rear list is checked in reverse (LIFO) order. + ///Note: elements are not necessarily checked in front-to-back (enumeration) order; the internal rear list is checked in reverse order. val exists: ('T -> bool) -> Deque<'T> -> bool ///O(n). Returns true if all elements of the deque satisfy the given predicate. - ///Note: elements are not necessarily checked in FIFO order; the internal rear list is checked in reverse (LIFO) order. + ///Note: elements are not necessarily checked in front-to-back (enumeration) order; the internal rear list is checked in reverse order. val forall: ('T -> bool) -> Deque<'T> -> bool ///O(1) amortized, O(n), worst case. Returns option first element and tail. diff --git a/tests/FSharpx.Collections.Tests/DequeTest.fs b/tests/FSharpx.Collections.Tests/DequeTest.fs index a222c24a..6d0355ad 100644 --- a/tests/FSharpx.Collections.Tests/DequeTest.fs +++ b/tests/FSharpx.Collections.Tests/DequeTest.fs @@ -1223,9 +1223,9 @@ module DequeTests = (Prop.forAll(Arb.fromGen intGensStart2.[2]) <| fun (q, l) -> List.ofSeq q.TryInitial.Value = (List.rev l |> List.tail |> List.rev)) - test "toList preserves FIFO order" { + test "toList preserves front-to-back order" { let q = Deque.ofSeq [ 1; 2; 3; 4; 5 ] - Expect.equal "toList" [ 1; 2; 3; 4; 5 ] (Deque.toList q) + Expect.equal "toList preserves front-to-back order" [ 1; 2; 3; 4; 5 ] (Deque.toList q) } test "toList empty deque" { Expect.equal "toList empty" [] (Deque.toList Deque.empty) } diff --git a/tests/FSharpx.Collections.Tests/QueueTest.fs b/tests/FSharpx.Collections.Tests/QueueTest.fs index f7f4acba..8924002a 100644 --- a/tests/FSharpx.Collections.Tests/QueueTest.fs +++ b/tests/FSharpx.Collections.Tests/QueueTest.fs @@ -330,6 +330,12 @@ module QueueTests = Expect.equal "toArray" [| 1; 2; 3 |] (Queue.toArray q) } + test "toArray preserves FIFO order across front/rBack boundary" { + let q = Queue.ofSeq [ 1; 2; 3 ] |> Queue.conj 4 |> Queue.conj 5 + Expect.equal "toArray front/rBack" [| 1; 2; 3; 4; 5 |] (Queue.toArray q) + } + + test "toArray empty queue" { Expect.equal "toArray empty" [||] (Queue.toArray Queue.empty) } test "map transforms elements" { let q = Queue.ofSeq [ 1; 2; 3 ] Expect.equal "map" [ 2; 4; 6 ] (Queue.map ((*) 2) q |> Queue.toList) From 8fc0e20cbe7f6e6c52ddd14aae79e1946d2fcaf4 Mon Sep 17 00:00:00 2001 From: Grzegorz Dziadkiewicz Date: Sun, 19 Apr 2026 14:23:16 +0200 Subject: [PATCH 05/14] Update tests/FSharpx.Collections.Tests/DequeTest.fs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- tests/FSharpx.Collections.Tests/DequeTest.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/FSharpx.Collections.Tests/DequeTest.fs b/tests/FSharpx.Collections.Tests/DequeTest.fs index 6d0355ad..01639174 100644 --- a/tests/FSharpx.Collections.Tests/DequeTest.fs +++ b/tests/FSharpx.Collections.Tests/DequeTest.fs @@ -1231,8 +1231,8 @@ module DequeTests = test "toList empty deque" { Expect.equal "toList empty" [] (Deque.toList Deque.empty) } test "toArray preserves FIFO order" { - let q = Deque.ofSeq [ 1; 2; 3 ] - Expect.equal "toArray" [| 1; 2; 3 |] (Deque.toArray q) + let q = Deque.ofSeq [ 1; 2; 3 ] |> Deque.conj 4 |> Deque.conj 5 + Expect.equal "toArray" [| 1; 2; 3; 4; 5 |] (Deque.toArray q) } test "map transforms elements" { From a1966733c25fd0045f4715bdcf1db2440495aae4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 19 Apr 2026 12:24:46 +0000 Subject: [PATCH 06/14] docs: fix FIFO/LIFO wording in Deque.exists/forall to front-to-back (enumeration) order Agent-Logs-Url: https://github.com/fsprojects/FSharpx.Collections/sessions/5eadd029-f378-41de-ae25-5542f541bada Co-authored-by: gdziadkiewicz <8547855+gdziadkiewicz@users.noreply.github.com> --- src/FSharpx.Collections/Deque.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/FSharpx.Collections/Deque.fs b/src/FSharpx.Collections/Deque.fs index 18fd46d6..3383d084 100644 --- a/src/FSharpx.Collections/Deque.fs +++ b/src/FSharpx.Collections/Deque.fs @@ -266,12 +266,12 @@ module Deque = List.iter f (List.rev q.rBack) ///O(n). Returns true if any element of the deque satisfies the given predicate. - ///Note: elements are not necessarily checked in FIFO order; the internal rear list is checked in reverse (LIFO) order. + ///Note: elements are not necessarily checked in front-to-back (enumeration) order; the internal rear list is checked in reverse order. let exists (predicate: 'T -> bool) (q: Deque<'T>) : bool = List.exists predicate q.front || List.exists predicate q.rBack ///O(n). Returns true if all elements of the deque satisfy the given predicate. - ///Note: elements are not necessarily checked in FIFO order; the internal rear list is checked in reverse (LIFO) order. + ///Note: elements are not necessarily checked in front-to-back (enumeration) order; the internal rear list is checked in reverse order. let forall (predicate: 'T -> bool) (q: Deque<'T>) : bool = List.forall predicate q.front && List.forall predicate q.rBack From 2f3fe67882b0c8c0e44421b91eede04c97fa8cfb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 25 Apr 2026 13:04:56 +0000 Subject: [PATCH 07/14] =?UTF-8?q?test:=20improve=20test=20coverage=20and?= =?UTF-8?q?=20rename=20FIFO=E2=86=92front-to-back=20in=20Deque=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Agent-Logs-Url: https://github.com/fsprojects/FSharpx.Collections/sessions/2df01a43-f11d-4d17-8335-41b66ae349ef Co-authored-by: gdziadkiewicz <8547855+gdziadkiewicz@users.noreply.github.com> --- tests/FSharpx.Collections.Tests/DequeTest.fs | 13 ++++++++++--- tests/FSharpx.Collections.Tests/QueueTest.fs | 6 ++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/tests/FSharpx.Collections.Tests/DequeTest.fs b/tests/FSharpx.Collections.Tests/DequeTest.fs index 01639174..aa9402f9 100644 --- a/tests/FSharpx.Collections.Tests/DequeTest.fs +++ b/tests/FSharpx.Collections.Tests/DequeTest.fs @@ -1230,17 +1230,19 @@ module DequeTests = test "toList empty deque" { Expect.equal "toList empty" [] (Deque.toList Deque.empty) } - test "toArray preserves FIFO order" { + test "toArray preserves front-to-back order" { let q = Deque.ofSeq [ 1; 2; 3 ] |> Deque.conj 4 |> Deque.conj 5 Expect.equal "toArray" [| 1; 2; 3; 4; 5 |] (Deque.toArray q) } + test "toArray empty deque" { Expect.equal "toArray empty" [||] (Deque.toArray Deque.empty) } + test "map transforms elements" { let q = Deque.ofSeq [ 1; 2; 3 ] Expect.equal "map" [ 2; 4; 6 ] (Deque.map ((*) 2) q |> Deque.toList) } - test "map preserves FIFO order" { + test "map preserves front-to-back order" { let q = Deque.ofSeq [ "a"; "b"; "c" ] |> Deque.conj "d" |> Deque.conj "e" Expect.equal "map order" [ "A"; "B"; "C"; "D"; "E" ] (Deque.map (fun (s: string) -> s.ToUpper()) q |> Deque.toList) @@ -1256,12 +1258,17 @@ module DequeTests = Expect.equal "filter order" [ 1; 3; 5 ] (Deque.filter (fun x -> x % 2 <> 0) q |> Deque.toList) } + test "filter preserves front-to-back order across front/rBack" { + let q = Deque.ofSeq [ 1; 2; 3 ] |> Deque.conj 4 |> Deque.conj 5 + Expect.equal "filter front/rBack" [ 2; 4 ] (Deque.filter (fun x -> x % 2 = 0) q |> Deque.toList) + } + test "filter returns empty deque when no elements match" { let q = Deque.ofSeq [ 1; 2; 3 ] Expect.isTrue "filter empty" (Deque.filter (fun _ -> false) q |> Deque.isEmpty) } - test "iter visits each element in FIFO order" { + test "iter visits each element in front-to-back order" { let q = Deque.ofSeq [ 1; 2; 3 ] let result = System.Collections.Generic.List() Deque.iter result.Add q diff --git a/tests/FSharpx.Collections.Tests/QueueTest.fs b/tests/FSharpx.Collections.Tests/QueueTest.fs index 8924002a..3d6f8a3c 100644 --- a/tests/FSharpx.Collections.Tests/QueueTest.fs +++ b/tests/FSharpx.Collections.Tests/QueueTest.fs @@ -362,6 +362,12 @@ module QueueTests = Expect.isTrue "filter all out" (Queue.filter (fun _ -> false) q |> Queue.isEmpty) } + test "filter rebuilds front when all front elements are filtered out" { + // front=[1;3], rBack=[4;2] — filtering for evens empties front, so List.rev rBack becomes new front + let q = Queue.ofSeq [ 1; 3 ] |> Queue.conj 2 |> Queue.conj 4 + Expect.equal "filter front rebuild" [ 2; 4 ] (Queue.filter (fun x -> x % 2 = 0) q |> Queue.toList) + } + test "iter visits each element in FIFO order" { let q = Queue.ofSeq [ 1; 2; 3 ] let result = System.Collections.Generic.List() From e3d0f2d99a2817a704c82cc1b800328b0916be98 Mon Sep 17 00:00:00 2001 From: Grzegorz Dziadkiewicz Date: Sat, 25 Apr 2026 16:17:54 +0200 Subject: [PATCH 08/14] Update src/FSharpx.Collections/Deque.fs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/FSharpx.Collections/Deque.fs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/FSharpx.Collections/Deque.fs b/src/FSharpx.Collections/Deque.fs index 3383d084..8b102e1d 100644 --- a/src/FSharpx.Collections/Deque.fs +++ b/src/FSharpx.Collections/Deque.fs @@ -250,8 +250,20 @@ module Deque = ///O(n). Returns an array of the deque elements in front-to-back (head-to-last) order. let toArray(q: Deque<'T>) : 'T[] = - Array.ofSeq q + let result = Array.zeroCreate q.Length + let mutable i = 0 + for x in q.front do + result.[i] <- x + i <- i + 1 + + let mutable j = q.Length - 1 + + for x in q.rBack do + result.[j] <- x + j <- j - 1 + + result ///O(n). Returns a new deque whose elements are the results of applying the given function to each element. let map (f: 'T -> 'U) (q: Deque<'T>) : Deque<'U> = Deque<'U>(List.map f q.front, List.map f q.rBack) From 32f979ffe920dda23d77492b7a047a4ba2acb03a Mon Sep 17 00:00:00 2001 From: Grzegorz Dziadkiewicz Date: Sat, 25 Apr 2026 16:18:22 +0200 Subject: [PATCH 09/14] Update tests/FSharpx.Collections.Tests/DequeTest.fs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- tests/FSharpx.Collections.Tests/DequeTest.fs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/FSharpx.Collections.Tests/DequeTest.fs b/tests/FSharpx.Collections.Tests/DequeTest.fs index aa9402f9..ddcd10c3 100644 --- a/tests/FSharpx.Collections.Tests/DequeTest.fs +++ b/tests/FSharpx.Collections.Tests/DequeTest.fs @@ -1285,6 +1285,10 @@ module DequeTests = Expect.isFalse "exists false" (Deque.exists ((=) 99) q) } + test "exists returns false on empty deque" { + let q = Deque.empty + Expect.isFalse "exists empty" (Deque.exists ((=) 1) q) + } test "forall returns true when all elements satisfy predicate" { let q = Deque.ofSeq [ 2; 4; 6 ] Expect.isTrue "forall" (Deque.forall (fun x -> x % 2 = 0) q) From 475ea52535b6e298d3f56ff9ded7010170ada37b Mon Sep 17 00:00:00 2001 From: Grzegorz Dziadkiewicz Date: Sat, 25 Apr 2026 16:18:41 +0200 Subject: [PATCH 10/14] Update tests/FSharpx.Collections.Tests/DequeTest.fs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- tests/FSharpx.Collections.Tests/DequeTest.fs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/FSharpx.Collections.Tests/DequeTest.fs b/tests/FSharpx.Collections.Tests/DequeTest.fs index ddcd10c3..c4857b24 100644 --- a/tests/FSharpx.Collections.Tests/DequeTest.fs +++ b/tests/FSharpx.Collections.Tests/DequeTest.fs @@ -1297,4 +1297,9 @@ module DequeTests = test "forall returns false when some elements do not" { let q = Deque.ofSeq [ 2; 3; 6 ] Expect.isFalse "forall false" (Deque.forall (fun x -> x % 2 = 0) q) + } + + test "forall returns true for empty deque" { + let q = Deque.empty + Expect.isTrue "forall empty" (Deque.forall (fun x -> x % 2 = 0) q) } ] From 368723fd334c6c693967aece59174fed4d26e9c7 Mon Sep 17 00:00:00 2001 From: Grzegorz Dziadkiewicz Date: Sat, 25 Apr 2026 16:19:06 +0200 Subject: [PATCH 11/14] Update tests/FSharpx.Collections.Tests/QueueTest.fs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- tests/FSharpx.Collections.Tests/QueueTest.fs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/FSharpx.Collections.Tests/QueueTest.fs b/tests/FSharpx.Collections.Tests/QueueTest.fs index 3d6f8a3c..5aa8ab3e 100644 --- a/tests/FSharpx.Collections.Tests/QueueTest.fs +++ b/tests/FSharpx.Collections.Tests/QueueTest.fs @@ -385,6 +385,10 @@ module QueueTests = Expect.isFalse "exists false" (Queue.exists ((=) 99) q) } + test "exists returns false on empty queue" { + let q = Queue.empty + Expect.isFalse "exists empty" (Queue.exists ((=) 1) q) + } test "forall returns true when all elements satisfy predicate" { let q = Queue.ofSeq [ 2; 4; 6 ] Expect.isTrue "forall" (Queue.forall (fun x -> x % 2 = 0) q) From 88e2369300cb89342f6ab4155aca8b5383005a3a Mon Sep 17 00:00:00 2001 From: Grzegorz Dziadkiewicz Date: Sat, 25 Apr 2026 18:54:48 +0200 Subject: [PATCH 12/14] Format code --- src/FSharpx.Collections/Deque.fs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/FSharpx.Collections/Deque.fs b/src/FSharpx.Collections/Deque.fs index 8b102e1d..edb3ac96 100644 --- a/src/FSharpx.Collections/Deque.fs +++ b/src/FSharpx.Collections/Deque.fs @@ -264,6 +264,7 @@ module Deque = j <- j - 1 result + ///O(n). Returns a new deque whose elements are the results of applying the given function to each element. let map (f: 'T -> 'U) (q: Deque<'T>) : Deque<'U> = Deque<'U>(List.map f q.front, List.map f q.rBack) From d25aa604c7baefde54e3de8ea8d1d1c4ed8218ec Mon Sep 17 00:00:00 2001 From: Grzegorz Dziadkiewicz Date: Sat, 25 Apr 2026 18:58:55 +0200 Subject: [PATCH 13/14] Update src/FSharpx.Collections/Queue.fs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/FSharpx.Collections/Queue.fs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/FSharpx.Collections/Queue.fs b/src/FSharpx.Collections/Queue.fs index 6d36ea23..b3ba2e23 100644 --- a/src/FSharpx.Collections/Queue.fs +++ b/src/FSharpx.Collections/Queue.fs @@ -163,11 +163,13 @@ module Queue = i <- i + 1) q.front + let mutable j = q.Length - 1 + List.iter (fun x -> - arr.[i] <- x - i <- i + 1) - (List.rev q.rBack) + arr.[j] <- x + j <- j - 1) + q.rBack arr From 5d668354cc271973a6458fec6bc2e7b2ed2d58e9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 25 Apr 2026 17:02:39 +0000 Subject: [PATCH 14/14] test: add empty-queue forall test for Queue Agent-Logs-Url: https://github.com/fsprojects/FSharpx.Collections/sessions/bb349dd2-2f46-45f5-88f9-0b306455ec7d Co-authored-by: gdziadkiewicz <8547855+gdziadkiewicz@users.noreply.github.com> --- tests/FSharpx.Collections.Tests/QueueTest.fs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/FSharpx.Collections.Tests/QueueTest.fs b/tests/FSharpx.Collections.Tests/QueueTest.fs index 5aa8ab3e..265ff9a5 100644 --- a/tests/FSharpx.Collections.Tests/QueueTest.fs +++ b/tests/FSharpx.Collections.Tests/QueueTest.fs @@ -397,4 +397,9 @@ module QueueTests = test "forall returns false when some elements do not satisfy predicate" { let q = Queue.ofSeq [ 2; 3; 6 ] Expect.isFalse "forall false" (Queue.forall (fun x -> x % 2 = 0) q) + } + + test "forall returns true for empty queue" { + let q = Queue.empty + Expect.isTrue "forall empty" (Queue.forall (fun x -> x % 2 = 0) q) } ]