massiv-1.0.2.0: src/Data/Massiv/Array/Manifest/Boxed.hs
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
-- |
-- Module : Data.Massiv.Array.Manifest.Boxed
-- Copyright : (c) Alexey Kuleshevich 2018-2022
-- License : BSD3
-- Maintainer : Alexey Kuleshevich <lehins@yandex.ru>
-- Stability : experimental
-- Portability : non-portable
--
module Data.Massiv.Array.Manifest.Boxed
( B(..)
, BL(..)
, BN(..)
, N
, pattern N
, Array(..)
, MArray(..)
, wrapLazyArray
, unwrapLazyArray
, unwrapNormalForm
, evalNormalForm
, unwrapArray
, evalArray
, toLazyArray
, evalLazyArray
, forceLazyArray
, unwrapMutableArray
, unwrapMutableLazyArray
, evalMutableArray
, unwrapNormalFormArray
, evalNormalFormArray
, unwrapNormalFormMutableArray
, evalNormalFormMutableArray
, toBoxedVector
, toBoxedMVector
, fromBoxedVector
, fromBoxedMVector
, evalBoxedVector
, evalBoxedMVector
, evalNormalBoxedVector
, evalNormalBoxedMVector
, coerceBoxedArray
, coerceNormalBoxedArray
, seqArray
, deepseqArray
) where
import Control.DeepSeq (NFData(..), deepseq)
import Control.Exception
import Control.Monad ((>=>))
import Control.Monad.Primitive
import qualified Data.Foldable as F (Foldable(..))
import Data.Massiv.Array.Delayed.Pull (D)
import Data.Massiv.Array.Delayed.Push (DL)
import Data.Massiv.Array.Delayed.Stream (DS)
import Data.Massiv.Array.Manifest.Internal (compute, computeAs)
import Data.Massiv.Array.Manifest.List as L
import Data.Massiv.Array.Mutable
import Data.Massiv.Array.Ops.Fold
import Data.Massiv.Array.Ops.Fold.Internal
import Data.Massiv.Array.Ops.Map (traverseA)
import Data.Massiv.Core.Common
import Data.Massiv.Core.List
import Data.Massiv.Core.Operations
import Data.Massiv.Vector.Stream as S (isteps, steps)
import qualified Data.Primitive.Array as A
import qualified Data.Vector as VB
import qualified Data.Vector.Mutable as MVB
import GHC.Exts as GHC
import Prelude hiding (mapM, replicate)
import System.IO.Unsafe (unsafePerformIO)
#if !MIN_VERSION_vector(0,13,0)
import Unsafe.Coerce (unsafeCoerce)
#endif
#include "massiv.h"
----------------
-- Boxed Lazy --
----------------
-- | Array representation for Boxed elements. This data structure is lazy with
-- respect to its elements.
--
-- ====__Example__
--
-- Memoized version of a factorial that relies on laziness. Note that
-- computing memoized factorial of a million would likely overflow memory.
--
-- >>> import Data.Massiv.Array as A
-- >>> :{
-- mkMemoFactorial :: Int -> (Int -> Integer)
-- mkMemoFactorial n =
-- let arr = makeVectorR BL Seq (Sz1 n) fact
-- fact i | i == 0 = 1
-- | otherwise = (arr ! (i - 1)) * toInteger i
-- in (arr !)
-- :}
--
-- >>> let fact = mkMemoFactorial 1000001
-- >>> fact 50
-- 30414093201713378043612608166064768844377641568960512000000000000
-- >>> length $ show $ fact 5000
-- 16326
--
data BL = BL deriving Show
data instance Array BL ix e = BLArray { blComp :: !Comp
, blSize :: !(Sz ix)
, blOffset :: {-# UNPACK #-} !Int
, blData :: {-# UNPACK #-} !(A.Array e)
}
data instance MArray s BL ix e =
MBLArray !(Sz ix) {-# UNPACK #-} !Int {-# UNPACK #-} !(A.MutableArray s e)
instance (Ragged L ix e, Show e) => Show (Array BL ix e) where
showsPrec = showsArrayPrec id
showList = showArrayList
instance (Ragged L ix e, Show e) => Show (Array DL ix e) where
showsPrec = showsArrayPrec (computeAs BL)
showList = showArrayList
instance Show e => Show (Array DS Ix1 e) where
showsPrec = showsArrayPrec (computeAs BL)
showList = showArrayList
instance (Index ix, NFData e) => NFData (Array BL ix e) where
rnf = (`deepseqArray` ())
{-# INLINE rnf #-}
instance (Index ix, Eq e) => Eq (Array BL ix e) where
(==) = eqArrays (==)
{-# INLINE (==) #-}
instance (Index ix, Ord e) => Ord (Array BL ix e) where
compare = compareArrays compare
{-# INLINE compare #-}
instance Strategy BL where
setComp c arr = arr { blComp = c }
{-# INLINE setComp #-}
getComp = blComp
{-# INLINE getComp #-}
repr = BL
instance Source BL e where
unsafeLinearIndex (BLArray _ _sz o a) i =
INDEX_CHECK("(Source BL ix e).unsafeLinearIndex",
SafeSz . A.sizeofArray, A.indexArray) a (i + o)
{-# INLINE unsafeLinearIndex #-}
unsafeOuterSlice (BLArray c _ o a) szL i = BLArray c szL (i * totalElem szL + o) a
{-# INLINE unsafeOuterSlice #-}
unsafeLinearSlice i k (BLArray c _ o a) = BLArray c k (o + i) a
{-# INLINE unsafeLinearSlice #-}
instance Manifest BL e where
unsafeLinearIndexM (BLArray _ _sz o a) i =
INDEX_CHECK("(Manifest BL ix e).unsafeLinearIndexM",
SafeSz . A.sizeofArray, A.indexArray) a (i + o)
{-# INLINE unsafeLinearIndexM #-}
sizeOfMArray (MBLArray sz _ _) = sz
{-# INLINE sizeOfMArray #-}
unsafeResizeMArray sz (MBLArray _ off marr) = MBLArray sz off marr
{-# INLINE unsafeResizeMArray #-}
unsafeLinearSliceMArray i k (MBLArray _ o a) = MBLArray k (i + o) a
{-# INLINE unsafeLinearSliceMArray #-}
unsafeThaw (BLArray _ sz o a) = MBLArray sz o <$> A.unsafeThawArray a
{-# INLINE unsafeThaw #-}
unsafeFreeze comp (MBLArray sz o ma) = BLArray comp sz o <$> A.unsafeFreezeArray ma
{-# INLINE unsafeFreeze #-}
unsafeNew sz = MBLArray sz 0 <$> A.newArray (totalElem sz) uninitialized
{-# INLINE unsafeNew #-}
initialize _ = return ()
{-# INLINE initialize #-}
newMArray sz e = MBLArray sz 0 <$> A.newArray (totalElem sz) e
{-# INLINE newMArray #-}
unsafeLinearRead (MBLArray _ o ma) i =
INDEX_CHECK("(Manifest BL ix e).unsafeLinearRead",
SafeSz . A.sizeofMutableArray, A.readArray) ma (i + o)
{-# INLINE unsafeLinearRead #-}
unsafeLinearWrite (MBLArray _sz o ma) i e =
INDEX_CHECK("(Manifest BL ix e).unsafeLinearWrite",
SafeSz . A.sizeofMutableArray, A.writeArray) ma (i + o) e
{-# INLINE unsafeLinearWrite #-}
instance Size BL where
size = blSize
{-# INLINE size #-}
unsafeResize !sz !arr = arr { blSize = sz }
{-# INLINE unsafeResize #-}
instance Index ix => Shape BL ix where
maxLinearSize = Just . SafeSz . elemsCount
{-# INLINE maxLinearSize #-}
instance Index ix => Load BL ix e where
makeArray comp sz f = compute (makeArray comp sz f :: Array D ix e)
{-# INLINE makeArray #-}
makeArrayLinear !comp !sz f = unsafePerformIO $ generateArrayLinear comp sz (pure . f)
{-# INLINE makeArrayLinear #-}
replicate comp sz e = runST (newMArray sz e >>= unsafeFreeze comp)
{-# INLINE replicate #-}
iterArrayLinearST_ !scheduler !arr =
splitLinearlyWith_ scheduler (elemsCount arr) (unsafeLinearIndex arr)
{-# INLINE iterArrayLinearST_ #-}
instance Index ix => StrideLoad BL ix e
instance Index ix => Stream BL ix e where
toStream = S.steps
{-# INLINE toStream #-}
toStreamIx = S.isteps
{-# INLINE toStreamIx #-}
-- | Row-major sequential folding over a Boxed array.
instance Index ix => Foldable (Array BL ix) where
fold = fold
{-# INLINE fold #-}
foldMap = foldMono
{-# INLINE foldMap #-}
foldl = lazyFoldlS
{-# INLINE foldl #-}
foldl' = foldlS
{-# INLINE foldl' #-}
foldr = foldrFB
{-# INLINE foldr #-}
foldr' = foldrS
{-# INLINE foldr' #-}
null (BLArray _ sz _ _) = totalElem sz == 0
{-# INLINE null #-}
length = totalElem . size
{-# INLINE length #-}
toList arr = build (\ c n -> foldrFB c n arr)
{-# INLINE toList #-}
instance Index ix => Functor (Array BL ix) where
fmap f arr = makeArrayLinear (blComp arr) (blSize arr) (f . unsafeLinearIndex arr)
{-# INLINE fmap #-}
(<$) e arr = replicate (getComp arr) (size arr) e
{-# INLINE (<$) #-}
instance Index ix => Traversable (Array BL ix) where
traverse = traverseA
{-# INLINE traverse #-}
instance (IsList (Array L ix e), Ragged L ix e) => IsList (Array BL ix e) where
type Item (Array BL ix e) = Item (Array L ix e)
fromList = L.fromLists' Seq
{-# INLINE fromList #-}
toList = GHC.toList . toListArray
{-# INLINE toList #-}
instance Num e => FoldNumeric BL e where
unsafeDotProduct = defaultUnsafeDotProduct
{-# INLINE unsafeDotProduct #-}
powerSumArray = defaultPowerSumArray
{-# INLINE powerSumArray #-}
foldArray = defaultFoldArray
{-# INLINE foldArray #-}
instance Num e => Numeric BL e where
unsafeLiftArray = defaultUnsafeLiftArray
{-# INLINE unsafeLiftArray #-}
unsafeLiftArray2 = defaultUnsafeLiftArray2
{-# INLINE unsafeLiftArray2 #-}
------------------
-- Boxed Strict --
------------------
-- | Array representation for Boxed elements. Its elements are strict to Weak
-- Head Normal Form (WHNF) only.
data B = B deriving Show
newtype instance Array B ix e = BArray (Array BL ix e)
newtype instance MArray s B ix e = MBArray (MArray s BL ix e)
instance (Ragged L ix e, Show e) => Show (Array B ix e) where
showsPrec = showsArrayPrec id
showList = showArrayList
instance (Index ix, NFData e) => NFData (Array B ix e) where
rnf = (`deepseqArray` ()) . coerce
{-# INLINE rnf #-}
instance (Index ix, Eq e) => Eq (Array B ix e) where
(==) = eqArrays (==)
{-# INLINE (==) #-}
instance (Index ix, Ord e) => Ord (Array B ix e) where
compare = compareArrays compare
{-# INLINE compare #-}
instance Source B e where
unsafeLinearIndex arr = unsafeLinearIndex (toLazyArray arr)
{-# INLINE unsafeLinearIndex #-}
unsafeLinearSlice i k arr = coerce (unsafeLinearSlice i k (toLazyArray arr))
{-# INLINE unsafeLinearSlice #-}
unsafeOuterSlice arr i = coerce (unsafeOuterSlice (toLazyArray arr) i)
{-# INLINE unsafeOuterSlice #-}
instance Strategy B where
getComp = blComp . coerce
{-# INLINE getComp #-}
setComp c arr = coerceBoxedArray (coerce arr) { blComp = c }
{-# INLINE setComp #-}
repr = B
instance Index ix => Shape B ix where
maxLinearSize = Just . SafeSz . elemsCount
{-# INLINE maxLinearSize #-}
instance Size B where
size = blSize . coerce
{-# INLINE size #-}
unsafeResize sz = coerce (\arr -> arr { blSize = sz })
{-# INLINE unsafeResize #-}
instance Manifest B e where
unsafeLinearIndexM = coerce unsafeLinearIndexM
{-# INLINE unsafeLinearIndexM #-}
sizeOfMArray = sizeOfMArray . coerce
{-# INLINE sizeOfMArray #-}
unsafeResizeMArray sz = MBArray . unsafeResizeMArray sz . coerce
{-# INLINE unsafeResizeMArray #-}
unsafeLinearSliceMArray i k = MBArray . unsafeLinearSliceMArray i k . coerce
{-# INLINE unsafeLinearSliceMArray #-}
unsafeThaw arr = MBArray <$> unsafeThaw (coerce arr)
{-# INLINE unsafeThaw #-}
unsafeFreeze comp marr = BArray <$> unsafeFreeze comp (coerce marr)
{-# INLINE unsafeFreeze #-}
unsafeNew sz = MBArray <$> unsafeNew sz
{-# INLINE unsafeNew #-}
initialize _ = return ()
{-# INLINE initialize #-}
newMArray sz !e = MBArray <$> newMArray sz e
{-# INLINE newMArray #-}
unsafeLinearRead ma = unsafeLinearRead (coerce ma)
{-# INLINE unsafeLinearRead #-}
unsafeLinearWrite ma i e = e `seq` unsafeLinearWrite (coerce ma) i e
{-# INLINE unsafeLinearWrite #-}
instance Index ix => Load B ix e where
makeArray comp sz f = compute (makeArray comp sz f :: Array D ix e)
{-# INLINE makeArray #-}
makeArrayLinear !comp !sz f = unsafePerformIO $ generateArrayLinear comp sz (pure . f)
{-# INLINE makeArrayLinear #-}
replicate comp sz e = runST (newMArray sz e >>= unsafeFreeze comp)
{-# INLINE replicate #-}
iterArrayLinearST_ scheduler = coerce (iterArrayLinearST_ scheduler)
{-# INLINE iterArrayLinearST_ #-}
instance Index ix => StrideLoad B ix e
instance Index ix => Stream B ix e where
toStream = S.steps
{-# INLINE toStream #-}
toStreamIx = S.isteps
{-# INLINE toStreamIx #-}
-- | Row-major sequential folding over a Boxed array.
instance Index ix => Foldable (Array B ix) where
fold = fold
{-# INLINE fold #-}
foldMap = foldMono
{-# INLINE foldMap #-}
foldl = lazyFoldlS
{-# INLINE foldl #-}
foldl' = foldlS
{-# INLINE foldl' #-}
foldr = foldrFB
{-# INLINE foldr #-}
foldr' = foldrS
{-# INLINE foldr' #-}
null arr = totalElem (size arr) == 0
{-# INLINE null #-}
length = totalElem . size
{-# INLINE length #-}
toList arr = build (\ c n -> foldrFB c n arr)
{-# INLINE toList #-}
instance Index ix => Functor (Array B ix) where
fmap f arr = makeArrayLinear (getComp arr) (size arr) (f . unsafeLinearIndex arr)
{-# INLINE fmap #-}
(<$) !e arr = replicate (getComp arr) (size arr) e
{-# INLINE (<$) #-}
instance Index ix => Traversable (Array B ix) where
traverse = traverseA
{-# INLINE traverse #-}
instance (IsList (Array L ix e), Ragged L ix e) => IsList (Array B ix e) where
type Item (Array B ix e) = Item (Array L ix e)
fromList = L.fromLists' Seq
{-# INLINE fromList #-}
toList = GHC.toList . toListArray
{-# INLINE toList #-}
instance Num e => FoldNumeric B e where
unsafeDotProduct = defaultUnsafeDotProduct
{-# INLINE unsafeDotProduct #-}
powerSumArray = defaultPowerSumArray
{-# INLINE powerSumArray #-}
foldArray = defaultFoldArray
{-# INLINE foldArray #-}
instance Num e => Numeric B e where
unsafeLiftArray = defaultUnsafeLiftArray
{-# INLINE unsafeLiftArray #-}
unsafeLiftArray2 = defaultUnsafeLiftArray2
{-# INLINE unsafeLiftArray2 #-}
-----------------------
-- Boxed Normal Form --
-----------------------
-- | Array representation for Boxed elements. Its elements are always in Normal
-- Form (NF), therefore `NFData` instance is required.
data BN = BN deriving Show
-- | Type and pattern `N` have been added for backwards compatibility and will be replaced
-- in the future in favor of `BN`.
--
-- /Deprecated/ - since 1.0.0
type N = BN
pattern N :: N
pattern N = BN
{-# COMPLETE N #-}
{-# DEPRECATED N "In favor of more consistently named `BN`" #-}
newtype instance Array BN ix e = BNArray (Array BL ix e)
newtype instance MArray s BN ix e = MBNArray (MArray s BL ix e)
instance (Ragged L ix e, Show e, NFData e) => Show (Array BN ix e) where
showsPrec = showsArrayPrec coerce
showList = showArrayList
-- | /O(1)/ - `BN` is already in normal form
instance NFData (Array BN ix e) where
rnf = (`seq` ())
{-# INLINE rnf #-}
instance (Index ix, NFData e, Eq e) => Eq (Array BN ix e) where
(==) = eqArrays (==)
{-# INLINE (==) #-}
instance (Index ix, NFData e, Ord e) => Ord (Array BN ix e) where
compare = compareArrays compare
{-# INLINE compare #-}
instance Strategy BN where
setComp c = coerce (setComp c)
{-# INLINE setComp #-}
getComp = blComp . coerce
{-# INLINE getComp #-}
repr = BN
instance NFData e => Source BN e where
unsafeLinearIndex (BNArray arr) = unsafeLinearIndex arr
{-# INLINE unsafeLinearIndex #-}
unsafeLinearSlice i k (BNArray a) = coerce (unsafeLinearSlice i k a)
{-# INLINE unsafeLinearSlice #-}
unsafeOuterSlice (BNArray a) i = coerce (unsafeOuterSlice a i)
{-# INLINE unsafeOuterSlice #-}
instance Index ix => Shape BN ix where
maxLinearSize = Just . SafeSz . elemsCount
{-# INLINE maxLinearSize #-}
instance Size BN where
size = blSize . coerce
{-# INLINE size #-}
unsafeResize !sz = coerce . unsafeResize sz . coerce
{-# INLINE unsafeResize #-}
instance NFData e => Manifest BN e where
unsafeLinearIndexM arr = unsafeLinearIndexM (coerce arr)
{-# INLINE unsafeLinearIndexM #-}
sizeOfMArray = sizeOfMArray . coerce
{-# INLINE sizeOfMArray #-}
unsafeResizeMArray sz = coerce . unsafeResizeMArray sz . coerce
{-# INLINE unsafeResizeMArray #-}
unsafeLinearSliceMArray i k = MBNArray . unsafeLinearSliceMArray i k . coerce
{-# INLINE unsafeLinearSliceMArray #-}
unsafeThaw arr = MBNArray <$> unsafeThaw (coerce arr)
{-# INLINE unsafeThaw #-}
unsafeFreeze comp marr = BNArray <$> unsafeFreeze comp (coerce marr)
{-# INLINE unsafeFreeze #-}
unsafeNew sz = MBNArray <$> unsafeNew sz
{-# INLINE unsafeNew #-}
initialize _ = return ()
{-# INLINE initialize #-}
newMArray sz e = e `deepseq` (MBNArray <$> newMArray sz e)
{-# INLINE newMArray #-}
unsafeLinearRead ma = unsafeLinearRead (coerce ma)
{-# INLINE unsafeLinearRead #-}
unsafeLinearWrite ma i e = e `deepseq` unsafeLinearWrite (coerce ma) i e
{-# INLINE unsafeLinearWrite #-}
instance (Index ix, NFData e) => Load BN ix e where
makeArray comp sz f = compute (makeArray comp sz f :: Array D ix e)
{-# INLINE makeArray #-}
makeArrayLinear !comp !sz f = unsafePerformIO $ generateArrayLinear comp sz (pure . f)
{-# INLINE makeArrayLinear #-}
replicate comp sz e = runST (newMArray sz e >>= unsafeFreeze comp)
{-# INLINE replicate #-}
iterArrayLinearST_ !scheduler !arr =
splitLinearlyWith_ scheduler (elemsCount arr) (unsafeLinearIndex arr)
{-# INLINE iterArrayLinearST_ #-}
instance (Index ix, NFData e) => StrideLoad BN ix e
instance (Index ix, NFData e) => Stream BN ix e where
toStream = toStream . coerce
{-# INLINE toStream #-}
toStreamIx = toStreamIx . coerce
{-# INLINE toStreamIx #-}
instance (NFData e, IsList (Array L ix e), Ragged L ix e) => IsList (Array BN ix e) where
type Item (Array BN ix e) = Item (Array L ix e)
fromList = L.fromLists' Seq
{-# INLINE fromList #-}
toList = GHC.toList . toListArray
{-# INLINE toList #-}
instance (NFData e, Num e) => FoldNumeric BN e where
unsafeDotProduct = defaultUnsafeDotProduct
{-# INLINE unsafeDotProduct #-}
powerSumArray = defaultPowerSumArray
{-# INLINE powerSumArray #-}
foldArray = defaultFoldArray
{-# INLINE foldArray #-}
instance (NFData e, Num e) => Numeric BN e where
unsafeLiftArray = defaultUnsafeLiftArray
{-# INLINE unsafeLiftArray #-}
unsafeLiftArray2 = defaultUnsafeLiftArray2
{-# INLINE unsafeLiftArray2 #-}
----------------------
-- Helper functions --
----------------------
uninitialized :: a
uninitialized = throw Uninitialized
---------------------
-- WHNF conversion --
---------------------
-- | /O(1)/ - Unwrap boxed array. This will discard any possible slicing that has been
-- applied to the array.
--
-- @since 0.2.1
unwrapArray :: Array B ix e -> A.Array e
unwrapArray = blData . coerce
{-# INLINE unwrapArray #-}
-- | /O(n)/ - Wrap a boxed array and evaluate all elements to a WHNF.
--
-- @since 0.2.1
evalArray ::
Comp -- ^ Computation strategy
-> A.Array e -- ^ Lazy boxed array from @primitive@ package.
-> Vector B e
evalArray comp a = evalLazyArray $ setComp comp $ wrapLazyArray a
{-# INLINE evalArray #-}
-- | /O(1)/ - Unwrap boxed array. This will discard any possible slicing that has been
-- applied to the array.
--
-- @since 0.6.0
unwrapLazyArray :: Array BL ix e -> A.Array e
unwrapLazyArray = blData
{-# INLINE unwrapLazyArray #-}
-- | /O(1)/ - Wrap a boxed array.
--
-- @since 0.6.0
wrapLazyArray :: A.Array e -> Vector BL e
wrapLazyArray a = BLArray Seq (SafeSz (A.sizeofArray a)) 0 a
{-# INLINE wrapLazyArray #-}
-- | /O(1)/ - Cast a strict boxed array into a lazy boxed array.
--
-- @since 0.6.0
toLazyArray :: Array B ix e -> Array BL ix e
toLazyArray = coerce
{-# INLINE toLazyArray #-}
-- | /O(n)/ - Evaluate all elements of a boxed lazy array to weak head normal form
--
-- @since 0.6.0
evalLazyArray :: Index ix => Array BL ix e -> Array B ix e
evalLazyArray arr = arr `seqArray` BArray arr
{-# INLINE evalLazyArray #-}
-- | /O(n)/ - Evaluate all elements of a boxed lazy array to normal form
--
-- @since 0.6.0
forceLazyArray :: (NFData e, Index ix) => Array BL ix e -> Array N ix e
forceLazyArray arr = arr `deepseqArray` BNArray arr
{-# INLINE forceLazyArray #-}
-- | /O(1)/ - Unwrap mutable boxed array. This will discard any possible slicing that has been
-- applied to the array.
--
-- @since 0.2.1
unwrapMutableArray :: MArray s B ix e -> A.MutableArray s e
unwrapMutableArray (MBArray (MBLArray _ _ marr)) = marr
{-# INLINE unwrapMutableArray #-}
-- | /O(1)/ - Unwrap mutable boxed lazy array. This will discard any possible slicing that has been
-- applied to the array.
--
-- @since 0.6.0
unwrapMutableLazyArray :: MArray s BL ix e -> A.MutableArray s e
unwrapMutableLazyArray (MBLArray _ _ marr) = marr
{-# INLINE unwrapMutableLazyArray #-}
-- | /O(n)/ - Wrap mutable boxed array and evaluate all elements to WHNF.
--
-- @since 0.2.1
evalMutableArray ::
PrimMonad m
=> A.MutableArray (PrimState m) e -- ^ Mutable array that will get wrapped
-> m (MArray (PrimState m) B Ix1 e)
evalMutableArray = fmap MBArray . fromMutableArraySeq seq
{-# INLINE evalMutableArray #-}
-------------------
-- NF conversion --
-------------------
-- | /O(1)/ - Unwrap a fully evaluated boxed array. This will discard any possible slicing
-- that has been applied to the array.
--
-- @since 0.2.1
unwrapNormalFormArray :: Array N ix e -> A.Array e
unwrapNormalFormArray = blData . coerce
{-# INLINE unwrapNormalFormArray #-}
-- | /O(n)/ - Wrap a boxed array and evaluate all elements to a Normal Form (NF).
--
-- @since 0.2.1
evalNormalFormArray ::
NFData e
=> Comp -- ^ Computation strategy
-> A.Array e -- ^ Lazy boxed array
-> Array N Ix1 e
evalNormalFormArray comp = forceLazyArray . setComp comp . wrapLazyArray
{-# INLINE evalNormalFormArray #-}
-- | /O(1)/ - Unwrap a fully evaluated mutable boxed array. This will discard any possible
-- slicing that has been applied to the array.
--
-- @since 0.2.1
unwrapNormalFormMutableArray :: MArray s N ix e -> A.MutableArray s e
unwrapNormalFormMutableArray = unwrapMutableLazyArray . coerce
{-# INLINE unwrapNormalFormMutableArray #-}
-- | /O(n)/ - Wrap mutable boxed array and evaluate all elements to NF.
--
-- @since 0.2.1
evalNormalFormMutableArray ::
(PrimMonad m, NFData e)
=> A.MutableArray (PrimState m) e
-> m (MArray (PrimState m) N Ix1 e)
evalNormalFormMutableArray marr = MBNArray <$> fromMutableArraySeq deepseq marr
{-# INLINE evalNormalFormMutableArray #-}
----------------------
-- Helper functions --
----------------------
fromMutableArraySeq ::
PrimMonad m
=> (e -> m () -> m a)
-> A.MutableArray (PrimState m) e
-> m (MArray (PrimState m) BL Ix1 e)
fromMutableArraySeq with ma = do
let !sz = A.sizeofMutableArray ma
loopA_ 0 (< sz) (+ 1) (A.readArray ma >=> (`with` return ()))
return $! MBLArray (SafeSz sz) 0 ma
{-# INLINE fromMutableArraySeq #-}
seqArray :: Index ix => Array BL ix a -> t -> t
seqArray !arr t = foldlInternal (flip seq) () (flip seq) () arr `seq` t
{-# INLINE seqArray #-}
deepseqArray :: (NFData a, Index ix) => Array BL ix a -> t -> t
deepseqArray !arr t = foldlInternal (flip deepseq) () (flip seq) () arr `seq` t
{-# INLINE deepseqArray #-}
-- | /O(1)/ - Converts array from `N` to `B` representation.
--
-- @since 0.5.0
unwrapNormalForm :: Array N ix e -> Array B ix e
unwrapNormalForm = coerce
{-# INLINE unwrapNormalForm #-}
-- | /O(n)/ - Compute all elements of a boxed array to NF (normal form)
--
-- @since 0.5.0
evalNormalForm :: (Index ix, NFData e) => Array B ix e -> Array N ix e
evalNormalForm (BArray arr) = arr `deepseqArray` BNArray arr
{-# INLINE evalNormalForm #-}
-- | /O(1)/ - Converts a boxed `Array` into a `VB.Vector` without touching any
-- elements.
--
-- @since 0.5.0
{-# INLINE toBoxedVector #-}
toBoxedVector :: Index ix => Array BL ix a -> VB.Vector a
toBoxedVector BLArray{blOffset = off, blSize = sz, blData = arr } =
#if MIN_VERSION_vector(0,13,0)
VB.unsafeFromArraySlice arr off (totalElem sz)
#elif MIN_VERSION_vector(0,12,2)
VB.unsafeTake (totalElem sz) (VB.unsafeDrop off (VB.fromArray arr))
#else
fromVectorCast $ VectorCast off (totalElem sz) arr
fromVectorCast :: VectorCast a -> VB.Vector a
fromVectorCast = unsafeCoerce
#endif
-- | /O(1)/ - Converts a boxed `MArray` into a `MVB.MVector`.
--
-- @since 0.5.0
toBoxedMVector :: Index ix => MArray s BL ix a -> MVB.MVector s a
toBoxedMVector (MBLArray sz o marr) = MVB.MVector o (totalElem sz) marr
{-# INLINE toBoxedMVector #-}
-- | /O(n)/ - Convert a boxed vector and evaluate all elements to WHNF. Computation
-- strategy will be respected during evaluation
--
-- @since 0.5.0
evalBoxedVector :: Comp -> VB.Vector a -> Array B Ix1 a
evalBoxedVector comp = evalLazyArray . setComp comp . fromBoxedVector
{-# INLINE evalBoxedVector #-}
-- | /O(n)/ - Convert mutable boxed vector and evaluate all elements to WHNF
-- sequentially. Both keep pointing to the same memory
--
-- @since 0.5.0
evalBoxedMVector :: PrimMonad m => MVB.MVector (PrimState m) a -> m (MArray (PrimState m) B Ix1 a)
evalBoxedMVector (MVB.MVector o k ma) =
let marr = MBArray (MBLArray (SafeSz k) o ma)
in marr <$ loopA_ o (< k) (+ 1) (A.readArray ma >=> (`seq` pure ()))
{-# INLINE evalBoxedMVector #-}
-- | /O(1)/ - Cast a boxed vector without touching any elements.
--
-- @since 0.6.0
fromBoxedVector :: VB.Vector a -> Vector BL a
{-# INLINE fromBoxedVector #-}
fromBoxedVector v =
BLArray {blComp = Seq, blSize = SafeSz n, blOffset = offset, blData = arr}
where
#if MIN_VERSION_vector(0,13,0)
(arr, offset, n) = VB.toArraySlice v
#else
VectorCast offset n arr = toVectorCast v
-- This internal type is needed to get into the internals of a boxed vector,
-- since it is not possible until vector-0.13 version.
data VectorCast a =
VectorCast {-# UNPACK #-}!Int {-# UNPACK #-}!Int {-# UNPACK #-}!(A.Array a)
toVectorCast :: VB.Vector a -> VectorCast a
toVectorCast = unsafeCoerce
#endif
-- | /O(1)/ - Convert mutable boxed vector to a lazy mutable boxed array. Both keep
-- pointing to the same memory
--
-- @since 0.6.0
fromBoxedMVector :: MVB.MVector s a -> MArray s BL Ix1 a
fromBoxedMVector (MVB.MVector o k ma) = MBLArray (SafeSz k) o ma
{-# INLINE fromBoxedMVector #-}
-- | /O(1)/ - Cast a boxed lazy array. It is unsafe because it can violate the invariant
-- that all elements of `N` array are in NF.
--
-- @since 0.6.0
coerceNormalBoxedArray :: Array BL ix e -> Array N ix e
coerceNormalBoxedArray = coerce
{-# INLINE coerceNormalBoxedArray #-}
-- | /O(1)/ - Cast a boxed lazy array. It is unsafe because it can violate the invariant
-- that all elements of `B` array are in WHNF.
--
-- @since 0.6.0
coerceBoxedArray :: Array BL ix e -> Array B ix e
coerceBoxedArray = coerce
{-# INLINE coerceBoxedArray #-}
-- | /O(n)/ - Convert mutable boxed vector and evaluate all elements to WHNF
-- sequentially. Both keep pointing to the same memory
--
-- @since 0.5.0
evalNormalBoxedMVector ::
(NFData a, PrimMonad m) => MVB.MVector (PrimState m) a -> m (MArray (PrimState m) N Ix1 a)
evalNormalBoxedMVector (MVB.MVector o k ma) =
let marr = MBNArray (MBLArray (SafeSz k) o ma)
in marr <$ loopA_ o (< k) (+ 1) (A.readArray ma >=> pure . rnf)
{-# INLINE evalNormalBoxedMVector #-}
-- | /O(n)/ - Convert a boxed vector and evaluate all elements to WHNF. Computation
-- strategy will be respected during evaluation
--
-- @since 0.5.0
evalNormalBoxedVector :: NFData a => Comp -> VB.Vector a -> Array N Ix1 a
evalNormalBoxedVector comp v =
runST $ do
MVB.MVector o k ma <- VB.unsafeThaw v
forceLazyArray <$> unsafeFreeze comp (MBLArray (SafeSz k) o ma)
{-# INLINE evalNormalBoxedVector #-}