@@ -100,6 +100,7 @@ touch :: MutableByteArray -> IO ()
100touch (MutableByteArray contents) =
100touch (MutableByteArray contents) =
101 IO $ \s -> case touch# contents s of s' -> (# s', () #)
101 IO $ \s -> case touch# contents s of s' -> (# s', () #)
103-- | Return the size of the array in bytes.
104-- | Return the size of the array in bytes.
104{-# INLINE sizeOfMutableByteArray #-}
105{-# INLINE sizeOfMutableByteArray #-}
105sizeOfMutableByteArray :: MutableByteArray -> IO Int
106sizeOfMutableByteArray :: MutableByteArray -> IO Int
@@ -107,6 +108,7 @@ sizeOfMutableByteArray (MutableByteArray arr) =
107 IO $ \s ->
108 IO $ \s ->
108 case getSizeofMutableByteArray# arr s of
109 case getSizeofMutableByteArray# arr s of
109 (# s1, i #) -> (# s1, I# i #)
110 (# s1, i #) -> (# s1, I# i #)
111--------------------------------------------------------------------------------
113--------------------------------------------------------------------------------
112-- Creation
114-- Creation
@@ -282,7 +284,9 @@ unpin arr@(MutableByteArray marr#) =
282-- The 'peekByteIndex' read operation converts a Haskell type from its unboxed
284-- The 'peekByteIndex' read operation converts a Haskell type from its unboxed
283-- representation stored in a mutable byte array, while the 'pokeByteIndex'
285-- representation stored in a mutable byte array, while the 'pokeByteIndex'
284-- write operation serializes a Haskell data type to its byte representation in
286-- write operation serializes a Haskell data type to its byte representation in
285−-- the mutable byte array.
287+-- the mutable byte array. These operations do not check the bounds of the
288+-- array, the user of the type class is expected to check the bounds before
289+-- peeking or poking.
287-- Instances can be derived via Generics or Template Haskell. Note that the
291-- Instances can be derived via Generics or Template Haskell. Note that the
288-- data type must be non-recursive.
292-- data type must be non-recursive.
@@ -326,10 +330,12 @@ unpin arr@(MutableByteArray marr#) =
326-- instance Unbox Object where
330-- instance Unbox Object where
327-- sizeOf _ = 16
331-- sizeOf _ = 16
328-- peekByteIndex i arr = do
332-- peekByteIndex i arr = do
333+-- -- Check the array bounds
329-- x0 <- peekByteIndex i arr
334-- x0 <- peekByteIndex i arr
330-- x1 <- peekByteIndex (i + 8) arr
335-- x1 <- peekByteIndex (i + 8) arr
331-- return $ Object x0 x1
336-- return $ Object x0 x1
332-- pokeByteIndex i arr (Object x0 x1) = do
337-- pokeByteIndex i arr (Object x0 x1) = do
338+-- -- Check the array bounds
333-- pokeByteIndex i arr x0
339-- pokeByteIndex i arr x0
334-- pokeByteIndex (i + 8) arr x1
340-- pokeByteIndex (i + 8) arr x1
@@ -587,6 +593,12 @@ readUnsafe = Peeker (Builder step)
587 step :: forall a. Unbox a => BoundedPtr -> IO (BoundedPtr, a)
593 step :: forall a. Unbox a => BoundedPtr -> IO (BoundedPtr, a)
588 step (BoundedPtr arr pos end) = do
594 step (BoundedPtr arr pos end) = do
589 let next = pos + sizeOf (Proxy :: Proxy a)
595 let next = pos + sizeOf (Proxy :: Proxy a)
598+ $ error $ "readUnsafe: reading beyond limit. next = "
600+ ++ " end = " ++ show end
590 r <- peekByteIndex pos arr
602 r <- peekByteIndex pos arr
591 return (BoundedPtr arr next end, r)
603 return (BoundedPtr arr next end, r)
@@ -600,7 +612,10 @@ read = Peeker (Builder step)
600 step :: forall a. Unbox a => BoundedPtr -> IO (BoundedPtr, a)
612 step :: forall a. Unbox a => BoundedPtr -> IO (BoundedPtr, a)
601 step (BoundedPtr arr pos end) = do
613 step (BoundedPtr arr pos end) = do
602 let next = pos + sizeOf (Proxy :: Proxy a)
614 let next = pos + sizeOf (Proxy :: Proxy a)
603− when (next > end) $ error "peekObject reading beyond limit"
616+ $ error $ "read: reading beyond limit. next = "
618+ ++ " end = " ++ show end
604 r <- peekByteIndex pos arr
619 r <- peekByteIndex pos arr
605 return (BoundedPtr arr next end, r)
620 return (BoundedPtr arr next end, r)
@@ -614,10 +629,12 @@ skipByte = Peeker (Builder step)
614 step :: BoundedPtr -> IO (BoundedPtr, ())
629 step :: BoundedPtr -> IO (BoundedPtr, ())
615 step (BoundedPtr arr pos end) = do
630 step (BoundedPtr arr pos end) = do
616 let next = pos + 1
631 let next = pos + 1
617 when (next > end)
633 when (next > end)
618 $ error $ "skipByte: reading beyond limit. next = "
634 $ error $ "skipByte: reading beyond limit. next = "
619 ++ show next
635 ++ show next
620 ++ " end = " ++ show end
636 ++ " end = " ++ show end
621 return (BoundedPtr arr next end, ())
638 return (BoundedPtr arr next end, ())
623{-# INLINE runPeeker #-}
640{-# INLINE runPeeker #-}
@@ -638,6 +655,12 @@ runPeeker (Peeker (Builder f)) ptr = fmap snd (f ptr)
638pokeBoundedPtrUnsafe :: forall a. Unbox a => a -> BoundedPtr -> IO BoundedPtr
655pokeBoundedPtrUnsafe :: forall a. Unbox a => a -> BoundedPtr -> IO BoundedPtr
639pokeBoundedPtrUnsafe a (BoundedPtr arr pos end) = do
656pokeBoundedPtrUnsafe a (BoundedPtr arr pos end) = do
640 let next = pos + sizeOf (Proxy :: Proxy a)
657 let next = pos + sizeOf (Proxy :: Proxy a)
660+ $ error $ "pokeBoundedPtrUnsafe: reading beyond limit. next = "
662+ ++ " end = " ++ show end
641 pokeByteIndex pos arr a
664 pokeByteIndex pos arr a
642 return (BoundedPtr arr next end)
665 return (BoundedPtr arr next end)
@@ -669,7 +692,10 @@ type family ArityCheck (b :: Bool) :: Constraint where
670-- Type constraint to restrict the sum type arity so that the constructor tag
693-- Type constraint to restrict the sum type arity so that the constructor tag
671-- can fit in a single byte.
694-- can fit in a single byte.
695+-- Note that Arity starts from 1 and constructor tags start from 0. So if max
696+-- arity is 256 then max constructor tag would be 255.
697+-- XXX Use variable length encoding to support more than 256 constructors.
672−type MaxArity256 n = ArityCheck (n <=? 255)
698+type MaxArity256 n = ArityCheck (n <=? 256)
674--------------------------------------------------------------------------------
700--------------------------------------------------------------------------------
675-- Generic Deriving of Unbox instance
701-- Generic Deriving of Unbox instance
@@ -735,8 +761,8 @@ instance (MaxArity256 (SumArity (f :+: g)), SizeOfRepSum f, SizeOfRepSum g) =>
736 -- The size of a sum type is the max of any of the constructor size.
762 -- The size of a sum type is the max of any of the constructor size.
737 -- sizeOfRepSum type class operation is used here instead of sizeOfRep so
763 -- sizeOfRepSum type class operation is used here instead of sizeOfRep so
738− -- that we add the constructor index byte only for the first time and avoid
764+ -- that we account the constructor index byte only for the first time and
739− -- including it for the subsequent sum constructors.
765+ -- avoid including it for the subsequent sum constructors.
740 {-# INLINE sizeOfRep #-}
766 {-# INLINE sizeOfRep #-}
741 sizeOfRep _ =
767 sizeOfRep _ =
742 -- One byte for the constructor id and then the constructor value.
768 -- One byte for the constructor id and then the constructor value.
@@ -753,6 +779,12 @@ instance (MaxArity256 (SumArity (f :+: g)), SizeOfRepSum f, SizeOfRepSum g) =>
753-- elements to make the size as 1. Or we can disallow arrays with elements
779-- elements to make the size as 1. Or we can disallow arrays with elements
754-- having size 0.
780-- having size 0.
784+-- data B = B -- one byte
785+-- data A = A B -- one byte
786+-- data X = X1 | X2 -- one byte (constructor tag only)
756{-# INLINE genericSizeOf #-}
788{-# INLINE genericSizeOf #-}
757genericSizeOf :: forall a. (SizeOfRep (Rep a)) => Proxy a -> Int
789genericSizeOf :: forall a. (SizeOfRep (Rep a)) => Proxy a -> Int
758genericSizeOf _ =
790genericSizeOf _ =
@@ -772,7 +804,7 @@ instance PokeRep f => PokeRep (M1 i c f) where
773instance Unbox a => PokeRep (K1 i a) where
805instance Unbox a => PokeRep (K1 i a) where
774 {-# INLINE pokeRep #-}
806 {-# INLINE pokeRep #-}
775− pokeRep a = pokeBoundedPtr (unK1 a)
807+ pokeRep a = pokeBoundedPtrUnsafe (unK1 a)
777instance PokeRep V1 where
809instance PokeRep V1 where
778 {-# INLINE pokeRep #-}
810 {-# INLINE pokeRep #-}
@@ -795,8 +827,8 @@ class KnownNat n => PokeRepSum (n :: Nat) (f :: Type -> Type) where
795instance (KnownNat n, PokeRep a) => PokeRepSum n (C1 c a) where
827instance (KnownNat n, PokeRep a) => PokeRepSum n (C1 c a) where
796 {-# INLINE pokeRepSum #-}
828 {-# INLINE pokeRepSum #-}
797 pokeRepSum _ x ptr = do
829 pokeRepSum _ x ptr = do
798− pokeBoundedPtr (fromInteger (natVal (Proxy :: Proxy n)) :: Word8) ptr
830+ let tag = fromInteger (natVal (Proxy :: Proxy n)) :: Word8
799− >>= pokeRep x
831+ pokeBoundedPtrUnsafe tag ptr >>= pokeRep x
801instance (PokeRepSum n f, PokeRepSum (n + SumArity f) g)
833instance (PokeRepSum n f, PokeRepSum (n + SumArity f) g)
802 => PokeRepSum n (f :+: g) where
834 => PokeRepSum n (f :+: g) where
@@ -827,14 +859,20 @@ genericPokeByteIndex :: (Generic a, PokeRep (Rep a)) =>
827 MutableByteArray -> Int -> a -> IO ()
859 MutableByteArray -> Int -> a -> IO ()
828genericPokeByteIndex arr index x = do
860genericPokeByteIndex arr index x = do
829 -- XXX Should we use unsafe poke?
861 -- XXX Should we use unsafe poke?
830 end <- sizeOfMutableByteArray arr
863 end <- sizeOfMutableByteArray arr
831 genericPokeObj x (BoundedPtr arr index end)
864 genericPokeObj x (BoundedPtr arr index end)
866+ genericPokeObj x (BoundedPtr arr index undefined)
833--------------------------------------------------------------------------------
869--------------------------------------------------------------------------------
834-- Generic peek
870-- Generic peek
835--------------------------------------------------------------------------------
871--------------------------------------------------------------------------------
837class PeekRep (f :: Type -> Type) where
873class PeekRep (f :: Type -> Type) where
874+ -- Like pokeRep, we can use the following signature instead of using Peeker
875+ -- peekRep :: BoundedPtr -> IO (BoundedPtr, f a)
838 peekRep :: Peeker (f x)
876 peekRep :: Peeker (f x)
840instance PeekRep f => PeekRep (M1 i c f) where
878instance PeekRep f => PeekRep (M1 i c f) where
@@ -843,7 +881,7 @@ instance PeekRep f => PeekRep (M1 i c f) where
844instance Unbox a => PeekRep (K1 i a) where
882instance Unbox a => PeekRep (K1 i a) where
845 {-# INLINE peekRep #-}
883 {-# INLINE peekRep #-}
846− peekRep = fmap K1 read
884+ peekRep = fmap K1 readUnsafe
848instance PeekRep V1 where
886instance PeekRep V1 where
849 {-# INLINE peekRep #-}
887 {-# INLINE peekRep #-}
@@ -865,6 +903,11 @@ class KnownNat n => PeekRepSum (n :: Nat) (f :: Type -> Type) where
866instance (KnownNat n, PeekRep a) => PeekRepSum n (C1 c a) where
904instance (KnownNat n, PeekRep a) => PeekRepSum n (C1 c a) where
867 {-# INLINE peekRepSum #-}
905 {-# INLINE peekRepSum #-}
906+ peekRepSum _ _ = peekRep
908+ -- These error checks are expensive, to avoid these
909+ -- we validate the max value of the tag in peekRep.
910+ -- XXX Add tests to cover all cases
868 peekRepSum _ tag
911 peekRepSum _ tag
869 | tag == curTag = peekRep
912 | tag == curTag = peekRep
870 | tag > curTag =
913 | tag > curTag =
@@ -876,6 +919,7 @@ instance (KnownNat n, PeekRep a) => PeekRepSum n (C1 c a) where
878 curTag = fromInteger (natVal (Proxy :: Proxy n))
921 curTag = fromInteger (natVal (Proxy :: Proxy n))
880instance (PeekRepSum n f, PeekRepSum (n + SumArity f) g)
924instance (PeekRepSum n f, PeekRepSum (n + SumArity f) g)
881 => PeekRepSum n (f :+: g) where
925 => PeekRepSum n (f :+: g) where
@@ -892,12 +936,21 @@ instance (PeekRepSum n f, PeekRepSum (n + SumArity f) g)
893-------------------------------------------------------------------------------
937-------------------------------------------------------------------------------
895−instance (MaxArity256 (SumArity (f :+: g)), PeekRepSum 0 (f :+: g))
939+instance ( MaxArity256 (SumArity (f :+: g))
940+ , KnownNat (SumArity (f :+: g))
941+ , PeekRepSum 0 (f :+: g))
896 => PeekRep (f :+: g) where
942 => PeekRep (f :+: g) where
897 {-# INLINE peekRep #-}
943 {-# INLINE peekRep #-}
898 peekRep = do
944 peekRep = do
899− tag <- read
945+ tag :: Word8 <- readUnsafe
946+ -- XXX test with 256 and more constructors
948+ fromInteger (natVal (Proxy :: Proxy (SumArity (f :+: g))))
949+ when (fromIntegral tag >= arity)
950+ $ error $ "peek: Tag " ++ show tag
951+ ++ " is greater than the max tag " ++ show (arity - 1)
952+ ++ " for the data type"
900− peekRepSum (Proxy :: Proxy 0) tag
953+ peekRepSum (Proxy :: Proxy 0) tag -- DataKinds
902{-# INLINE genericPeeker #-}
955{-# INLINE genericPeeker #-}
903genericPeeker :: (Generic a, PeekRep (Rep a)) => Peeker a
956genericPeeker :: (Generic a, PeekRep (Rep a)) => Peeker a
@@ -912,5 +965,9 @@ genericPeekByteIndex :: (Generic a, PeekRep (Rep a)) =>
912 MutableByteArray -> Int -> IO a
965 MutableByteArray -> Int -> IO a
913genericPeekByteIndex arr index = do
966genericPeekByteIndex arr index = do
914 -- XXX Should we use unsafe peek?
967 -- XXX Should we use unsafe peek?
915 end <- sizeOfMutableByteArray arr
969 end <- sizeOfMutableByteArray arr
916 genericPeekBoundedPtr (BoundedPtr arr index end)
970 genericPeekBoundedPtr (BoundedPtr arr index end)
972+ genericPeekBoundedPtr (BoundedPtr arr index undefined)