diff options
author | lehins <> | 2021-04-06 19:54:00 (GMT) |
---|---|---|
committer | hdiff <hdiff@hdiff.luite.com> | 2021-04-06 19:54:00 (GMT) |
commit | 3406684e53da48c14b760f9e04a95ac6ead32f0c (patch) | |
tree | 610e552f0b2861cad2af66f255fad4669b9e00fd | |
parent | 20de90be67e0c2800840c6dc9ff3cea52077e243 (diff) |
-rw-r--r-- | Data/Vector/Generic/Mutable.hs | 234 | ||||
-rw-r--r-- | Data/Vector/Mutable.hs | 205 | ||||
-rw-r--r-- | Data/Vector/Primitive/Mutable.hs | 205 | ||||
-rw-r--r-- | Data/Vector/Storable.hs | 6 | ||||
-rw-r--r-- | Data/Vector/Storable/Internal.hs | 18 | ||||
-rw-r--r-- | Data/Vector/Storable/Mutable.hs | 231 | ||||
-rw-r--r-- | Data/Vector/Unboxed/Mutable.hs | 207 | ||||
-rw-r--r-- | changelog.md | 12 | ||||
-rw-r--r-- | tests/Tests/Vector/Property.hs | 122 | ||||
-rw-r--r-- | tests/Utilities.hs | 15 | ||||
-rw-r--r-- | vector.cabal | 2 |
11 files changed, 1218 insertions, 39 deletions
diff --git a/Data/Vector/Generic/Mutable.hs b/Data/Vector/Generic/Mutable.hs index f9eedd8..c878064 100644 --- a/Data/Vector/Generic/Mutable.hs +++ b/Data/Vector/Generic/Mutable.hs @@ -30,7 +30,7 @@ module Data.Vector.Generic.Mutable ( -- * Construction -- ** Initialisation - new, unsafeNew, replicate, replicateM, clone, + new, unsafeNew, replicate, replicateM, generate, generateM, clone, -- ** Growing grow, unsafeGrow, @@ -40,8 +40,15 @@ module Data.Vector.Generic.Mutable ( clear, -- * Accessing individual elements - read, write, modify, swap, exchange, - unsafeRead, unsafeWrite, unsafeModify, unsafeSwap, unsafeExchange, + read, write, modify, modifyM, swap, exchange, + unsafeRead, unsafeWrite, unsafeModify, unsafeModifyM, unsafeSwap, unsafeExchange, + + -- * Folds + mapM_, imapM_, forM_, iforM_, + foldl, foldl', foldM, foldM', + foldr, foldr', foldrM, foldrM', + ifoldl, ifoldl', ifoldM, ifoldM', + ifoldr, ifoldr', ifoldrM, ifoldrM', -- * Modifying vectors nextPermutation, @@ -71,10 +78,10 @@ import qualified Data.Vector.Fusion.Stream.Monadic as Stream import Data.Vector.Fusion.Bundle.Size import Data.Vector.Fusion.Util ( delay_inline ) -import Control.Monad.Primitive ( PrimMonad, PrimState ) +import Control.Monad.Primitive ( PrimMonad, PrimState, stToPrim ) import Prelude hiding ( length, null, replicate, reverse, map, read, - take, drop, splitAt, init, tail ) + take, drop, splitAt, init, tail, mapM_, foldr, foldl ) #include "vector.h" @@ -616,6 +623,30 @@ replicateM :: (PrimMonad m, MVector v a) => Int -> m a -> m (v (PrimState m) a) {-# INLINE replicateM #-} replicateM n m = munstream (MBundle.replicateM n m) +-- | /O(n)/ Create a mutable vector of the given length (0 if the length is negative) +-- and fill it with the results of applying the function to each index. +-- +-- @since 0.12.3.0 +generate :: (PrimMonad m, MVector v a) => Int -> (Int -> a) -> m (v (PrimState m) a) +{-# INLINE generate #-} +generate n f = stToPrim $ generateM n (return . f) + +-- | /O(n)/ Create a mutable vector of the given length (0 if the length is +-- negative) and fill it with the results of applying the monadic function to each +-- index. Iteration starts at index 0. +-- +-- @since 0.12.3.0 +generateM :: (PrimMonad m, MVector v a) => Int -> (Int -> m a) -> m (v (PrimState m) a) +{-# INLINE generateM #-} +generateM n f + | n <= 0 = new 0 + | otherwise = do + vec <- new n + let loop i | i >= n = return vec + | otherwise = do unsafeWrite vec i =<< f i + loop (i + 1) + loop 0 + -- | Create a copy of a mutable vector. clone :: (PrimMonad m, MVector v a) => v (PrimState m) a -> m (v (PrimState m) a) {-# INLINE clone #-} @@ -755,6 +786,14 @@ modify :: (PrimMonad m, MVector v a) => v (PrimState m) a -> (a -> a) -> Int -> modify v f i = BOUNDS_CHECK(checkIndex) "modify" i (length v) $ unsafeModify v f i +-- | Modify the element at the given position using a monadic function. +-- +-- @since 0.12.3.0 +modifyM :: (PrimMonad m, MVector v a) => v (PrimState m) a -> (a -> m a) -> Int -> m () +{-# INLINE modifyM #-} +modifyM v f i = BOUNDS_CHECK(checkIndex) "modifyM" i (length v) + $ unsafeModifyM v f i + -- | Swap the elements at the given positions. swap :: (PrimMonad m, MVector v a) => v (PrimState m) a -> Int -> Int -> m () {-# INLINE swap #-} @@ -788,6 +827,15 @@ unsafeModify v f i = UNSAFE_CHECK(checkIndex) "unsafeModify" i (length v) $ basicUnsafeRead v i >>= \x -> basicUnsafeWrite v i (f x) +-- | Modify the element at the given position using a monadic +-- function. No bounds checks are performed. +-- +-- @since 0.12.3.0 +unsafeModifyM :: (PrimMonad m, MVector v a) => v (PrimState m) a -> (a -> m a) -> Int -> m () +{-# INLINE unsafeModifyM #-} +unsafeModifyM v f i = UNSAFE_CHECK(checkIndex) "unsafeModifyM" i (length v) + $ stToPrim . basicUnsafeWrite v i =<< f =<< stToPrim (basicUnsafeRead v i) + -- | Swap the elements at the given positions. No bounds checks are performed. unsafeSwap :: (PrimMonad m, MVector v a) => v (PrimState m) a -> Int -> Int -> m () @@ -811,6 +859,182 @@ unsafeExchange v i x = UNSAFE_CHECK(checkIndex) "unsafeExchange" i (length v) unsafeWrite v i x return y +-- Folds +-- ----- + +forI_ :: (Monad m, MVector v a) => v (PrimState m) a -> (Int -> m b) -> m () +{-# INLINE forI_ #-} +forI_ v f = loop 0 + where + loop i | i >= n = return () + | otherwise = f i >> loop (i + 1) + n = length v + +-- | /O(n)/ Apply the monadic action to every element of the vector, discarding the results. +-- +-- @since 0.12.3.0 +mapM_ :: (PrimMonad m, MVector v a) => (a -> m b) -> v (PrimState m) a -> m () +{-# INLINE mapM_ #-} +mapM_ f v = forI_ v $ \i -> f =<< unsafeRead v i + +-- | /O(n)/ Apply the monadic action to every element of the vector and its index, discarding the results. +-- +-- @since 0.12.3.0 +imapM_ :: (PrimMonad m, MVector v a) => (Int -> a -> m b) -> v (PrimState m) a -> m () +{-# INLINE imapM_ #-} +imapM_ f v = forI_ v $ \i -> f i =<< unsafeRead v i + +-- | /O(n)/ Apply the monadic action to every element of the vector, +-- discarding the results. It's same as the @flip mapM_@. +-- +-- @since 0.12.3.0 +forM_ :: (PrimMonad m, MVector v a) => v (PrimState m) a -> (a -> m b) -> m () +{-# INLINE forM_ #-} +forM_ = flip mapM_ + +-- | /O(n)/ Apply the monadic action to every element of the vector +-- and its index, discarding the results. It's same as the @flip imapM_@. +-- +-- @since 0.12.3.0 +iforM_ :: (PrimMonad m, MVector v a) => v (PrimState m) a -> (Int -> a -> m b) -> m () +{-# INLINE iforM_ #-} +iforM_ = flip imapM_ + +-- | /O(n)/ Pure left fold. +-- +-- @since 0.12.3.0 +foldl :: (PrimMonad m, MVector v a) => (b -> a -> b) -> b -> v (PrimState m) a -> m b +{-# INLINE foldl #-} +foldl f = ifoldl (\b _ -> f b) + +-- | /O(n)/ Pure left fold with strict accumulator. +-- +-- @since 0.12.3.0 +foldl' :: (PrimMonad m, MVector v a) => (b -> a -> b) -> b -> v (PrimState m) a -> m b +{-# INLINE foldl' #-} +foldl' f = ifoldl' (\b _ -> f b) + +-- | /O(n)/ Pure left fold (function applied to each element and its index). +-- +-- @since 0.12.3.0 +ifoldl :: (PrimMonad m, MVector v a) => (b -> Int -> a -> b) -> b -> v (PrimState m) a -> m b +{-# INLINE ifoldl #-} +ifoldl f b0 v = stToPrim $ ifoldM (\b i a -> return $ f b i a) b0 v + +-- | /O(n)/ Pure left fold with strict accumulator (function applied to each element and its index). +-- +-- @since 0.12.3.0 +ifoldl' :: (PrimMonad m, MVector v a) => (b -> Int -> a -> b) -> b -> v (PrimState m) a -> m b +{-# INLINE ifoldl' #-} +ifoldl' f b0 v = stToPrim $ ifoldM' (\b i a -> return $ f b i a) b0 v + +-- | /O(n)/ Pure right fold. +-- +-- @since 0.12.3.0 +foldr :: (PrimMonad m, MVector v a) => (a -> b -> b) -> b -> v (PrimState m) a -> m b +{-# INLINE foldr #-} +foldr f = ifoldr (const f) + +-- | /O(n)/ Pure right fold with strict accumulator. +-- +-- @since 0.12.3.0 +foldr' :: (PrimMonad m, MVector v a) => (a -> b -> b) -> b -> v (PrimState m) a -> m b +{-# INLINE foldr' #-} +foldr' f = ifoldr' (const f) + +-- | /O(n)/ Pure right fold (function applied to each element and its index). +-- +-- @since 0.12.3.0 +ifoldr :: (PrimMonad m, MVector v a) => (Int -> a -> b -> b) -> b -> v (PrimState m) a -> m b +{-# INLINE ifoldr #-} +ifoldr f b0 v = stToPrim $ ifoldrM (\i a b -> return $ f i a b) b0 v + +-- | /O(n)/ Pure right fold with strict accumulator (function applied +-- to each element and its index). +-- +-- @since 0.12.3.0 +ifoldr' :: (PrimMonad m, MVector v a) => (Int -> a -> b -> b) -> b -> v (PrimState m) a -> m b +{-# INLINE ifoldr' #-} +ifoldr' f b0 v = stToPrim $ ifoldrM' (\i a b -> return $ f i a b) b0 v + +-- | /O(n)/ Monadic fold. +-- +-- @since 0.12.3.0 +foldM :: (PrimMonad m, MVector v a) => (b -> a -> m b) -> b -> v (PrimState m) a -> m b +{-# INLINE foldM #-} +foldM f = ifoldM (\x _ -> f x) + +-- | /O(n)/ Monadic fold with strict accumulator. +-- +-- @since 0.12.3.0 +foldM' :: (PrimMonad m, MVector v a) => (b -> a -> m b) -> b -> v (PrimState m) a -> m b +{-# INLINE foldM' #-} +foldM' f = ifoldM' (\x _ -> f x) + +-- | /O(n)/ Monadic fold (action applied to each element and its index). +-- +-- @since 0.12.3.0 +ifoldM :: (PrimMonad m, MVector v a) => (b -> Int -> a -> m b) -> b -> v (PrimState m) a -> m b +{-# INLINE ifoldM #-} +ifoldM f b0 v = loop 0 b0 + where + loop i b | i >= n = return b + | otherwise = do a <- unsafeRead v i + loop (i + 1) =<< f b i a + n = length v + +-- | /O(n)/ Monadic fold with strict accumulator (action applied to each element and its index). +-- +-- @since 0.12.3.0 +ifoldM' :: (PrimMonad m, MVector v a) => (b -> Int -> a -> m b) -> b -> v (PrimState m) a -> m b +{-# INLINE ifoldM' #-} +ifoldM' f b0 v = loop 0 b0 + where + loop i !b | i >= n = return b + | otherwise = do a <- unsafeRead v i + loop (i + 1) =<< f b i a + n = length v + +-- | /O(n)/ Monadic right fold. +-- +-- @since 0.12.3.0 +foldrM :: (PrimMonad m, MVector v a) => (a -> b -> m b) -> b -> v (PrimState m) a -> m b +{-# INLINE foldrM #-} +foldrM f = ifoldrM (const f) + +-- | /O(n)/ Monadic right fold with strict accumulator. +-- +-- @since 0.12.3.0 +foldrM' :: (PrimMonad m, MVector v a) => (a -> b -> m b) -> b -> v (PrimState m) a -> m b +{-# INLINE foldrM' #-} +foldrM' f = ifoldrM' (const f) + +-- | /O(n)/ Monadic right fold (action applied to each element and its index). +-- +-- @since 0.12.3.0 +ifoldrM :: (PrimMonad m, MVector v a) => (Int -> a -> b -> m b) -> b -> v (PrimState m) a -> m b +{-# INLINE ifoldrM #-} +ifoldrM f b0 v = loop (n-1) b0 + where + loop i b | i < 0 = return b + | otherwise = do a <- unsafeRead v i + loop (i - 1) =<< f i a b + n = length v + +-- | /O(n)/ Monadic right fold with strict accumulator (action applied +-- to each element and its index). +-- +-- @since 0.12.3.0 +ifoldrM' :: (PrimMonad m, MVector v a) => (Int -> a -> b -> m b) -> b -> v (PrimState m) a -> m b +{-# INLINE ifoldrM' #-} +ifoldrM' f b0 v = loop (n-1) b0 + where + loop i !b | i < 0 = return b + | otherwise = do a <- unsafeRead v i + loop (i - 1) =<< f i a b + n = length v + + -- Filling and copying -- ------------------- diff --git a/Data/Vector/Mutable.hs b/Data/Vector/Mutable.hs index 9069ce2..e99f7ef 100644 --- a/Data/Vector/Mutable.hs +++ b/Data/Vector/Mutable.hs @@ -31,7 +31,7 @@ module Data.Vector.Mutable ( -- * Construction -- ** Initialisation - new, unsafeNew, replicate, replicateM, clone, + new, unsafeNew, replicate, replicateM, generate, generateM, clone, -- ** Growing grow, unsafeGrow, @@ -40,8 +40,15 @@ module Data.Vector.Mutable ( clear, -- * Accessing individual elements - read, write, modify, swap, - unsafeRead, unsafeWrite, unsafeModify, unsafeSwap, + read, write, modify, modifyM, swap, exchange, + unsafeRead, unsafeWrite, unsafeModify, unsafeModifyM, unsafeSwap, unsafeExchange, + + -- * Folds + mapM_, imapM_, forM_, iforM_, + foldl, foldl', foldM, foldM', + foldr, foldr', foldrM, foldrM', + ifoldl, ifoldl', ifoldM, ifoldM', + ifoldr, ifoldr', ifoldrM, ifoldrM', -- * Modifying vectors nextPermutation, @@ -60,7 +67,7 @@ import Data.Primitive.Array import Control.Monad.Primitive import Prelude hiding ( length, null, replicate, reverse, read, - take, drop, splitAt, init, tail ) + take, drop, splitAt, init, tail, foldr, foldl, mapM_ ) import Data.Typeable ( Typeable ) @@ -299,6 +306,23 @@ replicateM :: PrimMonad m => Int -> m a -> m (MVector (PrimState m) a) {-# INLINE replicateM #-} replicateM = G.replicateM +-- | /O(n)/ Create a mutable vector of the given length (0 if the length is negative) +-- and fill it with the results of applying the function to each index. +-- +-- @since 0.12.3.0 +generate :: (PrimMonad m) => Int -> (Int -> a) -> m (MVector (PrimState m) a) +{-# INLINE generate #-} +generate = G.generate + +-- | /O(n)/ Create a mutable vector of the given length (0 if the length is +-- negative) and fill it with the results of applying the monadic function to each +-- index. Iteration starts at index 0. +-- +-- @since 0.12.3.0 +generateM :: (PrimMonad m) => Int -> (Int -> m a) -> m (MVector (PrimState m) a) +{-# INLINE generateM #-} +generateM = G.generateM + -- | Create a copy of a mutable vector. clone :: PrimMonad m => MVector (PrimState m) a -> m (MVector (PrimState m) a) {-# INLINE clone #-} @@ -382,11 +406,22 @@ modify :: PrimMonad m => MVector (PrimState m) a -> (a -> a) -> Int -> m () {-# INLINE modify #-} modify = G.modify +-- | Modify the element at the given position using a monadic function. +-- +-- @since 0.12.3.0 +modifyM :: (PrimMonad m) => MVector (PrimState m) a -> (a -> m a) -> Int -> m () +{-# INLINE modifyM #-} +modifyM = G.modifyM + -- | Swap the elements at the given positions. swap :: PrimMonad m => MVector (PrimState m) a -> Int -> Int -> m () {-# INLINE swap #-} swap = G.swap +-- | Replace the element at the given position and return the old element. +exchange :: (PrimMonad m) => MVector (PrimState m) a -> Int -> a -> m a +{-# INLINE exchange #-} +exchange = G.exchange -- | Yield the element at the given position. No bounds checks are performed. unsafeRead :: PrimMonad m => MVector (PrimState m) a -> Int -> m a @@ -403,11 +438,25 @@ unsafeModify :: PrimMonad m => MVector (PrimState m) a -> (a -> a) -> Int -> m ( {-# INLINE unsafeModify #-} unsafeModify = G.unsafeModify +-- | Modify the element at the given position using a monadic +-- function. No bounds checks are performed. +-- +-- @since 0.12.3.0 +unsafeModifyM :: (PrimMonad m) => MVector (PrimState m) a -> (a -> m a) -> Int -> m () +{-# INLINE unsafeModifyM #-} +unsafeModifyM = G.unsafeModifyM + -- | Swap the elements at the given positions. No bounds checks are performed. unsafeSwap :: PrimMonad m => MVector (PrimState m) a -> Int -> Int -> m () {-# INLINE unsafeSwap #-} unsafeSwap = G.unsafeSwap +-- | Replace the element at the given position and return the old element. No +-- bounds checks are performed. +unsafeExchange :: (PrimMonad m) => MVector (PrimState m) a -> Int -> a -> m a +{-# INLINE unsafeExchange #-} +unsafeExchange = G.unsafeExchange + -- Filling and copying -- ------------------- @@ -464,6 +513,154 @@ nextPermutation :: (PrimMonad m,Ord e) => MVector (PrimState m) e -> m Bool {-# INLINE nextPermutation #-} nextPermutation = G.nextPermutation + +-- Folds +-- ----- + +-- | /O(n)/ Apply the monadic action to every element of the vector, discarding the results. +-- +-- @since 0.12.3.0 +mapM_ :: (PrimMonad m) => (a -> m b) -> MVector (PrimState m) a -> m () +{-# INLINE mapM_ #-} +mapM_ = G.mapM_ + +-- | /O(n)/ Apply the monadic action to every element of the vector and its index, discarding the results. +-- +-- @since 0.12.3.0 +imapM_ :: (PrimMonad m) => (Int -> a -> m b) -> MVector (PrimState m) a -> m () +{-# INLINE imapM_ #-} +imapM_ = G.imapM_ + +-- | /O(n)/ Apply the monadic action to every element of the vector, +-- discarding the results. It's same as the @flip mapM_@. +-- +-- @since 0.12.3.0 +forM_ :: (PrimMonad m) => MVector (PrimState m) a -> (a -> m b) -> m () +{-# INLINE forM_ #-} +forM_ = G.forM_ + +-- | /O(n)/ Apply the monadic action to every element of the vector +-- and its index, discarding the results. It's same as the @flip imapM_@. +-- +-- @since 0.12.3.0 +iforM_ :: (PrimMonad m) => MVector (PrimState m) a -> (Int -> a -> m b) -> m () +{-# INLINE iforM_ #-} +iforM_ = G.iforM_ + +-- | /O(n)/ Pure left fold. +-- +-- @since 0.12.3.0 +foldl :: (PrimMonad m) => (b -> a -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldl #-} +foldl = G.foldl + +-- | /O(n)/ Pure left fold with strict accumulator. +-- +-- @since 0.12.3.0 +foldl' :: (PrimMonad m) => (b -> a -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldl' #-} +foldl' = G.foldl' + +-- | /O(n)/ Pure left fold (function applied to each element and its index). +-- +-- @since 0.12.3.0 +ifoldl :: (PrimMonad m) => (b -> Int -> a -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldl #-} +ifoldl = G.ifoldl + +-- | /O(n)/ Pure left fold with strict accumulator (function applied to each element and its index). +-- +-- @since 0.12.3.0 +ifoldl' :: (PrimMonad m) => (b -> Int -> a -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldl' #-} +ifoldl' = G.ifoldl' + +-- | /O(n)/ Pure right fold. +-- +-- @since 0.12.3.0 +foldr :: (PrimMonad m) => (a -> b -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldr #-} +foldr = G.foldr + +-- | /O(n)/ Pure right fold with strict accumulator. +-- +-- @since 0.12.3.0 +foldr' :: (PrimMonad m) => (a -> b -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldr' #-} +foldr' = G.foldr' + +-- | /O(n)/ Pure right fold (function applied to each element and its index). +-- +-- @since 0.12.3.0 +ifoldr :: (PrimMonad m) => (Int -> a -> b -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldr #-} +ifoldr = G.ifoldr + +-- | /O(n)/ Pure right fold with strict accumulator (function applied +-- to each element and its index). +-- +-- @since 0.12.3.0 +ifoldr' :: (PrimMonad m) => (Int -> a -> b -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldr' #-} +ifoldr' = G.ifoldr' + +-- | /O(n)/ Monadic fold. +-- +-- @since 0.12.3.0 +foldM :: (PrimMonad m) => (b -> a -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldM #-} +foldM = G.foldM + +-- | /O(n)/ Monadic fold with strict accumulator. +-- +-- @since 0.12.3.0 +foldM' :: (PrimMonad m) => (b -> a -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldM' #-} +foldM' = G.foldM' + +-- | /O(n)/ Monadic fold (action applied to each element and its index). +-- +-- @since 0.12.3.0 +ifoldM :: (PrimMonad m) => (b -> Int -> a -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldM #-} +ifoldM = G.ifoldM + +-- | /O(n)/ Monadic fold with strict accumulator (action applied to each element and its index). +-- +-- @since 0.12.3.0 +ifoldM' :: (PrimMonad m) => (b -> Int -> a -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldM' #-} +ifoldM' = G.ifoldM' + +-- | /O(n)/ Monadic right fold. +-- +-- @since 0.12.3.0 +foldrM :: (PrimMonad m) => (a -> b -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldrM #-} +foldrM = G.foldrM + +-- | /O(n)/ Monadic right fold with strict accumulator. +-- +-- @since 0.12.3.0 +foldrM' :: (PrimMonad m) => (a -> b -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldrM' #-} +foldrM' = G.foldrM' + +-- | /O(n)/ Monadic right fold (action applied to each element and its index). +-- +-- @since 0.12.3.0 +ifoldrM :: (PrimMonad m) => (Int -> a -> b -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldrM #-} +ifoldrM = G.ifoldrM + +-- | /O(n)/ Monadic right fold with strict accumulator (action applied +-- to each element and its index). +-- +-- @since 0.12.3.0 +ifoldrM' :: (PrimMonad m) => (Int -> a -> b -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldrM' #-} +ifoldrM' = G.ifoldrM' + -- Conversions - Arrays -- ----------------------------- diff --git a/Data/Vector/Primitive/Mutable.hs b/Data/Vector/Primitive/Mutable.hs index fd2768b..c161264 100644 --- a/Data/Vector/Primitive/Mutable.hs +++ b/Data/Vector/Primitive/Mutable.hs @@ -31,7 +31,7 @@ module Data.Vector.Primitive.Mutable ( -- * Construction -- ** Initialisation - new, unsafeNew, replicate, replicateM, clone, + new, unsafeNew, replicate, replicateM, generate, generateM, clone, -- ** Growing grow, unsafeGrow, @@ -40,8 +40,15 @@ module Data.Vector.Primitive.Mutable ( clear, -- * Accessing individual elements - read, write, modify, swap, - unsafeRead, unsafeWrite, unsafeModify, unsafeSwap, + read, write, modify, modifyM, swap, exchange, + unsafeRead, unsafeWrite, unsafeModify, unsafeModifyM, unsafeSwap, unsafeExchange, + + -- * Folds + mapM_, imapM_, forM_, iforM_, + foldl, foldl', foldM, foldM', + foldr, foldr', foldrM, foldrM', + ifoldl, ifoldl', ifoldM, ifoldM', + ifoldr, ifoldr', ifoldrM, ifoldrM', -- * Modifying vectors nextPermutation, @@ -64,7 +71,7 @@ import Control.DeepSeq ( NFData(rnf) ) import Prelude hiding ( length, null, replicate, reverse, map, read, - take, drop, splitAt, init, tail ) + take, drop, splitAt, init, tail, foldr, foldl, mapM_ ) import Data.Typeable ( Typeable ) @@ -247,6 +254,23 @@ replicateM :: (PrimMonad m, Prim a) => Int -> m a -> m (MVector (PrimState m) a) {-# INLINE replicateM #-} replicateM = G.replicateM +-- | /O(n)/ Create a mutable vector of the given length (0 if the length is negative) +-- and fill it with the results of applying the function to each index. +-- +-- @since 0.12.3.0 +generate :: (PrimMonad m, Prim a) => Int -> (Int -> a) -> m (MVector (PrimState m) a) +{-# INLINE generate #-} +generate = G.generate + +-- | /O(n)/ Create a mutable vector of the given length (0 if the length is +-- negative) and fill it with the results of applying the monadic function to each +-- index. Iteration starts at index 0. +-- +-- @since 0.12.3.0 +generateM :: (PrimMonad m, Prim a) => Int -> (Int -> m a) -> m (MVector (PrimState m) a) +{-# INLINE generateM #-} +generateM = G.generateM + -- | Create a copy of a mutable vector. clone :: (PrimMonad m, Prim a) => MVector (PrimState m) a -> m (MVector (PrimState m) a) @@ -332,11 +356,22 @@ modify :: (PrimMonad m, Prim a) => MVector (PrimState m) a -> (a -> a) -> Int -> {-# INLINE modify #-} modify = G.modify +-- | Modify the element at the given position using a monadic function. +-- +-- @since 0.12.3.0 +modifyM :: (PrimMonad m, Prim a) => MVector (PrimState m) a -> (a -> m a) -> Int -> m () +{-# INLINE modifyM #-} +modifyM = G.modifyM + -- | Swap the elements at the given positions. swap :: (PrimMonad m, Prim a) => MVector (PrimState m) a -> Int -> Int -> m () {-# INLINE swap #-} swap = G.swap +-- | Replace the element at the given position and return the old element. +exchange :: (PrimMonad m, Prim a) => MVector (PrimState m) a -> Int -> a -> m a +{-# INLINE exchange #-} +exchange = G.exchange -- | Yield the element at the given position. No bounds checks are performed. unsafeRead :: (PrimMonad m, Prim a) => MVector (PrimState m) a -> Int -> m a @@ -354,12 +389,26 @@ unsafeModify :: (PrimMonad m, Prim a) => MVector (PrimState m) a -> (a -> a) -> {-# INLINE unsafeModify #-} unsafeModify = G.unsafeModify +-- | Modify the element at the given position using a monadic +-- function. No bounds checks are performed. +-- +-- @since 0.12.3.0 +unsafeModifyM :: (PrimMonad m, Prim a) => MVector (PrimState m) a -> (a -> m a) -> Int -> m () +{-# INLINE unsafeModifyM #-} +unsafeModifyM = G.unsafeModifyM + -- | Swap the elements at the given positions. No bounds checks are performed. unsafeSwap :: (PrimMonad m, Prim a) => MVector (PrimState m) a -> Int -> Int -> m () {-# INLINE unsafeSwap #-} unsafeSwap = G.unsafeSwap +-- | Replace the element at the given position and return the old element. No +-- bounds checks are performed. +unsafeExchange :: (PrimMonad m, Prim a) => MVector (PrimState m) a -> Int -> a -> m a +{-# INLINE unsafeExchange #-} +unsafeExchange = G.unsafeExchange + -- Filling and copying -- ------------------- @@ -419,3 +468,151 @@ unsafeMove = G.unsafeMove nextPermutation :: (PrimMonad m,Ord e,Prim e) => MVector (PrimState m) e -> m Bool {-# INLINE nextPermutation #-} nextPermutation = G.nextPermutation + + +-- Folds +-- ----- + +-- | /O(n)/ Apply the monadic action to every element of the vector, discarding the results. +-- +-- @since 0.12.3.0 +mapM_ :: (PrimMonad m, Prim a) => (a -> m b) -> MVector (PrimState m) a -> m () +{-# INLINE mapM_ #-} +mapM_ = G.mapM_ + +-- | /O(n)/ Apply the monadic action to every element of the vector and its index, discarding the results. +-- +-- @since 0.12.3.0 +imapM_ :: (PrimMonad m, Prim a) => (Int -> a -> m b) -> MVector (PrimState m) a -> m () +{-# INLINE imapM_ #-} +imapM_ = G.imapM_ + +-- | /O(n)/ Apply the monadic action to every element of the vector, +-- discarding the results. It's same as the @flip mapM_@. +-- +-- @since 0.12.3.0 +forM_ :: (PrimMonad m, Prim a) => MVector (PrimState m) a -> (a -> m b) -> m () +{-# INLINE forM_ #-} +forM_ = G.forM_ + +-- | /O(n)/ Apply the monadic action to every element of the vector +-- and its index, discarding the results. It's same as the @flip imapM_@. +-- +-- @since 0.12.3.0 +iforM_ :: (PrimMonad m, Prim a) => MVector (PrimState m) a -> (Int -> a -> m b) -> m () +{-# INLINE iforM_ #-} +iforM_ = G.iforM_ + +-- | /O(n)/ Pure left fold. +-- +-- @since 0.12.3.0 +foldl :: (PrimMonad m, Prim a) => (b -> a -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldl #-} +foldl = G.foldl + +-- | /O(n)/ Pure left fold with strict accumulator. +-- +-- @since 0.12.3.0 +foldl' :: (PrimMonad m, Prim a) => (b -> a -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldl' #-} +foldl' = G.foldl' + +-- | /O(n)/ Pure left fold (function applied to each element and its index). +-- +-- @since 0.12.3.0 +ifoldl :: (PrimMonad m, Prim a) => (b -> Int -> a -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldl #-} +ifoldl = G.ifoldl + +-- | /O(n)/ Pure left fold with strict accumulator (function applied to each element and its index). +-- +-- @since 0.12.3.0 +ifoldl' :: (PrimMonad m, Prim a) => (b -> Int -> a -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldl' #-} +ifoldl' = G.ifoldl' + +-- | /O(n)/ Pure right fold. +-- +-- @since 0.12.3.0 +foldr :: (PrimMonad m, Prim a) => (a -> b -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldr #-} +foldr = G.foldr + +-- | /O(n)/ Pure right fold with strict accumulator. +-- +-- @since 0.12.3.0 +foldr' :: (PrimMonad m, Prim a) => (a -> b -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldr' #-} +foldr' = G.foldr' + +-- | /O(n)/ Pure right fold (function applied to each element and its index). +-- +-- @since 0.12.3.0 +ifoldr :: (PrimMonad m, Prim a) => (Int -> a -> b -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldr #-} +ifoldr = G.ifoldr + +-- | /O(n)/ Pure right fold with strict accumulator (function applied +-- to each element and its index). +-- +-- @since 0.12.3.0 +ifoldr' :: (PrimMonad m, Prim a) => (Int -> a -> b -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldr' #-} +ifoldr' = G.ifoldr' + +-- | /O(n)/ Monadic fold. +-- +-- @since 0.12.3.0 +foldM :: (PrimMonad m, Prim a) => (b -> a -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldM #-} +foldM = G.foldM + +-- | /O(n)/ Monadic fold with strict accumulator. +-- +-- @since 0.12.3.0 +foldM' :: (PrimMonad m, Prim a) => (b -> a -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldM' #-} +foldM' = G.foldM' + +-- | /O(n)/ Monadic fold (action applied to each element and its index). +-- +-- @since 0.12.3.0 +ifoldM :: (PrimMonad m, Prim a) => (b -> Int -> a -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldM #-} +ifoldM = G.ifoldM + +-- | /O(n)/ Monadic fold with strict accumulator (action applied to each element and its index). +-- +-- @since 0.12.3.0 +ifoldM' :: (PrimMonad m, Prim a) => (b -> Int -> a -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldM' #-} +ifoldM' = G.ifoldM' + +-- | /O(n)/ Monadic right fold. +-- +-- @since 0.12.3.0 +foldrM :: (PrimMonad m, Prim a) => (a -> b -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldrM #-} +foldrM = G.foldrM + +-- | /O(n)/ Monadic right fold with strict accumulator. +-- +-- @since 0.12.3.0 +foldrM' :: (PrimMonad m, Prim a) => (a -> b -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldrM' #-} +foldrM' = G.foldrM' + +-- | /O(n)/ Monadic right fold (action applied to each element and its index). +-- +-- @since 0.12.3.0 +ifoldrM :: (PrimMonad m, Prim a) => (Int -> a -> b -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldrM #-} +ifoldrM = G.ifoldrM + +-- | /O(n)/ Monadic right fold with strict accumulator (action applied +-- to each element and its index). +-- +-- @since 0.12.3.0 +ifoldrM' :: (PrimMonad m, Prim a) => (Int -> a -> b -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldrM' #-} +ifoldrM' = G.ifoldrM' diff --git a/Data/Vector/Storable.hs b/Data/Vector/Storable.hs index bf464c0..e58de40 100644 --- a/Data/Vector/Storable.hs +++ b/Data/Vector/Storable.hs @@ -255,14 +255,14 @@ instance Storable a => G.Vector Vector a where {-# INLINE basicUnsafeIndexM #-} basicUnsafeIndexM (Vector _ fp) i = return . unsafeInlineIO - $ withForeignPtr fp $ \p -> + $ unsafeWithForeignPtr fp $ \p -> peekElemOff p i {-# INLINE basicUnsafeCopy #-} basicUnsafeCopy (MVector n fp) (Vector _ fq) = unsafePrimToPrim - $ withForeignPtr fp $ \p -> - withForeignPtr fq $ \q -> + $ unsafeWithForeignPtr fp $ \p -> + unsafeWithForeignPtr fq $ \q -> copyArray p q n {-# INLINE elemseq #-} diff --git a/Data/Vector/Storable/Internal.hs b/Data/Vector/Storable/Internal.hs index 0ed2188..eafc70d 100644 --- a/Data/Vector/Storable/Internal.hs +++ b/Data/Vector/Storable/Internal.hs @@ -1,3 +1,5 @@ +{-# LANGUAGE CPP #-} + -- | -- Module : Data.Vector.Storable.Internal -- Copyright : (c) Roman Leshchinskiy 2009-2010 @@ -11,12 +13,17 @@ -- module Data.Vector.Storable.Internal ( - getPtr, setPtr, updPtr + getPtr, setPtr, updPtr, unsafeWithForeignPtr ) where import Foreign.ForeignPtr () import Foreign.Ptr () import GHC.ForeignPtr ( ForeignPtr(..) ) +#if MIN_VERSION_base(4,15,0) +import GHC.ForeignPtr ( unsafeWithForeignPtr ) +#else +import Foreign.ForeignPtr ( withForeignPtr ) +#endif import GHC.Ptr ( Ptr(..) ) getPtr :: ForeignPtr a -> Ptr a @@ -31,3 +38,12 @@ updPtr :: (Ptr a -> Ptr a) -> ForeignPtr a -> ForeignPtr a {-# INLINE updPtr #-} updPtr f (ForeignPtr p c) = case f (Ptr p) of { Ptr q -> ForeignPtr q c } +#if !MIN_VERSION_base(4,15,0) +-- | A compatibility wrapper for 'GHC.ForeignPtr.unsafeWithForeignPtr' provided +-- by GHC 9.0.1 and later. +-- +-- Only to be used when the continuation is known not to +-- unconditionally diverge lest unsoundness can result. +unsafeWithForeignPtr :: ForeignPtr a -> (Ptr a -> IO b) -> IO b +unsafeWithForeignPtr = withForeignPtr +#endif diff --git a/Data/Vector/Storable/Mutable.hs b/Data/Vector/Storable/Mutable.hs index 75ff781..01f3e44 100644 --- a/Data/Vector/Storable/Mutable.hs +++ b/Data/Vector/Storable/Mutable.hs @@ -33,7 +33,7 @@ module Data.Vector.Storable.Mutable( -- * Construction -- ** Initialisation - new, unsafeNew, replicate, replicateM, clone, + new, unsafeNew, replicate, replicateM, generate, generateM, clone, -- ** Growing grow, unsafeGrow, @@ -42,10 +42,18 @@ module Data.Vector.Storable.Mutable( clear, -- * Accessing individual elements - read, write, modify, swap, - unsafeRead, unsafeWrite, unsafeModify, unsafeSwap, + read, write, modify, modifyM, swap, exchange, + unsafeRead, unsafeWrite, unsafeModify, unsafeModifyM, unsafeSwap, unsafeExchange, + + -- * Folds + mapM_, imapM_, forM_, iforM_, + foldl, foldl', foldM, foldM', + foldr, foldr', foldrM, foldrM', + ifoldl, ifoldl', ifoldM, ifoldM', + ifoldr, ifoldr', ifoldrM, ifoldrM', -- * Modifying vectors + nextPermutation, -- ** Filling and copying set, copy, move, unsafeCopy, unsafeMove, @@ -94,7 +102,7 @@ import GHC.Word (Word8, Word16, Word32, Word64) import GHC.Ptr (Ptr(..)) import Prelude hiding ( length, null, replicate, reverse, map, read, - take, drop, splitAt, init, tail ) + take, drop, splitAt, init, tail, foldr, foldl, mapM_ ) import Data.Typeable ( Typeable ) @@ -154,12 +162,12 @@ instance Storable a => G.MVector MVector a where {-# INLINE basicUnsafeRead #-} basicUnsafeRead (MVector _ fp) i = unsafePrimToPrim - $ withForeignPtr fp (`peekElemOff` i) + $ unsafeWithForeignPtr fp (`peekElemOff` i) {-# INLINE basicUnsafeWrite #-} basicUnsafeWrite (MVector _ fp) i x = unsafePrimToPrim - $ withForeignPtr fp $ \p -> pokeElemOff p i x + $ unsafeWithForeignPtr fp $ \p -> pokeElemOff p i x {-# INLINE basicSet #-} basicSet = storableSet @@ -167,20 +175,20 @@ instance Storable a => G.MVector MVector a where {-# INLINE basicUnsafeCopy #-} basicUnsafeCopy (MVector n fp) (MVector _ fq) = unsafePrimToPrim - $ withForeignPtr fp $ \p -> - withForeignPtr fq $ \q -> + $ unsafeWithForeignPtr fp $ \p -> + unsafeWithForeignPtr fq $ \q -> copyArray p q n {-# INLINE basicUnsafeMove #-} basicUnsafeMove (MVector n fp) (MVector _ fq) = unsafePrimToPrim - $ withForeignPtr fp $ \p -> - withForeignPtr fq $ \q -> + $ unsafeWithForeignPtr fp $ \p -> + unsafeWithForeignPtr fq $ \q -> moveArray p q n storableZero :: forall a m. (Storable a, PrimMonad m) => MVector (PrimState m) a -> m () {-# INLINE storableZero #-} -storableZero (MVector n fp) = unsafePrimToPrim . withForeignPtr fp $ \ptr-> do +storableZero (MVector n fp) = unsafePrimToPrim . unsafeWithForeignPtr fp $ \ptr-> do memsetPrimPtr_vector (castPtr ptr) byteSize (0 :: Word8) where x :: a @@ -198,7 +206,7 @@ storableSet (MVector n fp) x 2 -> storableSetAsPrim n fp x (undefined :: Word16) 4 -> storableSetAsPrim n fp x (undefined :: Word32) 8 -> storableSetAsPrim n fp x (undefined :: Word64) - _ -> withForeignPtr fp $ \p -> do + _ -> unsafeWithForeignPtr fp $ \p -> do poke p x let do_set i @@ -212,7 +220,7 @@ storableSet (MVector n fp) x storableSetAsPrim :: forall a b . (Storable a, Prim b) => Int -> ForeignPtr a -> a -> b -> IO () {-# INLINE [0] storableSetAsPrim #-} -storableSetAsPrim n fp x _y = withForeignPtr fp $ \ ptr -> do +storableSetAsPrim n fp x _y = unsafeWithForeignPtr fp $ \ ptr -> do poke ptr x -- we dont equate storable and prim reps, so we need to write to a slot -- in storable @@ -375,6 +383,23 @@ replicateM :: (PrimMonad m, Storable a) => Int -> m a -> m (MVector (PrimState m {-# INLINE replicateM #-} replicateM = G.replicateM +-- | /O(n)/ Create a mutable vector of the given length (0 if the length is negative) +-- and fill it with the results of applying the function to each index. +-- +-- @since 0.12.3.0 +generate :: (PrimMonad m, Storable a) => Int -> (Int -> a) -> m (MVector (PrimState m) a) +{-# INLINE generate #-} +generate = G.generate + +-- | /O(n)/ Create a mutable vector of the given length (0 if the length is +-- negative) and fill it with the results of applying the monadic function to each +-- index. Iteration starts at index 0. +-- +-- @since 0.12.3.0 +generateM :: (PrimMonad m, Storable a) => Int -> (Int -> m a) -> m (MVector (PrimState m) a) +{-# INLINE generateM #-} +generateM = G.generateM + -- | Create a copy of a mutable vector. clone :: (PrimMonad m, Storable a) => MVector (PrimState m) a -> m (MVector (PrimState m) a) @@ -461,12 +486,23 @@ modify :: (PrimMonad m, Storable a) => MVector (PrimState m) a -> (a -> a) -> In {-# INLINE modify #-} modify = G.modify +-- | Modify the element at the given position using a monadic function. +-- +-- @since 0.12.3.0 +modifyM :: (PrimMonad m, Storable a) => MVector (PrimState m) a -> (a -> m a) -> Int -> m () +{-# INLINE modifyM #-} +modifyM = G.modifyM + -- | Swap the elements at the given positions. swap :: (PrimMonad m, Storable a) => MVector (PrimState m) a -> Int -> Int -> m () {-# INLINE swap #-} swap = G.swap +-- | Replace the element at the given position and return the old element. +exchange :: (PrimMonad m, Storable a) => MVector (PrimState m) a -> Int -> a -> m a +{-# INLINE exchange #-} +exchange = G.exchange -- | Yield the element at the given position. No bounds checks are performed. unsafeRead :: (PrimMonad m, Storable a) => MVector (PrimState m) a -> Int -> m a @@ -484,12 +520,26 @@ unsafeModify :: (PrimMonad m, Storable a) => MVector (PrimState m) a -> (a -> a) {-# INLINE unsafeModify #-} unsafeModify = G.unsafeModify +-- | Modify the element at the given position using a monadic +-- function. No bounds checks are performed. +-- +-- @since 0.12.3.0 +unsafeModifyM :: (PrimMonad m, Storable a) => MVector (PrimState m) a -> (a -> m a) -> Int -> m () +{-# INLINE unsafeModifyM #-} +unsafeModifyM = G.unsafeModifyM + -- | Swap the elements at the given positions. No bounds checks are performed. unsafeSwap :: (PrimMonad m, Storable a) => MVector (PrimState m) a -> Int -> Int -> m () {-# INLINE unsafeSwap #-} unsafeSwap = G.unsafeSwap +-- | Replace the element at the given position and return the old element. No +-- bounds checks are performed. +unsafeExchange :: (PrimMonad m, Storable a) => MVector (PrimState m) a -> Int -> a -> m a +{-# INLINE unsafeExchange #-} +unsafeExchange = G.unsafeExchange + -- Filling and copying -- ------------------- @@ -544,6 +594,161 @@ unsafeMove :: (PrimMonad m, Storable a) {-# INLINE unsafeMove #-} unsafeMove = G.unsafeMove +-- | Compute the next (lexicographically) permutation of given vector in-place. +-- Returns False when input is the last permutation +nextPermutation :: (PrimMonad m, Storable e, Ord e) => MVector (PrimState m) e -> m Bool +{-# INLINE nextPermutation #-} +nextPermutation = G.nextPermutation + + +-- Folds +-- ----- + +-- | /O(n)/ Apply the monadic action to every element of the vector, discarding the results. +-- +-- @since 0.12.3.0 +mapM_ :: (PrimMonad m, Storable a) => (a -> m b) -> MVector (PrimState m) a -> m () +{-# INLINE mapM_ #-} +mapM_ = G.mapM_ + +-- | /O(n)/ Apply the monadic action to every element of the vector and its index, discarding the results. +-- +-- @since 0.12.3.0 +imapM_ :: (PrimMonad m, Storable a) => (Int -> a -> m b) -> MVector (PrimState m) a -> m () +{-# INLINE imapM_ #-} +imapM_ = G.imapM_ + +-- | /O(n)/ Apply the monadic action to every element of the vector, +-- discarding the results. It's same as the @flip mapM_@. +-- +-- @since 0.12.3.0 +forM_ :: (PrimMonad m, Storable a) => MVector (PrimState m) a -> (a -> m b) -> m () +{-# INLINE forM_ #-} +forM_ = G.forM_ + +-- | /O(n)/ Apply the monadic action to every element of the vector +-- and its index, discarding the results. It's same as the @flip imapM_@. +-- +-- @since 0.12.3.0 +iforM_ :: (PrimMonad m, Storable a) => MVector (PrimState m) a -> (Int -> a -> m b) -> m () +{-# INLINE iforM_ #-} +iforM_ = G.iforM_ + +-- | /O(n)/ Pure left fold. +-- +-- @since 0.12.3.0 +foldl :: (PrimMonad m, Storable a) => (b -> a -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldl #-} +foldl = G.foldl + +-- | /O(n)/ Pure left fold with strict accumulator. +-- +-- @since 0.12.3.0 +foldl' :: (PrimMonad m, Storable a) => (b -> a -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldl' #-} +foldl' = G.foldl' + +-- | /O(n)/ Pure left fold (function applied to each element and its index). +-- +-- @since 0.12.3.0 +ifoldl :: (PrimMonad m, Storable a) => (b -> Int -> a -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldl #-} +ifoldl = G.ifoldl + +-- | /O(n)/ Pure left fold with strict accumulator (function applied to each element and its index). +-- +-- @since 0.12.3.0 +ifoldl' :: (PrimMonad m, Storable a) => (b -> Int -> a -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldl' #-} +ifoldl' = G.ifoldl' + +-- | /O(n)/ Pure right fold. +-- +-- @since 0.12.3.0 +foldr :: (PrimMonad m, Storable a) => (a -> b -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldr #-} +foldr = G.foldr + +-- | /O(n)/ Pure right fold with strict accumulator. +-- +-- @since 0.12.3.0 +foldr' :: (PrimMonad m, Storable a) => (a -> b -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldr' #-} +foldr' = G.foldr' + +-- | /O(n)/ Pure right fold (function applied to each element and its index). +-- +-- @since 0.12.3.0 +ifoldr :: (PrimMonad m, Storable a) => (Int -> a -> b -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldr #-} +ifoldr = G.ifoldr + +-- | /O(n)/ Pure right fold with strict accumulator (function applied +-- to each element and its index). +-- +-- @since 0.12.3.0 +ifoldr' :: (PrimMonad m, Storable a) => (Int -> a -> b -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldr' #-} +ifoldr' = G.ifoldr' + +-- | /O(n)/ Monadic fold. +-- +-- @since 0.12.3.0 +foldM :: (PrimMonad m, Storable a) => (b -> a -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldM #-} +foldM = G.foldM + +-- | /O(n)/ Monadic fold with strict accumulator. +-- +-- @since 0.12.3.0 +foldM' :: (PrimMonad m, Storable a) => (b -> a -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldM' #-} +foldM' = G.foldM' + +-- | /O(n)/ Monadic fold (action applied to each element and its index). +-- +-- @since 0.12.3.0 +ifoldM :: (PrimMonad m, Storable a) => (b -> Int -> a -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldM #-} +ifoldM = G.ifoldM + +-- | /O(n)/ Monadic fold with strict accumulator (action applied to each element and its index). +-- +-- @since 0.12.3.0 +ifoldM' :: (PrimMonad m, Storable a) => (b -> Int -> a -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldM' #-} +ifoldM' = G.ifoldM' + +-- | /O(n)/ Monadic right fold. +-- +-- @since 0.12.3.0 +foldrM :: (PrimMonad m, Storable a) => (a -> b -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldrM #-} +foldrM = G.foldrM + +-- | /O(n)/ Monadic right fold with strict accumulator. +-- +-- @since 0.12.3.0 +foldrM' :: (PrimMonad m, Storable a) => (a -> b -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldrM' #-} +foldrM' = G.foldrM' + +-- | /O(n)/ Monadic right fold (action applied to each element and its index). +-- +-- @since 0.12.3.0 +ifoldrM :: (PrimMonad m, Storable a) => (Int -> a -> b -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldrM #-} +ifoldrM = G.ifoldrM + +-- | /O(n)/ Monadic right fold with strict accumulator (action applied +-- to each element and its index). +-- +-- @since 0.12.3.0 +ifoldrM' :: (PrimMonad m, Storable a) => (Int -> a -> b -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldrM' #-} +ifoldrM' = G.ifoldrM' + + -- Unsafe conversions -- ------------------ diff --git a/Data/Vector/Unboxed/Mutable.hs b/Data/Vector/Unboxed/Mutable.hs index 90b5301..2ecfe2c 100644 --- a/Data/Vector/Unboxed/Mutable.hs +++ b/Data/Vector/Unboxed/Mutable.hs @@ -31,7 +31,7 @@ module Data.Vector.Unboxed.Mutable ( -- * Construction -- ** Initialisation - new, unsafeNew, replicate, replicateM, clone, + new, unsafeNew, replicate, replicateM, generate, generateM, clone, -- ** Growing grow, unsafeGrow, @@ -44,8 +44,15 @@ module Data.Vector.Unboxed.Mutable ( unzip, unzip3, unzip4, unzip5, unzip6, -- * Accessing individual elements - read, write, modify, swap, - unsafeRead, unsafeWrite, unsafeModify, unsafeSwap, + read, write, modify, modifyM, swap, exchange, + unsafeRead, unsafeWrite, unsafeModify, unsafeModifyM, unsafeSwap, unsafeExchange, + + -- * Folds + mapM_, imapM_, forM_, iforM_, + foldl, foldl', foldM, foldM', + foldr, foldr', foldrM, foldrM', + ifoldl, ifoldl', ifoldM, ifoldM', + ifoldr, ifoldr', ifoldrM, ifoldrM', -- * Modifying vectors nextPermutation, @@ -61,7 +68,7 @@ import Control.Monad.Primitive import Prelude hiding ( length, null, replicate, reverse, map, read, take, drop, splitAt, init, tail, - zip, zip3, unzip, unzip3 ) + zip, zip3, unzip, unzip3, foldr, foldl, mapM_ ) -- don't import an unused Data.Vector.Internal.Check #define NOT_VECTOR_MODULE @@ -176,6 +183,23 @@ replicateM :: (PrimMonad m, Unbox a) => Int -> m a -> m (MVector (PrimState m) a {-# INLINE replicateM #-} replicateM = G.replicateM +-- | /O(n)/ Create a mutable vector of the given length (0 if the length is negative) +-- and fill it with the results of applying the function to each index. +-- +-- @since 0.12.3.0 +generate :: (PrimMonad m, Unbox a) => Int -> (Int -> a) -> m (MVector (PrimState m) a) +{-# INLINE generate #-} +generate = G.generate + +-- | /O(n)/ Create a mutable vector of the given length (0 if the length is +-- negative) and fill it with the results of applying the monadic function to each +-- index. Iteration starts at index 0. +-- +-- @since 0.12.3.0 +generateM :: (PrimMonad m, Unbox a) => Int -> (Int -> m a) -> m (MVector (PrimState m) a) +{-# INLINE generateM #-} +generateM = G.generateM + -- | Create a copy of a mutable vector. clone :: (PrimMonad m, Unbox a) => MVector (PrimState m) a -> m (MVector (PrimState m) a) @@ -261,11 +285,22 @@ modify :: (PrimMonad m, Unbox a) => MVector (PrimState m) a -> (a -> a) -> Int - {-# INLINE modify #-} modify = G.modify +-- | Modify the element at the given position using a monadic function. +-- +-- @since 0.12.3.0 +modifyM :: (PrimMonad m, Unbox a) => MVector (PrimState m) a -> (a -> m a) -> Int -> m () +{-# INLINE modifyM #-} +modifyM = G.modifyM + -- | Swap the elements at the given positions. swap :: (PrimMonad m, Unbox a) => MVector (PrimState m) a -> Int -> Int -> m () {-# INLINE swap #-} swap = G.swap +-- | Replace the element at the given position and return the old element. +exchange :: (PrimMonad m, Unbox a) => MVector (PrimState m) a -> Int -> a -> m a +{-# INLINE exchange #-} +exchange = G.exchange -- | Yield the element at the given position. No bounds checks are performed. unsafeRead :: (PrimMonad m, Unbox a) => MVector (PrimState m) a -> Int -> m a @@ -283,12 +318,26 @@ unsafeModify :: (PrimMonad m, Unbox a) => MVector (PrimState m) a -> (a -> a) -> {-# INLINE unsafeModify #-} unsafeModify = G.unsafeModify +-- | Modify the element at the given position using a monadic +-- function. No bounds checks are performed. +-- +-- @since 0.12.3.0 +unsafeModifyM :: (PrimMonad m, Unbox a) => MVector (PrimState m) a -> (a -> m a) -> Int -> m () +{-# INLINE unsafeModifyM #-} +unsafeModifyM = G.unsafeModifyM + -- | Swap the elements at the given positions. No bounds checks are performed. unsafeSwap :: (PrimMonad m, Unbox a) => MVector (PrimState m) a -> Int -> Int -> m () {-# INLINE unsafeSwap #-} unsafeSwap = G.unsafeSwap +-- | Replace the element at the given position and return the old element. No +-- bounds checks are performed. +unsafeExchange :: (PrimMonad m, Unbox a) => MVector (PrimState m) a -> Int -> a -> m a +{-# INLINE unsafeExchange #-} +unsafeExchange = G.unsafeExchange + -- Filling and copying -- ------------------- @@ -349,5 +398,155 @@ nextPermutation :: (PrimMonad m,Ord e,Unbox e) => MVector (PrimState m) e -> m B {-# INLINE nextPermutation #-} nextPermutation = G.nextPermutation + +-- Folds +-- ----- + +-- | /O(n)/ Apply the monadic action to every element of the vector, discarding the results. +-- +-- @since 0.12.3.0 +mapM_ :: (PrimMonad m, Unbox a) => (a -> m b) -> MVector (PrimState m) a -> m () +{-# INLINE mapM_ #-} +mapM_ = G.mapM_ + +-- | /O(n)/ Apply the monadic action to every element of the vector and its index, +-- discarding the results. +-- +-- @since 0.12.3.0 +imapM_ :: (PrimMonad m, Unbox a) => (Int -> a -> m b) -> MVector (PrimState m) a -> m () +{-# INLINE imapM_ #-} +imapM_ = G.imapM_ + +-- | /O(n)/ Apply the monadic action to every element of the vector, +-- discarding the results. It's same as the @flip mapM_@. +-- +-- @since 0.12.3.0 +forM_ :: (PrimMonad m, Unbox a) => MVector (PrimState m) a -> (a -> m b) -> m () +{-# INLINE forM_ #-} +forM_ = G.forM_ + +-- | /O(n)/ Apply the monadic action to every element of the vector +-- and its index, discarding the results. It's same as the @flip imapM_@. +-- +-- @since 0.12.3.0 +iforM_ :: (PrimMonad m, Unbox a) => MVector (PrimState m) a -> (Int -> a -> m b) -> m () +{-# INLINE iforM_ #-} +iforM_ = G.iforM_ + +-- | /O(n)/ Pure left fold. +-- +-- @since 0.12.3.0 +foldl :: (PrimMonad m, Unbox a) => (b -> a -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldl #-} +foldl = G.foldl + +-- | /O(n)/ Pure left fold with strict accumulator. +-- +-- @since 0.12.3.0 +foldl' :: (PrimMonad m, Unbox a) => (b -> a -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldl' #-} +foldl' = G.foldl' + +-- | /O(n)/ Pure left fold (function applied to each element and its index). +-- +-- @since 0.12.3.0 +ifoldl :: (PrimMonad m, Unbox a) => (b -> Int -> a -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldl #-} +ifoldl = G.ifoldl + +-- | /O(n)/ Pure left fold with strict accumulator (function applied to each element and its index). +-- +-- @since 0.12.3.0 +ifoldl' :: (PrimMonad m, Unbox a) => (b -> Int -> a -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldl' #-} +ifoldl' = G.ifoldl' + +-- | /O(n)/ Pure right fold. +-- +-- @since 0.12.3.0 +foldr :: (PrimMonad m, Unbox a) => (a -> b -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldr #-} +foldr = G.foldr + +-- | /O(n)/ Pure right fold with strict accumulator. +-- +-- @since 0.12.3.0 +foldr' :: (PrimMonad m, Unbox a) => (a -> b -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldr' #-} +foldr' = G.foldr' + +-- | /O(n)/ Pure right fold (function applied to each element and its index). +-- +-- @since 0.12.3.0 +ifoldr :: (PrimMonad m, Unbox a) => (Int -> a -> b -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldr #-} +ifoldr = G.ifoldr + +-- | /O(n)/ Pure right fold with strict accumulator (function applied +-- to each element and its index). +-- +-- @since 0.12.3.0 +ifoldr' :: (PrimMonad m, Unbox a) => (Int -> a -> b -> b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldr' #-} +ifoldr' = G.ifoldr' + +-- | /O(n)/ Monadic fold. +-- +-- @since 0.12.3.0 +foldM :: (PrimMonad m, Unbox a) => (b -> a -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldM #-} +foldM = G.foldM + +-- | /O(n)/ Monadic fold with strict accumulator. +-- +-- @since 0.12.3.0 +foldM' :: (PrimMonad m, Unbox a) => (b -> a -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldM' #-} +foldM' = G.foldM' + +-- | /O(n)/ Monadic fold (action applied to each element and its index). +-- +-- @since 0.12.3.0 +ifoldM :: (PrimMonad m, Unbox a) => (b -> Int -> a -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldM #-} +ifoldM = G.ifoldM + +-- | /O(n)/ Monadic fold with strict accumulator (action applied to each element and its index). +-- +-- @since 0.12.3.0 +ifoldM' :: (PrimMonad m, Unbox a) => (b -> Int -> a -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldM' #-} +ifoldM' = G.ifoldM' + +-- | /O(n)/ Monadic right fold. +-- +-- @since 0.12.3.0 +foldrM :: (PrimMonad m, Unbox a) => (a -> b -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldrM #-} +foldrM = G.foldrM + +-- | /O(n)/ Monadic right fold with strict accumulator. +-- +-- @since 0.12.3.0 +foldrM' :: (PrimMonad m, Unbox a) => (a -> b -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE foldrM' #-} +foldrM' = G.foldrM' + +-- | /O(n)/ Monadic right fold (action applied to each element and its index). +-- +-- @since 0.12.3.0 +ifoldrM :: (PrimMonad m, Unbox a) => (Int -> a -> b -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldrM #-} +ifoldrM = G.ifoldrM + +-- | /O(n)/ Monadic right fold with strict accumulator (action applied +-- to each element and its index). +-- +-- @since 0.12.3.0 +ifoldrM' :: (PrimMonad m, Unbox a) => (Int -> a -> b -> m b) -> b -> MVector (PrimState m) a -> m b +{-# INLINE ifoldrM' #-} +ifoldrM' = G.ifoldrM' + + #define DEFINE_MUTABLE #include "unbox-tuple-instances" diff --git a/changelog.md b/changelog.md index 03b667e..9868044 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,15 @@ +# Changes in version 0.12.3.0 + + * Fix performance regression due to introduction of `keepAlive#` primop in ghc-9.0: [#372](https://github.com/haskell/vector/pull/372) + + * Add monadic functions for mutable vectors: [#338](https://github.com/haskell/vector/pull/338) + + * Added folds for monadic functions: `mapM_`, `imapM_`, `forM_`, `iforM_`, + `foldl`, `foldl'`, `foldM`, `foldM'`, `ifoldl`, `ifoldl'`, `ifoldM`, + `ifoldM'` + * Added `modifyM` and `unsafeModifyM` for mutable vectors + * Added `generate` and `generateM` for mutable vectors + # Changes in version 0.12.2.0 * Add `MINIMAL` pragma to `Vector` & `MVector` type classes: [#11](https://github.com/haskell/vector/issues/11) diff --git a/tests/Tests/Vector/Property.hs b/tests/Tests/Vector/Property.hs index 3022db8..5910abc 100644 --- a/tests/Tests/Vector/Property.hs +++ b/tests/Tests/Vector/Property.hs @@ -28,12 +28,14 @@ import Boilerplater import Utilities as Util hiding (limitUnfolds) import Control.Monad -import Data.Functor.Identity +import Control.Monad.ST import qualified Data.Traversable as T (Traversable(..)) import Data.Foldable (Foldable(foldMap)) +import Data.Functor.Identity import Data.Orphans () - +import Data.Foldable (foldrM) import qualified Data.Vector.Generic as V +import qualified Data.Vector.Generic.Mutable as MV import qualified Data.Vector.Fusion.Bundle as S import Test.QuickCheck @@ -196,7 +198,17 @@ testPolymorphicFunctions _ = $(testProperties [ 'prop_prescanr, 'prop_prescanr', 'prop_postscanr, 'prop_postscanr', 'prop_scanr, 'prop_scanr', 'prop_scanr1, 'prop_scanr1', - 'prop_iscanr, 'prop_iscanr' + 'prop_iscanr, 'prop_iscanr', + + -- Mutable API + 'prop_mut_read, 'prop_mut_write, 'prop_mut_modify, + + 'prop_mut_generate, 'prop_mut_generateM, + 'prop_mut_mapM_, 'prop_mut_imapM_, 'prop_mut_forM_, 'prop_mut_iforM_, + 'prop_mut_foldr, 'prop_mut_foldr', 'prop_mut_foldl, 'prop_mut_foldl', + 'prop_mut_ifoldr, 'prop_mut_ifoldr', 'prop_mut_ifoldl, 'prop_mut_ifoldl', + 'prop_mut_foldM, 'prop_mut_foldM', 'prop_mut_foldrM, 'prop_mut_foldrM', + 'prop_mut_ifoldM, 'prop_mut_ifoldM', 'prop_mut_ifoldrM, 'prop_mut_ifoldrM' ]) where -- Prelude @@ -474,6 +486,110 @@ testPolymorphicFunctions _ = $(testProperties [ constructrN xs 0 _ = xs constructrN xs n f = constructrN (f xs : xs) (n-1) f + prop_mut_foldr :: P ((a -> a -> a) -> a -> v a -> a) = + (\f z v -> runST $ MV.foldr f z =<< V.thaw v) `eq` foldr + prop_mut_foldr' :: P ((a -> a -> a) -> a -> v a -> a) = + (\f z v -> runST $ MV.foldr' f z =<< V.thaw v) `eq` foldr + prop_mut_foldl :: P ((a -> a -> a) -> a -> v a -> a) = + (\f z v -> runST $ MV.foldl f z =<< V.thaw v) `eq` foldl + prop_mut_foldl' :: P ((a -> a -> a) -> a -> v a -> a) = + (\f z v -> runST $ MV.foldl' f z =<< V.thaw v) `eq` foldl' + prop_mut_ifoldr :: P ((Int -> a -> a -> a) -> a -> v a -> a) = + (\f z v -> runST $ MV.ifoldr f z =<< V.thaw v) `eq` ifoldr + prop_mut_ifoldr' :: P ((Int -> a -> a -> a) -> a -> v a -> a) = + (\f z v -> runST $ MV.ifoldr' f z =<< V.thaw v) `eq` ifoldr + prop_mut_ifoldl :: P ((a -> Int -> a -> a) -> a -> v a -> a) = + (\f z v -> runST $ MV.ifoldl f z =<< V.thaw v) `eq` ifoldl + prop_mut_ifoldl' :: P ((a -> Int -> a -> a) -> a -> v a -> a) = + (\f z v -> runST $ MV.ifoldl' f z =<< V.thaw v) `eq` ifoldl + + prop_mut_foldM :: P ((a -> a -> Identity a) -> a -> v a -> Identity a) + = (\f z v -> Identity $ runST $ MV.foldM (\b -> pure . runIdentity . f b) z =<< V.thaw v) + `eq` foldM + prop_mut_foldM' :: P ((a -> a -> Identity a) -> a -> v a -> Identity a) + = (\f z v -> Identity $ runST $ MV.foldM' (\b -> pure . runIdentity . f b) z =<< V.thaw v) + `eq` foldM + prop_mut_foldrM :: P ((a -> a -> Identity a) -> a -> v a -> Identity a) + = (\f z v -> Identity $ runST $ MV.foldrM (\a -> pure . runIdentity . f a) z =<< V.thaw v) + `eq` + foldrM + prop_mut_foldrM' :: P ((a -> a -> Identity a) -> a -> v a -> Identity a) + = (\f z v -> Identity $ runST $ MV.foldrM' (\a b -> pure $ runIdentity $ f a b) z =<< V.thaw v) + `eq` + foldrM + + prop_mut_read = \xs -> + not (V.null xs) ==> + forAll (choose (0, V.length xs-1)) $ \i -> + unP prop xs i + where + prop :: P (v a -> Int -> a) = (\v i -> runST $ do mv <- V.thaw v + MV.read mv i + ) `eq` (!!) + prop_mut_write = \xs -> + not (V.null xs) ==> + forAll (choose (0, V.length xs-1)) $ \i -> + unP prop xs i + where + prop :: P (v a -> Int -> a -> v a) = (\v i a -> runST $ do mv <- V.thaw v + MV.write mv i a + V.freeze mv + ) `eq` writeList + prop_mut_modify = \xs f -> + not (V.null xs) ==> + forAll (choose (0, V.length xs-1)) $ \i -> + unP prop xs f i + where + prop :: P (v a -> (a -> a) -> Int -> v a) + = (\v f i -> runST $ do mv <- V.thaw v + MV.modify mv f i + V.freeze mv + ) `eq` modifyList + + + + prop_mut_generate :: P (Int -> (Int -> a) -> v a) + = (\n _ -> n < 1000) ===> (\n f -> runST $ V.freeze =<< MV.generate n f) + `eq` Util.generate + prop_mut_generateM :: P (Int -> (Int -> Writer [a] a) -> Writer [a] (v a)) + = (\n _ -> n < 1000) ===> (\n f -> liftRunST $ V.freeze =<< MV.generateM n (hoistST . f)) + `eq` Util.generateM + + prop_mut_ifoldM :: P ((a -> Int -> a -> Identity a) -> a -> v a -> Identity a) + = (\f z v -> Identity $ runST $ MV.ifoldM (\b i -> pure . runIdentity . f b i) z =<< V.thaw v) + `eq` ifoldM + prop_mut_ifoldM' :: P ((a -> Int -> a -> Identity a) -> a -> v a -> Identity a) + = (\f z v -> Identity $ runST $ MV.ifoldM' (\b i -> pure . runIdentity . f b i) z =<< V.thaw v) + `eq` ifoldM + prop_mut_ifoldrM :: P ((Int -> a -> a -> Identity a) -> a -> v a -> Identity a) + = (\f z v -> Identity $ runST $ MV.ifoldrM (\i b -> pure . runIdentity . f i b) z =<< V.thaw v) + `eq` + ifoldrM + prop_mut_ifoldrM' :: P ((Int -> a -> a -> Identity a) -> a -> v a -> Identity a) + = (\f z v -> Identity $ runST $ MV.ifoldrM' (\i b -> pure . runIdentity . f i b) z =<< V.thaw v) + `eq` + ifoldrM + + prop_mut_forM_ :: P (v a -> (a -> Writer [a] ()) -> Writer [a] ()) + = (\v f -> liftRunST $ do mv <- V.thaw v + MV.forM_ mv (hoistST . f)) + `eq` flip mapM_ + prop_mut_iforM_ :: P (v a -> (Int -> a -> Writer [a] ()) -> Writer [a] ()) + = (\v f -> liftRunST $ do mv <- V.thaw v + MV.iforM_ mv (\i x -> hoistST $ f i x)) + `eq` flip imapM_ + prop_mut_mapM_ :: P ((a -> Writer [a] ()) -> v a -> Writer [a] ()) + = (\f v -> liftRunST $ MV.mapM_ (hoistST . f) =<< V.thaw v) `eq` mapM_ + prop_mut_imapM_ :: P ((Int -> a -> Writer [a] ()) -> v a -> Writer [a] ()) + = (\f v -> liftRunST $ MV.imapM_ (\i x -> hoistST $ f i x) =<< V.thaw v) `eq` imapM_ + + +liftRunST :: (forall s. WriterT w (ST s) a) -> Writer w a +liftRunST m = WriterT $ Identity $ runST $ runWriterT m + +hoistST :: Writer w a -> WriterT w (ST s) a +hoistST = WriterT . pure . runWriter + -- copied from GHC source code partitionWith :: (a -> Either b c) -> [a] -> ([b], [c]) partitionWith _ [] = ([],[]) diff --git a/tests/Utilities.hs b/tests/Utilities.hs index 0e411f5..d33b095 100644 --- a/tests/Utilities.hs +++ b/tests/Utilities.hs @@ -3,6 +3,7 @@ module Utilities where import Test.QuickCheck +import Data.Foldable import qualified Data.Vector as DV import qualified Data.Vector.Generic as DVG import qualified Data.Vector.Primitive as DVP @@ -278,6 +279,15 @@ xs // ps = go xs ps' 0 withIndexFirst m f = m (uncurry f) . zip [0..] +modifyList :: [a] -> (a -> a) -> Int -> [a] +modifyList xs f i = zipWith merge xs (replicate i Nothing ++ [Just f] ++ repeat Nothing) + where + merge x Nothing = x + merge x (Just g) = g x + +writeList :: [a] -> Int -> a -> [a] +writeList xs i a = modifyList xs (const a) i + imap :: (Int -> a -> a) -> [a] -> [a] imap = withIndexFirst map @@ -322,9 +332,12 @@ iscanr f z = scanr (uncurry f) z . zip [0..] ifoldr :: (Int -> a -> b -> b) -> b -> [a] -> b ifoldr f z = foldr (uncurry f) z . zip [0..] -ifoldM :: Monad m => (a -> Int -> a -> m a) -> a -> [a] -> m a +ifoldM :: Monad m => (b -> Int -> a -> m b) -> b -> [a] -> m b ifoldM = indexedLeftFold foldM +ifoldrM :: Monad m => (Int -> a -> b -> m b) -> b -> [a] -> m b +ifoldrM f z xs = foldrM (\(i,a) b -> f i a b) z ([0..] `zip` xs) + ifoldM_ :: Monad m => (b -> Int -> a -> m b) -> b -> [a] -> m () ifoldM_ = indexedLeftFold foldM_ diff --git a/vector.cabal b/vector.cabal index 3ba4baf..a883166 100644 --- a/vector.cabal +++ b/vector.cabal @@ -1,5 +1,5 @@ Name: vector -Version: 0.12.2.0 +Version: 0.12.3.0 -- don't forget to update the changelog file! License: BSD3 License-File: LICENSE |