on master help sign in
Add serialization/deserialization using Unbox
350b6acHarendra Kumar
core/src/Streamly/Internal/Data/MutArray/Type.hs+133−3
@@ -213,6 +213,16 @@ module Streamly.Internal.Data.MutArray.Type
213 -- , appendSlice
213 -- , appendSlice
214 -- , appendSliceFrom
214 -- , appendSliceFrom
215
215
216+ -- ** Serialization using Unbox
217+ , pokeAppend
218+ , pokeAppendMay
219+ , pokeSkipUnsafe
220+
221+ -- ** Deserialization using Unbox
222+ , peekUncons
223+ , peekUnconsUnsafe
224+ , peekSkipUnsafe
225+
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
492 }
502 }
493
503
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.
497--
507--
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
1053
1063
1064+-------------------------------------------------------------------------------
1065+-- Serialization/Deserialization
1066+-------------------------------------------------------------------------------
1067+
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}
1075+
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
1079+-- element.
1080+--
1081+-- /Internal/
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
1086+
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})
1094+
1095+-- | Like 'pokeAppend' but does not grow the array when pre-allocated array
1096+-- capacity becomes full.
1097+--
1098+-- /Internal/
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
1107+
1108+{-# NOINLINE pokeWithRealloc #-}
1109+pokeWithRealloc :: forall m a. (MonadIO m, Unbox a) =>
1110+ (Int -> Int)
1111+ -> MutArray Word8
1112+ -> 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
1117+
1118+{-# INLINE pokeAppendWith #-}
1119+pokeAppendWith :: forall m a. (MonadIO m, Unbox a) =>
1120+ (Int -> Int)
1121+ -> MutArray Word8
1122+ -> 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
1129+
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.
1132+--
1133+-- Definition:
1134+--
1135+-- >>> pokeAppend arr x = MutArray.castUnsafe <$> MutArray.snoc (MutArray.castUnsafe arr) x
1136+--
1137+{-# INLINE pokeAppend #-}
1138+pokeAppend :: forall m a. (MonadIO m, Unbox a) =>
1139+ MutArray Word8 -> a -> m (MutArray Word8)
1140+pokeAppend = pokeAppendWith f
1141+
1142+ where
1143+
1144+ f oldSize =
1145+ if isPower2 oldSize
1146+ then oldSize * 2
1147+ else roundUpToPower2 oldSize * 2
1148+
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.
1152+--
1153+-- /Internal/
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 ())
1160+ liftIO $ do
1161+ r <- peekAt arrStart arrContents
1162+ return (r, MutArray arrContents start1 arrEnd arrBound)
1163+
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)
1170+
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)
1178+ if start1 > arrEnd
1179+ then return (Nothing, arr)
1180+ else liftIO $ do
1181+ r <- peekAt arrStart arrContents
1182+ return (Just r, MutArray arrContents start1 arrEnd arrBound)
1183+
1054-------------------------------------------------------------------------------
1184-------------------------------------------------------------------------------
1055-- Random reads
1185-- Random reads
1056-------------------------------------------------------------------------------
1186-------------------------------------------------------------------------------