@@ -213,6 +213,16 @@ module Streamly.Internal.Data.MutArray.Type
213 -- , appendSlice
213 -- , appendSlice
214 -- , appendSliceFrom
214 -- , appendSliceFrom
216+ -- ** Serialization using Unbox
221+ -- ** Deserialization using Unbox
216 -- Arrays of arrays
226 -- Arrays of arrays
217 -- We can add dimensionality parameter to the array type to get
227 -- We can add dimensionality parameter to the array type to get
218 -- multidimensional arrays. Multidimensional arrays would just be a
228 -- multidimensional arrays. Multidimensional arrays would just be a
@@ -491,9 +501,9 @@ newBytesAs ps bytes = do
491 , arrBound = bytes
501 , arrBound = bytes
494−-- | Allocates a pinned empty array that can hold 'count' items. The memory of
504+-- | Allocates a pinned empty array that with a reserved capacity of bytes.
495−-- the array is uninitialized and the allocation is aligned as per the
505+-- The memory of the array is uninitialized and the allocation is aligned as
496−-- 'Unboxed' instance of the type.
506+-- per the 'Unboxed' instance of the type.
498-- /Pre-release/
508-- /Pre-release/
499{-# INLINE pinnedNewBytes #-}
509{-# INLINE pinnedNewBytes #-}
@@ -1051,6 +1061,126 @@ snoc = snocWith f
1051 then oldSize * 2
1061 then oldSize * 2
1052 else roundUpToPower2 oldSize * 2
1062 else roundUpToPower2 oldSize * 2
1064+-------------------------------------------------------------------------------
1065+-- Serialization/Deserialization
1066+-------------------------------------------------------------------------------
1068+{-# INLINE pokeNewEnd #-}
1069+pokeNewEnd :: (MonadIO m, Unbox a) =>
1070+ Int -> MutArray Word8 -> a -> m (MutArray Word8)
1071+pokeNewEnd newEnd arr@MutArray{..} x = liftIO $ do
1072+ assert (newEnd <= arrBound) (return ())
1073+ liftIO $ pokeAt arrEnd arrContents x
1074+ return $ arr {arrEnd = newEnd}
1076+-- | Really really unsafe, unboxes a Haskell type and appends the resulting
1077+-- bytes to the byte array, may cause silent data corruption or if you are
1078+-- lucky a segfault if the array does not have enough space to append the
1082+{-# INLINE pokeAppendUnsafe #-}
1083+pokeAppendUnsafe :: forall m a. (MonadIO m, Unbox a) =>
1084+ MutArray Word8 -> a -> m (MutArray Word8)
1085+pokeAppendUnsafe arr@MutArray{..} = pokeNewEnd (arrEnd + SIZE_OF(a)) arr
1087+-- | Skip the specified number of bytes in the array. The data in the skipped
1088+-- region remains uninitialzed.
1089+{-# INLINE pokeSkipUnsafe #-}
1090+pokeSkipUnsafe :: Int -> MutArray Word8 -> MutArray Word8
1091+pokeSkipUnsafe n arr@MutArray{..} = do
1092+ let newEnd = arrEnd + n
1093+ in assert (newEnd <= arrBound) (arr {arrEnd = newEnd})
1095+-- | Like 'pokeAppend' but does not grow the array when pre-allocated array
1096+-- capacity becomes full.
1099+{-# INLINE pokeAppendMay #-}
1100+pokeAppendMay :: forall m a. (MonadIO m, Unbox a) =>
1101+ MutArray Word8 -> a -> m (Maybe (MutArray Word8))
1102+pokeAppendMay arr@MutArray{..} x = liftIO $ do
1103+ let newEnd = arrEnd + SIZE_OF(a)
1104+ if newEnd <= arrBound
1105+ then Just <$> pokeNewEnd newEnd arr x
1106+ else return Nothing
1108+{-# NOINLINE pokeWithRealloc #-}
1109+pokeWithRealloc :: forall m a. (MonadIO m, Unbox a) =>
1113+ -> m (MutArray Word8)
1114+pokeWithRealloc sizer arr x = do
1115+ arr1 <- liftIO $ reallocWith "pokeWithRealloc" sizer (SIZE_OF(a)) arr
1116+ pokeAppendUnsafe arr1 x
1118+{-# INLINE pokeAppendWith #-}
1119+pokeAppendWith :: forall m a. (MonadIO m, Unbox a) =>
1123+ -> m (MutArray Word8)
1124+pokeAppendWith allocSize arr x = liftIO $ do
1125+ let newEnd = arrEnd arr + SIZE_OF(a)
1126+ if newEnd <= arrBound arr
1127+ then pokeNewEnd newEnd arr x
1128+ else pokeWithRealloc allocSize arr x
1130+-- | Unbox a Haskell type and append the resulting bytes to a mutable byte
1131+-- array. The array is grown exponentially when more space is needed.
1135+-- >>> pokeAppend arr x = MutArray.castUnsafe <$> MutArray.snoc (MutArray.castUnsafe arr) x
1137+{-# INLINE pokeAppend #-}
1138+pokeAppend :: forall m a. (MonadIO m, Unbox a) =>
1139+ MutArray Word8 -> a -> m (MutArray Word8)
1140+pokeAppend = pokeAppendWith f
1145+ if isPower2 oldSize
1147+ else roundUpToPower2 oldSize * 2
1149+-- | Really really unsafe, create a Haskell value from an unboxed byte array,
1150+-- does not check if the array is big enough, may return garbage or if you are
1151+-- lucky may cause a segfault.
1154+{-# INLINE peekUnconsUnsafe #-}
1155+peekUnconsUnsafe :: forall m a. (MonadIO m, Unbox a) =>
1156+ MutArray Word8 -> m (a, MutArray Word8)
1157+peekUnconsUnsafe MutArray{..} = do
1158+ let start1 = arrStart + SIZE_OF(a)
1159+ assert (start1 <= arrEnd) (return ())
1161+ r <- peekAt arrStart arrContents
1162+ return (r, MutArray arrContents start1 arrEnd arrBound)
1164+-- | Discard the specified number of bytes in the array.
1165+{-# INLINE peekSkipUnsafe #-}
1166+peekSkipUnsafe :: Int -> MutArray Word8 -> MutArray Word8
1167+peekSkipUnsafe n MutArray{..} =
1168+ let start1 = arrStart + n
1169+ in assert (start1 <= arrEnd) (MutArray arrContents start1 arrEnd arrBound)
1171+-- | Create a Haskell value from its unboxed representation from the head of a
1172+-- byte array, return the value and the remaining array.
1173+{-# INLINE peekUncons #-}
1174+peekUncons :: forall m a. (MonadIO m, Unbox a) =>
1175+ MutArray Word8 -> m (Maybe a, MutArray Word8)
1176+peekUncons arr@MutArray{..} = do
1177+ let start1 = arrStart + SIZE_OF(a)
1179+ then return (Nothing, arr)
1181+ r <- peekAt arrStart arrContents
1182+ return (Just r, MutArray arrContents start1 arrEnd arrBound)
1054-------------------------------------------------------------------------------
1184-------------------------------------------------------------------------------
1055-- Random reads
1185-- Random reads
1056-------------------------------------------------------------------------------
1186-------------------------------------------------------------------------------