@@ -28,57 +28,80 @@
29module Streamly.Internal.Data.MutArray.Type
29module Streamly.Internal.Data.MutArray.Type
31− -- * Type
31+ -- ** Type
32 -- $arrayNotes
32 -- $arrayNotes
33 MutArray (..)
33 MutArray (..)
34− , MutableByteArray
34+
35− , touch
35+ -- ** Conversion
36+ -- *** Pinned and Unpinned
38 , isPinned
39 , isPinned
40− -- * Constructing and Writing
41+ -- ** Casting
43+ , castUnsafe -- XXX unsafeCast
41 -- ** Construction
48 -- ** Construction
52+ -- | New arrays are always empty arrays with some reserve capacity to
53+ -- extend the length without reallocating.
55+ , newArrayWith -- emptyAlignedWith
57+ , pinnedNewAligned -- XXX not required
58+ -- , new -- uninitialized array of specified length
44− -- *** Uninitialized Arrays
64+ -- *** Slicing
45− , pinnedNew
65+ -- | Get a subarray without copying
46− , pinnedNewBytes
66+ , getSliceUnsafe -- XXX unsafeGetSlice
47− , pinnedNewAligned
67+ , getSlice
48− , new
68+ , splitAt -- XXX should be able to express using getSlice
49− , newArrayWith
69+ , breakOn
51− -- *** From streams
71+ -- *** Stream Folds
52 , ArrayUnsafe (..)
72 , ArrayUnsafe (..)
53− , writeNWithUnsafe
73+ , unsafeCreateOfWith
54− , writeNWith
74+ , unsafeCreateOf
55− , writeNUnsafe
75+ , unsafePinnedCreateOf
56− , pinnedWriteNUnsafe
76+ , pinnedCreateOf
57− , writeN
77+ , createOfWith
58− , pinnedWriteN
78+ , createOf
59− , pinnedWriteNAligned
79+ , revCreateOf
61− , writeWith
81+ , pinnedCreate
62− , write
82+ , createWith
63− , pinnedWrite
83+ , create
68− -- ** From containers
86+ -- *** From containers
69 , fromListN
87 , fromListN
70 , pinnedFromListN
88 , pinnedFromListN
71 , fromList
89 , fromList
72 , pinnedFromList
90 , pinnedFromList
73 , fromListRevN
91 , fromListRevN
74 , fromListRev
92 , fromListRev
75− , fromStreamDN
93+ , fromStreamN
76− , fromStreamD
94+ , fromStream
77 , fromPureStream
96 , fromPureStream
100+ , fromChunksRealloced -- fromSmallChunks
79− -- * Random writes
102+ -- ** Random writes
80 , putIndex
103 , putIndex
81− , putIndexUnsafe
104+ , putIndexUnsafe -- XXX unsafePutIndex
82 , putIndices
105 , putIndices
83 -- , putFromThenTo
106 -- , putFromThenTo
84 -- , putFrom -- start writing at the given position
107 -- , putFrom -- start writing at the given position
@@ -86,78 +109,71 @@ module Streamly.Internal.Data.MutArray.Type
86 -- , putFromTo
109 -- , putFromTo
87 -- , putFromRev
110 -- , putFromRev
88 -- , putUptoRev
111 -- , putUptoRev
89− , modifyIndexUnsafe
112+ , modifyIndexUnsafe -- XXX unsafeModifyIndex
90 , modifyIndex
113 , modifyIndex
91 , modifyIndices
114 , modifyIndices
93 , swapIndices
116 , swapIndices
94 , unsafeSwapIndices
117 , unsafeSwapIndices
96− -- * Growing and Shrinking
119+ -- ** Reading
97− -- Arrays grow only at the end, though it is possible to grow on both sides
98− -- and therefore have a cons as well as snoc. But that will require two
99− -- bounds in the array representation.
101− -- ** Appending elements
108− -- ** Appending streams
109− , writeAppendNUnsafe
114− -- * Eliminating and Reading
121+ -- *** Indexing
116− -- ** To streams
123+ , getIndexUnsafe -- XXX unsafeGetIndex
117− , reader
124+ -- , getFromThenTo
118− , readerRevWith
125+ , getIndexRev -- getRevIndex?
119− , readerRev
126+ , indexReader
121− -- ** To containers
129+ -- *** To Streams
127 , readRev
131 , readRev
128 , toStreamK
134 , toStreamK
129 , toStreamKRev
136 , toStreamKRev
139+ -- *** To Containers
132 -- experimental
143 -- experimental
133 , producerWith
144 , producerWith
134 , producer
145 , producer
136− -- ** Random reads
147+ , reader
137− , getIndex
148+ , readerRevWith
138− , getIndexUnsafe
149+ , readerRev
144− -- * Memory Management
147− , allocBytesToElemCount
151+ -- ** Size and Capacity
153− -- * Size
152+ -- *** Size
155 , byteLength
154 , byteLength
156 -- , capacity
157 -- , capacity
157 , byteCapacity
158 , byteCapacity
158 , bytesFree
159 , bytesFree
161+ -- *** Capacity Management
164+ , allocBytesToElemCount
165+ , realloc -- this is "resize"
160− -- * In-place Mutation Algorithms
176+ -- ** In-place Mutation Algorithms
162 , reverse
178 , reverse
163 , permute
179 , permute
@@ -167,62 +183,121 @@ module Streamly.Internal.Data.MutArray.Type
167 , mergeBy
183 , mergeBy
170− -- * Casting
186+ -- ** Growing and Shrinking
171− , cast
187+ -- | Arrays grow only at the end, though it is possible to grow on both
172− , castUnsafe
188+ -- sides and therefore have a cons as well as snoc. But that will require
173− , asBytes
189+ -- both lower and upper bound in the array representation.
181− -- * Arrays of arrays
182− -- We can add dimensionality parameter to the array type to get
183− -- multidimensional arrays. Multidimensional arrays would just be a
184− -- convenience wrapper on top of single dimensional arrays.
186− -- | Operations dealing with multiple arrays, streams of arrays or
191+ -- *** Appending elements
187− -- multidimensional array representations.
192+ , snocWith
189− -- ** Construct from streams
194+ , snocLinear
190− , chunksOf
195+ , snocMay
191− , pinnedChunksOf
196+ , snocUnsafe -- XXX unsafeSnoc
194− -- ** Eliminate to streams
199− -- ** Construct from arrays
200− -- get chunks without copying
203− -- , getSlicesFromLenN
204− , splitAt -- XXX should be able to express using getSlice
207− -- ** Cloning arrays
198+ -- *** Appending streams
208− , clone
199+ , unsafeAppendN
209− , pinnedClone
200+ , appendN
211− -- ** Appending arrays
204+ -- *** Appending arrays
212 , spliceCopy
205 , spliceCopy
213 , spliceWith
206 , spliceWith
215 , spliceExp
208 , spliceExp
216− , spliceUnsafe
209+ , spliceUnsafe -- XXX unsafeSplice
217 -- , putSlice
210 -- , putSlice
218 -- , appendSlice
211 -- , appendSlice
219 -- , appendSliceFrom
212 -- , appendSliceFrom
214+ -- ** Serialization using Unbox
217+ , pokeSkipUnsafe -- unsafePokeSkip
219+ -- ** Deserialization using Unbox
221+ , peekUnconsUnsafe -- unsafePeekUncons
222+ , peekSkipUnsafe -- unsafePeekSkip
225+ -- We can add dimensionality parameter to the array type to get
226+ -- multidimensional arrays. Multidimensional arrays would just be a
227+ -- convenience wrapper on top of single dimensional arrays.
229+ -- ** Streams of Arrays
231+ -- | Group a stream into arrays.
237+ -- | Split an array into slices.
239+ -- , getSlicesFromLenN
244+ -- | Append the arrays in a stream to form a stream of elements.
251+ -- | Append the arrays in a stream to form a stream of larger arrays.
221− -- * Utilities
263+ -- ** Utilities
222 , roundUpToPower2
264 , roundUpToPower2
225 , c_memchr
267 , c_memchr
286+ , writeAppendNUnsafe
293+ , pinnedWriteNUnsafe
296+ , pinnedWriteNAligned -- XXX not required
@@ -233,49 +308,52 @@ where
234import Control.Monad (when, void)
309import Control.Monad (when, void)
235import Control.Monad.IO.Class (MonadIO(..))
310import Control.Monad.IO.Class (MonadIO(..))
311+import Data.Bifunctor (first)
236import Data.Bits (shiftR, (.|.), (.&.))
312import Data.Bits (shiftR, (.|.), (.&.))
237import Data.Functor.Identity (Identity(..))
313import Data.Functor.Identity (Identity(..))
238import Data.Proxy (Proxy(..))
314import Data.Proxy (Proxy(..))
239import Data.Word (Word8)
315import Data.Word (Word8)
240import Foreign.C.Types (CSize(..), CInt(..))
316import Foreign.C.Types (CSize(..), CInt(..))
241import Foreign.Ptr (plusPtr, minusPtr, nullPtr)
317import Foreign.Ptr (plusPtr, minusPtr, nullPtr)
242−import Streamly.Internal.Data.Unbox
318+import Streamly.Internal.Data.MutByteArray.Type
243− ( MutableByteArray(..)
319+ ( MutByteArray(..)
245 , PinnedState(..)
320 , PinnedState(..)
246 , getMutableByteArray#
321 , getMutableByteArray#
248 , putSliceUnsafe
322 , putSliceUnsafe
324+import Streamly.Internal.Data.Unbox (Unbox(..))
250import GHC.Base
325import GHC.Base
252 , Int(..)
327 , Int(..)
253− , byteArrayContents#
254 , compareByteArrays#
328 , compareByteArrays#
255 , copyMutableByteArray#
329 , copyMutableByteArray#
257import GHC.Base (noinline)
331import GHC.Base (noinline)
258−import GHC.Exts (unsafeCoerce#)
332+import GHC.Exts (unsafeCoerce#, Addr#)
259import GHC.Ptr (Ptr(..))
333import GHC.Ptr (Ptr(..))
261import Streamly.Internal.Data.Fold.Type (Fold(..))
335import Streamly.Internal.Data.Fold.Type (Fold(..))
262import Streamly.Internal.Data.Producer.Type (Producer (..))
336import Streamly.Internal.Data.Producer.Type (Producer (..))
263import Streamly.Internal.Data.Stream.Type (Stream)
337import Streamly.Internal.Data.Stream.Type (Stream)
338+import Streamly.Internal.Data.Parser.Type (Parser (..))
264import Streamly.Internal.Data.StreamK.Type (StreamK)
339import Streamly.Internal.Data.StreamK.Type (StreamK)
265import Streamly.Internal.Data.SVar.Type (adaptState, defState)
340import Streamly.Internal.Data.SVar.Type (adaptState, defState)
341+import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
266import Streamly.Internal.Data.Unfold.Type (Unfold(..))
342import Streamly.Internal.Data.Unfold.Type (Unfold(..))
267import Streamly.Internal.System.IO (arrayPayloadSize, defaultChunkSize)
343import Streamly.Internal.System.IO (arrayPayloadSize, defaultChunkSize)
269import qualified Streamly.Internal.Data.Fold.Type as FL
345import qualified Streamly.Internal.Data.Fold.Type as FL
346+import qualified Streamly.Internal.Data.MutByteArray.Type as Unboxed
347+import qualified Streamly.Internal.Data.Parser.Type as Parser
348+-- import qualified Streamly.Internal.Data.Fold.Type as Fold
270import qualified Streamly.Internal.Data.Producer as Producer
349import qualified Streamly.Internal.Data.Producer as Producer
271import qualified Streamly.Internal.Data.Stream.Type as D
350import qualified Streamly.Internal.Data.Stream.Type as D
272import qualified Streamly.Internal.Data.Stream.Lift as D
351import qualified Streamly.Internal.Data.Stream.Lift as D
273import qualified Streamly.Internal.Data.StreamK.Type as K
352import qualified Streamly.Internal.Data.StreamK.Type as K
274−import qualified Streamly.Internal.Data.Unbox as Unboxed
275import qualified Prelude
353import qualified Prelude
277import Prelude hiding
355import Prelude hiding
278− (Foldable(..), read, unlines, splitAt, reverse, truncate)
356+ (Foldable(..), concat, read, unlines, splitAt, reverse, truncate)
280#include "DocTestDataMutArray.hs"
358#include "DocTestDataMutArray.hs"
@@ -283,6 +361,7 @@ import Prelude hiding
283-- Foreign helpers
361-- Foreign helpers
284-------------------------------------------------------------------------------
362-------------------------------------------------------------------------------
364+-- NOTE: Have to be "ccall unsafe" so that we can pass unpinned memory to these
286foreign import ccall unsafe "string.h memcpy" c_memcpy
365foreign import ccall unsafe "string.h memcpy" c_memcpy
287 :: Ptr Word8 -> Ptr Word8 -> CSize -> IO (Ptr Word8)
366 :: Ptr Word8 -> Ptr Word8 -> CSize -> IO (Ptr Word8)
@@ -292,6 +371,9 @@ foreign import ccall unsafe "string.h memchr" c_memchr
292foreign import ccall unsafe "string.h memcmp" c_memcmp
371foreign import ccall unsafe "string.h memcmp" c_memcmp
293 :: Ptr Word8 -> Ptr Word8 -> CSize -> IO CInt
372 :: Ptr Word8 -> Ptr Word8 -> CSize -> IO CInt
374+foreign import ccall unsafe "string.h strlen" c_strlen
375+ :: Ptr Word8 -> IO CSize
295-- | Given an 'Unboxed' type (unused first arg) and a number of bytes, return
377-- | Given an 'Unboxed' type (unused first arg) and a number of bytes, return
296-- how many elements of that type will completely fit in those bytes.
378-- how many elements of that type will completely fit in those bytes.
@@ -346,7 +428,7 @@ data MutArray a =
346 -- The array is a range into arrContents. arrContents may be a superset of
428 -- The array is a range into arrContents. arrContents may be a superset of
347 -- the slice represented by the array. All offsets are in bytes.
429 -- the slice represented by the array. All offsets are in bytes.
349− { arrContents :: {-# UNPACK #-} !MutableByteArray
431+ { arrContents :: {-# UNPACK #-} !MutByteArray
350 , arrStart :: {-# UNPACK #-} !Int -- ^ index into arrContents
432 , arrStart :: {-# UNPACK #-} !Int -- ^ index into arrContents
351 , arrEnd :: {-# UNPACK #-} !Int -- ^ index into arrContents
433 , arrEnd :: {-# UNPACK #-} !Int -- ^ index into arrContents
352 -- Represents the first invalid index of
434 -- Represents the first invalid index of
@@ -358,8 +440,8 @@ data MutArray a =
358-- Pinning & Unpinning
440-- Pinning & Unpinning
359-------------------------------------------------------------------------------
441-------------------------------------------------------------------------------
361−-- | Copy the 'MutArray' to pinned memory if unpinned, else do nothing. The
443+-- | Return a copy of the array in pinned memory if unpinned, else return the
362−-- overhead is a copy if the input array is unpinned.
444+-- original array.
363{-# INLINE pin #-}
445{-# INLINE pin #-}
364pin :: MutArray a -> IO (MutArray a)
446pin :: MutArray a -> IO (MutArray a)
365pin arr@MutArray{..} =
447pin arr@MutArray{..} =
@@ -367,8 +449,8 @@ pin arr@MutArray{..} =
367 then pure arr
449 then pure arr
368 else pinnedClone arr
450 else pinnedClone arr
370−-- | Copy the 'MutArray' to unpinned memory if pinned, else do nothing. The
452+-- | Return a copy of the array in unpinned memory if pinned, else return the
371−-- overhead is a copy if the input array is pinned.
453+-- original array.
372{-# INLINE unpin #-}
454{-# INLINE unpin #-}
373unpin :: MutArray a -> IO (MutArray a)
455unpin :: MutArray a -> IO (MutArray a)
374unpin arr@MutArray{..} =
456unpin arr@MutArray{..} =
@@ -376,6 +458,7 @@ unpin arr@MutArray{..} =
376 then clone arr
458 then clone arr
377 else pure arr
459 else pure arr
461+-- | Return 'True' if the array is allocated in pinned memory.
379{-# INLINE isPinned #-}
462{-# INLINE isPinned #-}
380isPinned :: MutArray a -> Bool
463isPinned :: MutArray a -> Bool
381isPinned MutArray{..} = Unboxed.isPinned arrContents
464isPinned MutArray{..} = Unboxed.isPinned arrContents
@@ -396,6 +479,8 @@ isPinned MutArray{..} = Unboxed.isPinned arrContents
396-- we need more than that. See stg_pinnedNewAlignedByteArrayzh and
479-- we need more than that. See stg_pinnedNewAlignedByteArrayzh and
397-- allocatePinned in GHC source.
480-- allocatePinned in GHC source.
482+-- XXX Rename to emptyAlignedWith, alignSize should be first arg.
399-- | @newArrayWith allocator alignment count@ allocates a new array of zero
484-- | @newArrayWith allocator alignment count@ allocates a new array of zero
400-- length and with a capacity to hold @count@ elements, using @allocator
485-- length and with a capacity to hold @count@ elements, using @allocator
401-- size alignment@ as the memory allocator function.
486-- size alignment@ as the memory allocator function.
@@ -408,7 +493,7 @@ isPinned MutArray{..} = Unboxed.isPinned arrContents
408-- /Pre-release/
493-- /Pre-release/
409{-# INLINE newArrayWith #-}
494{-# INLINE newArrayWith #-}
410newArrayWith :: forall m a. (MonadIO m, Unbox a)
495newArrayWith :: forall m a. (MonadIO m, Unbox a)
411− => (Int -> Int -> m MutableByteArray) -> Int -> Int -> m (MutArray a)
496+ => (Int -> Int -> m MutByteArray) -> Int -> Int -> m (MutArray a)
412newArrayWith alloc alignSize count = do
497newArrayWith alloc alignSize count = do
413 let size = max (count * SIZE_OF(a)) 0
498 let size = max (count * SIZE_OF(a)) 0
414 contents <- alloc size alignSize
499 contents <- alloc size alignSize
@@ -419,12 +504,25 @@ newArrayWith alloc alignSize count = do
419 , arrBound = size
504 , arrBound = size
507+-- For arrays "nil" sounds a bit odd. empty is better. The only problem with
508+-- empty is that it is also used by the Alternative type class. But assuming we
509+-- will mostly import the Array module qualified this should be fine.
511+-- | Create an empty array.
517+empty = MutArray Unboxed.empty 0 0 0
519+{-# DEPRECATED nil "Please use empty instead." #-}
423#ifdef DEVBUILD
521#ifdef DEVBUILD
424 Unbox a =>
522 Unbox a =>
426 MutArray a
524 MutArray a
427−nil = MutArray Unboxed.nil 0 0 0
525+nil = empty
429{-# INLINE newBytesAs #-}
527{-# INLINE newBytesAs #-}
430newBytesAs :: MonadIO m =>
528newBytesAs :: MonadIO m =>
@@ -441,12 +539,13 @@ newBytesAs ps bytes = do
441 , arrBound = bytes
539 , arrBound = bytes
444−-- | Allocates a pinned empty array that can hold 'count' items. The memory of
542+-- | Allocates a pinned empty array that with a reserved capacity of bytes.
445−-- the array is uninitialized and the allocation is aligned as per the
543+-- The memory of the array is uninitialized and the allocation is aligned as
446−-- 'Unboxed' instance of the type.
544+-- per the 'Unboxed' instance of the type.
448-- /Pre-release/
546-- /Pre-release/
449{-# INLINE pinnedNewBytes #-}
547{-# INLINE pinnedNewBytes #-}
548+{-# DEPRECATED pinnedNewBytes "Please use pinnedEmptyOf with appropriate calculation" #-}
450pinnedNewBytes :: MonadIO m =>
549pinnedNewBytes :: MonadIO m =>
451#ifdef DEVBUILD
550#ifdef DEVBUILD
452 Unbox a =>
551 Unbox a =>
@@ -471,21 +570,31 @@ newAs ps =
471 (error "new: alignment is not used in unpinned arrays.")
570 (error "new: alignment is not used in unpinned arrays.")
473-- XXX can unaligned allocation be more efficient when alignment is not needed?
572-- XXX can unaligned allocation be more efficient when alignment is not needed?
475−-- | Allocates an empty pinned array that can hold 'count' items. The memory of
574+-- | Allocates a pinned array of zero length but growable to the specified
476−-- the array is uninitialized and the allocation is aligned as per the 'Unboxed'
575+-- capacity without reallocation.
477−-- instance of the type.
576+{-# INLINE pinnedEmptyOf #-}
478−--
577+pinnedEmptyOf :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a)
578+pinnedEmptyOf = newAs Pinned
580+-- XXX Deprecate in major
581+-- {-# DEPRECATED pinnedNew "Please use pinnedEmptyOf instead." #-}
479{-# INLINE pinnedNew #-}
582{-# INLINE pinnedNew #-}
480pinnedNew :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a)
583pinnedNew :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a)
481−pinnedNew = newAs Pinned
584+pinnedNew = pinnedEmptyOf
483−-- | Allocates an empty unpinned array that can hold 'count' items. The memory
586+-- | Allocates an unpinned array of zero length but growable to the specified
484−-- of the array is uninitialized.
587+-- capacity without reallocation.
589+{-# INLINE emptyOf #-}
590+emptyOf :: (MonadIO m, Unbox a) => Int -> m (MutArray a)
591+emptyOf = newAs Unpinned
593+-- XXX Deprecate in major
594+-- {-# DEPRECATED new "Please use emptyOf instead." #-}
486{-# INLINE new #-}
595{-# INLINE new #-}
487new :: (MonadIO m, Unbox a) => Int -> m (MutArray a)
596new :: (MonadIO m, Unbox a) => Int -> m (MutArray a)
488−new = newAs Unpinned
597+new = emptyOf
490-------------------------------------------------------------------------------
599-------------------------------------------------------------------------------
491-- Random writes
600-- Random writes
@@ -501,7 +610,7 @@ putIndexUnsafe :: forall m a. (MonadIO m, Unbox a)
501putIndexUnsafe i MutArray{..} x = do
610putIndexUnsafe i MutArray{..} x = do
502 let index = INDEX_OF(arrStart, i, a)
611 let index = INDEX_OF(arrStart, i, a)
503 assert (i >= 0 && INDEX_VALID(index, arrEnd, a)) (return ())
612 assert (i >= 0 && INDEX_VALID(index, arrEnd, a)) (return ())
504− liftIO $ pokeByteIndex index arrContents x
613+ liftIO $ pokeAt index arrContents x
506invalidIndex :: String -> Int -> a
615invalidIndex :: String -> Int -> a
507invalidIndex label i =
616invalidIndex label i =
@@ -519,7 +628,7 @@ putIndex :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> a -> m ()
519putIndex i MutArray{..} x = do
628putIndex i MutArray{..} x = do
520 let index = INDEX_OF(arrStart,i,a)
629 let index = INDEX_OF(arrStart,i,a)
521 if i >= 0 && INDEX_VALID(index,arrEnd,a)
630 if i >= 0 && INDEX_VALID(index,arrEnd,a)
522− then liftIO $ pokeByteIndex index arrContents x
631+ then liftIO $ pokeAt index arrContents x
523 else invalidIndex "putIndex" i
632 else invalidIndex "putIndex" i
525-- | Write an input stream of (index, value) pairs to an array. Throws an
634-- | Write an input stream of (index, value) pairs to an array. Throws an
@@ -533,7 +642,7 @@ putIndices arr = FL.foldlM' step (return ())
536− step () (i, x) = liftIO (putIndex i arr x)
645+ step () (i, x) = putIndex i arr x
538-- | Modify a given index of an array using a modifier function.
647-- | Modify a given index of an array using a modifier function.
@@ -545,9 +654,9 @@ modifyIndexUnsafe :: forall m a b. (MonadIO m, Unbox a) =>
545modifyIndexUnsafe i MutArray{..} f = liftIO $ do
654modifyIndexUnsafe i MutArray{..} f = liftIO $ do
546 let index = INDEX_OF(arrStart,i,a)
655 let index = INDEX_OF(arrStart,i,a)
547 assert (i >= 0 && INDEX_NEXT(index,a) <= arrEnd) (return ())
656 assert (i >= 0 && INDEX_NEXT(index,a) <= arrEnd) (return ())
548− r <- peekByteIndex index arrContents
657+ r <- peekAt index arrContents
549 let (x, res) = f r
658 let (x, res) = f r
550− pokeByteIndex index arrContents x
659+ pokeAt index arrContents x
551 return res
660 return res
553-- | Modify a given index of an array using a modifier function.
662-- | Modify a given index of an array using a modifier function.
@@ -559,9 +668,9 @@ modifyIndex i MutArray{..} f = do
559 let index = INDEX_OF(arrStart,i,a)
668 let index = INDEX_OF(arrStart,i,a)
560 if i >= 0 && INDEX_VALID(index,arrEnd,a)
669 if i >= 0 && INDEX_VALID(index,arrEnd,a)
561 then liftIO $ do
670 then liftIO $ do
562− r <- peekByteIndex index arrContents
671+ r <- peekAt index arrContents
563 let (x, res) = f r
672 let (x, res) = f r
564− pokeByteIndex index arrContents x
673+ pokeAt index arrContents x
565 return res
674 return res
566 else invalidIndex "modifyIndex" i
675 else invalidIndex "modifyIndex" i
@@ -595,8 +704,8 @@ modify MutArray{..} f = liftIO $
597 when (INDEX_VALID(i,arrEnd,a)) $ do
706 when (INDEX_VALID(i,arrEnd,a)) $ do
598− r <- peekByteIndex i arrContents
707+ r <- peekAt i arrContents
599− pokeByteIndex i arrContents (f r)
708+ pokeAt i arrContents (f r)
600 go (INDEX_NEXT(i,a))
709 go (INDEX_NEXT(i,a))
602-- XXX We could specify the number of bytes to swap instead of Proxy. Need
711-- XXX We could specify the number of bytes to swap instead of Proxy. Need
@@ -605,15 +714,15 @@ modify MutArray{..} f = liftIO $
605swapArrayByteIndices ::
714swapArrayByteIndices ::
606 forall a. Unbox a
715 forall a. Unbox a
607 => Proxy a
716 => Proxy a
608− -> MutableByteArray
717+ -> MutByteArray
612swapArrayByteIndices _ arrContents i1 i2 = do
721swapArrayByteIndices _ arrContents i1 i2 = do
613− r1 <- peekByteIndex i1 arrContents
722+ r1 <- peekAt i1 arrContents
614− r2 <- peekByteIndex i2 arrContents
723+ r2 <- peekAt i2 arrContents
615− pokeByteIndex i1 arrContents (r2 :: a)
724+ pokeAt i1 arrContents (r2 :: a)
616− pokeByteIndex i2 arrContents (r1 :: a)
725+ pokeAt i2 arrContents (r1 :: a)
618-- | Swap the elements at two indices without validating the indices.
727-- | Swap the elements at two indices without validating the indices.
@@ -729,26 +838,23 @@ arrayChunkBytes = 1024
729roundDownTo :: Int -> Int -> Int
838roundDownTo :: Int -> Int -> Int
730roundDownTo elemSize size = size - (size `mod` elemSize)
839roundDownTo elemSize size = size - (size `mod` elemSize)
732−-- XXX See if resizing can be implemented by reading the old array as a stream
733−-- and then using writeN to the new array.
735-- NOTE: we are passing elemSize explicitly to avoid an Unboxed constraint.
841-- NOTE: we are passing elemSize explicitly to avoid an Unboxed constraint.
736-- Since this is not inlined Unboxed consrraint leads to dictionary passing
842-- Since this is not inlined Unboxed consrraint leads to dictionary passing
737-- which complicates some inspection tests.
843-- which complicates some inspection tests.
739−{-# NOINLINE reallocExplicit #-}
845+{-# NOINLINE reallocExplicitAs #-}
740−reallocExplicit :: Int -> Int -> MutArray a -> IO (MutArray a)
846+reallocExplicitAs :: PinnedState -> Int -> Int -> MutArray a -> IO (MutArray a)
741−reallocExplicit elemSize newCapacityInBytes MutArray{..} = do
847+reallocExplicitAs ps elemSize newCapacityInBytes MutArray{..} = do
742 assertM(arrEnd <= arrBound)
848 assertM(arrEnd <= arrBound)
744 -- Allocate new array
850 -- Allocate new array
745 let newCapMaxInBytes = roundUpLargeArray newCapacityInBytes
851 let newCapMaxInBytes = roundUpLargeArray newCapacityInBytes
746 contents <-
852 contents <-
747− if Unboxed.isPinned arrContents
853+ if ps == Pinned
748− then Unboxed.pinnedNewBytes newCapMaxInBytes
854+ then Unboxed.pinnedNew newCapMaxInBytes
749− else Unboxed.newBytes newCapMaxInBytes
855+ else Unboxed.new newCapMaxInBytes
750− let !(MutableByteArray mbarrFrom#) = arrContents
856+ let !(MutByteArray mbarrFrom#) = arrContents
751− !(MutableByteArray mbarrTo#) = contents
857+ !(MutByteArray mbarrTo#) = contents
753 -- Copy old data
859 -- Copy old data
754 let oldStart = arrStart
860 let oldStart = arrStart
@@ -769,6 +875,10 @@ reallocExplicit elemSize newCapacityInBytes MutArray{..} = do
769 , arrBound = newCapInBytes
875 , arrBound = newCapInBytes
878+-- XXX Should these be called reallocBytes etc?
879+-- XXX We may also need reallocAs to allocate as pinned/unpinned explicitly. In
880+-- fact clone/pinnedClone can be implemented using reallocAs.
772-- | @realloc newCapacity array@ reallocates the array to the specified
882-- | @realloc newCapacity array@ reallocates the array to the specified
773-- capacity in bytes.
883-- capacity in bytes.
@@ -780,7 +890,12 @@ reallocExplicit elemSize newCapacityInBytes MutArray{..} = do
780-- If the original array is pinned, the newly allocated array is also pinned.
890-- If the original array is pinned, the newly allocated array is also pinned.
781{-# INLINABLE realloc #-}
891{-# INLINABLE realloc #-}
782realloc :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m (MutArray a)
892realloc :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m (MutArray a)
783−realloc bytes arr = liftIO $ reallocExplicit (SIZE_OF(a)) bytes arr
898+ in liftIO $ reallocExplicitAs ps (SIZE_OF(a)) bytes arr
785-- | @reallocWith label capSizer minIncrBytes array@. The label is used
900-- | @reallocWith label capSizer minIncrBytes array@. The label is used
786-- in error messages and the capSizer is used to determine the capacity of the
901-- in error messages and the capSizer is used to determine the capacity of the
@@ -803,14 +918,14 @@ reallocWith label capSizer minIncrBytes arr = do
805 badSize newSize =
920 badSize newSize =
806− concat
921+ Prelude.concat
808 , ": new array size (in bytes) is less than required size "
923 , ": new array size (in bytes) is less than required size "
809 , show newSize
924 , show newSize
810 , ". Please check the sizing function passed."
925 , ". Please check the sizing function passed."
813−-- | @resize newCapacity array@ changes the total capacity of the array so that
928+-- | @grow newCapacity array@ changes the total capacity of the array so that
814-- it is enough to hold the specified number of elements. Nothing is done if
929-- it is enough to hold the specified number of elements. Nothing is done if
815-- the specified capacity is less than the length of the array.
930-- the specified capacity is less than the length of the array.
@@ -818,34 +933,46 @@ reallocWith label capSizer minIncrBytes arr = do
818-- the block size (4K).
933-- the block size (4K).
820-- /Pre-release/
935-- /Pre-release/
821−{-# INLINE resize #-}
936+{-# INLINE grow #-}
822−resize :: forall m a. (MonadIO m, Unbox a) =>
937+grow :: forall m a. (MonadIO m, Unbox a) =>
823 Int -> MutArray a -> m (MutArray a)
938 Int -> MutArray a -> m (MutArray a)
824−resize nElems arr@MutArray{..} = do
939+grow nElems arr@MutArray{..} = do
825 let req = SIZE_OF(a) * nElems
940 let req = SIZE_OF(a) * nElems
826− len = arrEnd - arrStart
941+ cap = arrBound - arrStart
827− if req < len
942+ if req < cap
828 then return arr
943 then return arr
829 else realloc req arr
944 else realloc req arr
946+{-# DEPRECATED resize "Please use grow instead." #-}
947+{-# INLINE resize #-}
948+resize :: forall m a. (MonadIO m, Unbox a) =>
949+ Int -> MutArray a -> m (MutArray a)
831−-- | Like 'resize' but if the byte capacity is more than 'largeObjectThreshold'
952+-- | Like 'grow' but if the requested byte capacity is more than
832−-- then it is rounded up to the closest power of 2.
953+-- 'largeObjectThreshold' then it is rounded up to the closest power of 2.
834-- /Pre-release/
955-- /Pre-release/
835−{-# INLINE resizeExp #-}
956+{-# INLINE growExp #-}
836−resizeExp :: forall m a. (MonadIO m, Unbox a) =>
957+growExp :: forall m a. (MonadIO m, Unbox a) =>
837 Int -> MutArray a -> m (MutArray a)
958 Int -> MutArray a -> m (MutArray a)
838−resizeExp nElems arr@MutArray{..} = do
959+growExp nElems arr@MutArray{..} = do
839 let req = roundUpLargeArray (SIZE_OF(a) * nElems)
960 let req = roundUpLargeArray (SIZE_OF(a) * nElems)
841 if req > largeObjectThreshold
962 if req > largeObjectThreshold
842 then roundUpToPower2 req
963 then roundUpToPower2 req
844− len = arrEnd - arrStart
965+ cap = arrBound - arrStart
845− if req1 < len
966+ if req1 < cap
846 then return arr
967 then return arr
847 else realloc req1 arr
968 else realloc req1 arr
970+{-# DEPRECATED resizeExp "Please use growExp instead." #-}
971+{-# INLINE resizeExp #-}
972+resizeExp :: forall m a. (MonadIO m, Unbox a) =>
973+ Int -> MutArray a -> m (MutArray a)
849-- | Resize the allocated memory to drop any reserved free space at the end of
976-- | Resize the allocated memory to drop any reserved free space at the end of
850-- the array and reallocate it to reduce wastage.
977-- the array and reallocate it to reduce wastage.
@@ -890,7 +1017,7 @@ rightSize arr@MutArray{..} = do
890snocNewEnd :: (MonadIO m, Unbox a) => Int -> MutArray a -> a -> m (MutArray a)
1017snocNewEnd :: (MonadIO m, Unbox a) => Int -> MutArray a -> a -> m (MutArray a)
891snocNewEnd newEnd arr@MutArray{..} x = liftIO $ do
1018snocNewEnd newEnd arr@MutArray{..} x = liftIO $ do
892 assert (newEnd <= arrBound) (return ())
1019 assert (newEnd <= arrBound) (return ())
893− pokeByteIndex arrEnd arrContents x
1020+ pokeAt arrEnd arrContents x
894 return $ arr {arrEnd = newEnd}
1021 return $ arr {arrEnd = newEnd}
896-- | Really really unsafe, appends the element into the first array, may
1023-- | Really really unsafe, appends the element into the first array, may
@@ -910,7 +1037,7 @@ snocUnsafe arr@MutArray{..} = snocNewEnd (INDEX_NEXT(arrEnd,a)) arr
910{-# INLINE snocMay #-}
1037{-# INLINE snocMay #-}
911snocMay :: forall m a. (MonadIO m, Unbox a) =>
1038snocMay :: forall m a. (MonadIO m, Unbox a) =>
912 MutArray a -> a -> m (Maybe (MutArray a))
1039 MutArray a -> a -> m (Maybe (MutArray a))
913−snocMay arr@MutArray{..} x = liftIO $ do
1040+snocMay arr@MutArray{..} x = do
914 let newEnd = INDEX_NEXT(arrEnd,a)
1041 let newEnd = INDEX_NEXT(arrEnd,a)
915 if newEnd <= arrBound
1042 if newEnd <= arrBound
916 then Just <$> snocNewEnd newEnd arr x
1043 then Just <$> snocNewEnd newEnd arr x
@@ -924,7 +1051,7 @@ snocWithRealloc :: forall m a. (MonadIO m, Unbox a) =>
925 -> m (MutArray a)
1052 -> m (MutArray a)
926snocWithRealloc sizer arr x = do
1053snocWithRealloc sizer arr x = do
927− arr1 <- liftIO $ reallocWith "snocWith" sizer (SIZE_OF(a)) arr
1054+ arr1 <- reallocWith "snocWith" sizer (SIZE_OF(a)) arr
928 snocUnsafe arr1 x
1055 snocUnsafe arr1 x
930-- | @snocWith sizer arr elem@ mutates @arr@ to append @elem@. The length of
1057-- | @snocWith sizer arr elem@ mutates @arr@ to append @elem@. The length of
@@ -946,7 +1073,7 @@ snocWith :: forall m a. (MonadIO m, Unbox a) =>
946 -> MutArray a
1073 -> MutArray a
948 -> m (MutArray a)
1075 -> m (MutArray a)
949−snocWith allocSize arr x = liftIO $ do
1076+snocWith allocSize arr x = do
950 let newEnd = INDEX_NEXT(arrEnd arr,a)
1077 let newEnd = INDEX_NEXT(arrEnd arr,a)
951 if newEnd <= arrBound arr
1078 if newEnd <= arrBound arr
952 then snocNewEnd newEnd arr x
1079 then snocNewEnd newEnd arr x
@@ -990,6 +1117,126 @@ snoc = snocWith f
990 then oldSize * 2
1117 then oldSize * 2
991 else roundUpToPower2 oldSize * 2
1118 else roundUpToPower2 oldSize * 2
1120+-------------------------------------------------------------------------------
1121+-- Serialization/Deserialization
1122+-------------------------------------------------------------------------------
1124+{-# INLINE pokeNewEnd #-}
1125+pokeNewEnd :: (MonadIO m, Unbox a) =>
1126+ Int -> MutArray Word8 -> a -> m (MutArray Word8)
1127+pokeNewEnd newEnd arr@MutArray{..} x = liftIO $ do
1128+ assert (newEnd <= arrBound) (return ())
1129+ liftIO $ pokeAt arrEnd arrContents x
1130+ return $ arr {arrEnd = newEnd}
1132+-- | Really really unsafe, unboxes a Haskell type and appends the resulting
1133+-- bytes to the byte array, may cause silent data corruption or if you are
1134+-- lucky a segfault if the array does not have enough space to append the
1138+{-# INLINE pokeAppendUnsafe #-}
1139+pokeAppendUnsafe :: forall m a. (MonadIO m, Unbox a) =>
1140+ MutArray Word8 -> a -> m (MutArray Word8)
1141+pokeAppendUnsafe arr@MutArray{..} = pokeNewEnd (arrEnd + SIZE_OF(a)) arr
1143+-- | Skip the specified number of bytes in the array. The data in the skipped
1144+-- region remains uninitialzed.
1145+{-# INLINE pokeSkipUnsafe #-}
1146+pokeSkipUnsafe :: Int -> MutArray Word8 -> MutArray Word8
1147+pokeSkipUnsafe n arr@MutArray{..} = do
1148+ let newEnd = arrEnd + n
1149+ in assert (newEnd <= arrBound) (arr {arrEnd = newEnd})
1151+-- | Like 'pokeAppend' but does not grow the array when pre-allocated array
1152+-- capacity becomes full.
1155+{-# INLINE pokeAppendMay #-}
1156+pokeAppendMay :: forall m a. (MonadIO m, Unbox a) =>
1157+ MutArray Word8 -> a -> m (Maybe (MutArray Word8))
1158+pokeAppendMay arr@MutArray{..} x = liftIO $ do
1159+ let newEnd = arrEnd + SIZE_OF(a)
1160+ if newEnd <= arrBound
1161+ then Just <$> pokeNewEnd newEnd arr x
1162+ else return Nothing
1164+{-# NOINLINE pokeWithRealloc #-}
1165+pokeWithRealloc :: forall m a. (MonadIO m, Unbox a) =>
1169+ -> m (MutArray Word8)
1170+pokeWithRealloc sizer arr x = do
1171+ arr1 <- liftIO $ reallocWith "pokeWithRealloc" sizer (SIZE_OF(a)) arr
1172+ pokeAppendUnsafe arr1 x
1174+{-# INLINE pokeAppendWith #-}
1175+pokeAppendWith :: forall m a. (MonadIO m, Unbox a) =>
1179+ -> m (MutArray Word8)
1180+pokeAppendWith allocSize arr x = liftIO $ do
1181+ let newEnd = arrEnd arr + SIZE_OF(a)
1182+ if newEnd <= arrBound arr
1183+ then pokeNewEnd newEnd arr x
1184+ else pokeWithRealloc allocSize arr x
1186+-- | Unbox a Haskell type and append the resulting bytes to a mutable byte
1187+-- array. The array is grown exponentially when more space is needed.
1191+-- >>> pokeAppend arr x = MutArray.castUnsafe <$> MutArray.snoc (MutArray.castUnsafe arr) x
1193+{-# INLINE pokeAppend #-}
1194+pokeAppend :: forall m a. (MonadIO m, Unbox a) =>
1195+ MutArray Word8 -> a -> m (MutArray Word8)
1196+pokeAppend = pokeAppendWith f
1201+ if isPower2 oldSize
1203+ else roundUpToPower2 oldSize * 2
1205+-- | Really really unsafe, create a Haskell value from an unboxed byte array,
1206+-- does not check if the array is big enough, may return garbage or if you are
1207+-- lucky may cause a segfault.
1210+{-# INLINE peekUnconsUnsafe #-}
1211+peekUnconsUnsafe :: forall m a. (MonadIO m, Unbox a) =>
1212+ MutArray Word8 -> m (a, MutArray Word8)
1213+peekUnconsUnsafe MutArray{..} = do
1214+ let start1 = arrStart + SIZE_OF(a)
1215+ assert (start1 <= arrEnd) (return ())
1217+ r <- peekAt arrStart arrContents
1218+ return (r, MutArray arrContents start1 arrEnd arrBound)
1220+-- | Discard the specified number of bytes in the array.
1221+{-# INLINE peekSkipUnsafe #-}
1222+peekSkipUnsafe :: Int -> MutArray Word8 -> MutArray Word8
1223+peekSkipUnsafe n MutArray{..} =
1224+ let start1 = arrStart + n
1225+ in assert (start1 <= arrEnd) (MutArray arrContents start1 arrEnd arrBound)
1227+-- | Create a Haskell value from its unboxed representation from the head of a
1228+-- byte array, return the value and the remaining array.
1229+{-# INLINE peekUncons #-}
1230+peekUncons :: forall m a. (MonadIO m, Unbox a) =>
1231+ MutArray Word8 -> m (Maybe a, MutArray Word8)
1232+peekUncons arr@MutArray{..} = do
1233+ let start1 = arrStart + SIZE_OF(a)
1235+ then return (Nothing, arr)
1237+ r <- peekAt arrStart arrContents
1238+ return (Just r, MutArray arrContents start1 arrEnd arrBound)
993-------------------------------------------------------------------------------
1240-------------------------------------------------------------------------------
994-- Random reads
1241-- Random reads
995-------------------------------------------------------------------------------
1242-------------------------------------------------------------------------------
@@ -1004,7 +1251,7 @@ getIndexUnsafe :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m a
1004getIndexUnsafe i MutArray{..} = do
1251getIndexUnsafe i MutArray{..} = do
1005 let index = INDEX_OF(arrStart,i,a)
1252 let index = INDEX_OF(arrStart,i,a)
1006 assert (i >= 0 && INDEX_VALID(index,arrEnd,a)) (return ())
1253 assert (i >= 0 && INDEX_VALID(index,arrEnd,a)) (return ())
1007− liftIO $ peekByteIndex index arrContents
1254+ liftIO $ peekAt index arrContents
1009-- | /O(1)/ Lookup the element at the given index. Index starts from 0.
1256-- | /O(1)/ Lookup the element at the given index. Index starts from 0.
@@ -1013,7 +1260,7 @@ getIndex :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m (Maybe a)
1013getIndex i MutArray{..} = do
1260getIndex i MutArray{..} = do
1014 let index = INDEX_OF(arrStart,i,a)
1261 let index = INDEX_OF(arrStart,i,a)
1015 if i >= 0 && INDEX_VALID(index,arrEnd,a)
1262 if i >= 0 && INDEX_VALID(index,arrEnd,a)
1016− then liftIO $ Just <$> peekByteIndex index arrContents
1263+ then liftIO $ Just <$> peekAt index arrContents
1017 else return Nothing
1264 else return Nothing
1019-- | /O(1)/ Lookup the element at the given index from the end of the array.
1266-- | /O(1)/ Lookup the element at the given index from the end of the array.
@@ -1026,21 +1273,16 @@ getIndexRev :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m a
1026getIndexRev i MutArray{..} = do
1273getIndexRev i MutArray{..} = do
1027 let index = RINDEX_OF(arrEnd,i,a)
1274 let index = RINDEX_OF(arrEnd,i,a)
1028 if i >= 0 && index >= arrStart
1275 if i >= 0 && index >= arrStart
1029− then liftIO $ peekByteIndex index arrContents
1276+ then liftIO $ peekAt index arrContents
1030 else invalidIndex "getIndexRev" i
1277 else invalidIndex "getIndexRev" i
1032data GetIndicesState contents start end st =
1279data GetIndicesState contents start end st =
1033 GetIndicesState contents start end st
1280 GetIndicesState contents start end st
1035−-- | Given an unfold that generates array indices, read the elements on those
1282+{-# INLINE indexReaderWith #-}
1036−-- indices from the supplied MutArray. An error is thrown if an index is out of
1040−{-# INLINE getIndicesD #-}
1041−getIndicesD :: (Monad m, Unbox a) =>
1283+indexReaderWith :: (Monad m, Unbox a) =>
1042 (forall b. IO b -> m b) -> D.Stream m Int -> Unfold m (MutArray a) a
1284 (forall b. IO b -> m b) -> D.Stream m Int -> Unfold m (MutArray a) a
1043−getIndicesD liftio (D.Stream stepi sti) = Unfold step inject
1285+indexReaderWith liftio (D.Stream stepi sti) = Unfold step inject
@@ -1059,9 +1301,26 @@ getIndicesD liftio (D.Stream stepi sti) = Unfold step inject
1059 D.Skip s -> return $ D.Skip (GetIndicesState contents start end s)
1301 D.Skip s -> return $ D.Skip (GetIndicesState contents start end s)
1060 D.Stop -> return D.Stop
1302 D.Stop -> return D.Stop
1304+{-# DEPRECATED getIndicesWith "Please use indexReaderWith instead." #-}
1305+{-# INLINE getIndicesWith #-}
1306+getIndicesWith :: (Monad m, Unbox a) =>
1307+ (forall b. IO b -> m b) -> D.Stream m Int -> Unfold m (MutArray a) a
1308+getIndicesWith = indexReaderWith
1310+-- | Given an unfold that generates array indices, read the elements on those
1311+-- indices from the supplied MutArray. An error is thrown if an index is out of
1315+{-# INLINE indexReader #-}
1316+indexReader :: (MonadIO m, Unbox a) => Stream m Int -> Unfold m (MutArray a) a
1317+indexReader = indexReaderWith liftIO
1319+-- XXX DO NOT REMOVE, change the signature to use Stream instead of unfold
1320+{-# DEPRECATED getIndices "Please use indexReader instead." #-}
1062{-# INLINE getIndices #-}
1321{-# INLINE getIndices #-}
1063getIndices :: (MonadIO m, Unbox a) => Stream m Int -> Unfold m (MutArray a) a
1322getIndices :: (MonadIO m, Unbox a) => Stream m Int -> Unfold m (MutArray a) a
1064−getIndices = getIndicesD liftIO
1323+getIndices = indexReader
1066-------------------------------------------------------------------------------
1325-------------------------------------------------------------------------------
1067-- Subarrays
1326-- Subarrays
@@ -1166,7 +1425,7 @@ partitionBy f arr@MutArray{..} = liftIO $ do
1167 -- Invariant low < high on entry, and on return as well
1426 -- Invariant low < high on entry, and on return as well
1168 moveHigh low high = do
1427 moveHigh low high = do
1169− h <- peekByteIndex high arrContents
1428+ h <- peekAt high arrContents
1172 -- Correctly classified, continue the loop
1431 -- Correctly classified, continue the loop
@@ -1186,7 +1445,7 @@ partitionBy f arr@MutArray{..} = liftIO $ do
1186 -- low <= high
1445 -- low <= high
1187 -- Both low and high are valid locations within the array
1446 -- Both low and high are valid locations within the array
1188 go low high = do
1447 go low high = do
1189− l <- peekByteIndex low arrContents
1448+ l <- peekAt low arrContents
1192 -- low is wrongly classified
1451 -- low is wrongly classified
@@ -1197,8 +1456,8 @@ partitionBy f arr@MutArray{..} = liftIO $ do
1197 case r of
1456 case r of
1198 Nothing -> return low
1457 Nothing -> return low
1199 Just (high1, h) -> do -- low < high1
1458 Just (high1, h) -> do -- low < high1
1200− pokeByteIndex low arrContents h
1459+ pokeAt low arrContents h
1201− pokeByteIndex high1 arrContents l
1460+ pokeAt high1 arrContents l
1202 let low1 = INDEX_NEXT(low,a)
1461 let low1 = INDEX_NEXT(low,a)
1203 high2 = INDEX_PREV(high1,a)
1462 high2 = INDEX_PREV(high1,a)
1204 if low1 <= high2
1463 if low1 <= high2
@@ -1332,7 +1591,7 @@ chunksOfAs ps n (D.Stream step state) =
1332 r <- step (adaptState gst) st
1591 r <- step (adaptState gst) st
1333 case r of
1592 case r of
1334 D.Yield x s -> do
1593 D.Yield x s -> do
1335− liftIO $ pokeByteIndex end contents x
1594+ liftIO $ pokeAt end contents x
1336 let end1 = INDEX_NEXT(end,a)
1595 let end1 = INDEX_NEXT(end,a)
1337 return $
1596 return $
1338 if end1 >= bound
1597 if end1 >= bound
@@ -1351,10 +1610,12 @@ chunksOfAs ps n (D.Stream step state) =
1352 step' _ GroupFinish = return D.Stop
1611 step' _ GroupFinish = return D.Stop
1354−-- | @chunksOf n stream@ groups the input stream into a stream of
1613+-- | @chunksOf n stream@ groups the elements in the input stream into arrays of
1355−-- arrays of size n.
1614+-- @n@ elements each.
1616+-- Same as the following but may be more efficient:
1357−-- @chunksOf n = StreamD.foldMany (MutArray.writeN n)@
1618+-- >>> chunksOf n = Stream.foldMany (MutArray.createOf n)
1359-- /Pre-release/
1620-- /Pre-release/
1360{-# INLINE_NORMAL chunksOf #-}
1621{-# INLINE_NORMAL chunksOf #-}
@@ -1363,17 +1624,29 @@ chunksOf :: forall m a. (MonadIO m, Unbox a)
1363-- XXX the idiomatic implementation leads to large regression in the D.reverse'
1624-- XXX the idiomatic implementation leads to large regression in the D.reverse'
1364-- benchmark. It seems it has difficulty producing optimized code when
1625-- benchmark. It seems it has difficulty producing optimized code when
1365-- converting to StreamK. Investigate GHC optimizations.
1626-- converting to StreamK. Investigate GHC optimizations.
1366−-- chunksOf n = D.foldMany (writeN n)
1627+-- chunksOf n = D.foldMany (createOf n)
1367chunksOf = chunksOfAs Unpinned
1628chunksOf = chunksOfAs Unpinned
1369-- | Like 'chunksOf' but creates pinned arrays.
1630-- | Like 'chunksOf' but creates pinned arrays.
1370{-# INLINE_NORMAL pinnedChunksOf #-}
1631{-# INLINE_NORMAL pinnedChunksOf #-}
1371pinnedChunksOf :: forall m a. (MonadIO m, Unbox a)
1632pinnedChunksOf :: forall m a. (MonadIO m, Unbox a)
1372 => Int -> D.Stream m a -> D.Stream m (MutArray a)
1633 => Int -> D.Stream m a -> D.Stream m (MutArray a)
1373−-- pinnedChunksOf n = D.foldMany (pinnedWriteN n)
1634+-- pinnedChunksOf n = D.foldMany (pinnedCreateOf n)
1374pinnedChunksOf = chunksOfAs Pinned
1635pinnedChunksOf = chunksOfAs Pinned
1376−-- XXX This should take a PinnedState
1637+-- | When we are buffering a stream of unknown size into an array we do not
1638+-- know how much space to pre-allocate. So we start with the min size and emit
1639+-- the array then keep on doubling the size every time. Thus we do not need to
1640+-- guess the optimum chunk size.
1642+-- We can incorporate this in chunksOfAs if the additional size parameter does
1645+{-# INLINE _chunksOfRange #-}
1646+_chunksOfRange :: -- (MonadIO m, Unbox a) =>
1647+ PinnedState -> Int -> Int -> D.Stream m a -> D.Stream m (MutArray a)
1648+_chunksOfRange _ps _low _hi = undefined
1377-- XXX buffer to a list instead?
1650-- XXX buffer to a list instead?
1378-- | Buffer the stream into arrays in memory.
1651-- | Buffer the stream into arrays in memory.
1379{-# INLINE arrayStreamKFromStreamDAs #-}
1652{-# INLINE arrayStreamKFromStreamDAs #-}
@@ -1391,16 +1664,10 @@ data FlattenState s contents a =
1391 OuterLoop s
1664 OuterLoop s
1392 | InnerLoop s contents !Int !Int
1665 | InnerLoop s contents !Int !Int
1394−-- | Use the "reader" unfold instead.
1396−-- @flattenArrays = unfoldMany reader@
1398−-- We can try this if there are any fusion issues in the unfold.
1400−{-# INLINE_NORMAL flattenArrays #-}
1667+{-# INLINE_NORMAL concatWith #-}
1401−flattenArrays :: forall m a. (MonadIO m, Unbox a)
1668+concatWith :: forall m a. (Monad m, Unbox a)
1402− => D.Stream m (MutArray a) -> D.Stream m a
1669+ => (forall b. IO b -> m b) -> D.Stream m (MutArray a) -> D.Stream m a
1403−flattenArrays (D.Stream step state) = D.Stream step' (OuterLoop state)
1670+concatWith liftio (D.Stream step state) = D.Stream step' (OuterLoop state)
@@ -1417,19 +1684,30 @@ flattenArrays (D.Stream step state) = D.Stream step' (OuterLoop state)
1417 return $ D.Skip $ OuterLoop st
1684 return $ D.Skip $ OuterLoop st
1419 step' _ (InnerLoop st contents p end) = do
1686 step' _ (InnerLoop st contents p end) = do
1420− x <- liftIO $ peekByteIndex p contents
1687+ x <- liftio $ peekAt p contents
1421 return $ D.Yield x (InnerLoop st contents (INDEX_NEXT(p,a)) end)
1688 return $ D.Yield x (InnerLoop st contents (INDEX_NEXT(p,a)) end)
1423−-- | Use the "readerRev" unfold instead.
1690+-- | Use the "reader" unfold instead.
1425−-- @flattenArrays = unfoldMany readerRev@
1692+-- @concat = unfoldMany reader@
1427-- We can try this if there are any fusion issues in the unfold.
1694-- We can try this if there are any fusion issues in the unfold.
1429−{-# INLINE_NORMAL flattenArraysRev #-}
1696+{-# INLINE_NORMAL concat #-}
1430−flattenArraysRev :: forall m a. (MonadIO m, Unbox a)
1697+concat :: forall m a. (MonadIO m, Unbox a)
1431 => D.Stream m (MutArray a) -> D.Stream m a
1698 => D.Stream m (MutArray a) -> D.Stream m a
1699+concat = concatWith liftIO
1701+{-# DEPRECATED flattenArrays "Please use \"unfoldMany reader\" instead." #-}
1702+{-# INLINE flattenArrays #-}
1703+flattenArrays :: forall m a. (MonadIO m, Unbox a)
1704+ => D.Stream m (MutArray a) -> D.Stream m a
1705+flattenArrays = concat
1707+{-# INLINE_NORMAL concatRevWith #-}
1708+concatRevWith :: forall m a. (Monad m, Unbox a)
1709+ => (forall b. IO b -> m b) -> D.Stream m (MutArray a) -> D.Stream m a
1432−flattenArraysRev (D.Stream step state) = D.Stream step' (OuterLoop state)
1710+concatRevWith liftio (D.Stream step state) = D.Stream step' (OuterLoop state)
@@ -1447,16 +1725,33 @@ flattenArraysRev (D.Stream step state) = D.Stream step' (OuterLoop state)
1447 return $ D.Skip $ OuterLoop st
1725 return $ D.Skip $ OuterLoop st
1449 step' _ (InnerLoop st contents p start) = do
1727 step' _ (InnerLoop st contents p start) = do
1450− x <- liftIO $ peekByteIndex p contents
1728+ x <- liftio $ peekAt p contents
1451 let cur = INDEX_PREV(p,a)
1729 let cur = INDEX_PREV(p,a)
1452 return $ D.Yield x (InnerLoop st contents cur start)
1730 return $ D.Yield x (InnerLoop st contents cur start)
1732+-- | Use the "readerRev" unfold instead.
1734+-- @concat = unfoldMany readerRev@
1736+-- We can try this if there are any fusion issues in the unfold.
1738+{-# INLINE_NORMAL concatRev #-}
1739+concatRev :: forall m a. (MonadIO m, Unbox a)
1740+ => D.Stream m (MutArray a) -> D.Stream m a
1741+concatRev = concatRevWith liftIO
1743+{-# DEPRECATED flattenArraysRev "Please use \"unfoldMany readerRev\" instead." #-}
1744+{-# INLINE flattenArraysRev #-}
1745+flattenArraysRev :: forall m a. (MonadIO m, Unbox a)
1746+ => D.Stream m (MutArray a) -> D.Stream m a
1747+flattenArraysRev = concatRev
1454-------------------------------------------------------------------------------
1749-------------------------------------------------------------------------------
1455-- Unfolds
1750-- Unfolds
1456-------------------------------------------------------------------------------
1751-------------------------------------------------------------------------------
1458data ArrayUnsafe a = ArrayUnsafe
1753data ArrayUnsafe a = ArrayUnsafe
1459− {-# UNPACK #-} !MutableByteArray -- contents
1754+ {-# UNPACK #-} !MutByteArray -- contents
1460 {-# UNPACK #-} !Int -- index 1
1755 {-# UNPACK #-} !Int -- index 1
1461 {-# UNPACK #-} !Int -- index 2
1756 {-# UNPACK #-} !Int -- index 2
@@ -1486,7 +1781,7 @@ producerWith liftio = Producer step (return . toArrayUnsafe) extract
1486 -- few actions for correctness and execution order sanity. We want
1781 -- few actions for correctness and execution order sanity. We want
1487 -- the peek to occur right here and not lazily at some later point
1782 -- the peek to occur right here and not lazily at some later point
1488 -- because we want the peek to be ordered with respect to the touch.
1783 -- because we want the peek to be ordered with respect to the touch.
1489− !x <- liftio $ peekByteIndex cur contents
1784+ !x <- liftio $ peekAt cur contents
1490 return $ D.Yield x (ArrayUnsafe contents (INDEX_NEXT(cur,a)) end)
1785 return $ D.Yield x (ArrayUnsafe contents (INDEX_NEXT(cur,a)) end)
1492 extract = return . fromArrayUnsafe
1787 extract = return . fromArrayUnsafe
@@ -1517,7 +1812,7 @@ readerRevWith liftio = Unfold step inject
1517 {-# INLINE_LATE step #-}
1812 {-# INLINE_LATE step #-}
1518 step (ArrayUnsafe _ start p) | p < start = return D.Stop
1813 step (ArrayUnsafe _ start p) | p < start = return D.Stop
1519 step (ArrayUnsafe contents start p) = do
1814 step (ArrayUnsafe contents start p) = do
1520− !x <- liftio $ peekByteIndex p contents
1815+ !x <- liftio $ peekAt p contents
1521 return $ D.Yield x (ArrayUnsafe contents start (INDEX_PREV(p,a)))
1816 return $ D.Yield x (ArrayUnsafe contents start (INDEX_PREV(p,a)))
1523-- | Unfold an array into a stream in reverse order.
1818-- | Unfold an array into a stream in reverse order.
@@ -1548,7 +1843,7 @@ toListFB c n MutArray{..} = go arrStart
1548 -- evaluated/written to before we peek at them.
1843 -- evaluated/written to before we peek at them.
1550 let !x = unsafeInlineIO $ do
1845 let !x = unsafeInlineIO $ do
1551− r <- peekByteIndex arrContents p
1846+ r <- peekAt arrContents p
1552 return r
1847 return r
1553 in c x (go (PTR_NEXT(p,a)))
1848 in c x (go (PTR_NEXT(p,a)))
@@ -1565,21 +1860,21 @@ toList MutArray{..} = liftIO $ go arrStart
1566 go p | assert (p <= arrEnd) (p == arrEnd) = return []
1861 go p | assert (p <= arrEnd) (p == arrEnd) = return []
1567 go p = do
1862 go p = do
1568− x <- peekByteIndex p arrContents
1863+ x <- peekAt p arrContents
1569 (:) x <$> go (INDEX_NEXT(p,a))
1864 (:) x <$> go (INDEX_NEXT(p,a))
1571−{-# INLINE_NORMAL toStreamDWith #-}
1866+{-# INLINE_NORMAL toStreamWith #-}
1572−toStreamDWith ::
1867+toStreamWith ::
1573 forall m a. (Monad m, Unbox a)
1868 forall m a. (Monad m, Unbox a)
1574 => (forall b. IO b -> m b) -> MutArray a -> D.Stream m a
1869 => (forall b. IO b -> m b) -> MutArray a -> D.Stream m a
1575−toStreamDWith liftio MutArray{..} = D.Stream step arrStart
1870+toStreamWith liftio MutArray{..} = D.Stream step arrStart
1579 {-# INLINE_LATE step #-}
1874 {-# INLINE_LATE step #-}
1580 step _ p | assert (p <= arrEnd) (p == arrEnd) = return D.Stop
1875 step _ p | assert (p <= arrEnd) (p == arrEnd) = return D.Stop
1581 step _ p = liftio $ do
1876 step _ p = liftio $ do
1582− r <- peekByteIndex p arrContents
1877+ r <- peekAt p arrContents
1583 return $ D.Yield r (INDEX_NEXT(p,a))
1878 return $ D.Yield r (INDEX_NEXT(p,a))
1585-- | Convert a 'MutArray' into a stream.
1880-- | Convert a 'MutArray' into a stream.
@@ -1588,7 +1883,7 @@ toStreamDWith liftio MutArray{..} = D.Stream step arrStart
1589{-# INLINE_NORMAL read #-}
1884{-# INLINE_NORMAL read #-}
1590read :: forall m a. (MonadIO m, Unbox a) => MutArray a -> D.Stream m a
1885read :: forall m a. (MonadIO m, Unbox a) => MutArray a -> D.Stream m a
1591−read = toStreamDWith liftIO
1886+read = toStreamWith liftIO
1593{-# INLINE toStreamKWith #-}
1888{-# INLINE toStreamKWith #-}
1594toStreamKWith ::
1889toStreamKWith ::
@@ -1600,18 +1895,18 @@ toStreamKWith liftio MutArray{..} = go arrStart
1601 go p | assert (p <= arrEnd) (p == arrEnd) = K.nil
1896 go p | assert (p <= arrEnd) (p == arrEnd) = K.nil
1602 | otherwise =
1897 | otherwise =
1603− let elemM = peekByteIndex p arrContents
1898+ let elemM = peekAt p arrContents
1604 in liftio elemM `K.consM` go (INDEX_NEXT(p,a))
1899 in liftio elemM `K.consM` go (INDEX_NEXT(p,a))
1606{-# INLINE toStreamK #-}
1901{-# INLINE toStreamK #-}
1607toStreamK :: forall m a. (MonadIO m, Unbox a) => MutArray a -> StreamK m a
1902toStreamK :: forall m a. (MonadIO m, Unbox a) => MutArray a -> StreamK m a
1608toStreamK = toStreamKWith liftIO
1903toStreamK = toStreamKWith liftIO
1610−{-# INLINE_NORMAL toStreamDRevWith #-}
1905+{-# INLINE_NORMAL toStreamRevWith #-}
1611−toStreamDRevWith ::
1906+toStreamRevWith ::
1612 forall m a. (Monad m, Unbox a)
1907 forall m a. (Monad m, Unbox a)
1613 => (forall b. IO b -> m b) -> MutArray a -> D.Stream m a
1908 => (forall b. IO b -> m b) -> MutArray a -> D.Stream m a
1614−toStreamDRevWith liftio MutArray{..} =
1909+toStreamRevWith liftio MutArray{..} =
1615 let p = INDEX_PREV(arrEnd,a)
1910 let p = INDEX_PREV(arrEnd,a)
1616 in D.Stream step p
1911 in D.Stream step p
@@ -1620,7 +1915,7 @@ toStreamDRevWith liftio MutArray{..} =
1620 {-# INLINE_LATE step #-}
1915 {-# INLINE_LATE step #-}
1621 step _ p | p < arrStart = return D.Stop
1916 step _ p | p < arrStart = return D.Stop
1622 step _ p = liftio $ do
1917 step _ p = liftio $ do
1623− r <- peekByteIndex p arrContents
1918+ r <- peekAt p arrContents
1624 return $ D.Yield r (INDEX_PREV(p,a))
1919 return $ D.Yield r (INDEX_PREV(p,a))
1626-- | Convert a 'MutArray' into a stream in reverse order.
1921-- | Convert a 'MutArray' into a stream in reverse order.
@@ -1629,7 +1924,7 @@ toStreamDRevWith liftio MutArray{..} =
1630{-# INLINE_NORMAL readRev #-}
1925{-# INLINE_NORMAL readRev #-}
1631readRev :: forall m a. (MonadIO m, Unbox a) => MutArray a -> D.Stream m a
1926readRev :: forall m a. (MonadIO m, Unbox a) => MutArray a -> D.Stream m a
1632−readRev = toStreamDRevWith liftIO
1927+readRev = toStreamRevWith liftIO
1634{-# INLINE toStreamKRevWith #-}
1929{-# INLINE toStreamKRevWith #-}
1635toStreamKRevWith ::
1930toStreamKRevWith ::
@@ -1643,7 +1938,7 @@ toStreamKRevWith liftio MutArray {..} =
1644 go p | p < arrStart = K.nil
1939 go p | p < arrStart = K.nil
1645 | otherwise =
1940 | otherwise =
1646− let elemM = peekByteIndex p arrContents
1941+ let elemM = peekAt p arrContents
1647 in liftio elemM `K.consM` go (INDEX_PREV(p,a))
1942 in liftio elemM `K.consM` go (INDEX_PREV(p,a))
1649{-# INLINE toStreamKRev #-}
1944{-# INLINE toStreamKRev #-}
@@ -1678,7 +1973,7 @@ foldr f z arr = D.foldr f z $ read arr
1679-- XXX Keep the bound intact to not lose any free space? Perf impact?
1974-- XXX Keep the bound intact to not lose any free space? Perf impact?
1681−-- | @writeAppendNUnsafe n arr@ appends up to @n@ input items to the supplied
1976+-- | @unsafeAppendN n arr@ appends up to @n@ input items to the supplied
1682-- array.
1977-- array.
1684-- Unsafe: Do not drive the fold beyond @n@ elements, it will lead to memory
1979-- Unsafe: Do not drive the fold beyond @n@ elements, it will lead to memory
@@ -1687,13 +1982,12 @@ foldr f z arr = D.foldr f z $ read arr
1687-- Any free space left in the array after appending @n@ elements is lost.
1982-- Any free space left in the array after appending @n@ elements is lost.
1689-- /Internal/
1984-- /Internal/
1690−{-# INLINE_NORMAL writeAppendNUnsafe #-}
1985+{-# INLINE_NORMAL unsafeAppendN #-}
1691−writeAppendNUnsafe :: forall m a. (MonadIO m, Unbox a) =>
1986+unsafeAppendN :: forall m a. (MonadIO m, Unbox a) =>
1693 -> m (MutArray a)
1988 -> m (MutArray a)
1694 -> Fold m a (MutArray a)
1989 -> Fold m a (MutArray a)
1695−writeAppendNUnsafe n action =
1696− fmap fromArrayUnsafe $ FL.foldlM' step initial
1990+unsafeAppendN n action = fmap fromArrayUnsafe $ FL.foldlM' step initial
@@ -1706,38 +2000,59 @@ writeAppendNUnsafe n action =
1706 -- otherwise we lose that space.
2000 -- otherwise we lose that space.
1708 if free < needed
2002 if free < needed
1709− then noinline reallocWith "writeAppendNUnsafeWith" (+ needed) needed arr
2003+ then noinline reallocWith "unsafeAppendN" (+ needed) needed arr
1710 else return arr
2004 else return arr
1711 return $ toArrayUnsafe arr1
2005 return $ toArrayUnsafe arr1
1713 step (ArrayUnsafe contents start end) x = do
2007 step (ArrayUnsafe contents start end) x = do
1714− liftIO $ pokeByteIndex end contents x
2008+ liftIO $ pokeAt end contents x
1715 return $ ArrayUnsafe contents start (INDEX_NEXT(end,a))
2009 return $ ArrayUnsafe contents start (INDEX_NEXT(end,a))
2011+{-# DEPRECATED writeAppendNUnsafe "Please use unsafeAppendN instead." #-}
2012+{-# INLINE writeAppendNUnsafe #-}
2013+writeAppendNUnsafe :: forall m a. (MonadIO m, Unbox a) =>
2016+ -> Fold m a (MutArray a)
2017+writeAppendNUnsafe = unsafeAppendN
1717-- | Append @n@ elements to an existing array. Any free space left in the array
2019-- | Append @n@ elements to an existing array. Any free space left in the array
1718-- after appending @n@ elements is lost.
2020-- after appending @n@ elements is lost.
1720−-- >>> writeAppendN n initial = Fold.take n (MutArray.writeAppendNUnsafe n initial)
2022+-- >>> appendN n initial = Fold.take n (MutArray.unsafeAppendN n initial)
1722−{-# INLINE_NORMAL writeAppendN #-}
2024+{-# INLINE_NORMAL appendN #-}
2025+appendN :: forall m a. (MonadIO m, Unbox a) =>
2026+ Int -> m (MutArray a) -> Fold m a (MutArray a)
2027+appendN n initial = FL.take n (unsafeAppendN n initial)
2029+-- XXX Deprecate in major
2030+-- {-# DEPRECATED writeAppendN "Please use appendN instead." #-}
2031+{-# INLINE writeAppendN #-}
1723writeAppendN :: forall m a. (MonadIO m, Unbox a) =>
2032writeAppendN :: forall m a. (MonadIO m, Unbox a) =>
1724 Int -> m (MutArray a) -> Fold m a (MutArray a)
2033 Int -> m (MutArray a) -> Fold m a (MutArray a)
1725−writeAppendN n initial = FL.take n (writeAppendNUnsafe n initial)
2034+writeAppendN = appendN
1727−-- | @writeAppendWith realloc action@ mutates the array generated by @action@ to
2036+-- | @appendWith realloc action@ mutates the array generated by @action@ to
1728-- append the input stream. If there is no reserved space available in the
2037-- append the input stream. If there is no reserved space available in the
1729-- array it is reallocated to a size in bytes determined by @realloc oldSize@,
2038-- array it is reallocated to a size in bytes determined by @realloc oldSize@,
1730-- where @oldSize@ is the current size of the array in bytes.
2039-- where @oldSize@ is the current size of the array in bytes.
1732-- Note that the returned array may be a mutated version of original array.
2041-- Note that the returned array may be a mutated version of original array.
1734−-- >>> writeAppendWith sizer = Fold.foldlM' (MutArray.snocWith sizer)
2043+-- >>> appendWith sizer = Fold.foldlM' (MutArray.snocWith sizer)
1736-- /Pre-release/
2045-- /Pre-release/
2046+{-# INLINE appendWith #-}
2047+appendWith :: forall m a. (MonadIO m, Unbox a) =>
2048+ (Int -> Int) -> m (MutArray a) -> Fold m a (MutArray a)
2049+appendWith sizer = FL.foldlM' (snocWith sizer)
2051+{-# DEPRECATED writeAppendWith "Please use appendWith instead." #-}
1737{-# INLINE writeAppendWith #-}
2052{-# INLINE writeAppendWith #-}
1738writeAppendWith :: forall m a. (MonadIO m, Unbox a) =>
2053writeAppendWith :: forall m a. (MonadIO m, Unbox a) =>
1739 (Int -> Int) -> m (MutArray a) -> Fold m a (MutArray a)
2054 (Int -> Int) -> m (MutArray a) -> Fold m a (MutArray a)
1740−writeAppendWith sizer = FL.foldlM' (snocWith sizer)
2055+writeAppendWith = appendWith
1742-- | @append action@ mutates the array generated by @action@ to append the
2057-- | @append action@ mutates the array generated by @action@ to append the
1743-- input stream. If there is no reserved space available in the array it is
2058-- input stream. If there is no reserved space available in the array it is
@@ -1745,70 +2060,101 @@ writeAppendWith sizer = FL.foldlM' (snocWith sizer)
1746-- Note that the returned array may be a mutated version of original array.
2061-- Note that the returned array may be a mutated version of original array.
1748−-- >>> writeAppend = MutArray.writeAppendWith (* 2)
2063+-- >>> append = MutArray.appendWith (* 2)
2065+{-# INLINE append #-}
2066+append :: forall m a. (MonadIO m, Unbox a) =>
2067+ m (MutArray a) -> Fold m a (MutArray a)
2068+append = appendWith (* 2)
2070+-- XXX Deprecate in major
2071+-- {-# DEPRECATED writeAppend "Please use append instead." #-}
1750{-# INLINE writeAppend #-}
2072{-# INLINE writeAppend #-}
1751writeAppend :: forall m a. (MonadIO m, Unbox a) =>
2073writeAppend :: forall m a. (MonadIO m, Unbox a) =>
1752 m (MutArray a) -> Fold m a (MutArray a)
2074 m (MutArray a) -> Fold m a (MutArray a)
1753−writeAppend = writeAppendWith (* 2)
2075+writeAppend = append
1755-- XXX We can carry bound as well in the state to make sure we do not lose the
2077-- XXX We can carry bound as well in the state to make sure we do not lose the
1756-- remaining capacity. Need to check perf impact.
2078-- remaining capacity. Need to check perf impact.
1758−-- | Like 'writeNUnsafe' but takes a new array allocator @alloc size@ function
2080+-- | Like 'unsafeCreateOf' but takes a new array allocator @alloc size@
1759−-- as argument.
2081+-- function as argument.
1761−-- >>> writeNWithUnsafe alloc n = MutArray.writeAppendNUnsafe (alloc n) n
2083+-- >>> unsafeCreateOfWith alloc n = MutArray.unsafeAppendN (alloc n) n
1763-- /Pre-release/
2085-- /Pre-release/
1764−{-# INLINE_NORMAL writeNWithUnsafe #-}
2086+{-# INLINE_NORMAL unsafeCreateOfWith #-}
1765−writeNWithUnsafe :: forall m a. (MonadIO m, Unbox a)
2087+unsafeCreateOfWith :: forall m a. (MonadIO m, Unbox a)
1766 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
2088 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
1767−writeNWithUnsafe alloc n = fromArrayUnsafe <$> FL.foldlM' step initial
2089+unsafeCreateOfWith alloc n = fromArrayUnsafe <$> FL.foldlM' step initial
1771 initial = toArrayUnsafe <$> alloc (max n 0)
2093 initial = toArrayUnsafe <$> alloc (max n 0)
1773 step (ArrayUnsafe contents start end) x = do
2095 step (ArrayUnsafe contents start end) x = do
1774− liftIO $ pokeByteIndex end contents x
2096+ liftIO $ pokeAt end contents x
1776 $ ArrayUnsafe contents start (INDEX_NEXT(end,a))
2098 $ ArrayUnsafe contents start (INDEX_NEXT(end,a))
2100+{-# DEPRECATED writeNWithUnsafe "Please use unsafeCreateOfWith instead." #-}
2101+{-# INLINE writeNWithUnsafe #-}
2102+writeNWithUnsafe :: forall m a. (MonadIO m, Unbox a)
2103+ => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
2104+writeNWithUnsafe = unsafeCreateOfWith
1778{-# INLINE_NORMAL writeNUnsafeAs #-}
2106{-# INLINE_NORMAL writeNUnsafeAs #-}
1779writeNUnsafeAs :: forall m a. (MonadIO m, Unbox a)
2107writeNUnsafeAs :: forall m a. (MonadIO m, Unbox a)
1780 => PinnedState -> Int -> Fold m a (MutArray a)
2108 => PinnedState -> Int -> Fold m a (MutArray a)
1781−writeNUnsafeAs ps = writeNWithUnsafe (newAs ps)
2109+writeNUnsafeAs ps = unsafeCreateOfWith (newAs ps)
1783−-- | Like 'writeN' but does not check the array bounds when writing. The fold
2111+-- | Like 'createOf' but does not check the array bounds when writing. The fold
1784-- driver must not call the step function more than 'n' times otherwise it will
2112-- driver must not call the step function more than 'n' times otherwise it will
1785-- corrupt the memory and crash. This function exists mainly because any
2113-- corrupt the memory and crash. This function exists mainly because any
1786-- conditional in the step function blocks fusion causing 10x performance
2114-- conditional in the step function blocks fusion causing 10x performance
1787-- slowdown.
2115-- slowdown.
1789−-- >>> writeNUnsafe = MutArray.writeNWithUnsafe MutArray.new
2117+-- >>> unsafeCreateOf = MutArray.unsafeCreateOfWith MutArray.emptyOf
2119+{-# INLINE_NORMAL unsafeCreateOf #-}
2120+unsafeCreateOf :: forall m a. (MonadIO m, Unbox a)
2121+ => Int -> Fold m a (MutArray a)
2122+unsafeCreateOf = writeNUnsafeAs Unpinned
2124+{-# DEPRECATED writeNUnsafe "Please use unsafeCreateOf instead." #-}
1791−{-# INLINE_NORMAL writeNUnsafe #-}
2125+{-# INLINE writeNUnsafe #-}
1792writeNUnsafe :: forall m a. (MonadIO m, Unbox a)
2126writeNUnsafe :: forall m a. (MonadIO m, Unbox a)
1793 => Int -> Fold m a (MutArray a)
2127 => Int -> Fold m a (MutArray a)
1794−writeNUnsafe = writeNUnsafeAs Unpinned
2128+writeNUnsafe = unsafeCreateOf
1796−-- | Like 'writeNUnsafe' but creates a pinned array.
2130+-- | Like 'unsafeCreateOf' but creates a pinned array.
2131+{-# INLINE_NORMAL unsafePinnedCreateOf #-}
2132+unsafePinnedCreateOf :: forall m a. (MonadIO m, Unbox a)
2133+ => Int -> Fold m a (MutArray a)
2134+unsafePinnedCreateOf = writeNUnsafeAs Pinned
2136+{-# DEPRECATED pinnedWriteNUnsafe "Please use unsafePinnedCreateOf instead." #-}
1797−{-# INLINE_NORMAL pinnedWriteNUnsafe #-}
2137+{-# INLINE pinnedWriteNUnsafe #-}
1798pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a)
2138pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a)
1799 => Int -> Fold m a (MutArray a)
2139 => Int -> Fold m a (MutArray a)
1800−pinnedWriteNUnsafe = writeNUnsafeAs Pinned
2140+pinnedWriteNUnsafe = unsafePinnedCreateOf
1802−-- | @writeNWith alloc n@ folds a maximum of @n@ elements into an array
2142+-- | @createOfWith alloc n@ folds a maximum of @n@ elements into an array
1803-- allocated using the @alloc@ function.
2143-- allocated using the @alloc@ function.
1805−-- >>> writeNWith alloc n = Fold.take n (MutArray.writeNWithUnsafe alloc n)
2145+-- >>> createOfWith alloc n = Fold.take n (MutArray.unsafeCreateOfWith alloc n)
1806−-- >>> writeNWith alloc n = MutArray.writeAppendN (alloc n) n
2146+-- >>> createOfWith alloc n = MutArray.appendN (alloc n) n
1808−{-# INLINE_NORMAL writeNWith #-}
2148+{-# INLINE_NORMAL createOfWith #-}
2149+createOfWith :: forall m a. (MonadIO m, Unbox a)
2150+ => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
2151+createOfWith alloc n = FL.take n (unsafeCreateOfWith alloc n)
2153+-- {-# DEPRECATED writeNWith "Please use createOfWith instead." #-}
2154+{-# INLINE writeNWith #-}
1809writeNWith :: forall m a. (MonadIO m, Unbox a)
2155writeNWith :: forall m a. (MonadIO m, Unbox a)
1810 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
2156 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
1811−writeNWith alloc n = FL.take n (writeNWithUnsafe alloc n)
2157+writeNWith = createOfWith
1813{-# INLINE_NORMAL writeNAs #-}
2159{-# INLINE_NORMAL writeNAs #-}
1814writeNAs ::
2160writeNAs ::
@@ -1816,28 +2162,42 @@ writeNAs ::
1816 => PinnedState
2162 => PinnedState
1818 -> Fold m a (MutArray a)
2164 -> Fold m a (MutArray a)
1819−writeNAs ps = writeNWith (newAs ps)
2165+writeNAs ps = createOfWith (newAs ps)
1821−-- | @writeN n@ folds a maximum of @n@ elements from the input stream to an
2167+-- | @createOf n@ folds a maximum of @n@ elements from the input stream to an
1822-- 'MutArray'.
2168-- 'MutArray'.
1824−-- >>> writeN = MutArray.writeNWith MutArray.new
2170+-- >>> createOf = MutArray.createOfWith MutArray.new
1825−-- >>> writeN n = Fold.take n (MutArray.writeNUnsafe n)
2171+-- >>> createOf n = Fold.take n (MutArray.unsafeCreateOf n)
1826−-- >>> writeN n = MutArray.writeAppendN n (MutArray.new n)
2172+-- >>> createOf n = MutArray.appendN n (MutArray.emptyOf n)
1828−{-# INLINE_NORMAL writeN #-}
2174+{-# INLINE_NORMAL createOf #-}
2175+createOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
2176+createOf = writeNAs Unpinned
2178+-- XXX Deprecate in major
2179+-- {-# DEPRECATED writeN "Please use createOf instead." #-}
2180+{-# INLINE writeN #-}
1829writeN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
2181writeN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
1830−writeN = writeNAs Unpinned
2182+writeN = createOf
2184+-- | Like 'createOf' but creates a pinned array.
2185+{-# INLINE_NORMAL pinnedCreateOf #-}
2187+ forall m a. (MonadIO m, Unbox a)
2189+ -> Fold m a (MutArray a)
2190+pinnedCreateOf = writeNAs Pinned
1832−-- | Like 'writeN' but creates a pinned array.
2192+{-# DEPRECATED pinnedWriteN "Please use pinnedCreateOf instead." #-}
1833−{-# INLINE_NORMAL pinnedWriteN #-}
2193+{-# INLINE pinnedWriteN #-}
1834pinnedWriteN ::
2194pinnedWriteN ::
1835 forall m a. (MonadIO m, Unbox a)
2195 forall m a. (MonadIO m, Unbox a)
1837 -> Fold m a (MutArray a)
2197 -> Fold m a (MutArray a)
1838−pinnedWriteN = writeNAs Pinned
2198+pinnedWriteN = pinnedCreateOf
1840−-- | Like writeNWithUnsafe but writes the array in reverse order.
2200+-- | Like unsafeCreateOfWith but writes the array in reverse order.
1842-- /Internal/
2202-- /Internal/
1843{-# INLINE_NORMAL writeRevNWithUnsafe #-}
2203{-# INLINE_NORMAL writeRevNWithUnsafe #-}
@@ -1854,11 +2214,11 @@ writeRevNWithUnsafe alloc n = fromArrayUnsafe <$> FL.foldlM' step initial
1855 step (ArrayUnsafe contents start end) x = do
2215 step (ArrayUnsafe contents start end) x = do
1856 let ptr = INDEX_PREV(start,a)
2216 let ptr = INDEX_PREV(start,a)
1857− liftIO $ pokeByteIndex ptr contents x
2217+ liftIO $ pokeAt ptr contents x
1859 $ ArrayUnsafe contents ptr end
2219 $ ArrayUnsafe contents ptr end
1861−-- | Like writeNWith but writes the array in reverse order.
2221+-- | Like createOfWith but writes the array in reverse order.
1863-- /Internal/
2223-- /Internal/
1864{-# INLINE_NORMAL writeRevNWith #-}
2224{-# INLINE_NORMAL writeRevNWith #-}
@@ -1866,31 +2226,36 @@ writeRevNWith :: forall m a. (MonadIO m, Unbox a)
1866 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
2226 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
1867writeRevNWith alloc n = FL.take n (writeRevNWithUnsafe alloc n)
2227writeRevNWith alloc n = FL.take n (writeRevNWithUnsafe alloc n)
1869−-- | Like writeN but writes the array in reverse order.
2229+-- | Like 'createOf' but writes the array in reverse order.
1871-- /Pre-release/
2231-- /Pre-release/
1872−{-# INLINE_NORMAL writeRevN #-}
2232+{-# INLINE_NORMAL revCreateOf #-}
2233+revCreateOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
2234+revCreateOf = writeRevNWith new
2236+{-# DEPRECATED writeRevN "Please use revCreateOf instead." #-}
2237+{-# INLINE writeRevN #-}
1873writeRevN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
2238writeRevN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
1874−writeRevN = writeRevNWith new
2239+writeRevN = revCreateOf
1876-- | @pinnedWriteNAligned align n@ folds a maximum of @n@ elements from the
2241-- | @pinnedWriteNAligned align n@ folds a maximum of @n@ elements from the
1877-- input stream to a 'MutArray' aligned to the given size.
2242-- input stream to a 'MutArray' aligned to the given size.
1879−-- >>> pinnedWriteNAligned align = MutArray.writeNWith (MutArray.pinnedNewAligned align)
2244+-- >>> pinnedWriteNAligned align = MutArray.createOfWith (MutArray.pinnedNewAligned align)
1880−-- >>> pinnedWriteNAligned align n = MutArray.writeAppendN n (MutArray.pinnedNewAligned align n)
2245+-- >>> pinnedWriteNAligned align n = MutArray.appendN n (MutArray.pinnedNewAligned align n)
1882-- /Pre-release/
2247-- /Pre-release/
1884{-# INLINE_NORMAL pinnedWriteNAligned #-}
2249{-# INLINE_NORMAL pinnedWriteNAligned #-}
1885pinnedWriteNAligned :: forall m a. (MonadIO m, Unbox a)
2250pinnedWriteNAligned :: forall m a. (MonadIO m, Unbox a)
1886 => Int -> Int -> Fold m a (MutArray a)
2251 => Int -> Int -> Fold m a (MutArray a)
1887−pinnedWriteNAligned align = writeNWith (pinnedNewAligned align)
2252+pinnedWriteNAligned align = createOfWith (pinnedNewAligned align)
1889-- XXX Buffer to a list instead?
2254-- XXX Buffer to a list instead?
1891-- | Buffer a stream into a stream of arrays.
2256-- | Buffer a stream into a stream of arrays.
1893−-- >>> writeChunks n = Fold.many (MutArray.writeN n) Fold.toStreamK
2258+-- >>> buildChunks n = Fold.many (MutArray.createOf n) Fold.toStreamK
1895-- Breaking an array into an array stream can be useful to consume a large
2260-- Breaking an array into an array stream can be useful to consume a large
1896-- array sequentially such that memory of the array is released incrementatlly.
2261-- array sequentially such that memory of the array is released incrementatlly.
@@ -1899,37 +2264,43 @@ pinnedWriteNAligned align = writeNWith (pinnedNewAligned align)
1900-- /Unimplemented/
2265-- /Unimplemented/
1902−{-# INLINE_NORMAL writeChunks #-}
2267+{-# INLINE_NORMAL buildChunks #-}
2268+buildChunks :: (MonadIO m, Unbox a) =>
2269+ Int -> Fold m a (StreamK n (MutArray a))
2270+buildChunks n = FL.many (createOf n) FL.toStreamK
2272+{-# DEPRECATED writeChunks "Please use buildChunks instead." #-}
2273+{-# INLINE writeChunks #-}
1903writeChunks :: (MonadIO m, Unbox a) =>
2274writeChunks :: (MonadIO m, Unbox a) =>
1904 Int -> Fold m a (StreamK n (MutArray a))
2275 Int -> Fold m a (StreamK n (MutArray a))
1905−writeChunks n = FL.many (writeN n) FL.toStreamK
2276+writeChunks = buildChunks
1907{-# INLINE_NORMAL writeWithAs #-}
2278{-# INLINE_NORMAL writeWithAs #-}
1908writeWithAs :: forall m a. (MonadIO m, Unbox a)
2279writeWithAs :: forall m a. (MonadIO m, Unbox a)
1909 => PinnedState -> Int -> Fold m a (MutArray a)
2280 => PinnedState -> Int -> Fold m a (MutArray a)
1910−-- writeWithAs ps n = FL.rmapM rightSize $ writeAppendWith (* 2) (newAs ps n)
2281+-- writeWithAs ps n = FL.rmapM rightSize $ appendWith (* 2) (newAs ps n)
1911writeWithAs ps elemCount =
2282writeWithAs ps elemCount =
1912 FL.rmapM extract $ FL.foldlM' step initial
2283 FL.rmapM extract $ FL.foldlM' step initial
1916 initial = do
2287 initial = do
1917− when (elemCount < 0) $ error "writeWith: elemCount is negative"
2288+ when (elemCount < 0) $ error "createWith: elemCount is negative"
1918− liftIO $ newAs ps elemCount
2289+ newAs ps elemCount
1920 step arr@(MutArray _ start end bound) x
2291 step arr@(MutArray _ start end bound) x
1921 | INDEX_NEXT(end,a) > bound = do
2292 | INDEX_NEXT(end,a) > bound = do
1922 let oldSize = end - start
2293 let oldSize = end - start
1923 newSize = max (oldSize * 2) 1
2294 newSize = max (oldSize * 2) 1
1924− arr1 <- liftIO $ reallocExplicit (SIZE_OF(a)) newSize arr
2295+ arr1 <- liftIO $ reallocExplicitAs ps (SIZE_OF(a)) newSize arr
1925 snocUnsafe arr1 x
2296 snocUnsafe arr1 x
1926 step arr x = snocUnsafe arr x
2297 step arr x = snocUnsafe arr x
1928 extract = liftIO . rightSize
2299 extract = liftIO . rightSize
1930−-- XXX Compare writeWith with fromStreamD which uses an array of streams
2301+-- XXX Compare createWith with fromStreamD which uses an array of streams
1931−-- implementation. We can write this using writeChunks above if that is faster.
2302+-- implementation. We can write this using buildChunks above if that is faster.
1932−-- If writeWith is faster then we should use that to implement
2303+-- If createWith is faster then we should use that to implement
1933-- fromStreamD.
2304-- fromStreamD.
1935-- XXX The realloc based implementation needs to make one extra copy if we use
2306-- XXX The realloc based implementation needs to make one extra copy if we use
@@ -1944,39 +2315,56 @@ writeWithAs ps elemCount =
1944-- XXX check if GHC's memory allocator is efficient enough. We can try the C
2315-- XXX check if GHC's memory allocator is efficient enough. We can try the C
1945-- malloc to compare against.
2316-- malloc to compare against.
1947−-- | @writeWith minCount@ folds the whole input to a single array. The array
2318+-- | @createWith minCount@ folds the whole input to a single array. The array
1948-- starts at a size big enough to hold minCount elements, the size is doubled
2319-- starts at a size big enough to hold minCount elements, the size is doubled
1949-- every time the array needs to be grown.
2320-- every time the array needs to be grown.
1951-- /Caution! Do not use this on infinite streams./
2322-- /Caution! Do not use this on infinite streams./
1953−-- >>> f n = MutArray.writeAppendWith (* 2) (MutArray.new n)
2324+-- >>> f n = MutArray.appendWith (* 2) (MutArray.emptyOf n)
1954−-- >>> writeWith n = Fold.rmapM MutArray.rightSize (f n)
2325+-- >>> createWith n = Fold.rmapM MutArray.rightSize (f n)
1955−-- >>> writeWith n = Fold.rmapM MutArray.fromArrayStreamK (MutArray.writeChunks n)
2326+-- >>> createWith n = Fold.rmapM MutArray.fromChunksK (MutArray.buildChunks n)
1957-- /Pre-release/
2328-- /Pre-release/
1958−{-# INLINE_NORMAL writeWith #-}
2329+{-# INLINE_NORMAL createWith #-}
2330+createWith :: forall m a. (MonadIO m, Unbox a)
2331+ => Int -> Fold m a (MutArray a)
2332+-- createWith n = FL.rmapM rightSize $ appendWith (* 2) (emptyOf n)
2333+createWith = writeWithAs Unpinned
2335+{-# DEPRECATED writeWith "Please use createWith instead." #-}
2336+{-# INLINE writeWith #-}
1959writeWith :: forall m a. (MonadIO m, Unbox a)
2337writeWith :: forall m a. (MonadIO m, Unbox a)
1960 => Int -> Fold m a (MutArray a)
2338 => Int -> Fold m a (MutArray a)
1961−-- writeWith n = FL.rmapM rightSize $ writeAppendWith (* 2) (new n)
2339+writeWith = createWith
1962−writeWith = writeWithAs Unpinned
1964-- | Fold the whole input to a single array.
2341-- | Fold the whole input to a single array.
1966−-- Same as 'writeWith' using an initial array size of 'arrayChunkBytes' bytes
2343+-- Same as 'createWith' using an initial array size of 'arrayChunkBytes' bytes
1967-- rounded up to the element size.
2344-- rounded up to the element size.
1969-- /Caution! Do not use this on infinite streams./
2346-- /Caution! Do not use this on infinite streams./
2348+{-# INLINE create #-}
2349+create :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
2350+create = createWith (allocBytesToElemCount (undefined :: a) arrayChunkBytes)
2352+-- XXX Deprecate in major
2353+-- {-# DEPRECATED write "Please use create instead." #-}
1971{-# INLINE write #-}
2354{-# INLINE write #-}
1972write :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
2355write :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
2358+-- | Like 'create' but creates a pinned array.
2359+{-# INLINE pinnedCreate #-}
2360+pinnedCreate :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
1973−write = writeWith (allocBytesToElemCount (undefined :: a) arrayChunkBytes)
2362+ writeWithAs Pinned (allocBytesToElemCount (undefined :: a) arrayChunkBytes)
1975−-- | Like 'write' but creates a pinned array.
2364+{-# DEPRECATED pinnedWrite "Please use pinnedCreate instead." #-}
1976{-# INLINE pinnedWrite #-}
2365{-# INLINE pinnedWrite #-}
1977pinnedWrite :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
2366pinnedWrite :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
1978−pinnedWrite =
2367+pinnedWrite = pinnedCreate
1979− writeWithAs Pinned (allocBytesToElemCount (undefined :: a) arrayChunkBytes)
1981-------------------------------------------------------------------------------
2369-------------------------------------------------------------------------------
1982-- construct from streams, known size
2370-- construct from streams, known size
@@ -1986,25 +2374,31 @@ pinnedWrite =
1986fromStreamDNAs :: forall m a. (MonadIO m, Unbox a)
2374fromStreamDNAs :: forall m a. (MonadIO m, Unbox a)
1987 => PinnedState -> Int -> D.Stream m a -> m (MutArray a)
2375 => PinnedState -> Int -> D.Stream m a -> m (MutArray a)
1988fromStreamDNAs ps limit str = do
2376fromStreamDNAs ps limit str = do
1989− (arr :: MutArray a) <- liftIO $ newAs ps limit
2377+ (arr :: MutArray a) <- newAs ps limit
1990 end <- D.foldlM' (fwrite (arrContents arr)) (return $ arrEnd arr) $ D.take limit str
2378 end <- D.foldlM' (fwrite (arrContents arr)) (return $ arrEnd arr) $ D.take limit str
1991 return $ arr {arrEnd = end}
2379 return $ arr {arrEnd = end}
1995 fwrite arrContents ptr x = do
2383 fwrite arrContents ptr x = do
1996− liftIO $ pokeByteIndex ptr arrContents x
2384+ liftIO $ pokeAt ptr arrContents x
1997 return $ INDEX_NEXT(ptr,a)
2385 return $ INDEX_NEXT(ptr,a)
1999−-- | Use the 'writeN' fold instead.
2387+-- | Use the 'createOf' fold instead.
2001−-- >>> fromStreamDN n = Stream.fold (MutArray.writeN n)
2389+-- >>> fromStreamN n = Stream.fold (MutArray.createOf n)
2391+{-# INLINE_NORMAL fromStreamN #-}
2392+fromStreamN :: forall m a. (MonadIO m, Unbox a)
2393+ => Int -> D.Stream m a -> m (MutArray a)
2394+-- fromStreamDN n = D.fold (createOf n)
2395+fromStreamN = fromStreamDNAs Unpinned
2397+{-# DEPRECATED fromStreamDN "Please use fromStreamN instead." #-}
2003−{-# INLINE_NORMAL fromStreamDN #-}
2398+{-# INLINE fromStreamDN #-}
2004fromStreamDN :: forall m a. (MonadIO m, Unbox a)
2399fromStreamDN :: forall m a. (MonadIO m, Unbox a)
2005 => Int -> D.Stream m a -> m (MutArray a)
2400 => Int -> D.Stream m a -> m (MutArray a)
2006−-- fromStreamDN n = D.fold (writeN n)
2401+fromStreamDN = fromStreamN
2007−fromStreamDN = fromStreamDNAs Unpinned
2009-- | Create a 'MutArray' from the first N elements of a list. The array is
2403-- | Create a 'MutArray' from the first N elements of a list. The array is
2010-- allocated to size N, if the list terminates before N elements then the
2404-- allocated to size N, if the list terminates before N elements then the
@@ -2024,16 +2418,70 @@ pinnedFromListN n xs = fromStreamDNAs Pinned n $ D.fromList xs
2024-- /Pre-release/
2418-- /Pre-release/
2025{-# INLINE fromListRevN #-}
2419{-# INLINE fromListRevN #-}
2026fromListRevN :: (MonadIO m, Unbox a) => Int -> [a] -> m (MutArray a)
2420fromListRevN :: (MonadIO m, Unbox a) => Int -> [a] -> m (MutArray a)
2027−fromListRevN n xs = D.fold (writeRevN n) $ D.fromList xs
2421+fromListRevN n xs = D.fold (revCreateOf n) $ D.fromList xs
2423+-- | Convert a pure stream in Identity monad to a mutable array.
2424+{-# INLINABLE fromPureStreamN #-}
2425+fromPureStreamN :: (MonadIO m, Unbox a) =>
2426+ Int -> Stream Identity a -> m (MutArray a)
2427+fromPureStreamN n xs =
2428+ D.fold (createOf n) $ D.morphInner (return . runIdentity) xs
2029-- | Convert a pure stream in Identity monad to a mutable array.
2430-- | Convert a pure stream in Identity monad to a mutable array.
2030{-# INLINABLE fromPureStream #-}
2431{-# INLINABLE fromPureStream #-}
2031fromPureStream :: (MonadIO m, Unbox a) => Stream Identity a -> m (MutArray a)
2432fromPureStream :: (MonadIO m, Unbox a) => Stream Identity a -> m (MutArray a)
2032fromPureStream xs =
2433fromPureStream xs =
2033− liftIO $ D.fold write $ D.morphInner (return . runIdentity) xs
2434+ D.fold create $ D.morphInner (return . runIdentity) xs
2436+{-# INLINABLE fromPtrN #-}
2437+fromPtrN :: MonadIO m => Int -> Ptr Word8 -> m (MutArray Word8)
2438+fromPtrN len addr = do
2439+ -- memcpy is better than stream copy when the size is known.
2440+ -- XXX We can implement a stream copy in a similar way by streaming Word64
2441+ -- first and then remaining Word8.
2443+ _ <- unsafeAsPtr arr
2444+ (\ptr -> liftIO $ c_memcpy ptr addr (fromIntegral len))
2445+ return (arr {arrEnd = len})
2447+{-# INLINABLE fromByteStr# #-}
2448+fromByteStr# :: MonadIO m => Addr# -> m (MutArray Word8)
2449+fromByteStr# addr = do
2450+ -- It is better to count the size first and allocate exact space.
2451+ -- Also, memcpy is better than stream copy when the size is known.
2452+ -- C strlen compares 4 bytes at a time, so is better than the stream
2453+ -- version. https://github.com/bminor/glibc/blob/master/string/strlen.c
2454+ -- XXX We can possibly use a stream of Word64 to do the same.
2455+ -- fromByteStr# addr = fromPureStream (D.fromByteStr# addr)
2456+ len <- liftIO $ c_strlen (Ptr addr)
2457+ let lenInt = fromIntegral len
2459+ _ <- unsafeAsPtr arr (\ptr -> liftIO $ c_memcpy ptr (Ptr addr) len)
2460+ return (arr {arrEnd = lenInt})
2035-------------------------------------------------------------------------------
2462-------------------------------------------------------------------------------
2463+-- convert a stream of arrays to a single array by reallocating and copying
2464+-------------------------------------------------------------------------------
2466+-- XXX Both of these implementations of splicing seem to perform equally well.
2467+-- We need to perform benchmarks over a range of sizes though.
2469+-- | Also see 'fromChunksK'.
2470+{-# INLINE fromChunksRealloced #-}
2471+fromChunksRealloced :: forall m a. (MonadIO m, Unbox a)
2472+ => Stream m (MutArray a) -> m (MutArray a)
2473+fromChunksRealloced s = do
2476+ Just (a, strm) -> do
2477+ arr <- D.foldlM' spliceExp (pure a) strm
2478+ -- Reallocation is exponential so there may be 50% empty space in
2479+ -- worst case. One more reallocation to reclaim the space.
2481+ Nothing -> pure nil
2483+-------------------------------------------------------------------------------
2036−-- convert stream to a single array
2484+-- convert a stream of arrays to a single array by buffering arrays first
2037-------------------------------------------------------------------------------
2485-------------------------------------------------------------------------------
2039{-# INLINE arrayStreamKLength #-}
2487{-# INLINE arrayStreamKLength #-}
@@ -2043,34 +2491,72 @@ arrayStreamKLength as = K.foldl' (+) 0 (K.map length as)
2043-- | Convert an array stream to an array. Note that this requires peak memory
2491-- | Convert an array stream to an array. Note that this requires peak memory
2044-- that is double the size of the array stream.
2492-- that is double the size of the array stream.
2494+{-# INLINE fromChunkskAs #-}
2495+fromChunkskAs :: (Unbox a, MonadIO m) =>
2496+ PinnedState -> StreamK m (MutArray a) -> m (MutArray a)
2497+fromChunkskAs ps as = do
2498+ len <- arrayStreamKLength as
2499+ arr <- newAs ps len
2500+ -- XXX is StreamK fold faster or StreamD fold?
2501+ K.foldlM' spliceUnsafe (pure arr) as
2502+ -- fromStreamDN len $ D.unfoldMany reader $ D.fromStreamK as
2504+-- XXX Need to compare this with fromChunks and fromChunkList and keep the
2505+-- fastest or simplest one if all are equally fast.
2507+-- | Convert an array stream to an array. Note that this requires peak memory
2508+-- that is double the size of the array stream.
2510+-- Also see 'fromChunksRealloced'.
2512+{-# INLINE fromChunksK #-}
2513+fromChunksK :: (Unbox a, MonadIO m) =>
2514+ StreamK m (MutArray a) -> m (MutArray a)
2515+fromChunksK = fromChunkskAs Unpinned
2517+{-# DEPRECATED fromArrayStreamK "Please use fromChunksK instead." #-}
2046{-# INLINE fromArrayStreamK #-}
2518{-# INLINE fromArrayStreamK #-}
2047fromArrayStreamK :: (Unbox a, MonadIO m) =>
2519fromArrayStreamK :: (Unbox a, MonadIO m) =>
2048 StreamK m (MutArray a) -> m (MutArray a)
2520 StreamK m (MutArray a) -> m (MutArray a)
2049−fromArrayStreamK as = do
2521+fromArrayStreamK = fromChunksK
2050− len <- arrayStreamKLength as
2051− fromStreamDN len $ D.unfoldMany reader $ D.fromStreamK as
2053{-# INLINE fromStreamDAs #-}
2523{-# INLINE fromStreamDAs #-}
2054fromStreamDAs ::
2524fromStreamDAs ::
2055 (MonadIO m, Unbox a) => PinnedState -> D.Stream m a -> m (MutArray a)
2525 (MonadIO m, Unbox a) => PinnedState -> D.Stream m a -> m (MutArray a)
2526+fromStreamDAs ps m =
2056−fromStreamDAs ps m = arrayStreamKFromStreamDAs ps m >>= fromArrayStreamK
2527+ arrayStreamKFromStreamDAs Unpinned m >>= fromChunkskAs ps
2529+-- | Create an 'Array' from a stream. This is useful when we want to create a
2530+-- single array from a stream of unknown size. 'createOf' is at least twice
2531+-- as efficient when the size is already known.
2533+-- Note that if the input stream is too large memory allocation for the array
2534+-- may fail. When the stream size is not known, `chunksOf` followed by
2535+-- processing of indvidual arrays in the resulting stream should be preferred.
2538+{-# INLINE fromStream #-}
2539+fromStream :: (MonadIO m, Unbox a) => Stream m a -> m (MutArray a)
2540+fromStream = fromStreamDAs Unpinned
2542+-- fromStream (Stream m) = P.fold create m
2058-- CAUTION: a very large number (millions) of arrays can degrade performance
2543-- CAUTION: a very large number (millions) of arrays can degrade performance
2059-- due to GC overhead because we need to buffer the arrays before we flatten
2544-- due to GC overhead because we need to buffer the arrays before we flatten
2060-- all the arrays.
2545-- all the arrays.
2062−-- XXX Compare if this is faster or "fold write".
2547+-- XXX Compare if this is faster or "fold create".
2064-- | We could take the approach of doubling the memory allocation on each
2549-- | We could take the approach of doubling the memory allocation on each
2065-- overflow. This would result in more or less the same amount of copying as in
2550-- overflow. This would result in more or less the same amount of copying as in
2066-- the chunking approach. However, if we have to shrink in the end then it may
2551-- the chunking approach. However, if we have to shrink in the end then it may
2067-- result in an extra copy of the entire data.
2552-- result in an extra copy of the entire data.
2069−-- >>> fromStreamD = StreamD.fold MutArray.write
2554+-- >>> fromStreamD = StreamD.fold MutArray.create
2071{-# INLINE fromStreamD #-}
2556{-# INLINE fromStreamD #-}
2557+{-# DEPRECATED fromStreamD "Please use fromStream instead." #-}
2072fromStreamD :: (MonadIO m, Unbox a) => D.Stream m a -> m (MutArray a)
2558fromStreamD :: (MonadIO m, Unbox a) => D.Stream m a -> m (MutArray a)
2073−fromStreamD = fromStreamDAs Unpinned
2559+fromStreamD = fromStream
2075-- | Create a 'MutArray' from a list. The list must be of finite size.
2561-- | Create a 'MutArray' from a list. The list must be of finite size.
@@ -2095,22 +2581,44 @@ fromListRev xs = fromListRevN (Prelude.length xs) xs
2095-- Cloning
2581-- Cloning
2096-------------------------------------------------------------------------------
2582-------------------------------------------------------------------------------
2584+-- Arrays are aligned on 64-bit boundaries. The fastest way to copy an array is
2585+-- to unsafeCast it to Word64, read it, write it to Word64 array and unsafeCast
2586+-- it again. We can use SIMD read/write as well.
2098{-# INLINE cloneAs #-}
2588{-# INLINE cloneAs #-}
2099−cloneAs :: MonadIO m => PinnedState -> MutArray a -> m (MutArray a)
2595+ => PinnedState -> MutArray a -> m (MutArray a)
2100cloneAs ps src =
2596cloneAs ps src =
2101− liftIO $ do
2597+ do
2102 let startSrc = arrStart src
2598 let startSrc = arrStart src
2103 srcLen = arrEnd src - startSrc
2599 srcLen = arrEnd src - startSrc
2104− newArrContents <- Unboxed.newBytesAs ps srcLen
2600+ newArrContents <-
2105− putSliceUnsafe (arrContents src) startSrc newArrContents 0 srcLen
2601+ Unboxed.cloneSliceUnsafeAs ps startSrc srcLen (arrContents src)
2106 return $ MutArray newArrContents 0 srcLen srcLen
2602 return $ MutArray newArrContents 0 srcLen srcLen
2108{-# INLINE clone #-}
2604{-# INLINE clone #-}
2109−clone :: MonadIO m => MutArray a -> m (MutArray a)
2611+ => MutArray a -> m (MutArray a)
2110clone = cloneAs Unpinned
2612clone = cloneAs Unpinned
2112{-# INLINE pinnedClone #-}
2614{-# INLINE pinnedClone #-}
2113−pinnedClone :: MonadIO m => MutArray a -> m (MutArray a)
2621+ => MutArray a -> m (MutArray a)
2114pinnedClone = cloneAs Pinned
2622pinnedClone = cloneAs Pinned
2116-------------------------------------------------------------------------------
2624-------------------------------------------------------------------------------
@@ -2125,17 +2633,16 @@ spliceCopy :: forall m a. MonadIO m =>
2125 Unbox a =>
2633 Unbox a =>
2127 MutArray a -> MutArray a -> m (MutArray a)
2635 MutArray a -> MutArray a -> m (MutArray a)
2128−spliceCopy arr1 arr2 = liftIO $ do
2636+spliceCopy arr1 arr2 = do
2129 let start1 = arrStart arr1
2637 let start1 = arrStart arr1
2130 start2 = arrStart arr2
2638 start2 = arrStart arr2
2131 len1 = arrEnd arr1 - start1
2639 len1 = arrEnd arr1 - start1
2132 len2 = arrEnd arr2 - start2
2640 len2 = arrEnd arr2 - start2
2133− let newLen = len1 + len2
2641+ let len = len1 + len2
2134 newArrContents <-
2642 newArrContents <-
2135 if Unboxed.isPinned (arrContents arr1)
2643 if Unboxed.isPinned (arrContents arr1)
2136− then Unboxed.pinnedNewBytes newLen
2644+ then liftIO $ Unboxed.pinnedNew len
2137− else Unboxed.newBytes newLen
2645+ else liftIO $ Unboxed.new len
2138− let len = len1 + len2
2139 putSliceUnsafe (arrContents arr1) start1 newArrContents 0 len1
2646 putSliceUnsafe (arrContents arr1) start1 newArrContents 0 len1
2140 putSliceUnsafe (arrContents arr2) start2 newArrContents len1 len2
2647 putSliceUnsafe (arrContents arr2) start2 newArrContents len1 len2
2141 return $ MutArray newArrContents 0 len len
2648 return $ MutArray newArrContents 0 len len
@@ -2147,7 +2654,7 @@ spliceCopy arr1 arr2 = liftIO $ do
2147spliceUnsafe :: MonadIO m =>
2654spliceUnsafe :: MonadIO m =>
2148 MutArray a -> MutArray a -> m (MutArray a)
2655 MutArray a -> MutArray a -> m (MutArray a)
2149spliceUnsafe dst src =
2656spliceUnsafe dst src =
2150− liftIO $ do
2657+ do
2151 let startSrc = arrStart src
2658 let startSrc = arrStart src
2152 srcLen = arrEnd src - startSrc
2659 srcLen = arrEnd src - startSrc
2153 endDst = arrEnd dst
2660 endDst = arrEnd dst
@@ -2169,7 +2676,7 @@ spliceWith :: forall m a. (MonadIO m, Unbox a) =>
2169 (Int -> Int -> Int) -> MutArray a -> MutArray a -> m (MutArray a)
2676 (Int -> Int -> Int) -> MutArray a -> MutArray a -> m (MutArray a)
2170spliceWith sizer dst@(MutArray _ start end bound) src = do
2677spliceWith sizer dst@(MutArray _ start end bound) src = do
2172− let f = writeAppendWith (`sizer` byteLength src) (return dst)
2679+ let f = appendWith (`sizer` byteLength src) (return dst)
2173 in D.fold f (toStreamD src)
2680 in D.fold f (toStreamD src)
2175 assert (end <= bound) (return ())
2682 assert (end <= bound) (return ())
@@ -2185,7 +2692,7 @@ spliceWith sizer dst@(MutArray _ start end bound) src = do
2185 $ "splice: newSize is less than the total size "
2692 $ "splice: newSize is less than the total size "
2186 ++ "of arrays being appended. Please check the "
2693 ++ "of arrays being appended. Please check the "
2187 ++ "sizer function passed."
2694 ++ "sizer function passed."
2188− liftIO $ realloc newSizeInBytes dst
2695+ realloc newSizeInBytes dst
2189 else return dst
2696 else return dst
2190 spliceUnsafe dst1 src
2697 spliceUnsafe dst1 src
@@ -2222,14 +2729,24 @@ spliceExp = spliceWith (\l1 l2 -> max (l1 * 2) (l1 + l2))
2222-- Splitting
2729-- Splitting
2223-------------------------------------------------------------------------------
2730-------------------------------------------------------------------------------
2732+-- | Generate a stream of array slices using a predicate. The array element
2733+-- matching the predicate is dropped.
2736+{-# INLINE splitOn #-}
2737+splitOn :: (MonadIO m, Unbox a) =>
2738+ (a -> Bool) -> MutArray a -> Stream m (MutArray a)
2739+splitOn predicate arr =
2740+ fmap (\(i, len) -> getSliceUnsafe i len arr)
2741+ $ D.indexOnSuffix predicate (read arr)
2225-- | Drops the separator byte
2743-- | Drops the separator byte
2226{-# INLINE breakOn #-}
2744{-# INLINE breakOn #-}
2227breakOn :: MonadIO m
2745breakOn :: MonadIO m
2228 => Word8 -> MutArray Word8 -> m (MutArray Word8, Maybe (MutArray Word8))
2746 => Word8 -> MutArray Word8 -> m (MutArray Word8, Maybe (MutArray Word8))
2229−breakOn sep arr@MutArray{..} = asPtrUnsafe arr $ \p -> liftIO $ do
2747+breakOn sep arr@MutArray{..} = unsafeAsPtr arr $ \p -> liftIO $ do
2230− -- XXX Instead of using asPtrUnsafe (pinning memory) we can pass unlifted
2231− -- Addr# to memchr and it should be safe (from ghc 8.4).
2232 -- XXX We do not need memchr here, we can use a Haskell equivalent.
2748 -- XXX We do not need memchr here, we can use a Haskell equivalent.
2749+ -- Need efficient stream based primitives that work on Word64.
2233 loc <- c_memchr p sep (fromIntegral $ byteLength arr)
2750 loc <- c_memchr p sep (fromIntegral $ byteLength arr)
2234 let sepIndex = loc `minusPtr` p
2751 let sepIndex = loc `minusPtr` p
2235 return $
2752 return $
@@ -2250,32 +2767,41 @@ breakOn sep arr@MutArray{..} = asPtrUnsafe arr $ \p -> liftIO $ do
2770+-- | Like 'splitAt' but does not check whether the index is valid.
2772+{-# INLINE unsafeSplitAt #-}
2773+unsafeSplitAt :: forall a. Unbox a =>
2774+ Int -> MutArray a -> (MutArray a, MutArray a)
2775+unsafeSplitAt i MutArray{..} =
2776+ let off = i * SIZE_OF(a)
2779+ { arrContents = arrContents
2780+ , arrStart = arrStart
2785+ { arrContents = arrContents
2788+ , arrBound = arrBound
2253-- | Create two slices of an array without copying the original array. The
2792-- | Create two slices of an array without copying the original array. The
2254-- specified index @i@ is the first index of the second slice.
2793-- specified index @i@ is the first index of the second slice.
2795+{-# INLINE splitAt #-}
2256splitAt :: forall a. Unbox a => Int -> MutArray a -> (MutArray a, MutArray a)
2796splitAt :: forall a. Unbox a => Int -> MutArray a -> (MutArray a, MutArray a)
2257−splitAt i arr@MutArray{..} =
2797+splitAt i arr =
2258 let maxIndex = length arr - 1
2798 let maxIndex = length arr - 1
2259 in if i < 0
2799 in if i < 0
2260 then error "sliceAt: negative array index"
2800 then error "sliceAt: negative array index"
2261 else if i > maxIndex
2801 else if i > maxIndex
2262 then error $ "sliceAt: specified array index " ++ show i
2802 then error $ "sliceAt: specified array index " ++ show i
2263 ++ " is beyond the maximum index " ++ show maxIndex
2803 ++ " is beyond the maximum index " ++ show maxIndex
2264− else let off = i * SIZE_OF(a)
2804+ else unsafeSplitAt i arr
2267− { arrContents = arrContents
2268− , arrStart = arrStart
2273− { arrContents = arrContents
2276− , arrBound = arrBound
2280-------------------------------------------------------------------------------
2806-------------------------------------------------------------------------------
2281-- Casting
2807-- Casting
@@ -2325,13 +2851,16 @@ cast arr =
2325-- guarantees that unsafe calls will be performed in the calling thread. Making
2851-- guarantees that unsafe calls will be performed in the calling thread. Making
2326-- it safe to pass heap-allocated objects to unsafe functions.
2852-- it safe to pass heap-allocated objects to unsafe functions.
2328−-- Unsafe because of direct pointer operations. The user must ensure that they
2329−-- are writing within the legal bounds of the array. Should we just name it
2330−-- asPtr, the unsafety is implicit for any pointer operations. And we are safe
2854+-- XXX Should we just name it asPtr, the unsafety is implicit for any pointer
2331−-- from Haskell perspective because we will be pinning the memory.
2855+-- operations. And we are safe from Haskell perspective because we will be
2856+-- pinning the memory.
2858+-- XXX we cannot pass the length of the ptr here as in some cases it may not be
2859+-- available e.g. a null terminated C string. However, we can create another
2860+-- flavor of the API e.g. asPtrN.
2333−-- | Use an @MutArray a@ as @Ptr a@. This is useful when we want to pass an array
2862+-- | Use a @MutArray a@ as @Ptr a@. This is useful when we want to pass an
2334−-- as a pointer to some operating system call or to a "safe" FFI call.
2863+-- array as a pointer to some operating system call or to a "safe" FFI call.
2336-- If the array is not pinned it is copied to pinned memory before passing it
2865-- If the array is not pinned it is copied to pinned memory before passing it
2337-- to the monadic action.
2866-- to the monadic action.
@@ -2341,57 +2870,382 @@ cast arr =
2341-- opportunistically before this operation occurs, to avoid the cost of a copy
2870-- opportunistically before this operation occurs, to avoid the cost of a copy
2342-- if possible.
2871-- if possible.
2344−-- /Unsafe/
2873+-- /Unsafe/ because of direct pointer operations. The user must ensure that
2874+-- they are writing within the legal bounds of the array.
2346-- /Pre-release/
2876-- /Pre-release/
2878+{-# INLINE unsafePinnedAsPtr #-}
2879+unsafePinnedAsPtr :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
2880+unsafePinnedAsPtr arr f =
2881+ Unboxed.unsafePinnedAsPtr
2882+ (arrContents arr) (\ptr -> f (ptr `plusPtr` arrStart arr))
2884+{-# DEPRECATED asPtrUnsafe "Please use unsafePinnedAsPtr instead." #-}
2348{-# INLINE asPtrUnsafe #-}
2885{-# INLINE asPtrUnsafe #-}
2349asPtrUnsafe :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
2886asPtrUnsafe :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
2350−asPtrUnsafe arr f = do
2887+asPtrUnsafe = unsafePinnedAsPtr
2351− contents <- liftIO $ Unboxed.pin $ arrContents arr
2352− let !ptr = Ptr (byteArrayContents#
2353− (unsafeCoerce# (getMutableByteArray# contents)))
2889+{-# INLINE unsafeAsPtr #-}
2890+unsafeAsPtr :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
2892+ Unboxed.unsafeAsPtr
2355− r <- f (ptr `plusPtr` arrStart arr)
2893+ (arrContents arr) (\ptr -> f (ptr `plusPtr` arrStart arr))
2356− liftIO $ touch contents
2359-------------------------------------------------------------------------------
2895-------------------------------------------------------------------------------
2360-- Equality
2896-- Equality
2361-------------------------------------------------------------------------------
2897-------------------------------------------------------------------------------
2363−-- | Compare the length of the arrays. If the length is equal, compare the
2899+-- | Byte compare two arrays. Compare the length of the arrays. If the length
2364−-- lexicographical ordering of two underlying byte arrays otherwise return the
2900+-- is equal, compare the lexicographical ordering of two underlying byte arrays
2365−-- result of length comparison.
2901+-- otherwise return the result of length comparison.
2903+-- /Unsafe/: Note that the 'Unbox' instance of sum types with constructors of
2904+-- different sizes may leave some memory uninitialized which can make byte
2905+-- comparison unreliable.
2367-- /Pre-release/
2907-- /Pre-release/
2908+{-# INLINE byteCmp #-}
2909+byteCmp :: MonadIO m => MutArray a -> MutArray a -> m Ordering
2910+byteCmp arr1 arr2 = do
2911+ let marr1 = getMutableByteArray# (arrContents arr1)
2912+ marr2 = getMutableByteArray# (arrContents arr2)
2913+ !(I# st1#) = arrStart arr1
2914+ !(I# st2#) = arrStart arr2
2915+ !(I# len#) = byteLength arr1
2916+ case compare (byteLength arr1) (byteLength arr2) of
2918+ r <- liftIO $ IO $ \s# ->
2921+ (compareByteArrays#
2922+ (unsafeCoerce# marr1)
2924+ (unsafeCoerce# marr2)
2928+ return $ compare r 0
2368{-# INLINE cmp #-}
2931{-# INLINE cmp #-}
2932+{-# DEPRECATED cmp "Please use byteCmp instead." #-}
2369cmp :: MonadIO m => MutArray a -> MutArray a -> m Ordering
2933cmp :: MonadIO m => MutArray a -> MutArray a -> m Ordering
2370−cmp arr1 arr2 =
2934+cmp = byteCmp
2372− $ do
2936+-- | Byte equality of two arrays.
2373− let marr1 = getMutableByteArray# (arrContents arr1)
2937+--
2374− marr2 = getMutableByteArray# (arrContents arr2)
2938+-- >>> byteEq arr1 arr2 = (==) EQ $ MArray.byteCmp arr1 arr2
2375− !(I# st1#) = arrStart arr1
2939+--
2376− !(I# st2#) = arrStart arr2
2940+-- /Unsafe/: See 'byteCmp'.
2377− !(I# len#) = byteLength arr1
2941+{-# INLINE byteEq #-}
2378− case compare (byteLength arr1) (byteLength arr2) of
2942+byteEq :: MonadIO m => MutArray a -> MutArray a -> m Bool
2379− EQ -> do
2943+byteEq arr1 arr2 = fmap (EQ ==) $ byteCmp arr1 arr2
2380− r <- liftIO $ IO $ \s# ->
2944+
2381− let res =
2945+-------------------------------------------------------------------------------
2383− (compareByteArrays#
2947+-------------------------------------------------------------------------------
2384− (unsafeCoerce# marr1)
2948+
2385− st1#
2949+-- Note: LE versions avoid an extra copy compared to GE. LE parser trades
2386− (unsafeCoerce# marr2)
2950+-- backtracking one array in lieu of avoiding a copy. However, LE and GE both
2387− st2#
2951+-- can leave some memory unused. They can split the last array to fit it
2388− len#)
2952+-- exactly in the space.
2389− in (# s#, res #)
2953+
2390− return $ compare r 0
2954+{-# INLINE_NORMAL pCompactLeAs #-}
2391− x -> return x
2955+pCompactLeAs ::
2956+ forall m a. (MonadIO m, Unbox a)
2957+ => PinnedState -> Int -> Parser (MutArray a) m (MutArray a)
2958+pCompactLeAs ps maxElems = Parser step initial extract
2962+ maxBytes = maxElems * SIZE_OF(a)
2964+ functionName = "Streamly.Internal.Data.MutArray.pCompactLE"
2971+ ++ ": the size of arrays ["
2972+ ++ show maxElems ++ "] must be a natural number"
2973+ else Parser.IPartial Nothing
2977+ $ let len = byteLength arr
2978+ in if len >= maxBytes
2979+ then Parser.Done 0 arr
2980+ else Parser.Partial 0 (Just arr)
2981+ -- XXX Split the last array to use the space more compactly.
2982+ step (Just buf) arr =
2983+ let len = byteLength buf + byteLength arr
2984+ in if len > maxBytes
2985+ then return $ Parser.Done 1 buf
2988+ if byteCapacity buf < maxBytes
2989+ then liftIO $ reallocExplicitAs
2990+ ps (SIZE_OF(a)) maxBytes buf
2992+ buf2 <- spliceUnsafe buf1 arr
2993+ return $ Parser.Partial 0 (Just buf2)
2995+ extract Nothing = return $ Parser.Done 0 nil
2996+ extract (Just buf) = return $ Parser.Done 0 buf
2998+-- | Parser @pCompactLE maxElems@ coalesces adjacent arrays in the input stream
2999+-- only if the combined size would be less than or equal to @maxElems@
3000+-- elements. Note that it won't split an array if the original array is already
3001+-- larger than maxElems.
3003+-- @maxElems@ must be greater than 0.
3005+-- Generates unpinned arrays irrespective of the pinning status of input
3009+{-# INLINE pCompactLE #-}
3011+ forall m a. (MonadIO m, Unbox a)
3012+ => Int -> Parser (MutArray a) m (MutArray a)
3013+pCompactLE = pCompactLeAs Unpinned
3015+-- | Pinned version of 'pCompactLE'.
3016+{-# INLINE pPinnedCompactLE #-}
3018+ forall m a. (MonadIO m, Unbox a)
3019+ => Int -> Parser (MutArray a) m (MutArray a)
3020+pPinnedCompactLE = pCompactLeAs Pinned
3022+data SpliceState s arr
3024+ | SpliceBuffering s arr
3025+ | SpliceYielding arr (SpliceState s arr)
3028+-- This mutates the first array (if it has space) to append values from the
3029+-- second one. This would work for immutable arrays as well because an
3030+-- immutable array never has additional space so a new array is allocated
3031+-- instead of mutating it.
3033+{-# INLINE_NORMAL compactLeAs #-}
3034+compactLeAs :: forall m a. (MonadIO m, Unbox a)
3035+ => PinnedState -> Int -> D.Stream m (MutArray a) -> D.Stream m (MutArray a)
3036+compactLeAs ps maxElems (D.Stream step state) =
3037+ D.Stream step' (SpliceInitial state)
3041+ maxBytes = maxElems * SIZE_OF(a)
3043+ functionName = "Streamly.Internal.Data.MutArray.rCompactLE"
3045+ {-# INLINE_LATE step' #-}
3046+ step' gst (SpliceInitial st) = do
3047+ when (maxElems <= 0) $
3048+ -- XXX we can pass the module string from the higher level API
3049+ error $ functionName ++ ": the size of arrays [" ++ show maxElems
3050+ ++ "] must be a natural number"
3053+ D.Yield arr s -> return $
3054+ let len = byteLength arr
3055+ in if len >= maxBytes
3056+ then D.Skip (SpliceYielding arr (SpliceInitial s))
3057+ else D.Skip (SpliceBuffering s arr)
3058+ D.Skip s -> return $ D.Skip (SpliceInitial s)
3059+ D.Stop -> return D.Stop
3061+ -- XXX Split the last array to use the space more compactly.
3062+ step' gst (SpliceBuffering st buf) = do
3065+ D.Yield arr s -> do
3066+ let len = byteLength buf + byteLength arr
3069+ D.Skip (SpliceYielding buf (SpliceBuffering s arr))
3071+ buf1 <- if byteCapacity buf < maxBytes
3072+ then liftIO $ reallocExplicitAs
3073+ ps (SIZE_OF(a)) maxBytes buf
3075+ buf2 <- spliceUnsafe buf1 arr
3076+ return $ D.Skip (SpliceBuffering s buf2)
3077+ D.Skip s -> return $ D.Skip (SpliceBuffering s buf)
3078+ D.Stop -> return $ D.Skip (SpliceYielding buf SpliceFinish)
3080+ step' _ SpliceFinish = return D.Stop
3082+ step' _ (SpliceYielding arr next) = return $ D.Yield arr next
3085+{-# INLINE_NORMAL fCompactGeAs #-}
3087+ forall m a. (MonadIO m, Unbox a)
3088+ => PinnedState -> Int -> FL.Fold m (MutArray a) (MutArray a)
3089+fCompactGeAs ps minElems = Fold step initial extract extract
3093+ minBytes = minElems * SIZE_OF(a)
3095+ functionName = "Streamly.Internal.Data.MutArray.fCompactGE"
3102+ ++ ": the size of arrays ["
3103+ ++ show minElems ++ "] must be a natural number"
3104+ else FL.Partial Nothing
3108+ $ let len = byteLength arr
3109+ in if len >= minBytes
3111+ else FL.Partial (Just arr)
3112+ -- XXX Buffer arrays as a list to avoid copy and reallocations
3113+ step (Just buf) arr = do
3114+ let len = byteLength buf + byteLength arr
3116+ if byteCapacity buf < len
3117+ then liftIO $ reallocExplicitAs
3118+ ps (SIZE_OF(a)) (max minBytes len) buf
3120+ buf2 <- spliceUnsafe buf1 arr
3122+ then return $ FL.Done buf2
3123+ else return $ FL.Partial (Just buf2)
3125+ extract Nothing = return nil
3126+ extract (Just buf) = return buf
3128+-- | Fold @fCompactGE minElems@ coalesces adjacent arrays in the input stream
3129+-- until the size becomes greater than or equal to @minElems@.
3131+-- Generates unpinned arrays irrespective of the pinning status of input
3133+{-# INLINE fCompactGE #-}
3135+ forall m a. (MonadIO m, Unbox a)
3136+ => Int -> FL.Fold m (MutArray a) (MutArray a)
3137+fCompactGE = fCompactGeAs Unpinned
3139+-- | Pinned version of 'fCompactGE'.
3140+{-# INLINE fPinnedCompactGE #-}
3142+ forall m a. (MonadIO m, Unbox a)
3143+ => Int -> FL.Fold m (MutArray a) (MutArray a)
3144+fPinnedCompactGE = fCompactGeAs Pinned
3146+{-# INLINE_NORMAL lCompactGeAs #-}
3147+lCompactGeAs :: forall m a. (MonadIO m, Unbox a)
3148+ => PinnedState -> Int -> Fold m (MutArray a) () -> Fold m (MutArray a) ()
3149+-- The fold version turns out to be a little bit slower.
3150+-- lCompactGeAs ps n = FL.many (fCompactGeAs ps n)
3151+lCompactGeAs ps minElems (Fold step1 initial1 _ final1) =
3152+ Fold step initial extract final
3156+ minBytes = minElems * SIZE_OF(a)
3158+ functionName = "Streamly.Internal.Data.MutArray.lCompactGE"
3161+ when (minElems <= 0) $
3162+ -- XXX we can pass the module string from the higher level API
3163+ error $ functionName ++ ": the size of arrays ["
3164+ ++ show minElems ++ "] must be a natural number"
3167+ return $ first (Tuple' Nothing) r
3169+ {-# INLINE runInner #-}
3170+ runInner len acc buf =
3175+ FL.Done _ -> return $ FL.Done ()
3179+ return $ first (Tuple' Nothing) res
3180+ else return $ FL.Partial $ Tuple' (Just buf) acc
3182+ step (Tuple' Nothing r1) arr =
3183+ runInner (byteLength arr) r1 arr
3185+ -- XXX Buffer arrays as a list to avoid copy and reallocations
3186+ step (Tuple' (Just buf) r1) arr = do
3187+ let len = byteLength buf + byteLength arr
3188+ buf1 <- if byteCapacity buf < len
3189+ then liftIO $ reallocExplicitAs
3190+ ps (SIZE_OF(a)) (max minBytes len) buf
3192+ buf2 <- spliceUnsafe buf1 arr
3193+ runInner len r1 buf2
3195+ -- XXX Several folds do extract >=> final, therefore, we need to make final
3196+ -- return "m b" rather than using extract post it if we want extract to be
3199+ -- extract forces the pending buffer to be sent to the fold which is not
3201+ extract _ = error "lCompactGE: not designed for scanning"
3203+ final (Tuple' Nothing r1) = final1 r1
3204+ final (Tuple' (Just buf) r1) = do
3207+ FL.Partial rr -> final1 rr
3208+ FL.Done _ -> return ()
3210+-- | Like 'compactGE' but for transforming folds instead of stream.
3212+-- >>> lCompactGE n = Fold.many (MutArray.fCompactGE n)
3214+-- Generates unpinned arrays irrespective of the pinning status of input
3216+{-# INLINE lCompactGE #-}
3217+lCompactGE :: forall m a. (MonadIO m, Unbox a)
3218+ => Int -> Fold m (MutArray a) () -> Fold m (MutArray a) ()
3219+lCompactGE = lCompactGeAs Unpinned
3221+-- | Pinned version of 'lCompactGE'.
3222+{-# INLINE lPinnedCompactGE #-}
3223+lPinnedCompactGE :: forall m a. (MonadIO m, Unbox a)
3224+ => Int -> Fold m (MutArray a) () -> Fold m (MutArray a) ()
3225+lPinnedCompactGE = lCompactGeAs Pinned
3227+-- | @compactGE n stream@ coalesces adjacent arrays in the @stream@ until
3228+-- the size becomes greater than or equal to @n@.
3230+-- >>> compactGE n = Stream.foldMany (MutArray.fCompactGE n)
3232+{-# INLINE compactGE #-}
3234+ (MonadIO m, Unbox a)
3235+ => Int -> Stream m (MutArray a) -> Stream m (MutArray a)
3236+compactGE n = D.foldMany (fCompactGE n)
3238+-- | 'compactEQ n' coalesces adajacent arrays in the input stream to
3239+-- arrays of exact size @n@.
3242+{-# INLINE compactEQ #-}
3243+compactEQ :: -- (MonadIO m, Unbox a) =>
3244+ Int -> Stream m (MutArray a) -> Stream m (MutArray a)
3245+compactEQ _n = undefined -- D.parseManyD (pCompactEQ n)
2393-------------------------------------------------------------------------------
3247-------------------------------------------------------------------------------
2394−-- NFData
3248+-- In-place mutation algorithms
2395-------------------------------------------------------------------------------
3249-------------------------------------------------------------------------------
2397-- | Strip elements which match with predicate from both ends.
3251-- | Strip elements which match with predicate from both ends.
@@ -2420,7 +3274,7 @@ strip eq arr@MutArray{..} = liftIO $ do
2420 getStart cur = do
3274 getStart cur = do
2421 if cur < arrEnd
3275 if cur < arrEnd
2423− r <- peekByteIndex cur arrContents
3277+ r <- peekAt cur arrContents
2425 then getStart (INDEX_NEXT(cur,a))
3279 then getStart (INDEX_NEXT(cur,a))
2426 else return cur
3280 else return cur
@@ -2430,7 +3284,7 @@ strip eq arr@MutArray{..} = liftIO $ do
2430 if cur > low
3284 if cur > low
2432 let prev = INDEX_PREV(cur,a)
3286 let prev = INDEX_PREV(cur,a)
2433− r <- peekByteIndex prev arrContents
3287+ r <- peekAt prev arrContents
2435 then getLast prev low
3289 then getLast prev low
2436 else return cur
3290 else return cur