on master help sign in
Use Proxy type in the sizeOf method of Unbox
commit96a7c99708287827832cd66d3b12284969a18a3e authorAdithya Kumar <adithya@composewell.com> dateMon 9 Jan 2023, 11:56 (4 years ago) parent5884b1e
18 files changed+51−41
core/src/Streamly/Internal/Data/Array.hs+1 core/src/Streamly/Internal/Data/Array/ArrayMacros.h+8−7 core/src/Streamly/Internal/Data/Array/Mut/Stream.hs+1 core/src/Streamly/Internal/Data/Array/Type.hs+1 core/src/Streamly/Internal/Data/Fold.hs+3−2 core/src/Streamly/Internal/Data/Fold/Chunked.hs+1 core/src/Streamly/Internal/Data/IORef/Unboxed.hs+2−1 core/src/Streamly/Internal/Data/Parser/Chunked.hs+1 core/src/Streamly/Internal/Data/Ring/Unboxed.hs+2−2 core/src/Streamly/Internal/Data/Stream/Chunked.hs+1 core/src/Streamly/Internal/Data/Stream/StreamD/Nesting.hs+3−2 core/src/Streamly/Internal/Data/Unboxed.hs+12−13 src/Streamly/Internal/Data/Array/ArrayMacros.h+8−7 test/Streamly/Test/Data/Array.hs+3−2 test/Streamly/Test/Data/Array/Common.hs+1−1 test/Streamly/Test/Data/Array/CommonImports.hs−2 test/Streamly/Test/Data/Unbox.hs+1−1 test/Streamly/Test/FileSystem/Handle.hs+2−1
core/src/Streamly/Internal/Data/Array.hs+1
@@ -122,6 +122,7 @@ import Control.Exception (assert)
122122import Control.Monad (when)
123123import Control.Monad.IO.Class (MonadIO(..))
124124import Data.Functor.Identity (Identity)
125+import Data.Proxy (Proxy(..))
125126import Data.Word (Word8)
126127import Foreign.C.String (CString)
127128import Foreign.Ptr (castPtr)
core/src/Streamly/Internal/Data/Array/ArrayMacros.h+8−7
@@ -8,22 +8,23 @@
88--
99-- XXX Check the core to see if max can be statically eliminated. llvm can
1010-- eliminate the comparison, but not sure if GHC NCG can.
11−#define SIZE_OF(a) max 1 (sizeOf (undefined :: a))
11+#define SIZE_OF(a) max 1 (sizeOf (Proxy :: Proxy a))
12+#define STORABLE_SIZE_OF(a) max 1 (sizeOf (undefined :: a))
1213
1314-- Move the pointer to ith element of specified type. Type is specified as the
1415-- type variable in the signature of the function where this macro is used.
15−#define PTR_NEXT(ptr,a) ptr `plusPtr` SIZE_OF(a)
16−#define PTR_PREV(ptr,a) ptr `plusPtr` negate (SIZE_OF(a))
16+#define PTR_NEXT(ptr,a) ptr `plusPtr` STORABLE_SIZE_OF(a)
17+#define PTR_PREV(ptr,a) ptr `plusPtr` negate (STORABLE_SIZE_OF(a))
1718
18−#define PTR_INDEX(ptr,i,a) ptr `plusPtr` (SIZE_OF(a) * i)
19−#define PTR_RINDEX(ptr,i,a) ptr `plusPtr` negate (SIZE_OF(a) * (i + 1))
19+#define PTR_INDEX(ptr,i,a) ptr `plusPtr` (STORABLE_SIZE_OF(a) * i)
20+#define PTR_RINDEX(ptr,i,a) ptr `plusPtr` negate (STORABLE_SIZE_OF(a) * (i + 1))
2021
2122-- XXX If we know that the array is guaranteed to have size multiples of the
2223-- element size then we can use a simpler check saying "ptr < end". Since we
2324-- always allocate in multiples of elem we can use the simpler check and assert
2425-- the rigorous check.
25−#define PTR_VALID(ptr,end,a) ptr `plusPtr` SIZE_OF(a) <= end
26−#define PTR_INVALID(ptr,end,a) ptr `plusPtr` SIZE_OF(a) > end
26+#define PTR_VALID(ptr,end,a) ptr `plusPtr` STORABLE_SIZE_OF(a) <= end
27+#define PTR_INVALID(ptr,end,a) ptr `plusPtr` STORABLE_SIZE_OF(a) > end
2728
2829-------------------------------------------------------------------------------
2930-- Macros to access array indices
core/src/Streamly/Internal/Data/Array/Mut/Stream.hs+1
@@ -30,6 +30,7 @@ where
3030import Control.Monad.IO.Class (MonadIO(..))
3131import Control.Monad (when)
3232import Data.Bifunctor (first)
33+import Data.Proxy (Proxy(..))
3334import Streamly.Internal.Data.Unboxed (Unbox, sizeOf)
3435import Streamly.Internal.Data.Array.Mut.Type (Array(..))
3536import Streamly.Internal.Data.Fold.Type (Fold(..))
core/src/Streamly/Internal/Data/Array/Type.hs+1
@@ -81,6 +81,7 @@ import Control.Exception (assert)
8181import Control.Monad (replicateM)
8282import Control.Monad.IO.Class (MonadIO(..))
8383import Data.Functor.Identity (Identity(..))
84+import Data.Proxy (Proxy(..))
8485import Data.Word (Word8)
8586import GHC.Base (build)
8687import GHC.Exts (IsList, IsString(..))
core/src/Streamly/Internal/Data/Fold.hs+3−2
@@ -309,6 +309,7 @@ import Data.Bifunctor (first)
309309import Data.Bits (shiftL, shiftR, (.|.), (.&.))
310310import Data.Either (isLeft, isRight, fromLeft, fromRight)
311311import Data.Int (Int64)
312+import Data.Proxy (Proxy(..))
312313import Data.Word (Word32)
313314import Foreign.Storable (Storable, peek)
314315import Streamly.Internal.Data.Maybe.Strict (Maybe'(..), toMaybe)
@@ -1707,7 +1708,7 @@ takeEndBySeq patArr (Fold fstep finitial fextract) =
17071708 | patLen == 1 -> do
17081709 pat <- liftIO $ Array.unsafeIndexIO 0 patArr
17091710 return $ Partial $ SplitOnSeqSingle acc pat
1710− | SIZE_OF(a) * patLen <= sizeOf (undefined :: Word) ->
1711+ | SIZE_OF(a) * patLen <= sizeOf (Proxy :: Proxy Word) ->
17111712 return $ Partial $ SplitOnSeqWord acc 0 0
17121713 | otherwise -> do
17131714 (rb, rhead) <- liftIO $ Ring.new patLen
@@ -1844,7 +1845,7 @@ takeEndBySeq_ patArr (Fold fstep finitial fextract) =
18441845 pat <- liftIO $ Array.unsafeIndexIO 0 patArr
18451846 return $ Partial $ SplitOnSeqSingle acc pat
18461847 -- XXX Need to add tests for this case
1847− | SIZE_OF(a) * patLen <= sizeOf (undefined :: Word) ->
1848+ | SIZE_OF(a) * patLen <= sizeOf (Proxy :: Proxy Word) ->
18481849 return $ Partial $ SplitOnSeqWord acc 0 0
18491850 | otherwise -> do
18501851 (rb, rhead) <- liftIO $ Ring.new patLen
core/src/Streamly/Internal/Data/Fold/Chunked.hs+1
@@ -60,6 +60,7 @@ import Control.Applicative (liftA2)
6060import Control.Exception (assert)
6161import Control.Monad.IO.Class (MonadIO(..))
6262import Data.Bifunctor (first)
63+import Data.Proxy (Proxy(..))
6364import Streamly.Internal.Data.Unboxed (peekWith, sizeOf, Unbox)
6465import GHC.Types (SPEC(..))
6566import Streamly.Internal.Data.Array.Mut.Type (touch)
core/src/Streamly/Internal/Data/IORef/Unboxed.hs+2−1
@@ -38,6 +38,7 @@ where
3838
3939#include "inline.hs"
4040
41+import Data.Proxy (Proxy(..))
4142import Control.Monad.IO.Class (MonadIO(..))
4243import Streamly.Internal.Data.Unboxed
4344 ( MutableByteArray(..)
@@ -59,7 +60,7 @@ newtype IORef a = IORef MutableByteArray
5960{-# INLINE newIORef #-}
6061newIORef :: forall a. Unbox a => a -> IO (IORef a)
6162newIORef x = do
62− var <- newUnpinnedBytes (sizeOf (undefined :: a))
63+ var <- newUnpinnedBytes (sizeOf (Proxy :: Proxy a))
6364 pokeWith var 0 x
6465 return $ IORef var
6566
core/src/Streamly/Internal/Data/Parser/Chunked.hs+1
@@ -37,6 +37,7 @@ where
3737#include "inline.hs"
3838
3939import Control.Monad.IO.Class (MonadIO(..))
40+import Data.Proxy (Proxy(..))
4041import GHC.Types (SPEC(..))
4142import Streamly.Internal.Data.Array.Type (Array(..))
4243import Streamly.Internal.Data.Parser.Chunked.Type (ChunkParser (..))
core/src/Streamly/Internal/Data/Ring/Unboxed.hs+2−2
@@ -166,7 +166,7 @@ moveBy by Ring {..} ringHead = ringStartPtr `plusPtr` advanceFromHead
166166
167167 where
168168
169− elemSize = SIZE_OF(a)
169+ elemSize = STORABLE_SIZE_OF(a)
170170 ringStartPtr = unsafeForeignPtrToPtr ringStart
171171 lenInBytes = ringBound `minusPtr` ringStartPtr
172172 offInBytes = ringHead `minusPtr` ringStartPtr
@@ -384,7 +384,7 @@ asBytes = castUnsafe
384384cast :: forall a b. Storable b => Ring a -> Maybe (Ring b)
385385cast arr =
386386 let len = byteLength arr
387− r = len `mod` SIZE_OF(b)
387+ r = len `mod` STORABLE_SIZE_OF(b)
388388 in if r /= 0
389389 then Nothing
390390 else Just $ castUnsafe arr
core/src/Streamly/Internal/Data/Stream/Chunked.hs+1
@@ -53,6 +53,7 @@ where
5353import Data.Bifunctor (second)
5454import Control.Exception (assert)
5555import Control.Monad.IO.Class (MonadIO(..))
56+import Data.Proxy (Proxy(..))
5657import Data.Word (Word8)
5758import Streamly.Internal.Data.Unboxed (Unbox, peekWith, sizeOf)
5859import Fusion.Plugin.Types (Fuse(..))
core/src/Streamly/Internal/Data/Stream/StreamD/Nesting.hs+3−2
@@ -153,6 +153,7 @@ import Control.Exception (assert)
153153import Control.Monad.IO.Class (MonadIO(..))
154154import Data.Bits (shiftR, shiftL, (.|.), (.&.))
155155import Data.Functor.Identity ( Identity )
156+import Data.Proxy (Proxy(..))
156157import Data.Word (Word32)
157158import Foreign.Storable (Storable, peek)
158159import Fusion.Plugin.Types (Fuse(..))
@@ -1961,7 +1962,7 @@ splitOnSeq patArr (Fold fstep initial done) (Stream step state) =
19611962 pat <- liftIO $ A.unsafeIndexIO 0 patArr
19621963 return $ Skip $ SplitOnSeqSingle acc state pat
19631964 else if SIZE_OF(a) * patLen
1964− <= sizeOf (undefined :: Word)
1965+ <= sizeOf (Proxy :: Proxy Word)
19651966 then return $ Skip $ SplitOnSeqWordInit acc state
19661967 else do
19671968 (rb, rhead) <- liftIO $ RB.new patLen
@@ -2294,7 +2295,7 @@ splitOnSuffixSeq withSep patArr (Fold fstep initial done) (Stream step state) =
22942295 pat <- liftIO $ A.unsafeIndexIO 0 patArr
22952296 skip $ SplitOnSuffixSeqSingleInit fs state pat
22962297 else if SIZE_OF(a) * patLen
2297− <= sizeOf (undefined :: Word)
2298+ <= sizeOf (Proxy :: Proxy Word)
22982299 then skip $ SplitOnSuffixSeqWordInit fs state
22992300 else do
23002301 (rb, rhead) <- liftIO $ RB.new patLen
core/src/Streamly/Internal/Data/Unboxed.hs+12−13
@@ -178,7 +178,6 @@ unpin arr@(MutableByteArray marr#) =
178178-- The Unbox type class
179179--------------------------------------------------------------------------------
180180
181−-- XXX Use Proxy type in sizeOf method.
182181-- XXX generate error if the size is < 1
183182
184183-- In theory we could convert a type to and from a byte stream and use that
@@ -257,10 +256,10 @@ unpin arr@(MutableByteArray marr#) =
257256--
258257class Unbox a where
259258 -- | Get the size.
260− sizeOf :: a -> Int
259+ sizeOf :: Proxy a -> Int
261260
262− default sizeOf :: (SizeOfRep (Rep a)) => a -> Int
263− sizeOf _ = genericSizeOf (Proxy :: Proxy a)
261+ default sizeOf :: (SizeOfRep (Rep a)) => Proxy a -> Int
262+ sizeOf = genericSizeOf
264263
265264 -- | Read an element of type "a" from a MutableByteArray given the byte
266265 -- index.
@@ -449,7 +448,7 @@ instance Unbox IoSubSystem where
449448 pokeByteIndex i arr a = pokeByteIndex i arr (fromEnum a)
450449
451450 {-# INLINE sizeOf #-}
452− sizeOf = sizeOf . fromEnum
451+ sizeOf _ = sizeOf (Proxy :: Proxy Int)
453452#endif
454453
455454instance Unbox Bool where
@@ -511,7 +510,7 @@ readUnsafe = Peeker (Builder step)
511510 {-# INLINE step #-}
512511 step :: forall a. Unbox a => BoundedPtr -> IO (BoundedPtr, a)
513512 step (BoundedPtr arr pos end) = do
514− let next = pos + sizeOf (undefined :: a)
513+ let next = pos + sizeOf (Proxy :: Proxy a)
515514 r <- peekByteIndex pos arr
516515 return (BoundedPtr arr next end, r)
517516
@@ -524,7 +523,7 @@ read = Peeker (Builder step)
524523 {-# INLINE step #-}
525524 step :: forall a. Unbox a => BoundedPtr -> IO (BoundedPtr, a)
526525 step (BoundedPtr arr pos end) = do
527− let next = pos + sizeOf (undefined :: a)
526+ let next = pos + sizeOf (Proxy :: Proxy a)
528527 when (next > end) $ error "peekObject reading beyond limit"
529528 r <- peekByteIndex pos arr
530529 return (BoundedPtr arr next end, r)
@@ -557,16 +556,16 @@ runPeeker (Peeker (Builder f)) ptr = fmap snd (f ptr)
557556
558557-- Does not check writing beyond bound.
559558{-# INLINE pokeBoundedPtrUnsafe #-}
560−pokeBoundedPtrUnsafe :: Unbox a => a -> BoundedPtr -> IO BoundedPtr
559+pokeBoundedPtrUnsafe :: forall a. Unbox a => a -> BoundedPtr -> IO BoundedPtr
561560pokeBoundedPtrUnsafe a (BoundedPtr arr pos end) = do
562− let next = pos + sizeOf a
561+ let next = pos + sizeOf (Proxy :: Proxy a)
563562 pokeByteIndex pos arr a
564563 return (BoundedPtr arr next end)
565564
566565{-# INLINE pokeBoundedPtr #-}
567−pokeBoundedPtr :: Unbox a => a -> BoundedPtr -> IO BoundedPtr
566+pokeBoundedPtr :: forall a. Unbox a => a -> BoundedPtr -> IO BoundedPtr
568567pokeBoundedPtr a (BoundedPtr arr pos end) = do
569− let next = pos + sizeOf a
568+ let next = pos + sizeOf (Proxy :: Proxy a)
570569 when (next > end) $ error "pokeBoundedPtr writing beyond limit"
571570 pokeByteIndex pos arr a
572571 return (BoundedPtr arr next end)
@@ -615,7 +614,7 @@ instance SizeOfRep f => SizeOfRep (M1 i c f) where
615614-- Primitive type "a".
616615instance Unbox a => SizeOfRep (K1 i a) where
617616 {-# INLINE sizeOfRep #-}
618− sizeOfRep _ = sizeOf (undefined :: a)
617+ sizeOfRep _ = sizeOf (Proxy :: Proxy a)
619618
620619-- Void: data type without constructors. Values of this type cannot exist,
621620-- therefore the size is undefined. We should never be serializing structures
@@ -671,7 +670,7 @@ instance (MaxArity256 (SumArity (f :+: g)), SizeOfRepSum f, SizeOfRepSum g) =>
671670 {-# INLINE sizeOfRep #-}
672671 sizeOfRep _ =
673672 -- One byte for the constructor id and then the constructor value.
674− sizeOf (undefined :: Word8) +
673+ sizeOf (Proxy :: Proxy Word8) +
675674 max (sizeOfRepSum (undefined :: f x))
676675 (sizeOfRepSum (undefined :: g x))
677676
src/Streamly/Internal/Data/Array/ArrayMacros.h+8−7
@@ -8,22 +8,23 @@
88--
99-- XXX Check the core to see if max can be statically eliminated. llvm can
1010-- eliminate the comparison, but not sure if GHC NCG can.
11−#define SIZE_OF(a) max 1 (sizeOf (undefined :: a))
11+#define SIZE_OF(a) max 1 (sizeOf (Proxy :: Proxy a))
12+#define STORABLE_SIZE_OF(a) max 1 (sizeOf (undefined :: a))
1213
1314-- Move the pointer to ith element of specified type. Type is specified as the
1415-- type variable in the signature of the function where this macro is used.
15−#define PTR_NEXT(ptr,a) ptr `plusPtr` SIZE_OF(a)
16−#define PTR_PREV(ptr,a) ptr `plusPtr` negate (SIZE_OF(a))
16+#define PTR_NEXT(ptr,a) ptr `plusPtr` STORABLE_SIZE_OF(a)
17+#define PTR_PREV(ptr,a) ptr `plusPtr` negate (STORABLE_SIZE_OF(a))
1718
18−#define PTR_INDEX(ptr,i,a) ptr `plusPtr` (SIZE_OF(a) * i)
19−#define PTR_RINDEX(ptr,i,a) ptr `plusPtr` negate (SIZE_OF(a) * (i + 1))
19+#define PTR_INDEX(ptr,i,a) ptr `plusPtr` (STORABLE_SIZE_OF(a) * i)
20+#define PTR_RINDEX(ptr,i,a) ptr `plusPtr` negate (STORABLE_SIZE_OF(a) * (i + 1))
2021
2122-- XXX If we know that the array is guaranteed to have size multiples of the
2223-- element size then we can use a simpler check saying "ptr < end". Since we
2324-- always allocate in multiples of elem we can use the simpler check and assert
2425-- the rigorous check.
25−#define PTR_VALID(ptr,end,a) ptr `plusPtr` SIZE_OF(a) <= end
26−#define PTR_INVALID(ptr,end,a) ptr `plusPtr` SIZE_OF(a) > end
26+#define PTR_VALID(ptr,end,a) ptr `plusPtr` STORABLE_SIZE_OF(a) <= end
27+#define PTR_INVALID(ptr,end,a) ptr `plusPtr` STORABLE_SIZE_OF(a) > end
2728
2829-------------------------------------------------------------------------------
2930-- Macros to access array indices
test/Streamly/Test/Data/Array.hs+3−2
@@ -10,6 +10,7 @@ module Streamly.Test.Data.Array (main) where
1010
1111import Data.Char (isLower)
1212import Data.List (sort)
13+import Data.Proxy (Proxy(..))
1314import Data.Word(Word8)
1415import Foreign.Storable (peek)
1516import GHC.Ptr (plusPtr)
@@ -196,7 +197,7 @@ testAsPtrUnsafeMA = do
196197
197198 where
198199
199− sizeOfInt = sizeOf (undefined :: Int)
200+ sizeOfInt = sizeOf (Proxy :: Proxy Int)
200201
201202 -- We need to be careful here. We assume Unboxed and Storable are compatible
202203 -- with each other. For Int, they are compatible.
@@ -210,7 +211,7 @@ testAsPtrUnsafeMA = do
210211reallocMA :: Property
211212reallocMA =
212213 let len = 10000
213− bSize = len * sizeOf (undefined :: Char)
214+ bSize = len * sizeOf (Proxy :: Proxy Char)
214215 in forAll (vectorOf len (arbitrary :: Gen Char)) $ \vec ->
215216 forAll (chooseInt (bSize - 2000, bSize + 2000)) $ \newBLen -> do
216217 arr <- MA.fromList vec
test/Streamly/Test/Data/Array/Common.hs+1−1
@@ -8,7 +8,7 @@ maxTestCount = 10
88#endif
99
1010allocOverhead :: Int
11−allocOverhead = 2 * sizeOf (undefined :: Int)
11+allocOverhead = 16
1212
1313-- XXX this should be in sync with the defaultChunkSize in Array code, or we
1414-- should expose that and use that. For fast testing we could reduce the
test/Streamly/Test/Data/Array/CommonImports.hs−2
@@ -1,6 +1,4 @@
11
2−import Streamly.Internal.Data.Unboxed (sizeOf)
3−
42import Test.Hspec.QuickCheck
53import Test.QuickCheck (Property, forAll, Gen, vectorOf, arbitrary, choose)
64import Test.QuickCheck.Monadic (monadicIO, assert, run)
test/Streamly/Test/Data/Unbox.hs+1−1
@@ -48,7 +48,7 @@ test v1 v2 = monadicIO $ do
4848
4949checkSizeOf :: forall a. Unbox a => Proxy a -> Int -> Property
5050checkSizeOf _ size = monadicIO $
51− assert (sizeOf (undefined :: a) == size)
51+ assert (sizeOf (Proxy :: Proxy a) == size)
5252
5353moduleName :: String
5454moduleName = "Data.Unbox"
test/Streamly/Test/FileSystem/Handle.hs+2−1
@@ -9,6 +9,7 @@
99module Streamly.Test.FileSystem.Handle (main) where
1010
1111import Data.Functor.Identity (runIdentity)
12+import Data.Proxy (Proxy(..))
1213import Data.Word (Word8)
1314import Streamly.Internal.Data.Unboxed (sizeOf)
1415import Streamly.Internal.Data.Stream (Stream)
@@ -36,7 +37,7 @@ import Test.Hspec as H
3637import Test.Hspec.QuickCheck
3738
3839allocOverhead :: Int
39−allocOverhead = 2 * sizeOf (undefined :: Int)
40+allocOverhead = 2 * sizeOf (Proxy :: Proxy Int)
4041
4142defaultChunkSize :: Int
4243defaultChunkSize = 32 * k - allocOverhead