From 11a10ad6c45ddd92608b55c58f18da033c8054f8 Mon Sep 17 00:00:00 2001 From: konsumlamm Date: Fri, 1 Dec 2023 22:04:31 +0100 Subject: [PATCH 1/4] Update CI --- .github/workflows/haskell.yaml | 6 +++--- rrb-vector.cabal | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/haskell.yaml b/.github/workflows/haskell.yaml index 2656d83..132d6bb 100644 --- a/.github/workflows/haskell.yaml +++ b/.github/workflows/haskell.yaml @@ -10,10 +10,10 @@ jobs: strategy: fail-fast: false matrix: - ghc: ['8.4', '8.6', '8.8', '8.10', '9.0', '9.2', '9.4', '9.6'] + ghc: ['8.4', '8.6', '8.8', '8.10', '9.0', '9.2', '9.4', '9.6', '9.8'] steps: - - uses: actions/checkout@v3 - - uses: haskell/actions/setup@v2 + - uses: actions/checkout@v4 + - uses: haskell-actions/setup@v2 with: ghc-version: ${{ matrix.ghc }} - name: Build diff --git a/rrb-vector.cabal b/rrb-vector.cabal index d5455ce..01ec33e 100644 --- a/rrb-vector.cabal +++ b/rrb-vector.cabal @@ -29,8 +29,9 @@ tested-with: GHC == 8.10.7 GHC == 9.0.2 GHC == 9.2.8 - GHC == 9.4.7 + GHC == 9.4.8 GHC == 9.6.3 + GHC == 9.8.1 source-repository head type: git From d130f20f44d7345604be29fc30373fc10921e05b Mon Sep 17 00:00:00 2001 From: konsumlamm Date: Sat, 2 Dec 2023 16:02:23 +0100 Subject: [PATCH 2/4] Add `findIndexL`, `findIndexR`, `findIndicesL`, `findIndicesR` --- CHANGELOG.md | 5 +++++ rrb-vector.cabal | 2 +- src/Data/RRBVector.hs | 1 + src/Data/RRBVector/Internal.hs | 17 +++++++++++++++++ test/Properties.hs | 19 +++++++++++++++++++ 5 files changed, 43 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a238138..01d77d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# 0.2.1.0 - December 2023 + +* Add `findIndexL`, `findIndexR`, `findIndicesL`, `findIndicesR` +* Fix bug in `|>` & `<|` ([#10](https://github.com/konsumlamm/rrb-vector/issues/10)) + # 0.2.0.1 - October 2023 * Support `primitive-0.9` and `deepseq-1.5` diff --git a/rrb-vector.cabal b/rrb-vector.cabal index 01ec33e..b182ccf 100644 --- a/rrb-vector.cabal +++ b/rrb-vector.cabal @@ -60,7 +60,7 @@ test-suite test Strictness type: exitcode-stdio-1.0 ghc-options: -Wall -Wno-orphans -Wno-type-defaults - build-depends: base, deepseq, quickcheck-classes-base, rrb-vector, tasty, tasty-quickcheck + build-depends: base, containers, deepseq, quickcheck-classes-base, rrb-vector, tasty, tasty-quickcheck if impl(ghc >= 8.6) build-depends: nothunks default-language: Haskell2010 diff --git a/src/Data/RRBVector.hs b/src/Data/RRBVector.hs index 10ed1c5..2a42dde 100644 --- a/src/Data/RRBVector.hs +++ b/src/Data/RRBVector.hs @@ -33,6 +33,7 @@ module Data.RRBVector , adjust, adjust' , take, drop, splitAt , insertAt, deleteAt + , findIndexL, findIndexR, findIndicesL, findIndicesR -- * With Index -- -- | Reexported from [indexed-traversable](https://hackage.haskell.org/package/indexed-traversable). diff --git a/src/Data/RRBVector/Internal.hs b/src/Data/RRBVector/Internal.hs index 2db512a..73d0fd8 100644 --- a/src/Data/RRBVector/Internal.hs +++ b/src/Data/RRBVector/Internal.hs @@ -24,6 +24,7 @@ module Data.RRBVector.Internal , adjust, adjust' , take, drop, splitAt , insertAt, deleteAt + , findIndexL, findIndexR, findIndicesL, findIndicesR -- * Transformations , map, map', reverse -- * Zipping and unzipping @@ -651,6 +652,22 @@ insertAt i x v = let (left, right) = splitAt i v in (left |> x) >< right deleteAt :: Int -> Vector a -> Vector a deleteAt i v = let (left, right) = splitAt (i + 1) v in take i left >< right +-- | \(O(n)\). Find the first index from the left that satisfies the predicate. +findIndexL :: (a -> Bool) -> Vector a -> Maybe Int +findIndexL f = ifoldr (\i x acc -> if f x then Just i else acc) Nothing + +-- | \(O(n)\). Find the first index from the right that satisfies the predicate. +findIndexR :: (a -> Bool) -> Vector a -> Maybe Int +findIndexR f = ifoldl (\i acc x -> if f x then Just i else acc) Nothing + +-- | \(O(n)\). Find the indices that satisfy the predicate, starting from the left. +findIndicesL :: (a -> Bool) -> Vector a -> [Int] +findIndicesL f = ifoldr (\i x acc -> if f x then i : acc else acc) [] + +-- | \(O(n)\). Find the indices that satisfy the predicate, starting from the right. +findIndicesR :: (a -> Bool) -> Vector a -> [Int] +findIndicesR f = ifoldl (\i acc x -> if f x then i : acc else acc) [] + -- concatenation -- | \(O(\log \max(n_1, n_2))\). Concatenates two vectors. diff --git a/test/Properties.hs b/test/Properties.hs index 14c2390..f6145f5 100644 --- a/test/Properties.hs +++ b/test/Properties.hs @@ -1,5 +1,7 @@ {-# LANGUAGE CPP #-} +{-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-} + module Properties ( properties ) where @@ -12,6 +14,7 @@ import Data.List (uncons) import Data.Proxy (Proxy(..)) import Prelude hiding ((==)) -- use @===@ instead +import qualified Data.Sequence as Seq import qualified Data.RRBVector as V import Test.QuickCheck.Classes.Base import Test.Tasty @@ -135,6 +138,22 @@ properties = testGroup "properties" , testProperty "satisfies `deleteAt 0 v = drop 1 v`" $ \v -> V.deleteAt 0 v === V.drop 1 v , testProperty "satisfies `deleteAt (length v - 1) v = take (length v - 1) v`" $ \v -> V.deleteAt (length v - 1) v === V.take (length v - 1) v ] + , testGroup "findIndexL" + [ testProperty "finds the first index" $ \v (Fn f) -> V.findIndexL f v === Seq.findIndexL f (Seq.fromList (toList v)) + , testProperty "returns Nothing for the empty vector" $ \(Fn f) -> V.findIndexL f V.empty === Nothing + ] + , testGroup "findIndexR" + [ testProperty "finds the last index" $ \v (Fn f) -> V.findIndexR f v === Seq.findIndexR f (Seq.fromList (toList v)) + , testProperty "returns Nothing for the empty vector" $ \(Fn f) -> V.findIndexR f V.empty === Nothing + ] + , localOption (QuickCheckMaxSize 1000) $ testGroup "findIndicesL" + [ testProperty "finds the indices starting from the left" $ \v (Fn f) -> V.findIndicesL f v === Seq.findIndicesL f (Seq.fromList (toList v)) + , testProperty "returns [] for the empty vector" $ \(Fn f) -> V.findIndicesL f V.empty === [] + ] + , localOption (QuickCheckMaxSize 1000) $ testGroup "findIndicesR" + [ testProperty "finds the indices starting from the right" $ \v (Fn f) -> V.findIndicesR f v === Seq.findIndicesR f (Seq.fromList (toList v)) + , testProperty "returns [] for the empty vector" $ \(Fn f) -> V.findIndicesR f V.empty === [] + ] , testGroup "reverse" [ testProperty "reverses the vector" $ \v -> toList (V.reverse v) === reverse (toList v) ] From d1ae5ea8c651a09caaf688cdf34455350ab603d5 Mon Sep 17 00:00:00 2001 From: konsumlamm Date: Sat, 2 Dec 2023 17:49:30 +0100 Subject: [PATCH 3/4] Add caching to CI --- .github/workflows/haskell.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/haskell.yaml b/.github/workflows/haskell.yaml index 132d6bb..9683c00 100644 --- a/.github/workflows/haskell.yaml +++ b/.github/workflows/haskell.yaml @@ -14,8 +14,15 @@ jobs: steps: - uses: actions/checkout@v4 - uses: haskell-actions/setup@v2 + id: setup-haskell with: ghc-version: ${{ matrix.ghc }} + - uses: actions/cache@v3 + with: + path: | + ${{ steps.setup-haskell.outputs.cabal-store }} + dist-newstyle + key: ${{ runner.os }}-${{ matrix.ghc }} - name: Build run: cabal build - name: Test From 204a6437c6fa170429555cc7bf524b3d3d916cb5 Mon Sep 17 00:00:00 2001 From: konsumlamm Date: Sat, 2 Dec 2023 17:57:58 +0100 Subject: [PATCH 4/4] Bump version to 0.2.1.0 --- rrb-vector.cabal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rrb-vector.cabal b/rrb-vector.cabal index b182ccf..961b35a 100644 --- a/rrb-vector.cabal +++ b/rrb-vector.cabal @@ -1,5 +1,5 @@ name: rrb-vector -version: 0.2.0.1 +version: 0.2.1.0 synopsis: Efficient RRB-Vectors description: An RRB-Vector is an efficient sequence data structure.