{-# LANGUAGE BangPatterns #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE MonoLocalBinds #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} -- | -- Module : Data.Massiv.Array.Mutable -- Copyright : (c) Alexey Kuleshevich 2018-2021 -- License : BSD3 -- Maintainer : Alexey Kuleshevich -- Stability : experimental -- Portability : non-portable -- module Data.Massiv.Array.Mutable ( -- ** Size sizeOfMArray , msize , resizeMArrayM , flattenMArray , outerSliceMArrayM , outerSlicesMArray -- ** Element-wise mutation , read , readM , write , write_ , writeM , modify , modify_ , modifyM , modifyM_ , swap , swap_ , swapM , swapM_ , zipSwapM_ -- ** Operations on @MArray@ -- *** Immutable conversion , thaw , thawS , freeze , freezeS -- *** Create mutable , newMArray , newMArray' , makeMArray , makeMArrayLinear , makeMArrayS , makeMArrayLinearS -- *** Create pure , createArray_ , createArray , createArrayS_ , createArrayS , createArrayST_ , createArrayST -- *** Generate , generateArray , generateArrayLinear , generateArrayS , generateArrayLinearS -- *** Stateful worker threads , generateArrayWS , generateArrayLinearWS -- *** Unfold , unfoldrPrimM_ , iunfoldrPrimM_ , unfoldrPrimM , iunfoldrPrimM , unfoldlPrimM_ , iunfoldlPrimM_ , unfoldlPrimM , iunfoldlPrimM -- *** Mapping , forPrimM , forPrimM_ , iforPrimM , iforPrimM_ , iforLinearPrimM , iforLinearPrimM_ , for2PrimM_ , ifor2PrimM_ -- *** Modify , withMArray , withMArray_ , withLoadMArray_ , withMArrayS , withLoadMArrayS , withMArrayS_ , withLoadMArrayS_ , withMArrayST , withLoadMArrayST , withMArrayST_ , withLoadMArrayST_ -- *** Initialize , initialize , initializeNew -- ** Computation , Manifest , MArray , RealWorld , computeInto , loadArray , loadArrayS ) where -- TODO: add fromListM, et al. import Data.Maybe (fromMaybe) import Control.Monad (void, when, unless, (>=>)) import Control.Monad.ST import Control.Monad.Primitive import Control.Scheduler import Data.Massiv.Core.Common import Data.Massiv.Array.Mutable.Internal import Data.Massiv.Array.Delayed.Pull (D) import Prelude hiding (mapM, read) -- | /O(1)/ - Change the size of a mutable array. Throws -- `SizeElementsMismatchException` if total number of elements does not match -- the supplied array. -- -- @since 1.0.0 resizeMArrayM :: (Manifest r e, Index ix', Index ix, MonadThrow m) => Sz ix' -> MArray s r ix e -> m (MArray s r ix' e) resizeMArrayM sz marr = unsafeResizeMArray sz marr <$ guardNumberOfElements (sizeOfMArray marr) sz {-# INLINE resizeMArrayM #-} -- | /O(1)/ - Change a mutable array to a mutable vector. -- -- @since 1.0.0 flattenMArray :: (Manifest r e, Index ix) => MArray s r ix e -> MVector s r e flattenMArray marr = unsafeResizeMArray (toLinearSz (sizeOfMArray marr)) marr {-# INLINE flattenMArray #-} -- | /O(1)/ - Slice a mutable array from the outside, while reducing its -- dimensionality by one. Same as `Data.Massiv.Array.!?>` operator, but for -- mutable arrays. -- -- @since 1.0.0 outerSliceMArrayM :: forall r ix e m s. (MonadThrow m, Index (Lower ix), Index ix, Manifest r e) => MArray s r ix e -> Ix1 -> m (MArray s r (Lower ix) e) outerSliceMArrayM !marr !i = do let (k, szL) = unconsSz (sizeOfMArray marr) unless (isSafeIndex k i) $ throwM $ IndexOutOfBoundsException k i pure $ unsafeResizeMArray szL $ unsafeLinearSliceMArray (i * totalElem szL) (toLinearSz szL) marr {-# INLINE outerSliceMArrayM #-} -- | /O(1)/ - Take all outer slices of a mutable array and construct a delayed -- vector out of them. In other words it applies `outerSliceMArrayM` to each -- outer index. Same as `Data.Massiv.Array.outerSlices` function, but for -- mutable arrays. -- -- ====__Examples__ -- -- >>> import Data.Massiv.Array as A -- >>> arr <- resizeM (Sz2 4 7) $ makeArrayR P Seq (Sz1 28) (+10) -- >>> arr -- Array P Seq (Sz (4 :. 7)) -- [ [ 10, 11, 12, 13, 14, 15, 16 ] -- , [ 17, 18, 19, 20, 21, 22, 23 ] -- , [ 24, 25, 26, 27, 28, 29, 30 ] -- , [ 31, 32, 33, 34, 35, 36, 37 ] -- ] -- -- Here we can see we can get individual rows from a mutable matrix -- -- >>> marr <- thawS arr -- >>> import Control.Monad ((<=<)) -- >>> mapIO_ (print <=< freezeS) $ outerSlicesMArray Seq marr -- Array P Seq (Sz1 7) -- [ 10, 11, 12, 13, 14, 15, 16 ] -- Array P Seq (Sz1 7) -- [ 17, 18, 19, 20, 21, 22, 23 ] -- Array P Seq (Sz1 7) -- [ 24, 25, 26, 27, 28, 29, 30 ] -- Array P Seq (Sz1 7) -- [ 31, 32, 33, 34, 35, 36, 37 ] -- -- For the sake of example what if our goal was to mutate array in such a way -- that rows from the top half were swapped with the bottom half: -- -- >>> (top, bottom) <- splitAtM 1 2 $ outerSlicesMArray Seq marr -- >>> mapIO_ (print <=< freezeS) top -- Array P Seq (Sz1 7) -- [ 10, 11, 12, 13, 14, 15, 16 ] -- Array P Seq (Sz1 7) -- [ 17, 18, 19, 20, 21, 22, 23 ] -- >>> mapIO_ (print <=< freezeS) bottom -- Array P Seq (Sz1 7) -- [ 24, 25, 26, 27, 28, 29, 30 ] -- Array P Seq (Sz1 7) -- [ 31, 32, 33, 34, 35, 36, 37 ] -- >>> szipWithM_ (zipSwapM_ 0) top bottom -- >>> freezeS marr -- Array P Seq (Sz (4 :. 7)) -- [ [ 24, 25, 26, 27, 28, 29, 30 ] -- , [ 31, 32, 33, 34, 35, 36, 37 ] -- , [ 10, 11, 12, 13, 14, 15, 16 ] -- , [ 17, 18, 19, 20, 21, 22, 23 ] -- ] -- -- @since 1.0.0 outerSlicesMArray :: forall r ix e s. (Index (Lower ix), Index ix, Manifest r e) => Comp -> MArray s r ix e -> Vector D (MArray s r (Lower ix) e) outerSlicesMArray comp marr = makeArray comp k (\i -> unsafeResizeMArray szL $ unsafeLinearSliceMArray (i * unSz kL) kL marr) where kL = toLinearSz szL (k, szL) = unconsSz $ sizeOfMArray marr {-# INLINE outerSlicesMArray #-} -- | /O(n)/ - Initialize a new mutable array. All elements will be set to some default value. For -- boxed arrays it will be a thunk with `Uninitialized` exception, while for others it will be -- simply zeros. -- -- ==== __Examples__ -- -- >>> import Data.Massiv.Array -- >>> marr <- newMArray' (Sz2 2 6) :: IO (MArray RealWorld P Ix2 Int) -- >>> freeze Seq marr -- Array P Seq (Sz (2 :. 6)) -- [ [ 0, 0, 0, 0, 0, 0 ] -- , [ 0, 0, 0, 0, 0, 0 ] -- ] -- -- Or using @TypeApplications@: -- -- >>> :set -XTypeApplications -- >>> newMArray' @P @Ix2 @Int (Sz2 2 6) >>= freezeS -- Array P Seq (Sz (2 :. 6)) -- [ [ 0, 0, 0, 0, 0, 0 ] -- , [ 0, 0, 0, 0, 0, 0 ] -- ] -- >>> newMArray' @B @_ @Int (Sz2 2 6) >>= freezeS -- *** Exception: Uninitialized -- -- @since 0.6.0 newMArray' :: forall r ix e m. (Manifest r e, Index ix, PrimMonad m) => Sz ix -> m (MArray (PrimState m) r ix e) newMArray' sz = unsafeNew sz >>= \ma -> ma <$ initialize ma {-# INLINE newMArray' #-} -- | /O(n)/ - Make a mutable copy of a pure array. Keep in mind that both `freeze` and `thaw` trigger a -- copy of the full array. -- -- ==== __Example__ -- -- >>> import Data.Massiv.Array -- >>> :set -XTypeApplications -- >>> arr <- fromListsM @U @Ix2 @Double Par [[12,21],[13,31]] -- >>> marr <- thaw arr -- >>> modify marr (pure . (+ 10)) (1 :. 0) -- Just 13.0 -- >>> freeze Par marr -- Array U Par (Sz (2 :. 2)) -- [ [ 12.0, 21.0 ] -- , [ 23.0, 31.0 ] -- ] -- -- @since 0.1.0 thaw :: forall r ix e m. (Manifest r e, Index ix, MonadIO m) => Array r ix e -> m (MArray RealWorld r ix e) thaw arr = liftIO $ do let sz = size arr totalLength = totalElem sz marr <- unsafeNew sz withMassivScheduler_ (getComp arr) $ \scheduler -> splitLinearly (numWorkers scheduler) totalLength $ \chunkLength slackStart -> do loopM_ 0 (< slackStart) (+ chunkLength) $ \ !start -> scheduleWork_ scheduler $ unsafeArrayLinearCopy arr start marr start (SafeSz chunkLength) let slackLength = totalLength - slackStart when (slackLength > 0) $ scheduleWork_ scheduler $ unsafeArrayLinearCopy arr slackStart marr slackStart (SafeSz slackLength) pure marr {-# INLINE thaw #-} -- | Same as `thaw`, but restrict computation to sequential only. -- -- ==== __Example__ -- -- >>> import Data.Massiv.Array -- >>> :set -XOverloadedLists -- >>> thawS @P @Ix1 @Double [1..10] -- >>> marr <- thawS @P @Ix1 @Double [1..10] -- >>> writeM marr 5 100 -- >>> freezeS marr -- Array P Seq (Sz1 10) -- [ 1.0, 2.0, 3.0, 4.0, 5.0, 100.0, 7.0, 8.0, 9.0, 10.0 ] -- -- @since 0.3.0 thawS :: forall r ix e m. (Manifest r e, Index ix, PrimMonad m) => Array r ix e -> m (MArray (PrimState m) r ix e) thawS arr = do tmarr <- unsafeNew (size arr) unsafeArrayLinearCopy arr 0 tmarr 0 (SafeSz (totalElem (size arr))) pure tmarr {-# INLINE thawS #-} -- | /O(n)/ - Yield an immutable copy of the mutable array. Note that mutable representations -- have to be the same. -- -- ==== __Example__ -- -- >>> import Data.Massiv.Array -- >>> marr <- newMArray @P (Sz2 2 6) (0 :: Int) -- >>> forM_ (range Seq 0 (Ix2 1 4)) $ \ix -> write marr ix 9 -- >>> freeze Seq marr -- Array P Seq (Sz (2 :. 6)) -- [ [ 9, 9, 9, 9, 0, 0 ] -- , [ 0, 0, 0, 0, 0, 0 ] -- ] -- -- @since 0.1.0 freeze :: forall r ix e m. (Manifest r e, Index ix, MonadIO m) => Comp -> MArray RealWorld r ix e -> m (Array r ix e) freeze comp smarr = liftIO $ do let sz = sizeOfMArray smarr totalLength = totalElem sz tmarr <- unsafeNew sz withMassivScheduler_ comp $ \scheduler -> splitLinearly (numWorkers scheduler) totalLength $ \chunkLength slackStart -> do loopM_ 0 (< slackStart) (+ chunkLength) $ \ !start -> scheduleWork_ scheduler $ unsafeLinearCopy smarr start tmarr start (SafeSz chunkLength) let slackLength = totalLength - slackStart when (slackLength > 0) $ scheduleWork_ scheduler $ unsafeLinearCopy smarr slackStart tmarr slackStart (SafeSz slackLength) unsafeFreeze comp tmarr {-# INLINE freeze #-} -- | Same as `freeze`, but do the copy of supplied muable array sequentially. Also, unlike `freeze` -- that has to be done in `IO`, `freezeS` can be used with `ST`. -- -- @since 0.3.0 freezeS :: forall r ix e m. (Manifest r e, Index ix, PrimMonad m) => MArray (PrimState m) r ix e -> m (Array r ix e) freezeS smarr = do let sz = sizeOfMArray smarr tmarr <- unsafeNew sz unsafeLinearCopy smarr 0 tmarr 0 (SafeSz (totalElem sz)) unsafeFreeze Seq tmarr {-# INLINE freezeS #-} unsafeNewUpper :: (Load r' ix e, Manifest r e, PrimMonad m) => Array r' ix e -> m (MArray (PrimState m) r Ix1 e) unsafeNewUpper !arr = unsafeNew (fromMaybe zeroSz (maxLinearSize arr)) {-# INLINE unsafeNewUpper #-} -- | Load sequentially a pure array into the newly created mutable array. -- -- @since 0.3.0 loadArrayS :: forall r ix e r' m. (Load r' ix e, Manifest r e, PrimMonad m) => Array r' ix e -> m (MArray (PrimState m) r ix e) loadArrayS arr = do marr <- unsafeNewUpper arr stToPrim $ unsafeLoadIntoST marr arr {-# INLINE loadArrayS #-} -- | Load a pure array into the newly created mutable array, while respecting computation startegy. -- -- @since 0.3.0 loadArray :: forall r ix e r' m. (Load r' ix e, Manifest r e, MonadIO m) => Array r' ix e -> m (MArray RealWorld r ix e) loadArray arr = liftIO $ do marr <- unsafeNewUpper arr unsafeLoadIntoIO marr arr {-# INLINE loadArray #-} -- | Compute an Array while loading the results into the supplied mutable target array. Number of -- elements for arrays must agree, otherwise `SizeElementsMismatchException` exception is thrown. -- -- @since 0.1.3 computeInto :: (Size r', Load r' ix' e, Manifest r e, Index ix, MonadIO m) => MArray RealWorld r ix e -- ^ Target Array -> Array r' ix' e -- ^ Array to load -> m () computeInto !mArr !arr = liftIO $ do unless (totalElem (sizeOfMArray mArr) == totalElem (size arr)) $ throwM $ SizeElementsMismatchException (sizeOfMArray mArr) (size arr) withMassivScheduler_ (getComp arr) $ \scheduler -> stToPrim $ iterArrayLinearST_ scheduler arr (unsafeLinearWrite mArr) {-# INLINE computeInto #-} -- | Create a mutable array using an index aware generating action. -- -- @since 0.3.0 makeMArrayS :: forall r ix e m. (Manifest r e, Index ix, PrimMonad m) => Sz ix -- ^ Size of the create array -> (ix -> m e) -- ^ Element generating action -> m (MArray (PrimState m) r ix e) makeMArrayS sz f = makeMArrayLinearS sz (f . fromLinearIndex sz) {-# INLINE makeMArrayS #-} -- | Same as `makeMArrayS`, but index supplied to the action is row-major linear index. -- -- @since 0.3.0 makeMArrayLinearS :: forall r ix e m. (Manifest r e, Index ix, PrimMonad m) => Sz ix -> (Int -> m e) -> m (MArray (PrimState m) r ix e) makeMArrayLinearS sz f = do marr <- unsafeNew sz loopM_ 0 (< totalElem (sizeOfMArray marr)) (+ 1) (\ !i -> f i >>= unsafeLinearWrite marr i) return marr {-# INLINE makeMArrayLinearS #-} -- | Just like `makeMArrayS`, but also accepts computation strategy and runs in `IO`. -- -- @since 0.3.0 makeMArray :: forall r ix e m. (MonadUnliftIO m, Manifest r e, Index ix) => Comp -> Sz ix -> (ix -> m e) -> m (MArray RealWorld r ix e) makeMArray comp sz f = makeMArrayLinear comp sz (f . fromLinearIndex sz) {-# INLINE makeMArray #-} -- | Just like `makeMArrayLinearS`, but also accepts computation strategy and runs in `IO`. -- -- @since 0.3.0 makeMArrayLinear :: forall r ix e m. (MonadUnliftIO m, Manifest r e, Index ix) => Comp -> Sz ix -> (Int -> m e) -> m (MArray RealWorld r ix e) makeMArrayLinear comp sz f = do marr <- liftIO $ unsafeNew sz withScheduler_ comp $ \scheduler -> withRunInIO $ \run -> splitLinearlyWithM_ scheduler (totalElem sz) (run . f) (unsafeLinearWrite marr) return marr {-# INLINE makeMArrayLinear #-} -- | Create a new array by supplying an action that will fill the new blank mutable array. Use -- `createArray` if you'd like to keep the result of the filling function. -- -- ====__Examples__ -- -- >>> :set -XTypeApplications -- >>> import Data.Massiv.Array -- >>> createArray_ @P @_ @Int Seq (Sz1 2) (\ s marr -> scheduleWork s (writeM marr 0 10) >> scheduleWork s (writeM marr 1 11)) -- Array P Seq (Sz1 2) -- [ 10, 11 ] -- -- @since 0.3.0 -- createArray_ :: forall r ix e a m. (Manifest r e, Index ix, MonadUnliftIO m) => Comp -- ^ Computation strategy to use after `MArray` gets frozen and onward. -> Sz ix -- ^ Size of the newly created array -> (Scheduler RealWorld () -> MArray RealWorld r ix e -> m a) -- ^ An action that should fill all elements of the brand new mutable array -> m (Array r ix e) createArray_ comp sz action = do marr <- liftIO $ newMArray' sz withScheduler_ comp (`action` marr) liftIO $ unsafeFreeze comp marr {-# INLINE createArray_ #-} -- | Just like `createArray_`, but together with `Array` it returns results of scheduled filling -- actions. -- -- @since 0.3.0 -- createArray :: forall r ix e a m b. (Manifest r e, Index ix, MonadUnliftIO m) => Comp -- ^ Computation strategy to use after `MArray` gets frozen and onward. -> Sz ix -- ^ Size of the newly created array -> (Scheduler RealWorld a -> MArray RealWorld r ix e -> m b) -- ^ An action that should fill all elements of the brand new mutable array -> m ([a], Array r ix e) createArray comp sz action = do marr <- liftIO $ newMArray' sz a <- withScheduler comp (`action` marr) arr <- liftIO $ unsafeFreeze comp marr return (a, arr) {-# INLINE createArray #-} -- | Create a new array by supplying an action that will fill the new blank mutable array. Use -- `createArrayS` if you'd like to keep the result of the filling function. -- -- ====__Examples__ -- -- >>> :set -XTypeApplications -- >>> import Data.Massiv.Array -- >>> createArrayS_ @P @_ @Int (Sz1 2) (\ marr -> write marr 0 10 >> write marr 1 12) -- Array P Seq (Sz1 2) -- [ 10, 12 ] -- -- @since 0.3.0 createArrayS_ :: forall r ix e a m. (Manifest r e, Index ix, PrimMonad m) => Sz ix -- ^ Size of the newly created array -> (MArray (PrimState m) r ix e -> m a) -- ^ An action that should fill all elements of the brand new mutable array -> m (Array r ix e) createArrayS_ sz action = snd <$> createArrayS sz action {-# INLINE createArrayS_ #-} -- | Just like `createArray_`, but together with `Array` it returns the result of the filling action. -- -- @since 0.3.0 createArrayS :: forall r ix e a m. (Manifest r e, Index ix, PrimMonad m) => Sz ix -- ^ Size of the newly created array -> (MArray (PrimState m) r ix e -> m a) -- ^ An action that should fill all elements of the brand new mutable array -> m (a, Array r ix e) createArrayS sz action = do marr <- newMArray' sz a <- action marr arr <- unsafeFreeze Seq marr return (a, arr) {-# INLINE createArrayS #-} -- | Just like `createArrayS_`, but restricted to `ST`. -- -- @since 0.3.0 createArrayST_ :: forall r ix e a. (Manifest r e, Index ix) => Sz ix -> (forall s. MArray s r ix e -> ST s a) -> Array r ix e createArrayST_ sz action = runST $ createArrayS_ sz action {-# INLINE createArrayST_ #-} -- | Just like `createArrayS`, but restricted to `ST`. -- -- @since 0.2.6 createArrayST :: forall r ix e a. (Manifest r e, Index ix) => Sz ix -> (forall s. MArray s r ix e -> ST s a) -> (a, Array r ix e) createArrayST sz action = runST $ createArrayS sz action {-# INLINE createArrayST #-} -- | Sequentially generate a pure array. Much like `makeArray` creates a pure array this -- function will use `Manifest` interface to generate a pure `Array` in the end, except that -- computation strategy is set to `Seq`. Element producing function no longer has to be pure -- but is a stateful action, becuase it is restricted to `PrimMonad` thus allows for sharing -- the state between computation of each element. -- -- ====__Examples__ -- -- >>> import Data.Massiv.Array -- >>> import Data.IORef -- >>> ref <- newIORef (0 :: Int) -- >>> generateArrayS (Sz1 6) (\ i -> modifyIORef' ref (+i) >> print i >> pure i) :: IO (Array U Ix1 Int) -- 0 -- 1 -- 2 -- 3 -- 4 -- 5 -- Array U Seq (Sz1 6) -- [ 0, 1, 2, 3, 4, 5 ] -- >>> readIORef ref -- 15 -- -- @since 0.2.6 generateArrayS :: forall r ix e m. (Manifest r e, Index ix, PrimMonad m) => Sz ix -- ^ Resulting size of the array -> (ix -> m e) -- ^ Element producing generator -> m (Array r ix e) generateArrayS sz gen = generateArrayLinearS sz (gen . fromLinearIndex sz) {-# INLINE generateArrayS #-} -- | Same as `generateArray` but with action that accepts row-major linear index. -- -- @since 0.3.0 generateArrayLinearS :: forall r ix e m. (Manifest r e, Index ix, PrimMonad m) => Sz ix -- ^ Resulting size of the array -> (Int -> m e) -- ^ Element producing generator -> m (Array r ix e) generateArrayLinearS sz gen = do marr <- unsafeNew sz loopM_ 0 (< totalElem (sizeOfMArray marr)) (+ 1) $ \i -> gen i >>= unsafeLinearWrite marr i unsafeFreeze Seq marr {-# INLINE generateArrayLinearS #-} -- | Just like `generateArrayS`, except this generator __will__ respect the supplied computation -- strategy, and for that reason it is restricted to `IO`. -- -- @since 0.2.6 generateArray :: forall r ix e m. (MonadUnliftIO m, Manifest r e, Index ix) => Comp -> Sz ix -> (ix -> m e) -> m (Array r ix e) generateArray comp sz f = generateArrayLinear comp sz (f . fromLinearIndex sz) {-# INLINE generateArray #-} -- | Just like `generateArray`, except generating action will receive a row-major linear -- index. -- -- @since 0.3.0 generateArrayLinear :: forall r ix e m. (MonadUnliftIO m, Manifest r e, Index ix) => Comp -> Sz ix -> (Int -> m e) -> m (Array r ix e) generateArrayLinear comp sz f = makeMArrayLinear comp sz f >>= liftIO . unsafeFreeze comp {-# INLINE generateArrayLinear #-} -- | Same as `generateArrayWS`, but use linear indexing instead. -- -- @since 0.3.4 generateArrayLinearWS :: forall r ix e s m. (Manifest r e, Index ix, MonadUnliftIO m, PrimMonad m) => WorkerStates s -> Sz ix -> (Int -> s -> m e) -> m (Array r ix e) generateArrayLinearWS states sz make = do marr <- unsafeNew sz withSchedulerWS_ states $ \schedulerWS -> splitLinearlyWithStatefulM_ schedulerWS (totalElem sz) make (unsafeLinearWrite marr) unsafeFreeze (workerStatesComp states) marr {-# INLINE generateArrayLinearWS #-} -- | Use per worker thread state while generating elements of the array. Very useful for -- things that are not thread safe. -- -- @since 0.3.4 generateArrayWS :: forall r ix e s m. (Manifest r e, Index ix, MonadUnliftIO m, PrimMonad m) => WorkerStates s -> Sz ix -> (ix -> s -> m e) -> m (Array r ix e) generateArrayWS states sz make = generateArrayLinearWS states sz (make . fromLinearIndex sz) {-# INLINE generateArrayWS #-} -- | Sequentially unfold an array from the left. -- -- ====__Examples__ -- -- Create an array with Fibonacci numbers while performing and `IO` action on the accumulator for -- each element of the array. -- -- >>> import Data.Massiv.Array -- >>> unfoldrPrimM_ (Sz1 10) (\a@(f0, f1) -> let fn = f0 + f1 in print a >> return (f0, (f1, fn))) (0, 1) :: IO (Array P Ix1 Int) -- (0,1) -- (1,1) -- (1,2) -- (2,3) -- (3,5) -- (5,8) -- (8,13) -- (13,21) -- (21,34) -- (34,55) -- Array P Seq (Sz1 10) -- [ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 ] -- -- @since 0.3.0 unfoldrPrimM_ :: forall r ix e a m. (Manifest r e, Index ix, PrimMonad m) => Sz ix -- ^ Size of the desired array -> (a -> m (e, a)) -- ^ Unfolding action -> a -- ^ Initial accumulator -> m (Array r ix e) unfoldrPrimM_ sz gen acc0 = snd <$> unfoldrPrimM sz gen acc0 {-# INLINE unfoldrPrimM_ #-} -- | Same as `unfoldrPrimM_` but do the unfolding with index aware function. -- -- @since 0.3.0 iunfoldrPrimM_ :: forall r ix e a m. (Manifest r e, Index ix, PrimMonad m) => Sz ix -- ^ Size of the desired array -> (a -> ix -> m (e, a)) -- ^ Unfolding action -> a -- ^ Initial accumulator -> m (Array r ix e) iunfoldrPrimM_ sz gen acc0 = snd <$> iunfoldrPrimM sz gen acc0 {-# INLINE iunfoldrPrimM_ #-} -- | Just like `iunfoldrPrimM_`, but also returns the final value of the accumulator. -- -- @since 0.3.0 iunfoldrPrimM :: forall r ix e a m. (Manifest r e, Index ix, PrimMonad m) => Sz ix -- ^ Size of the desired array -> (a -> ix -> m (e, a)) -- ^ Unfolding action -> a -- ^ Initial accumulator -> m (a, Array r ix e) iunfoldrPrimM sz gen acc0 = unsafeCreateArrayS sz $ \marr -> let sz' = sizeOfMArray marr in iterLinearM sz' 0 (totalElem sz') 1 (<) acc0 $ \ !i ix !acc -> do (e, acc') <- gen acc ix unsafeLinearWrite marr i e pure acc' {-# INLINE iunfoldrPrimM #-} -- | Just like `iunfoldrPrimM`, but do the unfolding with index aware function. -- -- @since 0.3.0 unfoldrPrimM :: forall r ix e a m. (Manifest r e, Index ix, PrimMonad m) => Sz ix -- ^ Size of the desired array -> (a -> m (e, a)) -- ^ Unfolding action -> a -- ^ Initial accumulator -> m (a, Array r ix e) unfoldrPrimM sz gen acc0 = unsafeCreateArrayS sz $ \marr -> let sz' = sizeOfMArray marr in loopM 0 (< totalElem sz') (+ 1) acc0 $ \ !i !acc -> do (e, acc') <- gen acc unsafeLinearWrite marr i e pure acc' {-# INLINE unfoldrPrimM #-} -- | Sequentially unfold an array from the left. -- -- ====__Examples__ -- -- Create an array with Fibonacci numbers starting at the end while performing and `IO` action on -- the accumulator for each element of the array. -- -- >>> import Data.Massiv.Array -- >>> unfoldlPrimM_ (Sz1 10) (\a@(f0, f1) -> let fn = f0 + f1 in print a >> return ((f1, fn), f0)) (0, 1) :: IO (Array P Ix1 Int) -- (0,1) -- (1,1) -- (1,2) -- (2,3) -- (3,5) -- (5,8) -- (8,13) -- (13,21) -- (21,34) -- (34,55) -- Array P Seq (Sz1 10) -- [ 34, 21, 13, 8, 5, 3, 2, 1, 1, 0 ] -- -- @since 0.3.0 unfoldlPrimM_ :: forall r ix e a m. (Manifest r e, Index ix, PrimMonad m) => Sz ix -- ^ Size of the desired array -> (a -> m (a, e)) -- ^ Unfolding action -> a -- ^ Initial accumulator -> m (Array r ix e) unfoldlPrimM_ sz gen acc0 = snd <$> unfoldlPrimM sz gen acc0 {-# INLINE unfoldlPrimM_ #-} -- | Same as `unfoldlPrimM_` but do the unfolding with index aware function. -- -- @since 0.3.0 iunfoldlPrimM_ :: forall r ix e a m. (Manifest r e, Index ix, PrimMonad m) => Sz ix -- ^ Size of the desired array -> (a -> ix -> m (a, e)) -- ^ Unfolding action -> a -- ^ Initial accumulator -> m (Array r ix e) iunfoldlPrimM_ sz gen acc0 = snd <$> iunfoldlPrimM sz gen acc0 {-# INLINE iunfoldlPrimM_ #-} -- | Just like `iunfoldlPrimM_`, but also returns the final value of the accumulator. -- -- @since 0.3.0 iunfoldlPrimM :: forall r ix e a m. (Manifest r e, Index ix, PrimMonad m) => Sz ix -- ^ Size of the desired array -> (a -> ix -> m (a, e)) -- ^ Unfolding action -> a -- ^ Initial accumulator -> m (a, Array r ix e) iunfoldlPrimM sz gen acc0 = unsafeCreateArrayS sz $ \marr -> let sz' = sizeOfMArray marr in iterLinearM sz' (totalElem sz' - 1) 0 (negate 1) (>=) acc0 $ \ !i ix !acc -> do (acc', e) <- gen acc ix unsafeLinearWrite marr i e pure acc' {-# INLINE iunfoldlPrimM #-} -- | Just like `iunfoldlPrimM`, but do the unfolding with index aware function. -- -- @since 0.3.0 unfoldlPrimM :: forall r ix e a m. (Manifest r e, Index ix, PrimMonad m) => Sz ix -- ^ Size of the desired array -> (a -> m (a, e)) -- ^ Unfolding action -> a -- ^ Initial accumulator -> m (a, Array r ix e) unfoldlPrimM sz gen acc0 = unsafeCreateArrayS sz $ \marr -> let sz' = sizeOfMArray marr in loopDeepM 0 (< totalElem sz') (+1) acc0 $ \ !i !acc -> do (acc', e) <- gen acc unsafeLinearWrite marr i e pure acc' {-# INLINE unfoldlPrimM #-} -- | Sequentially loop over a mutable array while reading each element and applying an -- action to it. There is no mutation to the array, unless the action itself modifies it. -- -- @since 0.4.0 forPrimM_ :: (Manifest r e, Index ix, PrimMonad m) => MArray (PrimState m) r ix e -> (e -> m ()) -> m () forPrimM_ marr f = loopM_ 0 (< totalElem (sizeOfMArray marr)) (+1) (unsafeLinearRead marr >=> f) {-# INLINE forPrimM_ #-} -- | Sequentially loop over a mutable array while modifying each element with an action. -- -- @since 0.4.0 forPrimM :: (Manifest r e, Index ix, PrimMonad m) => MArray (PrimState m) r ix e -> (e -> m e) -> m () forPrimM marr f = loopM_ 0 (< totalElem (sizeOfMArray marr)) (+1) (unsafeLinearModify marr f) {-# INLINE forPrimM #-} -- | Sequentially loop over a mutable array while reading each element and applying an -- index aware action to it. There is no mutation to the array, unless the -- action itself modifies it. -- -- @since 0.4.0 iforPrimM_ :: (Manifest r e, Index ix, PrimMonad m) => MArray (PrimState m) r ix e -> (ix -> e -> m ()) -> m () iforPrimM_ marr f = iforLinearPrimM_ marr (f . fromLinearIndex (sizeOfMArray marr)) {-# INLINE iforPrimM_ #-} -- | Sequentially loop over a mutable array while modifying each element with an index aware action. -- -- @since 0.4.0 iforPrimM :: (Manifest r e, Index ix, PrimMonad m) => MArray (PrimState m) r ix e -> (ix -> e -> m e) -> m () iforPrimM marr f = iforLinearPrimM marr (f . fromLinearIndex (sizeOfMArray marr)) {-# INLINE iforPrimM #-} -- | Sequentially loop over a mutable array while reading each element and applying a -- linear index aware action to it. There is no mutation to the array, unless the action -- itself modifies it. -- -- @since 0.4.0 iforLinearPrimM_ :: (Manifest r e, Index ix, PrimMonad m) => MArray (PrimState m) r ix e -> (Int -> e -> m ()) -> m () iforLinearPrimM_ marr f = loopM_ 0 (< totalElem (sizeOfMArray marr)) (+ 1) (\i -> unsafeLinearRead marr i >>= f i) {-# INLINE iforLinearPrimM_ #-} -- | Sequentially loop over a mutable array while modifying each element with an index aware action. -- -- @since 0.4.0 iforLinearPrimM :: (Manifest r e, Index ix, PrimMonad m) => MArray (PrimState m) r ix e -> (Int -> e -> m e) -> m () iforLinearPrimM marr f = loopM_ 0 (< totalElem (sizeOfMArray marr)) (+ 1) (\i -> unsafeLinearModify marr (f i) i) {-# INLINE iforLinearPrimM #-} -- | Sequentially loop over the intersection of two mutable arrays while reading -- elements from both and applying an action to it. There is no mutation to the -- actual arrays, unless the action itself modifies either one of them. -- -- @since 1.0.0 for2PrimM_ :: forall r1 r2 e1 e2 ix m. (PrimMonad m, Index ix, Manifest r1 e1, Manifest r2 e2) => MArray (PrimState m) r1 ix e1 -> MArray (PrimState m) r2 ix e2 -> (e1 -> e2 -> m ()) -> m () for2PrimM_ m1 m2 f = ifor2PrimM_ m1 m2 (const f) {-# INLINE for2PrimM_ #-} -- | Same as `for2PrimM_`, but with index aware action. -- -- @since 1.0.0 ifor2PrimM_ :: forall r1 r2 e1 e2 ix m. (PrimMonad m, Index ix, Manifest r1 e1, Manifest r2 e2) => MArray (PrimState m) r1 ix e1 -> MArray (PrimState m) r2 ix e2 -> (ix -> e1 -> e2 -> m ()) -> m () ifor2PrimM_ m1 m2 f = do let sz = liftIndex2 min (unSz (sizeOfMArray m1)) (unSz (sizeOfMArray m2)) iterM_ zeroIndex sz oneIndex (<) $ \ix -> do e1 <- unsafeRead m1 ix e2 <- unsafeRead m2 ix f ix e1 e2 {-# INLINE ifor2PrimM_ #-} -- | Same as `withMArray_`, but allows to keep artifacts of scheduled tasks. -- -- @since 0.5.0 withMArray :: (Manifest r e, Index ix, MonadUnliftIO m) => Array r ix e -> (Scheduler RealWorld a -> MArray RealWorld r ix e -> m b) -> m ([a], Array r ix e) withMArray arr action = do marr <- thaw arr xs <- withScheduler (getComp arr) (`action` marr) liftIO ((,) xs <$> unsafeFreeze (getComp arr) marr) {-# INLINE withMArray #-} -- | Create a copy of a pure array, mutate it in place and return its frozen version. The big -- difference between `withMArrayS` is that it's not only gonna respect the computation strategy -- supplied to it while making a copy, but it will also pass extra argumens to the action that -- suppose to modify the mutable copy of the source array. These two extra arguments are: -- -- * Number of capabilities derived from the `Comp`utation strategy of the array. -- -- * An action that can be used to schedule arbitrary number of jobs that will be executed in -- parallel. -- -- * And, of course, the mutable array itself. -- -- @since 0.5.0 withMArray_ :: (Manifest r e, Index ix, MonadUnliftIO m) => Array r ix e -> (Scheduler RealWorld () -> MArray RealWorld r ix e -> m a) -> m (Array r ix e) withMArray_ arr action = do marr <- thaw arr withScheduler_ (getComp arr) (`action` marr) liftIO $ unsafeFreeze (getComp arr) marr {-# INLINE withMArray_ #-} -- | Same as `withMArray_`, but the array supplied to this function can be any loadable -- array. For that reason it will be faster if supplied array is delayed. -- -- @since 0.6.1 withLoadMArray_ :: forall r ix e r' m b. (Load r' ix e, Manifest r e, MonadUnliftIO m) => Array r' ix e -> (Scheduler RealWorld () -> MArray RealWorld r ix e -> m b) -> m (Array r ix e) withLoadMArray_ arr action = do marr <- loadArray arr withScheduler_ (getComp arr) (`action` marr) liftIO $ unsafeFreeze (getComp arr) marr {-# INLINE[2] withLoadMArray_ #-} {-# RULES "withLoadMArray_/withMArray_" [~2] withLoadMArray_ = withMArray_ "withLoadMArrayS/withMArrayS" [~2] withLoadMArrayS = withMArrayS "withLoadMArrayS_/withMArrayS_" [~2] withLoadMArrayS_ = withMArrayS_ #-} -- | Create a copy of a pure array, mutate it in place and return its frozen version. The important -- benefit over doing a manual `thawS` followed by a `freezeS` is that an array will only be copied -- once. -- -- @since 0.5.0 withMArrayS :: (Manifest r e, Index ix, PrimMonad m) => Array r ix e -> (MArray (PrimState m) r ix e -> m a) -> m (a, Array r ix e) withMArrayS arr action = do marr <- thawS arr a <- action marr (,) a <$> unsafeFreeze (getComp arr) marr {-# INLINE withMArrayS #-} -- | Same as `withMArrayS`, except it discards the value produced by the supplied action -- -- @since 0.5.0 withMArrayS_ :: (Manifest r e, Index ix, PrimMonad m) => Array r ix e -> (MArray (PrimState m) r ix e -> m a) -> m (Array r ix e) withMArrayS_ arr action = snd <$> withMArrayS arr action {-# INLINE withMArrayS_ #-} -- | Same as `withMArrayS`, but will work with any loadable array. -- -- @since 0.6.1 withLoadMArrayS :: forall r ix e r' m a. (Load r' ix e, Manifest r e, PrimMonad m) => Array r' ix e -> (MArray (PrimState m) r ix e -> m a) -> m (a, Array r ix e) withLoadMArrayS arr action = do marr <- loadArrayS arr a <- action marr (,) a <$> unsafeFreeze (getComp arr) marr {-# INLINE[2] withLoadMArrayS #-} -- | Same as `withMArrayS_`, but will work with any loadable array. -- -- @since 0.6.1 withLoadMArrayS_ :: forall r ix e r' m a. (Load r' ix e, Manifest r e, PrimMonad m) => Array r' ix e -> (MArray (PrimState m) r ix e -> m a) -> m (Array r ix e) withLoadMArrayS_ arr action = snd <$> withLoadMArrayS arr action {-# INLINE[2] withLoadMArrayS_ #-} -- | Same as `withMArrayS` but in `ST`. This is not only pure, but also the safest way to do -- mutation to the array. -- -- @since 0.5.0 withMArrayST :: (Manifest r e, Index ix) => Array r ix e -> (forall s . MArray s r ix e -> ST s a) -> (a, Array r ix e) withMArrayST arr f = runST $ withMArrayS arr f {-# INLINE withMArrayST #-} -- | Same as `withMArrayS` but in `ST`. This is not only pure, but also the safest way to do -- mutation to the array. -- -- @since 0.5.0 withMArrayST_ :: (Manifest r e, Index ix) => Array r ix e -> (forall s. MArray s r ix e -> ST s a) -> Array r ix e withMArrayST_ arr f = runST $ withMArrayS_ arr f {-# INLINE withMArrayST_ #-} -- | Same as `withMArrayST`, but works with any loadable array. -- -- @since 0.6.1 withLoadMArrayST :: forall r ix e r' a. (Load r' ix e, Manifest r e) => Array r' ix e -> (forall s. MArray s r ix e -> ST s a) -> (a, Array r ix e) withLoadMArrayST arr f = runST $ withLoadMArrayS arr f {-# INLINE[2] withLoadMArrayST #-} -- | Same as `withMArrayST_`, but works with any loadable array. -- -- @since 0.6.1 withLoadMArrayST_ :: forall r ix e r' a. (Load r' ix e, Manifest r e) => Array r' ix e -> (forall s. MArray s r ix e -> ST s a) -> Array r ix e withLoadMArrayST_ arr f = runST $ withLoadMArrayS_ arr f {-# INLINE[2] withLoadMArrayST_ #-} -- | /O(1)/ - Lookup an element in the mutable array. Returns `Nothing` when index is out of bounds. -- -- @since 0.1.0 read :: (Manifest r e, Index ix, PrimMonad m) => MArray (PrimState m) r ix e -> ix -> m (Maybe e) read marr ix = if isSafeIndex (sizeOfMArray marr) ix then Just <$> unsafeRead marr ix else return Nothing {-# INLINE read #-} -- | /O(1)/ - Same as `read`, but throws `IndexOutOfBoundsException` on an invalid index. -- -- @since 0.4.0 readM :: (Manifest r e, Index ix, PrimMonad m, MonadThrow m) => MArray (PrimState m) r ix e -> ix -> m e readM marr ix = read marr ix >>= \case Just e -> pure e Nothing -> throwM $ IndexOutOfBoundsException (sizeOfMArray marr) ix {-# INLINE readM #-} -- | /O(1)/ - Write an element into the cell of a mutable array. Returns `False` when index is out -- of bounds. -- -- @since 0.1.0 write :: (Manifest r e, Index ix, PrimMonad m) => MArray (PrimState m) r ix e -> ix -> e -> m Bool write marr ix e = if isSafeIndex (sizeOfMArray marr) ix then unsafeWrite marr ix e >> pure True else pure False {-# INLINE write #-} -- | /O(1)/ - Write an element into the cell of a mutable array. Same as `write` function -- in case of an out of bounds index it is noop, but unlike `write`, there is no -- information is returned about was the writing of element successful or not. In other -- words, just like `writeM`, but doesn't throw an exception. -- -- @since 0.4.4 write_ :: (Manifest r e, Index ix, PrimMonad m) => MArray (PrimState m) r ix e -> ix -> e -> m () write_ marr ix = when (isSafeIndex (sizeOfMArray marr) ix) . unsafeWrite marr ix {-# INLINE write_ #-} -- | /O(1)/ - Same as `write`, but throws `IndexOutOfBoundsException` on an invalid index. -- -- @since 0.4.0 writeM :: (Manifest r e, Index ix, PrimMonad m, MonadThrow m) => MArray (PrimState m) r ix e -> ix -> e -> m () writeM marr ix e = write marr ix e >>= (`unless` throwM (IndexOutOfBoundsException (sizeOfMArray marr) ix)) {-# INLINE writeM #-} -- | /O(1)/ - Modify an element in the cell of a mutable array with a supplied -- action. Returns the previous value, if index was not out of bounds. -- -- @since 0.1.0 modify :: (Manifest r e, Index ix, PrimMonad m) => MArray (PrimState m) r ix e -- ^ Array to mutate. -> (e -> m e) -- ^ Monadic action that modifies the element -> ix -- ^ Index at which to perform modification. -> m (Maybe e) modify marr f ix = if isSafeIndex (sizeOfMArray marr) ix then Just <$> unsafeModify marr f ix else return Nothing {-# INLINE modify #-} -- | /O(1)/ - Same as `modify`, except that neither the previous value, nor any -- information on whether the modification was successful are returned. In other words, -- just like `modifyM_`, but doesn't throw an exception. -- -- @since 0.4.4 modify_ :: (Manifest r e, Index ix, PrimMonad m) => MArray (PrimState m) r ix e -- ^ Array to mutate. -> (e -> m e) -- ^ Monadic action that modifies the element -> ix -- ^ Index at which to perform modification. -> m () modify_ marr f ix = when (isSafeIndex (sizeOfMArray marr) ix) $ void $ unsafeModify marr f ix {-# INLINE modify_ #-} -- | /O(1)/ - Modify an element in the cell of a mutable array with a supplied -- action. Throws an `IndexOutOfBoundsException` exception for invalid index and returns -- the previous value otherwise. -- -- @since 0.4.0 modifyM :: (Manifest r e, Index ix, PrimMonad m, MonadThrow m) => MArray (PrimState m) r ix e -- ^ Array to mutate. -> (e -> m e) -- ^ Monadic action that modifies the element -> ix -- ^ Index at which to perform modification. -> m e modifyM marr f ix | isSafeIndex (sizeOfMArray marr) ix = unsafeModify marr f ix | otherwise = throwM (IndexOutOfBoundsException (sizeOfMArray marr) ix) {-# INLINE modifyM #-} -- | /O(1)/ - Same as `modifyM`, but discard the returned element -- -- ====__Examples__ -- -- >>> :set -XTypeApplications -- >>> import Control.Monad.ST -- >>> import Data.Massiv.Array -- >>> runST $ newMArray' @P @Ix1 @Int (Sz1 3) >>= (\ma -> modifyM_ ma (pure . (+10)) 1 >> freezeS ma) -- Array P Seq (Sz1 3) -- [ 0, 10, 0 ] -- -- @since 0.4.0 modifyM_ :: (Manifest r e, Index ix, PrimMonad m, MonadThrow m) => MArray (PrimState m) r ix e -- ^ Array to mutate. -> (e -> m e) -- ^ Monadic action that modifies the element -> ix -- ^ Index at which to perform modification. -> m () modifyM_ marr f ix = void $ modifyM marr f ix {-# INLINE modifyM_ #-} -- | /O(1)/ - Same as `swapM`, but instead of throwing an exception returns `Nothing` when -- either one of the indices is out of bounds and `Just` elements under those indices -- otherwise. -- -- @since 0.1.0 swap :: (Manifest r e, Index ix, PrimMonad m) => MArray (PrimState m) r ix e -> ix -> ix -> m (Maybe (e, e)) swap marr ix1 ix2 = let !sz = sizeOfMArray marr in if isSafeIndex sz ix1 && isSafeIndex sz ix2 then Just <$> unsafeSwap marr ix1 ix2 else pure Nothing {-# INLINE swap #-} -- | /O(1)/ - Same as `swap`, but instead of returning `Nothing` it does nothing. In other -- words, it is similar to `swapM_`, but does not throw any exceptions. -- -- @since 0.4.4 swap_ :: (Manifest r e, Index ix, PrimMonad m) => MArray (PrimState m) r ix e -> ix -> ix -> m () swap_ marr ix1 ix2 = let !sz = sizeOfMArray marr in when (isSafeIndex sz ix1 && isSafeIndex sz ix2) $ void $ unsafeSwap marr ix1 ix2 {-# INLINE swap_ #-} -- | /O(1)/ - Swap two elements in a mutable array under the supplied indices. Throws an -- `IndexOutOfBoundsException` when either one of the indices is out of bounds and -- elements under those indices otherwise. -- -- @since 0.4.0 swapM :: (Manifest r e, Index ix, PrimMonad m, MonadThrow m) => MArray (PrimState m) r ix e -> ix -- ^ Index for the first element, which will be returned as the first element in the -- tuple. -> ix -- ^ Index for the second element, which will be returned as the second element in -- the tuple. -> m (e, e) swapM marr ix1 ix2 | not (isSafeIndex sz ix1) = throwM $ IndexOutOfBoundsException (sizeOfMArray marr) ix1 | not (isSafeIndex sz ix2) = throwM $ IndexOutOfBoundsException (sizeOfMArray marr) ix2 | otherwise = unsafeSwap marr ix1 ix2 where !sz = sizeOfMArray marr {-# INLINE swapM #-} -- | /O(1)/ - Same as `swapM`, but discard the returned elements -- -- @since 0.4.0 swapM_ :: (Manifest r e, Index ix, PrimMonad m, MonadThrow m) => MArray (PrimState m) r ix e -> ix -> ix -> m () swapM_ marr ix1 ix2 = void $ swapM marr ix1 ix2 {-# INLINE swapM_ #-} -- | Swap elements in the intersection of two mutable arrays starting at the -- initial index. -- -- @since 1.0.0 zipSwapM_ :: forall r1 r2 ix e m s. (MonadPrim s m, Manifest r2 e, Manifest r1 e, Index ix) => ix -> MArray s r1 ix e -> MArray s r2 ix e -> m () zipSwapM_ startIx m1 m2 = do let sz1 = sizeOfMArray m1 sz2 = sizeOfMArray m2 sz = liftIndex2 min (unSz sz1) (unSz sz2) iterM_ startIx sz oneIndex (<) $ \ix -> do let i1 = toLinearIndex sz1 ix i2 = toLinearIndex sz2 ix e1 <- unsafeLinearRead m1 i1 e2 <- unsafeLinearRead m2 i2 unsafeLinearWrite m2 i2 e1 unsafeLinearWrite m1 i1 e2 {-# INLINE zipSwapM_ #-} -- | Get the size of a mutable array. -- -- @since 0.1.0 msize :: (Manifest r e, Index ix) => MArray s r ix e -> Sz ix msize = sizeOfMArray {-# DEPRECATED msize "In favor of `sizeOfMArray`" #-}