{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
module Data.Massiv.Array.Manifest.Boxed
( B(..)
, N(..)
, Array(..)
, unwrapNormalForm
, evalNormalForm
, unwrapArray
, evalArray
, unwrapMutableArray
, evalMutableArray
, unwrapNormalFormArray
, evalNormalFormArray
, unwrapNormalFormMutableArray
, evalNormalFormMutableArray
, toBoxedVector
, toBoxedMVector
, evalBoxedVector
, evalBoxedMVector
, evalNormalBoxedVector
, evalNormalBoxedMVector
, unsafeBoxedArray
, unsafeNormalBoxedArray
, unsafeFromBoxedVector
, seqArray
, deepseqArray
) where
import Control.DeepSeq (NFData(..), deepseq)
import Control.Exception
import Control.Monad ((>=>))
import Control.Monad.Primitive
import Control.Monad.ST (runST)
import qualified Data.Foldable as F (Foldable(..))
import Data.Massiv.Array.Delayed.Pull (eq, ord)
import Data.Massiv.Array.Delayed.Push (DL)
import Data.Massiv.Array.Delayed.Stream (DS)
import Data.Massiv.Array.Manifest.Internal (M, computeAs, toManifest)
import Data.Massiv.Array.Manifest.List as L
import Data.Massiv.Vector.Stream as S (steps, isteps)
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 qualified Data.Primitive.Array as A
import qualified Data.Vector as VB
import qualified Data.Vector.Mutable as MVB
import GHC.Base (build)
import GHC.Exts as GHC
import Prelude hiding (mapM)
import System.IO.Unsafe (unsafePerformIO)
#include "massiv.h"
sizeofArray :: A.Array e -> Int
sizeofMutableArray :: A.MutableArray s e -> Int
#if MIN_VERSION_primitive(0,6,2)
sizeofArray = A.sizeofArray
sizeofMutableArray = A.sizeofMutableArray
#else
sizeofArray (A.Array a#) = I# (sizeofArray# a#)
sizeofMutableArray (A.MutableArray ma#) = I# (sizeofMutableArray# ma#)
#endif
data B = B deriving Show
data instance Array B ix e = BArray { bComp :: !Comp
, bSize :: !(Sz ix)
, bOffset :: {-# UNPACK #-} !Int
, bData :: {-# UNPACK #-} !(A.Array e)
}
instance (Ragged L ix e, Show e) => Show (Array B ix e) where
showsPrec = showsArrayPrec id
showList = showArrayList
instance (Ragged L ix e, Show e) => Show (Array DL ix e) where
showsPrec = showsArrayPrec (computeAs B)
showList = showArrayList
instance Show e => Show (Array DS Ix1 e) where
showsPrec = showsArrayPrec (computeAs B)
showList = showArrayList
instance (Index ix, NFData e) => NFData (Array B ix e) where
rnf = (`deepseqArray` ())
{-# INLINE rnf #-}
instance (Index ix, Eq e) => Eq (Array B ix e) where
(==) = eq (==)
{-# INLINE (==) #-}
instance (Index ix, Ord e) => Ord (Array B ix e) where
compare = ord compare
{-# INLINE compare #-}
instance Index ix => Construct B ix e where
setComp c arr = arr { bComp = c }
{-# INLINE setComp #-}
makeArrayLinear !comp !sz f = unsafePerformIO $ generateArrayLinear comp sz (\ !i -> return $! f i)
{-# INLINE makeArrayLinear #-}
instance Index ix => Source B ix e where
unsafeLinearIndex (BArray _ _sz o a) i =
INDEX_CHECK("(Source B ix e).unsafeLinearIndex",
SafeSz . sizeofArray, A.indexArray) a (i + o)
{-# INLINE unsafeLinearIndex #-}
unsafeLinearSlice i k (BArray c _ o a) = BArray c k (o + i) a
{-# INLINE unsafeLinearSlice #-}
instance Index ix => Resize B ix where
unsafeResize !sz !arr = arr { bSize = sz }
{-# INLINE unsafeResize #-}
instance Index ix => Extract B ix e where
unsafeExtract !sIx !newSz !arr = unsafeExtract sIx newSz (toManifest arr)
{-# INLINE unsafeExtract #-}
instance ( Index ix
, Index (Lower ix)
, Elt M ix e ~ Array M (Lower ix) e
, Elt B ix e ~ Array M (Lower ix) e
) =>
OuterSlice B ix e where
unsafeOuterSlice arr = unsafeOuterSlice (toManifest arr)
{-# INLINE unsafeOuterSlice #-}
instance ( Index ix
, Index (Lower ix)
, Elt M ix e ~ Array M (Lower ix) e
, Elt B ix e ~ Array M (Lower ix) e
) =>
InnerSlice B ix e where
unsafeInnerSlice arr = unsafeInnerSlice (toManifest arr)
{-# INLINE unsafeInnerSlice #-}
instance {-# OVERLAPPING #-} Slice B Ix1 e where
unsafeSlice arr i _ _ = pure (unsafeLinearIndex arr i)
{-# INLINE unsafeSlice #-}
instance Index ix => Manifest B ix e where
unsafeLinearIndexM (BArray _ _sz o a) i =
INDEX_CHECK("(Manifest B ix e).unsafeLinearIndexM",
SafeSz . sizeofArray, A.indexArray) a (i + o)
{-# INLINE unsafeLinearIndexM #-}
instance Index ix => Mutable B ix e where
data MArray s B ix e = MBArray !(Sz ix) {-# UNPACK #-} !Int {-# UNPACK #-} !(A.MutableArray s e)
msize (MBArray sz _ _) = sz
{-# INLINE msize #-}
unsafeThaw (BArray _ sz o a) = MBArray sz o <$> A.unsafeThawArray a
{-# INLINE unsafeThaw #-}
unsafeFreeze comp (MBArray sz o ma) = BArray comp sz o <$> A.unsafeFreezeArray ma
{-# INLINE unsafeFreeze #-}
unsafeNew sz = MBArray sz 0 <$> A.newArray (totalElem sz) uninitialized
{-# INLINE unsafeNew #-}
initialize _ = return ()
{-# INLINE initialize #-}
unsafeLinearRead (MBArray _ o ma) i =
INDEX_CHECK("(Mutable B ix e).unsafeLinearRead",
SafeSz . sizeofMutableArray, A.readArray) ma (i + o)
{-# INLINE unsafeLinearRead #-}
unsafeLinearWrite (MBArray _sz o ma) i e = e `seq`
INDEX_CHECK("(Mutable B ix e).unsafeLinearWrite",
SafeSz . sizeofMutableArray, A.writeArray) ma (i + o) e
{-# INLINE unsafeLinearWrite #-}
instance Index ix => Load B ix e where
type R B = M
size = bSize
{-# INLINE size #-}
getComp = bComp
{-# INLINE getComp #-}
loadArrayM !scheduler !arr = splitLinearlyWith_ scheduler (elemsCount arr) (unsafeLinearIndex arr)
{-# INLINE loadArrayM #-}
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 #-}
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 (BArray _ 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 B ix) where
fmap f arr = makeArrayLinear (bComp arr) (bSize arr) (f . unsafeLinearIndex arr)
{-# INLINE fmap #-}
instance Index ix => Traversable (Array B ix) where
traverse = traverseA
{-# INLINE traverse #-}
instance ( IsList (Array L ix e)
, Nested LN ix e
, Nested 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 #-}
data N = N deriving Show
newtype instance Array N ix e = NArray { bArray :: Array B ix e }
instance (Ragged L ix e, Show e, NFData e) => Show (Array N ix e) where
showsPrec = showsArrayPrec bArray
showList = showArrayList
instance (Index ix, NFData e) => NFData (Array N ix e) where
rnf (NArray barr) = barr `deepseqArray` ()
{-# INLINE rnf #-}
instance (Index ix, NFData e, Eq e) => Eq (Array N ix e) where
(==) = eq (==)
{-# INLINE (==) #-}
instance (Index ix, NFData e, Ord e) => Ord (Array N ix e) where
compare = ord compare
{-# INLINE compare #-}
instance (Index ix, NFData e) => Construct N ix e where
setComp c (NArray arr) = NArray (arr {bComp = c})
{-# INLINE setComp #-}
makeArray !comp !sz f =
unsafePerformIO $
generateArray
comp
sz
(\ !ix ->
let res = f ix
in res `deepseq` return res)
{-# INLINE makeArray #-}
instance (Index ix, NFData e) => Source N ix e where
unsafeLinearIndex (NArray arr) = unsafeLinearIndex arr
{-# INLINE unsafeLinearIndex #-}
unsafeLinearSlice i k (NArray a) = NArray $ unsafeLinearSlice i k a
{-# INLINE unsafeLinearSlice #-}
instance Index ix => Resize N ix where
unsafeResize !sz = NArray . unsafeResize sz . bArray
{-# INLINE unsafeResize #-}
instance (Index ix, NFData e) => Extract N ix e where
unsafeExtract !sIx !newSz !arr = unsafeExtract sIx newSz (toManifest arr)
{-# INLINE unsafeExtract #-}
instance ( NFData e
, Index ix
, Index (Lower ix)
, Elt M ix e ~ Array M (Lower ix) e
, Elt N ix e ~ Array M (Lower ix) e
) =>
OuterSlice N ix e where
unsafeOuterSlice = unsafeOuterSlice . toManifest
{-# INLINE unsafeOuterSlice #-}
instance ( NFData e
, Index ix
, Index (Lower ix)
, Elt M ix e ~ Array M (Lower ix) e
, Elt N ix e ~ Array M (Lower ix) e
) =>
InnerSlice N ix e where
unsafeInnerSlice = unsafeInnerSlice . toManifest
{-# INLINE unsafeInnerSlice #-}
instance {-# OVERLAPPING #-} NFData e => Slice N Ix1 e where
unsafeSlice arr i _ _ = pure (unsafeLinearIndex arr i)
{-# INLINE unsafeSlice #-}
instance (Index ix, NFData e) => Manifest N ix e where
unsafeLinearIndexM (NArray arr) = unsafeLinearIndexM arr
{-# INLINE unsafeLinearIndexM #-}
instance (Index ix, NFData e) => Mutable N ix e where
newtype MArray s N ix e = MNArray { bmArray :: MArray s B ix e }
msize = msize . bmArray
{-# INLINE msize #-}
unsafeThaw (NArray arr) = MNArray <$> unsafeThaw arr
{-# INLINE unsafeThaw #-}
unsafeFreeze comp (MNArray marr) = NArray <$> unsafeFreeze comp marr
{-# INLINE unsafeFreeze #-}
unsafeNew sz = MNArray <$> unsafeNew sz
{-# INLINE unsafeNew #-}
initialize _ = return ()
{-# INLINE initialize #-}
unsafeLinearRead (MNArray ma) = unsafeLinearRead ma
{-# INLINE unsafeLinearRead #-}
unsafeLinearWrite (MNArray ma) i e = e `deepseq` unsafeLinearWrite ma i e
{-# INLINE unsafeLinearWrite #-}
instance (Index ix, NFData e) => Load N ix e where
type R N = M
size = bSize . bArray
{-# INLINE size #-}
getComp = bComp . bArray
{-# INLINE getComp #-}
loadArrayM !scheduler !arr = splitLinearlyWith_ scheduler (elemsCount arr) (unsafeLinearIndex arr)
{-# INLINE loadArrayM #-}
instance (Index ix, NFData e) => StrideLoad N ix e
instance (Index ix, NFData e) => Stream N ix e where
toStream = toStream . coerce
{-# INLINE toStream #-}
toStreamIx = toStreamIx . coerce
{-# INLINE toStreamIx #-}
instance ( NFData e
, IsList (Array L ix e)
, Nested LN ix e
, Nested L ix e
, Ragged L ix e
) =>
IsList (Array N ix e) where
type Item (Array N ix e) = Item (Array L ix e)
fromList = L.fromLists' Seq
{-# INLINE fromList #-}
toList = GHC.toList . toListArray
{-# INLINE toList #-}
uninitialized :: a
uninitialized = throw Uninitialized
unwrapArray :: Array B ix e -> A.Array e
unwrapArray = bData
{-# INLINE unwrapArray #-}
evalArray ::
Comp
-> A.Array e
-> Array B Ix1 e
evalArray = fromArraySeq (\a -> a `seqArray` a)
{-# INLINE evalArray #-}
unwrapMutableArray :: MArray s B ix e -> A.MutableArray s e
unwrapMutableArray (MBArray _ _ marr) = marr
{-# INLINE unwrapMutableArray #-}
evalMutableArray ::
PrimMonad m
=> A.MutableArray (PrimState m) e
-> m (MArray (PrimState m) B Ix1 e)
evalMutableArray = fromMutableArraySeq seq
{-# INLINE evalMutableArray #-}
unwrapNormalFormArray :: Array N ix e -> A.Array e
unwrapNormalFormArray = bData . bArray
{-# INLINE unwrapNormalFormArray #-}
evalNormalFormArray ::
NFData e
=> Comp
-> A.Array e
-> Array N Ix1 e
evalNormalFormArray = fromArraySeq (\a -> a `deepseqArray` NArray a)
{-# INLINE evalNormalFormArray #-}
unwrapNormalFormMutableArray :: MArray s N ix e -> A.MutableArray s e
unwrapNormalFormMutableArray (MNArray marr) = unwrapMutableArray marr
{-# INLINE unwrapNormalFormMutableArray #-}
evalNormalFormMutableArray ::
(PrimMonad m, NFData e)
=> A.MutableArray (PrimState m) e
-> m (MArray (PrimState m) N Ix1 e)
evalNormalFormMutableArray marr = MNArray <$> fromMutableArraySeq deepseq marr
{-# INLINE evalNormalFormMutableArray #-}
fromMutableArraySeq ::
PrimMonad m
=> (e -> m () -> m a)
-> A.MutableArray (PrimState m) e
-> m (MArray (PrimState m) B Ix1 e)
fromMutableArraySeq with ma = do
let !sz = sizeofMutableArray ma
loopM_ 0 (< sz) (+ 1) (A.readArray ma >=> (`with` return ()))
return $! MBArray (SafeSz sz) 0 ma
{-# INLINE fromMutableArraySeq #-}
fromArraySeq ::
(Array B Ix1 e -> a)
-> Comp
-> A.Array e
-> a
fromArraySeq with comp barr = with (BArray comp (SafeSz (sizeofArray barr)) 0 barr)
{-# INLINE fromArraySeq #-}
seqArray :: Index ix => Array B ix a -> t -> t
seqArray !arr t = foldlInternal (flip seq) () (flip seq) () arr `seq` t
{-# INLINE seqArray #-}
deepseqArray :: (NFData a, Index ix) => Array B ix a -> t -> t
deepseqArray !arr t = foldlInternal (flip deepseq) () (flip seq) () arr `seq` t
{-# INLINE deepseqArray #-}
unwrapNormalForm :: Array N ix e -> Array B ix e
unwrapNormalForm = coerce
{-# INLINE unwrapNormalForm #-}
evalNormalForm :: (Index ix, NFData e) => Array B ix e -> Array N ix e
evalNormalForm arr = arr `deepseqArray` NArray arr
{-# INLINE evalNormalForm #-}
toBoxedVector :: Index ix => Array B ix a -> VB.Vector a
toBoxedVector arr = runST $ VB.unsafeFreeze . toBoxedMVector =<< unsafeThaw arr
{-# INLINE toBoxedVector #-}
toBoxedMVector :: Index ix => MArray s B ix a -> MVB.MVector s a
toBoxedMVector (MBArray sz o marr) = MVB.MVector o (totalElem sz) marr
{-# INLINE toBoxedMVector #-}
evalBoxedVector :: Comp -> VB.Vector a -> Array B Ix1 a
evalBoxedVector comp v = arr `seqArray` arr
where
arr = setComp comp $ unsafeFromBoxedVector v
{-# INLINE evalBoxedVector #-}
evalBoxedMVector :: PrimMonad m => MVB.MVector (PrimState m) a -> m (MArray (PrimState m) B Ix1 a)
evalBoxedMVector (MVB.MVector o k ma) = do
let marr = MBArray (SafeSz k) o ma
loopM_ o (< k) (+ 1) (A.readArray ma >=> (`seq` pure ()))
pure marr
{-# INLINE evalBoxedMVector #-}
unsafeFromBoxedVector :: VB.Vector a -> Array B Ix1 a
unsafeFromBoxedVector v =
runST $ do
MVB.MVector o k ma <- VB.unsafeThaw v
unsafeFreeze Seq $ MBArray (SafeSz k) o ma
{-# INLINE unsafeFromBoxedVector #-}
unsafeBoxedArray :: A.Array e -> Array B Ix1 e
unsafeBoxedArray = fromArraySeq id Seq
{-# INLINE unsafeBoxedArray #-}
unsafeNormalBoxedArray :: Array B ix e -> Array N ix e
unsafeNormalBoxedArray = coerce
{-# INLINE unsafeNormalBoxedArray #-}
evalNormalBoxedMVector ::
(NFData a, PrimMonad m) => MVB.MVector (PrimState m) a -> m (MArray (PrimState m) N Ix1 a)
evalNormalBoxedMVector (MVB.MVector o k ma) = do
let marr = MNArray (MBArray (SafeSz k) o ma)
loopM_ o (< k) (+ 1) (A.readArray ma >=> (`deepseq` pure ()))
pure marr
{-# INLINE evalNormalBoxedMVector #-}
evalNormalBoxedVector :: NFData a => Comp -> VB.Vector a -> Array N Ix1 a
evalNormalBoxedVector comp v =
runST $ do
MVB.MVector o k ma <- VB.unsafeThaw v
arr <- unsafeFreeze comp $ MBArray (SafeSz k) o ma
arr `deepseqArray` pure (NArray arr)
{-# INLINE evalNormalBoxedVector #-}