@@ -119,7 +119,8 @@ module Streamly.Internal.Data.Array.Foreign.Mut.Type
120 -- * Memory Management
120 -- * Memory Management
121 , blockSize
121 , blockSize
122− , arrayChunkSize
122+ , arrayChunkBytes
123+ , allocBytesToElemCount
123 , realloc
124 , realloc
125 , resizeExp
126 , resizeExp
@@ -187,7 +188,6 @@ module Streamly.Internal.Data.Array.Foreign.Mut.Type
187 -- , appendSliceFrom
188 -- , appendSliceFrom
189 -- * Utilities
190 -- * Utilities
193 , c_memchr
193 , c_memchr
@@ -227,7 +227,7 @@ import Streamly.Internal.Data.SVar.Type (adaptState)
227import Streamly.Internal.Data.Unfold.Type (Unfold(..))
227import Streamly.Internal.Data.Unfold.Type (Unfold(..))
229import Streamly.Internal.System.IO
229import Streamly.Internal.System.IO
230− (defaultChunkSize, mkChunkSize, unsafeInlineIO)
230+ (defaultChunkSize, arrayPayloadSize, unsafeInlineIO)
232#ifdef DEVBUILD
232#ifdef DEVBUILD
233import qualified Data.Foldable as F
233import qualified Data.Foldable as F
@@ -272,13 +272,13 @@ foreign import ccall unsafe "string.h memcmp" c_memcmp
272 :: Ptr Word8 -> Ptr Word8 -> CSize -> IO CInt
272 :: Ptr Word8 -> Ptr Word8 -> CSize -> IO CInt
274-- | Given a 'Storable' type (unused first arg) and a number of bytes, return
274-- | Given a 'Storable' type (unused first arg) and a number of bytes, return
275−-- how many elements of that type will fit in after rounding the bytes up to
275+-- how many elements of that type will completely fit in those bytes.
276−-- the element size.
276+--
277{-# INLINE bytesToElemCount #-}
277{-# INLINE bytesToElemCount #-}
278bytesToElemCount :: Storable a => a -> Int -> Int
278bytesToElemCount :: Storable a => a -> Int -> Int
279bytesToElemCount x n =
279bytesToElemCount x n =
280 let elemSize = sizeOf x
280 let elemSize = sizeOf x
281− in n + elemSize - 1 `div` elemSize
281+ in n `div` elemSize
283-- XXX we are converting Int to CSize
283-- XXX we are converting Int to CSize
284memcpy :: Ptr Word8 -> Ptr Word8 -> Int -> IO ()
284memcpy :: Ptr Word8 -> Ptr Word8 -> Int -> IO ()
@@ -588,13 +588,30 @@ roundUpToPower2 :: Int -> Int
588roundUpToPower2 = undefined
588roundUpToPower2 = undefined
591−-- XXX remove mkChunkSize, it is not required.
591+-- | @allocBytesToBytes elem allocatedBytes@ returns the array size in bytes
592+-- such that the real allocation is less than or equal to @allocatedBytes@,
593+-- unless @allocatedBytes@ is less than the size of one array element in which
594+-- case it returns one element's size.
596+{-# INLINE allocBytesToBytes #-}
597+allocBytesToBytes :: forall a. Storable a => a -> Int -> Int
598+allocBytesToBytes _ n =
599+ max (arrayPayloadSize n) (sizeOf (undefined :: a))
601+-- | Given a 'Storable' type (unused first arg) and real allocation size
602+-- (including overhead), return how many elements of that type will completely
603+-- fit in it, returns at least 1.
605+{-# INLINE allocBytesToElemCount #-}
606+allocBytesToElemCount :: Storable a => a -> Int -> Int
607+allocBytesToElemCount x bytes =
608+ let n = bytesToElemCount x (allocBytesToBytes x bytes)
609+ in assert (n >= 1) n
592-- | The default chunk size by which the array creation routines increase the
611-- | The default chunk size by which the array creation routines increase the
593-- size of the array when the array is grown linearly.
612-- size of the array when the array is grown linearly.
594−--
613+arrayChunkBytes :: Int
595−{-# INLINE arrayChunkSize #-}
614+arrayChunkBytes = 1024
596−arrayChunkSize :: Int
597−arrayChunkSize = mkChunkSize 1024
599-------------------------------------------------------------------------------
616-------------------------------------------------------------------------------
@@ -708,7 +725,7 @@ snocWith allocSize arr x = liftIO $ do
709-- | The array is mutated to append an additional element to it. If there
726-- | The array is mutated to append an additional element to it. If there
710-- is no reserved space available in the array then it is reallocated to grow
727-- is no reserved space available in the array then it is reallocated to grow
711−-- it by 'arrayChunkSize' rounded up to 'blockSize' when the size becomes more
728+-- it by 'arrayChunkBytes' rounded up to 'blockSize' when the size becomes more
712-- than 'largeObjectThreshold'.
729-- than 'largeObjectThreshold'.
714-- Note that the returned array may be a mutated version of the original array.
731-- Note that the returned array may be a mutated version of the original array.
@@ -718,7 +735,7 @@ snocWith allocSize arr x = liftIO $ do
718-- /Pre-release/
735-- /Pre-release/
719{-# INLINE snocLinear #-}
736{-# INLINE snocLinear #-}
720snocLinear :: forall m a. (MonadIO m, Storable a) => Array a -> a -> m (Array a)
737snocLinear :: forall m a. (MonadIO m, Storable a) => Array a -> a -> m (Array a)
721−snocLinear = snocWith (+ arrayChunkSize)
738+snocLinear = snocWith (+ allocBytesToBytes (undefined :: a) arrayChunkBytes)
723-- XXX round it to next power of 2.
740-- XXX round it to next power of 2.
@@ -1162,9 +1179,11 @@ arraysOf n (D.Stream step state) =
1162-- XXX buffer to a list instead?
1179-- XXX buffer to a list instead?
1163-- | Buffer the stream into arrays in memory.
1180-- | Buffer the stream into arrays in memory.
1164{-# INLINE arrayStreamKFromStreamD #-}
1181{-# INLINE arrayStreamKFromStreamD #-}
1165−arrayStreamKFromStreamD :: (MonadIO m, Storable a) =>
1182+arrayStreamKFromStreamD :: forall m a. (MonadIO m, Storable a) =>
1166 D.Stream m a -> m (K.Stream m (Array a))
1183 D.Stream m a -> m (K.Stream m (Array a))
1167−arrayStreamKFromStreamD m = D.foldr K.cons K.nil $ arraysOf defaultChunkSize m
1184+arrayStreamKFromStreamD =
1185+ let n = allocBytesToElemCount (undefined :: a) defaultChunkSize
1186+ in D.foldr K.cons K.nil . arraysOf n
1169-------------------------------------------------------------------------------
1188-------------------------------------------------------------------------------
1170-- Streams of arrays - Flattening
1189-- Streams of arrays - Flattening
@@ -1725,7 +1744,7 @@ writeWith elemCount =
1726-- | Fold the whole input to a single array.
1745-- | Fold the whole input to a single array.
1728−-- Same as 'writeWith' using an initial array size of 'arrayChunkSize' bytes
1747+-- Same as 'writeWith' using an initial array size of 'arrayChunkBytes' bytes
1729-- rounded up to the element size.
1748-- rounded up to the element size.
1731-- /Caution! Do not use this on infinite streams./
1750-- /Caution! Do not use this on infinite streams./
@@ -1733,7 +1752,7 @@ writeWith elemCount =
1733-- @since 0.7.0
1752-- @since 0.7.0
1734{-# INLINE write #-}
1753{-# INLINE write #-}
1735write :: forall m a. (MonadIO m, Storable a) => Fold m a (Array a)
1754write :: forall m a. (MonadIO m, Storable a) => Fold m a (Array a)
1736−write = writeWith (bytesToElemCount (undefined :: a) arrayChunkSize)
1755+write = writeWith (allocBytesToElemCount (undefined :: a) arrayChunkBytes)
1738-------------------------------------------------------------------------------
1757-------------------------------------------------------------------------------
1739-- construct from streams, known size
1758-- construct from streams, known size