Use Proxy type in the sizeOf method of Unbox

This commit is contained in:
Adithya Kumar 2023-01-09 11:56:48 +05:30
parent 5884b1ee09
commit 96a7c99708
18 changed files with 51 additions and 41 deletions

View File

@ -122,6 +122,7 @@ import Control.Exception (assert)
import Control.Monad (when)
import Control.Monad.IO.Class (MonadIO(..))
import Data.Functor.Identity (Identity)
import Data.Proxy (Proxy(..))
import Data.Word (Word8)
import Foreign.C.String (CString)
import Foreign.Ptr (castPtr)

View File

@ -8,22 +8,23 @@
--
-- XXX Check the core to see if max can be statically eliminated. llvm can
-- eliminate the comparison, but not sure if GHC NCG can.
#define SIZE_OF(a) max 1 (sizeOf (undefined :: a))
#define SIZE_OF(a) max 1 (sizeOf (Proxy :: Proxy a))
#define STORABLE_SIZE_OF(a) max 1 (sizeOf (undefined :: a))
-- Move the pointer to ith element of specified type. Type is specified as the
-- type variable in the signature of the function where this macro is used.
#define PTR_NEXT(ptr,a) ptr `plusPtr` SIZE_OF(a)
#define PTR_PREV(ptr,a) ptr `plusPtr` negate (SIZE_OF(a))
#define PTR_NEXT(ptr,a) ptr `plusPtr` STORABLE_SIZE_OF(a)
#define PTR_PREV(ptr,a) ptr `plusPtr` negate (STORABLE_SIZE_OF(a))
#define PTR_INDEX(ptr,i,a) ptr `plusPtr` (SIZE_OF(a) * i)
#define PTR_RINDEX(ptr,i,a) ptr `plusPtr` negate (SIZE_OF(a) * (i + 1))
#define PTR_INDEX(ptr,i,a) ptr `plusPtr` (STORABLE_SIZE_OF(a) * i)
#define PTR_RINDEX(ptr,i,a) ptr `plusPtr` negate (STORABLE_SIZE_OF(a) * (i + 1))
-- XXX If we know that the array is guaranteed to have size multiples of the
-- element size then we can use a simpler check saying "ptr < end". Since we
-- always allocate in multiples of elem we can use the simpler check and assert
-- the rigorous check.
#define PTR_VALID(ptr,end,a) ptr `plusPtr` SIZE_OF(a) <= end
#define PTR_INVALID(ptr,end,a) ptr `plusPtr` SIZE_OF(a) > end
#define PTR_VALID(ptr,end,a) ptr `plusPtr` STORABLE_SIZE_OF(a) <= end
#define PTR_INVALID(ptr,end,a) ptr `plusPtr` STORABLE_SIZE_OF(a) > end
-------------------------------------------------------------------------------
-- Macros to access array indices

View File

@ -30,6 +30,7 @@ where
import Control.Monad.IO.Class (MonadIO(..))
import Control.Monad (when)
import Data.Bifunctor (first)
import Data.Proxy (Proxy(..))
import Streamly.Internal.Data.Unboxed (Unbox, sizeOf)
import Streamly.Internal.Data.Array.Mut.Type (Array(..))
import Streamly.Internal.Data.Fold.Type (Fold(..))

View File

@ -81,6 +81,7 @@ import Control.Exception (assert)
import Control.Monad (replicateM)
import Control.Monad.IO.Class (MonadIO(..))
import Data.Functor.Identity (Identity(..))
import Data.Proxy (Proxy(..))
import Data.Word (Word8)
import GHC.Base (build)
import GHC.Exts (IsList, IsString(..))

View File

@ -309,6 +309,7 @@ import Data.Bifunctor (first)
import Data.Bits (shiftL, shiftR, (.|.), (.&.))
import Data.Either (isLeft, isRight, fromLeft, fromRight)
import Data.Int (Int64)
import Data.Proxy (Proxy(..))
import Data.Word (Word32)
import Foreign.Storable (Storable, peek)
import Streamly.Internal.Data.Maybe.Strict (Maybe'(..), toMaybe)
@ -1707,7 +1708,7 @@ takeEndBySeq patArr (Fold fstep finitial fextract) =
| patLen == 1 -> do
pat <- liftIO $ Array.unsafeIndexIO 0 patArr
return $ Partial $ SplitOnSeqSingle acc pat
| SIZE_OF(a) * patLen <= sizeOf (undefined :: Word) ->
| SIZE_OF(a) * patLen <= sizeOf (Proxy :: Proxy Word) ->
return $ Partial $ SplitOnSeqWord acc 0 0
| otherwise -> do
(rb, rhead) <- liftIO $ Ring.new patLen
@ -1844,7 +1845,7 @@ takeEndBySeq_ patArr (Fold fstep finitial fextract) =
pat <- liftIO $ Array.unsafeIndexIO 0 patArr
return $ Partial $ SplitOnSeqSingle acc pat
-- XXX Need to add tests for this case
| SIZE_OF(a) * patLen <= sizeOf (undefined :: Word) ->
| SIZE_OF(a) * patLen <= sizeOf (Proxy :: Proxy Word) ->
return $ Partial $ SplitOnSeqWord acc 0 0
| otherwise -> do
(rb, rhead) <- liftIO $ Ring.new patLen

View File

@ -60,6 +60,7 @@ import Control.Applicative (liftA2)
import Control.Exception (assert)
import Control.Monad.IO.Class (MonadIO(..))
import Data.Bifunctor (first)
import Data.Proxy (Proxy(..))
import Streamly.Internal.Data.Unboxed (peekWith, sizeOf, Unbox)
import GHC.Types (SPEC(..))
import Streamly.Internal.Data.Array.Mut.Type (touch)

View File

@ -38,6 +38,7 @@ where
#include "inline.hs"
import Data.Proxy (Proxy(..))
import Control.Monad.IO.Class (MonadIO(..))
import Streamly.Internal.Data.Unboxed
( MutableByteArray(..)
@ -59,7 +60,7 @@ newtype IORef a = IORef MutableByteArray
{-# INLINE newIORef #-}
newIORef :: forall a. Unbox a => a -> IO (IORef a)
newIORef x = do
var <- newUnpinnedBytes (sizeOf (undefined :: a))
var <- newUnpinnedBytes (sizeOf (Proxy :: Proxy a))
pokeWith var 0 x
return $ IORef var

View File

@ -37,6 +37,7 @@ where
#include "inline.hs"
import Control.Monad.IO.Class (MonadIO(..))
import Data.Proxy (Proxy(..))
import GHC.Types (SPEC(..))
import Streamly.Internal.Data.Array.Type (Array(..))
import Streamly.Internal.Data.Parser.Chunked.Type (ChunkParser (..))

View File

@ -166,7 +166,7 @@ moveBy by Ring {..} ringHead = ringStartPtr `plusPtr` advanceFromHead
where
elemSize = SIZE_OF(a)
elemSize = STORABLE_SIZE_OF(a)
ringStartPtr = unsafeForeignPtrToPtr ringStart
lenInBytes = ringBound `minusPtr` ringStartPtr
offInBytes = ringHead `minusPtr` ringStartPtr
@ -384,7 +384,7 @@ asBytes = castUnsafe
cast :: forall a b. Storable b => Ring a -> Maybe (Ring b)
cast arr =
let len = byteLength arr
r = len `mod` SIZE_OF(b)
r = len `mod` STORABLE_SIZE_OF(b)
in if r /= 0
then Nothing
else Just $ castUnsafe arr

View File

@ -53,6 +53,7 @@ where
import Data.Bifunctor (second)
import Control.Exception (assert)
import Control.Monad.IO.Class (MonadIO(..))
import Data.Proxy (Proxy(..))
import Data.Word (Word8)
import Streamly.Internal.Data.Unboxed (Unbox, peekWith, sizeOf)
import Fusion.Plugin.Types (Fuse(..))

View File

@ -153,6 +153,7 @@ import Control.Exception (assert)
import Control.Monad.IO.Class (MonadIO(..))
import Data.Bits (shiftR, shiftL, (.|.), (.&.))
import Data.Functor.Identity ( Identity )
import Data.Proxy (Proxy(..))
import Data.Word (Word32)
import Foreign.Storable (Storable, peek)
import Fusion.Plugin.Types (Fuse(..))
@ -1961,7 +1962,7 @@ splitOnSeq patArr (Fold fstep initial done) (Stream step state) =
pat <- liftIO $ A.unsafeIndexIO 0 patArr
return $ Skip $ SplitOnSeqSingle acc state pat
else if SIZE_OF(a) * patLen
<= sizeOf (undefined :: Word)
<= sizeOf (Proxy :: Proxy Word)
then return $ Skip $ SplitOnSeqWordInit acc state
else do
(rb, rhead) <- liftIO $ RB.new patLen
@ -2294,7 +2295,7 @@ splitOnSuffixSeq withSep patArr (Fold fstep initial done) (Stream step state) =
pat <- liftIO $ A.unsafeIndexIO 0 patArr
skip $ SplitOnSuffixSeqSingleInit fs state pat
else if SIZE_OF(a) * patLen
<= sizeOf (undefined :: Word)
<= sizeOf (Proxy :: Proxy Word)
then skip $ SplitOnSuffixSeqWordInit fs state
else do
(rb, rhead) <- liftIO $ RB.new patLen

View File

@ -178,7 +178,6 @@ unpin arr@(MutableByteArray marr#) =
-- The Unbox type class
--------------------------------------------------------------------------------
-- XXX Use Proxy type in sizeOf method.
-- XXX generate error if the size is < 1
-- In theory we could convert a type to and from a byte stream and use that
@ -257,10 +256,10 @@ unpin arr@(MutableByteArray marr#) =
--
class Unbox a where
-- | Get the size.
sizeOf :: a -> Int
sizeOf :: Proxy a -> Int
default sizeOf :: (SizeOfRep (Rep a)) => a -> Int
sizeOf _ = genericSizeOf (Proxy :: Proxy a)
default sizeOf :: (SizeOfRep (Rep a)) => Proxy a -> Int
sizeOf = genericSizeOf
-- | Read an element of type "a" from a MutableByteArray given the byte
-- index.
@ -449,7 +448,7 @@ instance Unbox IoSubSystem where
pokeByteIndex i arr a = pokeByteIndex i arr (fromEnum a)
{-# INLINE sizeOf #-}
sizeOf = sizeOf . fromEnum
sizeOf _ = sizeOf (Proxy :: Proxy Int)
#endif
instance Unbox Bool where
@ -511,7 +510,7 @@ readUnsafe = Peeker (Builder step)
{-# INLINE step #-}
step :: forall a. Unbox a => BoundedPtr -> IO (BoundedPtr, a)
step (BoundedPtr arr pos end) = do
let next = pos + sizeOf (undefined :: a)
let next = pos + sizeOf (Proxy :: Proxy a)
r <- peekByteIndex pos arr
return (BoundedPtr arr next end, r)
@ -524,7 +523,7 @@ read = Peeker (Builder step)
{-# INLINE step #-}
step :: forall a. Unbox a => BoundedPtr -> IO (BoundedPtr, a)
step (BoundedPtr arr pos end) = do
let next = pos + sizeOf (undefined :: a)
let next = pos + sizeOf (Proxy :: Proxy a)
when (next > end) $ error "peekObject reading beyond limit"
r <- peekByteIndex pos arr
return (BoundedPtr arr next end, r)
@ -557,16 +556,16 @@ runPeeker (Peeker (Builder f)) ptr = fmap snd (f ptr)
-- Does not check writing beyond bound.
{-# INLINE pokeBoundedPtrUnsafe #-}
pokeBoundedPtrUnsafe :: Unbox a => a -> BoundedPtr -> IO BoundedPtr
pokeBoundedPtrUnsafe :: forall a. Unbox a => a -> BoundedPtr -> IO BoundedPtr
pokeBoundedPtrUnsafe a (BoundedPtr arr pos end) = do
let next = pos + sizeOf a
let next = pos + sizeOf (Proxy :: Proxy a)
pokeByteIndex pos arr a
return (BoundedPtr arr next end)
{-# INLINE pokeBoundedPtr #-}
pokeBoundedPtr :: Unbox a => a -> BoundedPtr -> IO BoundedPtr
pokeBoundedPtr :: forall a. Unbox a => a -> BoundedPtr -> IO BoundedPtr
pokeBoundedPtr a (BoundedPtr arr pos end) = do
let next = pos + sizeOf a
let next = pos + sizeOf (Proxy :: Proxy a)
when (next > end) $ error "pokeBoundedPtr writing beyond limit"
pokeByteIndex pos arr a
return (BoundedPtr arr next end)
@ -615,7 +614,7 @@ instance SizeOfRep f => SizeOfRep (M1 i c f) where
-- Primitive type "a".
instance Unbox a => SizeOfRep (K1 i a) where
{-# INLINE sizeOfRep #-}
sizeOfRep _ = sizeOf (undefined :: a)
sizeOfRep _ = sizeOf (Proxy :: Proxy a)
-- Void: data type without constructors. Values of this type cannot exist,
-- therefore the size is undefined. We should never be serializing structures
@ -671,7 +670,7 @@ instance (MaxArity256 (SumArity (f :+: g)), SizeOfRepSum f, SizeOfRepSum g) =>
{-# INLINE sizeOfRep #-}
sizeOfRep _ =
-- One byte for the constructor id and then the constructor value.
sizeOf (undefined :: Word8) +
sizeOf (Proxy :: Proxy Word8) +
max (sizeOfRepSum (undefined :: f x))
(sizeOfRepSum (undefined :: g x))

View File

@ -8,22 +8,23 @@
--
-- XXX Check the core to see if max can be statically eliminated. llvm can
-- eliminate the comparison, but not sure if GHC NCG can.
#define SIZE_OF(a) max 1 (sizeOf (undefined :: a))
#define SIZE_OF(a) max 1 (sizeOf (Proxy :: Proxy a))
#define STORABLE_SIZE_OF(a) max 1 (sizeOf (undefined :: a))
-- Move the pointer to ith element of specified type. Type is specified as the
-- type variable in the signature of the function where this macro is used.
#define PTR_NEXT(ptr,a) ptr `plusPtr` SIZE_OF(a)
#define PTR_PREV(ptr,a) ptr `plusPtr` negate (SIZE_OF(a))
#define PTR_NEXT(ptr,a) ptr `plusPtr` STORABLE_SIZE_OF(a)
#define PTR_PREV(ptr,a) ptr `plusPtr` negate (STORABLE_SIZE_OF(a))
#define PTR_INDEX(ptr,i,a) ptr `plusPtr` (SIZE_OF(a) * i)
#define PTR_RINDEX(ptr,i,a) ptr `plusPtr` negate (SIZE_OF(a) * (i + 1))
#define PTR_INDEX(ptr,i,a) ptr `plusPtr` (STORABLE_SIZE_OF(a) * i)
#define PTR_RINDEX(ptr,i,a) ptr `plusPtr` negate (STORABLE_SIZE_OF(a) * (i + 1))
-- XXX If we know that the array is guaranteed to have size multiples of the
-- element size then we can use a simpler check saying "ptr < end". Since we
-- always allocate in multiples of elem we can use the simpler check and assert
-- the rigorous check.
#define PTR_VALID(ptr,end,a) ptr `plusPtr` SIZE_OF(a) <= end
#define PTR_INVALID(ptr,end,a) ptr `plusPtr` SIZE_OF(a) > end
#define PTR_VALID(ptr,end,a) ptr `plusPtr` STORABLE_SIZE_OF(a) <= end
#define PTR_INVALID(ptr,end,a) ptr `plusPtr` STORABLE_SIZE_OF(a) > end
-------------------------------------------------------------------------------
-- Macros to access array indices

View File

@ -10,6 +10,7 @@ module Streamly.Test.Data.Array (main) where
import Data.Char (isLower)
import Data.List (sort)
import Data.Proxy (Proxy(..))
import Data.Word(Word8)
import Foreign.Storable (peek)
import GHC.Ptr (plusPtr)
@ -196,7 +197,7 @@ testAsPtrUnsafeMA = do
where
sizeOfInt = sizeOf (undefined :: Int)
sizeOfInt = sizeOf (Proxy :: Proxy Int)
-- We need to be careful here. We assume Unboxed and Storable are compatible
-- with each other. For Int, they are compatible.
@ -210,7 +211,7 @@ testAsPtrUnsafeMA = do
reallocMA :: Property
reallocMA =
let len = 10000
bSize = len * sizeOf (undefined :: Char)
bSize = len * sizeOf (Proxy :: Proxy Char)
in forAll (vectorOf len (arbitrary :: Gen Char)) $ \vec ->
forAll (chooseInt (bSize - 2000, bSize + 2000)) $ \newBLen -> do
arr <- MA.fromList vec

View File

@ -8,7 +8,7 @@ maxTestCount = 10
#endif
allocOverhead :: Int
allocOverhead = 2 * sizeOf (undefined :: Int)
allocOverhead = 16
-- XXX this should be in sync with the defaultChunkSize in Array code, or we
-- should expose that and use that. For fast testing we could reduce the

View File

@ -1,6 +1,4 @@
import Streamly.Internal.Data.Unboxed (sizeOf)
import Test.Hspec.QuickCheck
import Test.QuickCheck (Property, forAll, Gen, vectorOf, arbitrary, choose)
import Test.QuickCheck.Monadic (monadicIO, assert, run)

View File

@ -48,7 +48,7 @@ test v1 v2 = monadicIO $ do
checkSizeOf :: forall a. Unbox a => Proxy a -> Int -> Property
checkSizeOf _ size = monadicIO $
assert (sizeOf (undefined :: a) == size)
assert (sizeOf (Proxy :: Proxy a) == size)
moduleName :: String
moduleName = "Data.Unbox"

View File

@ -9,6 +9,7 @@
module Streamly.Test.FileSystem.Handle (main) where
import Data.Functor.Identity (runIdentity)
import Data.Proxy (Proxy(..))
import Data.Word (Word8)
import Streamly.Internal.Data.Unboxed (sizeOf)
import Streamly.Internal.Data.Stream (Stream)
@ -36,7 +37,7 @@ import Test.Hspec as H
import Test.Hspec.QuickCheck
allocOverhead :: Int
allocOverhead = 2 * sizeOf (undefined :: Int)
allocOverhead = 2 * sizeOf (Proxy :: Proxy Int)
defaultChunkSize :: Int
defaultChunkSize = 32 * k - allocOverhead