packages feed

fixed-vector-2.1.0.0: Data/Vector/Fixed/Storable.hs

{-# LANGUAGE MagicHash            #-}
{-# LANGUAGE UnboxedTuples        #-}
{-# LANGUAGE UndecidableInstances #-}
-- |
-- Storable-based unboxed vectors.
module Data.Vector.Fixed.Storable (
    -- * Immutable
    Vec
  , Vec1
  , Vec2
  , Vec3
  , Vec4
  , Vec5
    -- * Raw pointers
  , unsafeFromForeignPtr
  , unsafeToForeignPtr
  , unsafeWith
    -- * Mutable
  , MVec(..)
    -- * Type classes
  , Storable
  ) where

import Control.Monad.Primitive
import Control.DeepSeq (NFData(..))
import Data.Monoid           (Monoid(..))
import Data.Semigroup        (Semigroup(..))
import Data.Data
import Data.Primitive.Types  (Prim)
import Foreign.Ptr           (castPtr)
import Foreign.Storable
import Foreign.Marshal.Array ( copyArray, moveArray )
import GHC.ForeignPtr        ( mallocPlainForeignPtrBytes )
import GHC.Ptr               ( Ptr(..) )
import GHC.Exts              ( proxy# )
import GHC.TypeLits
import GHC.ForeignPtr       ( unsafeWithForeignPtr )
import Foreign.ForeignPtr   ( ForeignPtr, withForeignPtr )
import Prelude ( Show(..),Eq(..),Ord(..),Num(..),Monad(..),IO,Int
               , ($),undefined,seq,pure)

import Data.Vector.Fixed hiding (index)
import Data.Vector.Fixed.Mono qualified as FM
import Data.Vector.Fixed.Mutable (Mutable, MVector(..), IVector(..), DimM, constructVec, inspectVec, index, new,unsafeFreeze)
import qualified Data.Vector.Fixed.Cont     as C
import           Data.Vector.Fixed.Cont     (ArityPeano(..))



----------------------------------------------------------------
-- Data types
----------------------------------------------------------------

-- | Storable-based vector with fixed length
newtype Vec (n :: Nat) a = Vec (ForeignPtr a)

-- | Storable-based mutable vector with fixed length
newtype MVec (n :: Nat) s a = MVec (ForeignPtr a)

type Vec1 = Vec 1
type Vec2 = Vec 2
type Vec3 = Vec 3
type Vec4 = Vec 4
type Vec5 = Vec 5

type instance Mutable (Vec  n)   = MVec n
type instance Dim     (Vec  n)   = Peano n
type instance Dim     (Vec  n a) = Peano n
type instance DimM    (MVec n)   = Peano n


----------------------------------------------------------------
-- Raw Ptrs
----------------------------------------------------------------

-- | Get underlying pointer. Data may not be modified through pointer.
unsafeToForeignPtr :: Vec n a -> ForeignPtr a
{-# INLINE unsafeToForeignPtr #-}
unsafeToForeignPtr (Vec fp) = fp

-- | Construct vector from foreign pointer.
unsafeFromForeignPtr :: ForeignPtr a -> Vec n a
{-# INLINE unsafeFromForeignPtr #-}
unsafeFromForeignPtr = Vec

-- | Pass pointer to the vector's data to the IO action. The data may
--   not be modified through the 'Ptr.
unsafeWith :: (Ptr a -> IO b) -> Vec n a -> IO b
{-# INLINE unsafeWith #-}
unsafeWith f (Vec fp) = withForeignPtr fp f



----------------------------------------------------------------
-- Instances
----------------------------------------------------------------

instance (Arity n, Storable a, NFData a) => NFData (Vec n a) where
  rnf x = seq x ()

deriving via ViaFixed (Vec n) a instance (Arity n, Storable a, Show      a) => Show      (Vec n a)
deriving via ViaFixed (Vec n) a instance (Arity n, Storable a, Eq        a) => Eq        (Vec n a)
deriving via ViaFixed (Vec n) a instance (Arity n, Storable a, Ord       a) => Ord       (Vec n a)
deriving via ViaFixed (Vec n) a instance (Arity n, Storable a, Semigroup a) => Semigroup (Vec n a)
deriving via ViaFixed (Vec n) a instance (Arity n, Storable a, Monoid    a) => Monoid    (Vec n a)

instance (Arity n, Storable a) => MVector (MVec n) a where
  basicNew = unsafePrimToPrim $ do
    fp <- mallocVector (peanoToInt (proxy# @(Peano n)))
    return $ MVec fp
  {-# INLINE basicNew         #-}
  basicCopy (MVec fp) (MVec fq)
    = unsafePrimToPrim
    $ unsafeWithForeignPtr fp $ \p ->
      unsafeWithForeignPtr fq $ \q ->
      copyArray p q (peanoToInt (proxy# @(Peano n)))
  {-# INLINE basicCopy        #-}
  basicUnsafeRead (MVec fp) i
    = unsafePrimToPrim
    $ unsafeWithForeignPtr fp (`peekElemOff` i)
  {-# INLINE basicUnsafeRead  #-}
  basicUnsafeWrite (MVec fp) i x
    = unsafePrimToPrim
    $ unsafeWithForeignPtr fp $ \p -> pokeElemOff p i x
  {-# INLINE basicUnsafeWrite #-}

instance (Arity n, Storable a) => IVector (Vec n) a where
  basicUnsafeFreeze (MVec fp) = return $ Vec  fp
  basicThaw         (Vec  fp) = do
    mv <- basicNew
    basicCopy mv (MVec fp)
    pure mv
  unsafeIndex  (Vec  fp) i
    = unsafeInlineIO
    $ unsafeWithForeignPtr fp (`peekElemOff` i)
  {-# INLINE basicUnsafeFreeze #-}
  {-# INLINE basicThaw         #-}
  {-# INLINE unsafeIndex       #-}

instance (Arity n, Storable a) => Vector (Vec n) a where
  construct  = constructVec
  inspect    = inspectVec
  basicIndex = index
  {-# INLINE construct  #-}
  {-# INLINE inspect    #-}
  {-# INLINE basicIndex #-}
instance (Arity n, Storable a) => FM.Prod a (Vec n a) where
  construct  = constructVec
  inspect    = inspectVec
  {-# INLINE construct  #-}
  {-# INLINE inspect    #-}
instance (Arity n, Storable a) => FM.Vector a (Vec n a)

instance (Arity n, Storable a) => Storable (Vec n a) where
  sizeOf    = defaultSizeOf
  alignment = defaultAlignemnt
  peek ptr = do
    arr@(MVec fp) <- new
    unsafeWithForeignPtr fp $ \p ->
      moveArray p (castPtr ptr) (peanoToInt (proxy# @(Peano n)))
    unsafeFreeze arr
  poke ptr (Vec fp)
    = unsafeWithForeignPtr fp $ \p ->
      moveArray (castPtr ptr) p (peanoToInt (proxy# @(Peano n)))

-- | @since 2.0.1.0
deriving via ViaFixed (Vec n) a instance (Arity n, Storable a, Prim a) => Prim (Vec n a)

instance (Typeable n, Arity n, Storable a, Data a) => Data (Vec n a) where
  gfoldl       = C.gfoldl
  gunfold      = C.gunfold
  toConstr   _ = con_Vec
  dataTypeOf _ = ty_Vec

ty_Vec :: DataType
ty_Vec  = mkDataType "Data.Vector.Fixed.Primitive.Vec" [con_Vec]

con_Vec :: Constr
con_Vec = mkConstr ty_Vec "Vec" [] Prefix




----------------------------------------------------------------
-- Helpers
----------------------------------------------------------------

-- Code copied verbatim from vector package

mallocVector :: forall a. Storable a => Int -> IO (ForeignPtr a)
{-# INLINE mallocVector #-}
mallocVector size
  = mallocPlainForeignPtrBytes (size * sizeOf (undefined :: a))