primal-0.2.0.0: src/Data/Prim.hs
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
-- |
-- Module : Data.Prim
-- Copyright : (c) Alexey Kuleshevich 2020
-- License : BSD3
-- Maintainer : Alexey Kuleshevich <alexey@kuleshevi.ch>
-- Stability : experimental
-- Portability : non-portable
--
module Data.Prim
( Prim
, Atom(..)
, Atomic
, AtomicCount
, AtomicBits
, MonadPrim
, RW
, RealWorld
-- * Prim type size
, byteCount
, byteCountType
, byteCountProxy
-- * Prim type alignment
, alignment
, alignmentType
, alignmentProxy
-- * Size
, Size(..)
-- * Count
, Count(..)
, unCountBytes
, toByteCount
, unCountBytes#
, fromByteCount
, fromByteCountRem
, countToOff
, countToByteOff
, countForType
, countForProxyTypeOf
-- * Offset
, Off(..)
, unOffBytes
, toByteOff
, unOffBytes#
, fromByteOff
, fromByteOffRem
, offToCount
, offToByteCount
, offForType
, offForProxyTypeOf
-- * Prefetch
, prefetchValue0
, prefetchValue1
, prefetchValue2
, prefetchValue3
-- * Re-export
, module Data.Word
, module Data.Int
, Ptr
, ForeignPtr
, Typeable
, Proxy(..)
, module Data.Semigroup
, module Data.Monoid
, module Data.Coerce
) where
import Control.DeepSeq
import Control.Prim.Monad
import Data.Coerce
import Data.Int
import Data.Monoid hiding (First(..), Last(..), (<>))
import Data.Prim.Atom
import Data.Prim.Atomic
import Data.Prim.Class
import Data.Semigroup
import Data.Typeable
import Data.Word
import Foreign.ForeignPtr (ForeignPtr)
import GHC.Base (quotInt, quotRemInt)
import GHC.Exts
newtype Size = Size { unSize :: Int }
deriving (Show, Eq, Ord, Num, Real, Integral, Bounded, Enum)
-- | Get the size of the data type in bytes. Argument is not evaluated.
--
-- >>> import Data.Prim
-- >>> byteCount (Just 'a')
-- Count {unCount = 5}
--
-- @since 0.1.0
byteCount :: forall e . Prim e => e -> Count Word8
byteCount _ = coerce (I# (sizeOf# (proxy# :: Proxy# e)))
{-# INLINE byteCount #-}
-- | Same as `sizeOf`, except that the type can be supplied as a type level argument
--
-- >>> :set -XTypeApplications
-- >>> import Data.Prim
-- >>> byteCountType @Int64
-- Count {unCount = 8}
--
-- @since 0.1.0
byteCountType :: forall e . Prim e => Count Word8
byteCountType = coerce (I# (sizeOf# (proxy# :: Proxy# e)))
{-# INLINE byteCountType #-}
-- | Same as `sizeOf`, but argument is a `Proxy` of @a@, instead of the type itself.
--
-- >>> import Data.Prim
-- >>> import Data.Proxy
-- >>> byteCountProxy (Proxy :: Proxy Int64)
-- Count {unCount = 8}
--
-- @since 0.1.0
byteCountProxy :: forall proxy e . Prim e => proxy e -> Count Word8
byteCountProxy _ = coerce (I# (sizeOf# (proxy# :: Proxy# e)))
{-# INLINE byteCountProxy #-}
-- | Get the alignemnt of the type in bytes. Argument is not evaluated.
--
-- @since 0.1.0
alignment :: forall e . Prim e => e -> Int
alignment _ = I# (alignment# (proxy# :: Proxy# e))
{-# INLINE alignment #-}
-- | Same as `alignment`, except that the type can be supplied with @TypeApplications@
--
-- >>> :set -XTypeApplications
-- >>> import Data.Prim
-- >>> alignmentType @Int32
-- 4
--
-- @since 0.1.0
alignmentType :: forall e . Prim e => Int
alignmentType = I# (alignment# (proxy# :: Proxy# e))
{-# INLINE alignmentType #-}
-- | Same as `alignment`, but argument is a `Proxy` of @a@, instead of the type itself.
--
-- >>> import Data.Proxy
-- >>> alignmentProxy (Proxy :: Proxy Int64)
-- 8
--
-- @since 0.1.0
alignmentProxy :: forall proxy e . Prim e => proxy e -> Int
alignmentProxy _ = I# (alignment# (proxy# :: Proxy# e))
{-# INLINE alignmentProxy #-}
-- | Number of elements
newtype Count e = Count
{ unCount :: Int
} deriving (Eq, Show, Ord, Enum, Bounded, Num, Integral, Real, NFData)
instance Prim (Count e) where
type PrimBase (Count e) = Int
unCountWord8# :: Count Word8 -> Int#
unCountWord8# (Count (I# n#)) = n#
{-# INLINE unCountWord8# #-}
unCountInt8# :: Count Int8 -> Int#
unCountInt8# (Count (I# n#)) = n#
{-# INLINE unCountInt8# #-}
unCountBytes# :: Prim e => Count e -> Int#
unCountBytes# c@(Count (I# n#)) =
case coerce (byteCountProxy c) of
I# sz# -> sz# *# n#
{-# INLINE[0] unCountBytes# #-}
{-# RULES
"unCountWord8#" unCountBytes# = unCountWord8#
"unCountInt8#" unCountBytes# = unCountInt8#
#-}
-- | Covert an element count to number of bytes it coresponds to as an `Int`. See
-- `toByteCount` for preserving the `Count` wrapper.
--
-- @since 0.1.0
unCountBytes :: Prim e => Count e -> Int
unCountBytes c = I# (unCountBytes# c)
{-# INLINE unCountBytes #-}
-- | Covert to the `Count` of bytes
--
-- @since 0.1.0
toByteCount :: Prim e => Count e -> Count Word8
toByteCount = Count . unCountBytes
{-# INLINE toByteCount #-}
-- | Cast a count to an offset of the same type
--
-- @since 0.2.0
countToOff :: Count e -> Off e
countToOff = coerce
countToByteOff :: Prim e => Count e -> Off Word8
countToByteOff = countToOff . toByteCount
{-# INLINE countToByteOff #-}
-- | Helper noop function that restricts `Count` to the type of proxy
--
-- @since 0.2.0
countForProxyTypeOf :: Count e -> proxy e -> Count e
countForProxyTypeOf count _ = count
-- | Restrict type argument of `Count` to the same type as the second argument, which
-- itself is not evaluated
--
-- @since 0.2.0
countForType :: Count e -> e -> Count e
countForType count _ = count
fromByteCountInt8 :: Count Word8 -> Count Int8
fromByteCountInt8 = coerce
{-# INLINE fromByteCountInt8 #-}
-- | Compute how many elements of type @e@ can fit in the supplied number of bytes.
--
-- @since 0.1.0
fromByteCount :: forall e . Prim e => Count Word8 -> Count e
fromByteCount sz = coerce (quotSizeOfWith (proxy# :: Proxy# e) (coerce sz) 0 quotInt)
{-# INLINE[0] fromByteCount #-}
{-# RULES
"fromByteCount" fromByteCount = id
"fromByteCount" fromByteCount = fromByteCountInt8
#-}
fromByteCountRemWord8 :: Count Word8 -> (Count Word8, Count Word8)
fromByteCountRemWord8 i = (coerce i, 0)
{-# INLINE fromByteCountRemWord8 #-}
fromByteCountRemInt8 :: Count Word8 -> (Count Int8, Count Word8)
fromByteCountRemInt8 i = (coerce i, 0)
{-# INLINE fromByteCountRemInt8 #-}
fromByteCountRem :: forall e . Prim e => Count Word8 -> (Count e, Count Word8)
fromByteCountRem sz = coerce (quotSizeOfWith (proxy# :: Proxy# e) (coerce sz) (0, 0) quotRemInt)
{-# INLINE[0] fromByteCountRem #-}
{-# RULES
"fromByteCountRemWord8" fromByteCountRem = fromByteCountRemWord8
"fromByteCountRemInt8" fromByteCountRem = fromByteCountRemInt8
#-}
quotSizeOfWith :: forall e b. Prim e => Proxy# e -> Int -> b -> (Int -> Int -> b) -> b
quotSizeOfWith px# sz onZero quotWith
| tySize <= 0 = onZero
| otherwise = sz `quotWith` tySize
where
tySize = I# (sizeOf# px#)
{-# INLINE quotSizeOfWith #-}
-- | Offset in number of elements
newtype Off e = Off
{ unOff :: Int
} deriving (Eq, Show, Ord, Enum, Bounded, Num, Integral, Real, NFData)
instance Prim (Off e) where
type PrimBase (Off e) = Int
-- | Helper noop function that restricts `Off`set to the type of proxy
--
-- @since 0.2.0
offForProxyTypeOf :: Off e -> proxy e -> Off e
offForProxyTypeOf off _ = off
-- | Restrict type argument of `Off` to the same type as the second argument, which itself
-- is not evaluated
--
-- @since 0.2.0
offForType :: Off e -> e -> Off e
offForType c _ = c
-- | Cast an offset to count. Useful for dealing with regions.
--
-- >>> import Data.Prim
-- >>> totalCount = Count 10 :: Count Word
-- >>> startOffset = Off 4 :: Off Word
-- >>> totalCount - offToCount startOffset
-- Count {unCount = 6}
--
-- @since 0.2.0
offToCount :: Off e -> Count e
offToCount = coerce
-- | Convert an offset in elements to count in bytres.
--
-- @since 0.2.0
offToByteCount :: Prim e => Off e -> Count Word8
offToByteCount = offToCount . toByteOff
{-# INLINE offToByteCount #-}
-- | Compute byte offset from an offset of `Prim` type
--
-- >>> toByteOff (10 :: Off Word64)
-- Off {unOff = 80}
--
-- @since 0.1.0
toByteOff :: Prim e => Off e -> Off Word8
toByteOff off = Off (I# (unOffBytes# off))
{-# INLINE toByteOff #-}
-- | Convert an offset for some type @e@ with `Prim` instance to the number of bytes as an
-- `Int`.
--
-- >>> unOffBytes (10 :: Off Word64)
-- 80
--
-- @since 0.2.0
unOffBytes :: Prim e => Off e -> Int
unOffBytes off = I# (unOffBytes# off)
{-# INLINE unOffBytes #-}
unOffWord8# :: Off Word8 -> Int#
unOffWord8# (Off (I# o#)) = o#
{-# INLINE unOffWord8# #-}
unOffInt8# :: Off Int8 -> Int#
unOffInt8# (Off (I# o#)) = o#
{-# INLINE unOffInt8# #-}
-- | Convert offset of some type into number of bytes
unOffBytes# :: Prim e => Off e -> Int#
unOffBytes# o@(Off (I# o#)) =
case coerce (byteCountProxy o) of
I# sz# -> sz# *# o#
{-# INLINE[0] unOffBytes# #-}
{-# RULES
"unOffWord8#" unOffBytes# = unOffWord8#
"unOffInt8#" unOffBytes# = unOffInt8#
#-}
fromByteOffInt8 :: Off Word8 -> Off Int8
fromByteOffInt8 = coerce
{-# INLINE fromByteOffInt8 #-}
fromByteOff :: forall e . Prim e => Off Word8 -> Off e
fromByteOff sz = coerce (quotSizeOfWith (proxy# :: Proxy# e) (coerce sz) 0 quotInt)
{-# INLINE[0] fromByteOff #-}
{-# RULES
"fromByteOff" fromByteOff = id
"fromByteOff" fromByteOff = fromByteOffInt8
#-}
fromByteOffRemWord8 :: Off Word8 -> (Off Word8, Off Word8)
fromByteOffRemWord8 i = (coerce i, 0)
{-# INLINE fromByteOffRemWord8 #-}
fromByteOffRemInt8 :: Off Word8 -> (Off Int8, Off Word8)
fromByteOffRemInt8 i = (coerce i, 0)
{-# INLINE fromByteOffRemInt8 #-}
fromByteOffRem :: forall e . Prim e => Off Word8 -> (Off e, Off Word8)
fromByteOffRem sz = coerce (quotSizeOfWith (proxy# :: Proxy# e) (coerce sz) (0, 0) quotRemInt)
{-# INLINE[0] fromByteOffRem #-}
{-# RULES
"fromByteOffRemWord8" fromByteOffRem = fromByteOffRemWord8
"fromByteOffRemInt8" fromByteOffRem = fromByteOffRemInt8
#-}
prefetchValue0 :: MonadPrim s m => a -> m ()
prefetchValue0 a = prim_ (prefetchValue0# a)
{-# INLINE prefetchValue0 #-}
prefetchValue1 :: MonadPrim s m => a -> m ()
prefetchValue1 a = prim_ (prefetchValue1# a)
{-# INLINE prefetchValue1 #-}
prefetchValue2 :: MonadPrim s m => a -> m ()
prefetchValue2 a = prim_ (prefetchValue2# a)
{-# INLINE prefetchValue2 #-}
prefetchValue3 :: MonadPrim s m => a -> m ()
prefetchValue3 a = prim_ (prefetchValue3# a)
{-# INLINE prefetchValue3 #-}