on master help sign in
Remove prim arrays and all related code
commit4015d5412802c93c2f20f9adaa7591c59c558b98 authorAdithya Kumar <adithya@composewell.com> dateFri 29 Jul 2022, 17:21 (4 years ago) parentadce8d0
18 files changed−2421
benchmark/Streamly/Benchmark/Data/Array/Prim.hs−57 benchmark/Streamly/Benchmark/Data/Array/Prim/Pinned.hs−57 benchmark/streamly-benchmarks.cabal−19 src/Streamly/Data/Prim/Array.hs−43 src/Streamly/Internal/Data/Array/Prim.hs−110 src/Streamly/Internal/Data/Array/Prim/Mut/Type.hs−94 src/Streamly/Internal/Data/Array/Prim/MutTypesInclude.hs−413 src/Streamly/Internal/Data/Array/Prim/Pinned.hs−108 src/Streamly/Internal/Data/Array/Prim/Pinned/Mut/Type.hs−176 src/Streamly/Internal/Data/Array/Prim/Pinned/Type.hs−127 src/Streamly/Internal/Data/Array/Prim/Type.hs−98 src/Streamly/Internal/Data/Array/Prim/TypesInclude.hs−706 src/Streamly/Internal/Data/Array/PrimInclude.hs−185 src/Streamly/Internal/Unicode/Array/Prim/Pinned.hs−91 streamly.cabal−15 test/Streamly/Test/Data/Array/Prim.hs−55 test/Streamly/Test/Data/Array/Prim/Pinned.hs−55 test/streamly-tests.cabal−12
benchmark/Streamly/Benchmark/Data/Array/Prim.hsdeleted−57
@@ -1,57 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−
3−#include "Streamly/Benchmark/Data/Array/CommonImports.hs"
4−
5−import qualified Streamly.Internal.Data.Array.Prim as A
6−type Stream = A.Array
7−
8−#include "Streamly/Benchmark/Data/Array/Common.hs"
9−
10−-------------------------------------------------------------------------------
11−-- Benchmark helpers
12−-------------------------------------------------------------------------------
13−
14−-- Drain a source that generates an array in the IO monad
15−{-# INLINE benchIOSrc #-}
16−benchIOSrc :: String -> (Int -> IO (Stream a)) -> Benchmark
17−benchIOSrc name src = benchIO name src id
18−
19−-------------------------------------------------------------------------------
20−-- Bench Ops
21−-------------------------------------------------------------------------------
22−
23−{-# INLINE sourceIntFromToFromList #-}
24−sourceIntFromToFromList :: MonadIO m => Int -> Int -> m (Stream Int)
25−sourceIntFromToFromList value n = P.return $ A.fromListN value [n..n + value]
26−
27−-- CPP:
28−{-# INLINE sourceIntFromToFromStream #-}
29−sourceIntFromToFromStream :: MonadIO m => Int -> Int -> m (Stream Int)
30−sourceIntFromToFromStream value n = S.fold A.write $ S.enumerateFromTo n (n + value)
31−
32−-------------------------------------------------------------------------------
33−-- Bench groups
34−-------------------------------------------------------------------------------
35−
36−o_1_space_generation :: Int -> [Benchmark]
37−o_1_space_generation value =
38− [ bgroup
39− "generation"
40− [ benchIOSrc "write . intFromTo" (sourceIntFromToFromStream value)
41− ]
42− ]
43−
44−moduleName :: String
45−moduleName = "Data.Array.Prim"
46−
47−defStreamSize :: Int
48−defStreamSize = defaultStreamSize
49−
50−main :: IO ()
51−main = runWithCLIOpts defStreamSize allBenchmarks
52−
53− where
54−
55− allBenchmarks size =
56− bgroup (o_1_space_prefix moduleName) (o_1_space_generation size)
57− : commonBenchmarks size
benchmark/Streamly/Benchmark/Data/Array/Prim/Pinned.hsdeleted−57
@@ -1,57 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−
3−#include "Streamly/Benchmark/Data/Array/CommonImports.hs"
4−
5−import qualified Streamly.Internal.Data.Array.Prim.Pinned as A
6−type Stream = A.Array
7−
8−#include "Streamly/Benchmark/Data/Array/Common.hs"
9−
10−-------------------------------------------------------------------------------
11−-- Benchmark helpers
12−-------------------------------------------------------------------------------
13−
14−-- Drain a source that generates an array in the IO monad
15−{-# INLINE benchIOSrc #-}
16−benchIOSrc :: String -> (Int -> IO (Stream a)) -> Benchmark
17−benchIOSrc name src = benchIO name src id
18−
19−-------------------------------------------------------------------------------
20−-- Bench Ops
21−-------------------------------------------------------------------------------
22−
23−{-# INLINE sourceIntFromToFromList #-}
24−sourceIntFromToFromList :: MonadIO m => Int -> Int -> m (Stream Int)
25−sourceIntFromToFromList value n = P.return $ A.fromListN value [n..n + value]
26−
27−-- CPP:
28−{-# INLINE sourceIntFromToFromStream #-}
29−sourceIntFromToFromStream :: MonadIO m => Int -> Int -> m (Stream Int)
30−sourceIntFromToFromStream value n = S.fold A.write $ S.enumerateFromTo n (n + value)
31−
32−-------------------------------------------------------------------------------
33−-- Bench groups
34−-------------------------------------------------------------------------------
35−
36−o_1_space_generation :: Int -> [Benchmark]
37−o_1_space_generation value =
38− [ bgroup
39− "generation"
40− [ benchIOSrc "write . intFromTo" (sourceIntFromToFromStream value)
41− ]
42− ]
43−
44−moduleName :: String
45−moduleName = "Data.Array.Prim.Pinned"
46−
47−defStreamSize :: Int
48−defStreamSize = defaultStreamSize
49−
50−main :: IO ()
51−main = runWithCLIOpts defStreamSize allBenchmarks
52−
53− where
54−
55− allBenchmarks size =
56− bgroup (o_1_space_prefix moduleName) (o_1_space_generation size)
57− : commonBenchmarks size
benchmark/streamly-benchmarks.cabal−19
@@ -493,16 +493,6 @@ benchmark Data.Array
493493 else
494494 buildable: True
495495
496−benchmark Data.Array.Prim
497− import: bench-options
498− type: exitcode-stdio-1.0
499− main-is: Streamly/Benchmark/Data/Array/Prim.hs
500− build-depends: primitive
501− if flag(bench-core)
502− buildable: False
503− else
504− buildable: True
505−
506496benchmark Data.SmallArray
507497 import: bench-options
508498 type: exitcode-stdio-1.0
@@ -512,15 +502,6 @@ benchmark Data.SmallArray
512502 else
513503 buildable: True
514504
515−benchmark Data.Array.Prim.Pinned
516− import: bench-options
517− type: exitcode-stdio-1.0
518− main-is: Streamly/Benchmark/Data/Array/Prim/Pinned.hs
519− if flag(bench-core)
520− buildable: False
521− else
522− buildable: True
523−
524505benchmark Data.Array.Foreign
525506 import: bench-options
526507 type: exitcode-stdio-1.0
src/Streamly/Data/Prim/Array.hsdeleted−43
@@ -1,43 +0,0 @@
1−-- |
2−-- Module : Streamly.Data.Prim.Array
3−-- Copyright : (c) 2019 Composewell Technologies
4−--
5−-- License : BSD-3-Clause
6−-- Maintainer : streamly@composewell.com
7−-- Stability : experimental
8−-- Portability : GHC
9−--
10−module Streamly.Data.Prim.Array
11− ( Array
12−
13− -- * Construction
14− , A.fromListN
15− , A.fromList
16−
17− -- Stream Folds
18− -- , A.fromStreamN
19− -- , A.fromStream
20−
21− -- MonadicAPIs
22− , A.writeN
23− , A.write
24−
25− -- * Elimination
26−
27− -- , A.toStream
28− -- , A.toStreamRev
29− , A.read
30−
31− -- * Random Access
32−
33− -- * Folding Arrays
34− -- , A.streamFold
35− -- , A.fold
36−
37− , A.length
38− )
39−where
40−
41−import Streamly.Internal.Data.Array.Prim (Array)
42−
43−import qualified Streamly.Internal.Data.Array.Prim as A
src/Streamly/Internal/Data/Array/Prim.hsdeleted−110
@@ -1,110 +0,0 @@
1−{-# OPTIONS_GHC -fno-warn-orphans #-}
2−
3−#include "inline.hs"
4−
5−-- |
6−-- Module : Streamly.Internal.Data.Array.Prim
7−-- Copyright : (c) 2020 Composewell Technologies
8−--
9−-- License : BSD-3-Clause
10−-- Maintainer : streamly@composewell.com
11−-- Stability : experimental
12−-- Portability : GHC
13−--
14−module Streamly.Internal.Data.Array.Prim
15− (
16− Array
17−
18− -- * Construction
19−
20− -- Pure List APIs
21− , A.fromListN
22− , A.fromList
23−
24− -- Stream Folds
25− , fromStreamN
26− , fromStream
27−
28− -- Monadic APIs
29− -- , newArray
30− , A.writeN -- drop new
31− , A.write -- full buffer
32−
33− -- * Elimination
34−
35− , A.toList
36− , toStream
37− , toStreamRev
38− , read
39− , unsafeRead
40−
41− -- * Random Access
42− , length
43− , null
44− , last
45− -- , (!!)
46− , readIndex
47− , A.unsafeIndex
48− -- , readIndices
49− -- , readRanges
50−
51− -- , readFrom -- read from a given position to the end of file
52− -- , readFromRev -- read from a given position to the beginning of file
53− -- , readTo -- read from beginning up to the given position
54− -- , readToRev -- read from end to the given position in file
55− -- , readFromTo
56− -- , readFromThenTo
57−
58− -- , readChunksOfFrom
59− -- , ...
60−
61− -- , writeIndex
62− -- , writeFrom -- start writing at the given position
63− -- , writeFromRev
64− -- , writeTo -- write from beginning up to the given position
65− -- , writeToRev
66− -- , writeFromTo
67− -- , writeFromThenTo
68− --
69− -- , writeChunksOfFrom
70− -- , ...
71−
72− -- , writeIndex
73− -- , writeIndices
74− -- , writeRanges
75−
76− -- -- * Search
77− -- , bsearch
78− -- , bsearchIndex
79− -- , find
80− -- , findIndex
81− -- , findIndices
82−
83− -- -- * In-pace mutation (for Mutable Array type)
84− -- , partitionBy
85− -- , shuffleBy
86− -- , foldtWith
87− -- , foldbWith
88−
89− -- * Immutable Transformations
90−-- , streamTransform
91−
92− -- * Folding Arrays
93− , streamFold
94− , fold
95−
96− -- * Folds with Array as the container
97−-- , D.lastN
98−
99− -- * Streaming array operations
100−
101− , concat
102− , compact
103−
104− )
105−where
106−
107−import Streamly.Internal.Data.Array.Prim.Type (Array(..), length)
108−import qualified Streamly.Internal.Data.Array.Prim.Type as A
109−
110−#include "Streamly/Internal/Data/Array/PrimInclude.hs"
src/Streamly/Internal/Data/Array/Prim/Mut/Type.hsdeleted−94
@@ -1,94 +0,0 @@
1−{-# LANGUAGE UnboxedTuples #-}
2−
3−#include "inline.hs"
4−
5−-- |
6−-- Module : Streamly.Internal.Data.Array.Prim.Mut.Type
7−-- Copyright : (c) 2020 Composewell Technologies
8−--
9−-- License : BSD-3-Clause
10−-- Maintainer : streamly@composewell.com
11−-- Stability : experimental
12−-- Portability : GHC
13−--
14−module Streamly.Internal.Data.Array.Prim.Mut.Type
15− (
16− Array (..)
17−
18− -- * Construction
19− , newArray
20− , unsafeWriteIndex
21−
22− , spliceTwo
23− , unsafeCopy
24−
25− , fromListM
26− , fromListNM
27− , fromStreamDN
28− , fromStreamD
29−
30− -- * Streams of arrays
31− , fromStreamDArraysOf
32−
33− , packArraysChunksOf
34− , lpackArraysChunksOf
35−
36−#if !defined(mingw32_HOST_OS)
37−-- , groupIOVecsOf
38−#endif
39−
40− -- * Elimination
41− , unsafeReadIndex
42− , length
43− , byteLength
44−
45− , writeN
46− , ArrayUnsafe(..)
47− , writeNUnsafe
48− , write
49−
50− -- * Utilities
51− , resizeArray
52− , shrinkArray
53− )
54−where
55−
56−#include "Streamly/Internal/Data/Array/Prim/MutTypesInclude.hs"
57−
58−-------------------------------------------------------------------------------
59−-- Allocation (Unpinned)
60−-------------------------------------------------------------------------------
61−
62−-- | Allocate an array that is unpinned and can hold 'count' items. The memory
63−-- of the array is uninitialized.
64−--
65−-- Note that this is internal routine, the reference to this array cannot be
66−-- given out until the array has been written to and frozen.
67−{-# INLINE newArray #-}
68−newArray ::
69− forall m a. (MonadIO m, Prim a)
70− => Int
71− -> m (Array a)
72−newArray (I# n#) =
73− liftIO $ do
74− let bytes = n# *# sizeOf# (undefined :: a)
75− primitive $ \s# ->
76− case newByteArray# bytes s# of
77− (# s1#, arr# #) -> (# s1#, Array arr# #)
78−
79−-- | Resize (unpinned) mutable byte array to new specified size (in elem
80−-- count). The returned array is either the original array resized in-place or,
81−-- if not possible, a newly allocated (unpinned) array (with the original
82−-- content copied over).
83−{-# INLINE resizeArray #-}
84−resizeArray ::
85− forall m a. (MonadIO m, Prim a)
86− => Array a
87− -> Int -- ^ new size in elem count
88− -> m (Array a)
89−resizeArray (Array arr#) (I# n#) =
90− liftIO $ do
91− let bytes = n# *# sizeOf# (undefined :: a)
92− primitive $ \s# ->
93− case resizeMutableByteArray# arr# bytes s# of
94− (# s1#, arr1# #) -> (# s1#, Array arr1# #)
src/Streamly/Internal/Data/Array/Prim/MutTypesInclude.hsdeleted−413
@@ -1,413 +0,0 @@
1−-- Copyright : (c) 2020 Composewell Technologies
2−-- License : BSD-3-Clause
3−-- Maintainer : streamly@composewell.com
4−-- Stability : experimental
5−-- Portability : GHC
6−
7−import Control.Monad (when)
8−import Control.Monad.IO.Class (MonadIO(..))
9−import Data.Bifunctor (first)
10−import Data.Primitive.Types (Prim(..), sizeOf)
11−import Streamly.Internal.Data.Fold.Type (Fold(..))
12−import Streamly.Internal.Data.SVar (adaptState)
13−import Streamly.Internal.Data.Tuple.Strict (Tuple'(..), Tuple3'(..))
14−
15−import qualified Streamly.Internal.Data.Fold as FL
16−import qualified Streamly.Internal.Data.Stream.StreamD as D
17−
18−import GHC.Exts
19−import Control.Monad.Primitive
20−import Prelude hiding (length, unlines)
21−
22−-------------------------------------------------------------------------------
23−-- Array Data Type
24−-------------------------------------------------------------------------------
25−
26−data Array a = Array (MutableByteArray# RealWorld)
27−
28−-------------------------------------------------------------------------------
29−-- Utilities
30−-------------------------------------------------------------------------------
31−
32−-- | Copy a range of the first array to the specified region in the second
33−-- array. Both arrays must fully contain the specified ranges, but this is not
34−-- checked. The regions are allowed to overlap, although this is only possible
35−-- when the same array is provided as both the source and the destination.
36−{-# INLINE unsafeCopy #-}
37−unsafeCopy ::
38− forall m a. (MonadIO m, Prim a)
39− => Array a -- ^ destination array
40− -> Int -- ^ offset into destination array
41− -> Array a -- ^ source array
42− -> Int -- ^ offset into source array
43− -> Int -- ^ number of elements to copy
44− -> m ()
45−unsafeCopy (Array dst#) (I# doff#) (Array src#) (I# soff#) (I# n#) =
46− liftIO $ do
47− let toBytes cnt# = cnt# *# (sizeOf# (undefined :: a))
48− primitive_ $
49− copyMutableByteArray#
50− src#
51− (toBytes soff#)
52− dst#
53− (toBytes doff#)
54− (toBytes n#)
55−
56−-------------------------------------------------------------------------------
57−-- Length
58−-------------------------------------------------------------------------------
59−
60−-- XXX rename to byteCount?
61−{-# INLINE byteLength #-}
62−byteLength :: MonadIO m => Array a -> m Int
63−byteLength (Array arr#) =
64− liftIO $
65− primitive
66− (\s0# ->
67− case getSizeofMutableByteArray# arr# s0# of
68− (# s1#, blen# #) -> (# s1#, I# blen# #))
69−
70−
71−-- XXX Rename length to elemCount so that there is no confusion bout what it
72−-- means.
73−--
74−-- XXX Since size of 'a' is statically known, we can replace `quot` with shift
75−-- when it is power of 2. Though it may not matter unless length is used too
76−-- often.
77−--
78−{-# INLINE length #-}
79−length ::
80− forall m a. (MonadIO m, Prim a)
81− => Array a
82− -> m Int
83−length arr =
84− liftIO $ do
85− blen <- byteLength arr
86− return $ blen `quot` (max 1 $ sizeOf (undefined :: a))
87−
88−-------------------------------------------------------------------------------
89−-- Random Access
90−-------------------------------------------------------------------------------
91−
92−{-# INLINE unsafeReadIndex #-}
93−unsafeReadIndex :: (MonadIO m, Prim a) => Array a -> Int -> m a
94−unsafeReadIndex (Array arr#) (I# i#) =
95− liftIO $ primitive (readByteArray# arr# i#)
96−
97−{-# INLINE unsafeWriteIndex #-}
98−unsafeWriteIndex ::
99− (MonadIO m, Prim a)
100− => Array a -- ^ array
101− -> Int -- ^ index
102− -> a -- ^ element
103− -> m ()
104−unsafeWriteIndex (Array arr#) (I# i#) x =
105− liftIO $ primitive_ (writeByteArray# arr# i# x)
106−
107−-------------------------------------------------------------------------------
108−-- Construction
109−-------------------------------------------------------------------------------
110−
111−-- Note: We do not store the actual length of the array in the Array
112−-- constructor. Therefore, for "length" API to work correctly we need to match
113−-- the ByteArray length with the used length by shrinking it.
114−--
115−-- However, it may be expensive to always shrink the array. We may want to
116−-- shrink only if significant space is being wasted. If we want to do that then
117−-- we will have to store the used length separately. Or does GHC take care of
118−-- that?
119−-- Although the docs are not explicit about it, given how the signature is,
120−-- the shrinking must me inplace. "resizeMutableByteArray#" shrinks the
121−-- array inplace.
122−{-# INLINE shrinkArray #-}
123−shrinkArray ::
124− forall m a. (MonadIO m, Prim a)
125− => Array a
126− -> Int -- ^ new size
127− -> m ()
128−shrinkArray (Array arr#) (I# n#) =
129− liftIO $ do
130− let bytes = n# *# (sizeOf# (undefined :: a))
131− primitive_ (shrinkMutableByteArray# arr# bytes)
132−
133−-- | Fold the whole input to a single array.
134−--
135−-- /Caution! Do not use this on infinite streams./
136−--
137−-- /Pre-release/
138−{-# INLINE_NORMAL write #-}
139−write :: (MonadIO m, Prim a) => Fold m a (Array a)
140−write = FL.rmapM extract $ FL.foldlM' step initial
141−
142− where
143−
144− initial = do
145− marr <- newArray 0
146− return $ Tuple3' marr 0 0
147−
148− step (Tuple3' marr i capacity) x
149− | i == capacity = do
150− let newCapacity = max (capacity * 2) 1
151− newMarr <- resizeArray marr newCapacity
152− unsafeWriteIndex newMarr i x
153− return $ Tuple3' newMarr (i + 1) newCapacity
154− | otherwise = do
155− unsafeWriteIndex marr i x
156− return $ Tuple3' marr (i + 1) capacity
157−
158− extract (Tuple3' marr len _) = shrinkArray marr len >> return marr
159−
160−-- | @writeN n@ folds a maximum of @n@ elements from the input stream to an
161−-- 'Array'.
162−--
163−-- /Pre-release/
164−{-# INLINE_NORMAL writeN #-}
165−writeN :: (MonadIO m, Prim a) => Int -> Fold m a (Array a)
166−writeN len = Fold step initial extract
167−
168− where
169−
170− {-# INLINE next #-}
171− next marr i = do
172− let i1 = i + 1
173− st = Tuple' marr i1
174− if len > i1
175− then return $ FL.Partial st
176− else fmap FL.Done $ extract st
177−
178− initial = do
179− marr <- liftIO $ newArray len
180− next marr (-1)
181−
182− step (Tuple' marr i) x = do
183− liftIO $ unsafeWriteIndex marr i x
184− next marr i
185−
186− extract (Tuple' marr l) = shrinkArray marr l >> return marr
187−
188−-- Use Tuple' instead?
189−data ArrayUnsafe a = ArrayUnsafe
190− {-# UNPACK #-} !(Array a)
191− {-# UNPACK #-} !Int
192−
193−-- | Like 'writeN' but does not check the array bounds when writing. The fold
194−-- driver must not call the step function more than 'n' times otherwise it will
195−-- corrupt the memory and crash. This function exists mainly because any
196−-- conditional in the step function blocks fusion causing 10x performance
197−-- slowdown.
198−--
199−-- /Pre-release/
200−{-# INLINE_NORMAL writeNUnsafe #-}
201−writeNUnsafe :: (MonadIO m, Prim a) => Int -> Fold m a (Array a)
202−writeNUnsafe n = FL.rmapM extract $ FL.foldlM' step initial
203−
204− where
205−
206− initial = do
207− arr <- newArray (max n 0)
208− return $ ArrayUnsafe arr 0
209− step (ArrayUnsafe marr i) x = do
210− unsafeWriteIndex marr i x
211− return $ ArrayUnsafe marr (i + 1)
212− extract (ArrayUnsafe marr i) = shrinkArray marr i >> return marr
213−
214−{-# INLINE_NORMAL fromStreamDN #-}
215−fromStreamDN :: (MonadIO m, Prim a) => Int -> D.Stream m a -> m (Array a)
216−fromStreamDN limit str = do
217− marr <- newArray (max limit 0)
218− let step i x = i `seq` (unsafeWriteIndex marr i x) >> return (i + 1)
219− n <- D.foldlM' step (return 0) $ D.take limit str
220− shrinkArray marr n
221− return marr
222−
223−{-# INLINE fromStreamD #-}
224−fromStreamD :: (MonadIO m, Prim a) => D.Stream m a -> m (Array a)
225−fromStreamD str = D.fold write str
226−
227−{-# INLINABLE fromListNM #-}
228−fromListNM :: (MonadIO m, Prim a) => Int -> [a] -> m (Array a)
229−fromListNM n xs = fromStreamDN n $ D.fromList xs
230−
231−{-# INLINABLE fromListM #-}
232−fromListM :: (MonadIO m, Prim a) => [a] -> m (Array a)
233−fromListM xs = fromStreamD $ D.fromList xs
234−
235−-------------------------------------------------------------------------------
236−-- Combining
237−-------------------------------------------------------------------------------
238−
239−-- Splice two mutable arrays creating a new array.
240−{-# INLINE spliceTwo #-}
241−spliceTwo :: (MonadIO m, Prim a) => Array a -> Array a -> m (Array a)
242−spliceTwo a1 a2 = do
243− l1 <- length a1
244− l2 <- length a2
245− a3 <- resizeArray a1 (l1 + l2)
246− unsafeCopy a2 0 a3 l1 l2
247− return a3
248−
249−-------------------------------------------------------------------------------
250−-- Stream of Arrays
251−-------------------------------------------------------------------------------
252−
253−data GroupState s a
254− = GroupStart s
255− | GroupBuffer s (Array a) Int
256− | GroupYield (Array a) s
257− | GroupLastYield (Array a) Int
258− | GroupFinish
259−
260−-- | @fromStreamArraysOf n stream@ groups the input stream into a stream of
261−-- arrays of size n.
262−{-# INLINE_NORMAL fromStreamDArraysOf #-}
263−fromStreamDArraysOf ::
264− (MonadIO m, Prim a) => Int -> D.Stream m a -> D.Stream m (Array a)
265−-- fromStreamDArraysOf n str = D.groupsOf n (writeN n) str
266−fromStreamDArraysOf n (D.Stream step state) = D.Stream step' (GroupStart state)
267−
268− where
269−
270− {-# INLINE_LATE step' #-}
271− step' _ (GroupStart st) = do
272− when (n <= 0) $
273− -- XXX we can pass the module string from the higher level API
274− error $
275− "Streamly.Internal.Data.Array.Foreign.Mut.Type.fromStreamDArraysOf: the size of " ++
276− "arrays [" ++ show n ++ "] must be a natural number"
277− arr <- newArray n
278− return $ D.Skip (GroupBuffer st arr 0)
279− step' gst (GroupBuffer st arr i)
280− | i < n = do
281− r <- step (adaptState gst) st
282− case r of
283− D.Yield x s -> do
284− unsafeWriteIndex arr i x
285− return $ D.Skip (GroupBuffer s arr (i + 1))
286− D.Skip s -> return $ D.Skip (GroupBuffer s arr i)
287− D.Stop -> return $ D.Skip (GroupLastYield arr i)
288− | otherwise = return $ D.Skip (GroupYield arr st)
289− step' _ (GroupYield arr st) = do
290− nArr <- newArray n
291− return $ D.Yield arr (GroupBuffer st nArr 0)
292− step' _ (GroupLastYield arr i)
293− | i == 0 = return D.Stop
294− | otherwise = do
295− shrinkArray arr i
296− return $ D.Yield arr GroupFinish
297− step' _ GroupFinish = return D.Stop
298−
299−data SpliceState s arr
300− = SpliceInitial s
301− | SpliceBuffering s arr
302− | SpliceYielding arr (SpliceState s arr)
303− | SpliceFinish
304−
305−-- XXX can use general grouping combinators to achieve this?
306−-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
307−-- maximum specified size in bytes. Note that if a single array is bigger than
308−-- the specified size we do not split it to fit. When we coalesce multiple
309−-- arrays if the size would exceed the specified size we do not coalesce
310−-- therefore the actual array size may be less than the specified chunk size.
311−--
312−-- /Pre-release/
313−{-# INLINE_NORMAL packArraysChunksOf #-}
314−packArraysChunksOf ::
315− (MonadIO m, Prim a)
316− => Int
317− -> D.Stream m (Array a)
318− -> D.Stream m (Array a)
319−packArraysChunksOf n (D.Stream step state) =
320− D.Stream step' (SpliceInitial state)
321−
322− where
323−
324− {-# INLINE_LATE step' #-}
325− step' gst (SpliceInitial st) = do
326− when (n <= 0) $
327− -- XXX we can pass the module string from the higher level API
328− error $ "Streamly.Internal.Data.Array.Foreign.Mut.Type.packArraysChunksOf: the size of "
329− ++ "arrays [" ++ show n ++ "] must be a natural number"
330− r <- step gst st
331− case r of
332− D.Yield arr s -> do
333− len <- byteLength arr
334− return $
335− if len >= n
336− then D.Skip $ SpliceYielding arr (SpliceInitial s)
337− else D.Skip $ SpliceBuffering s arr
338− D.Skip s -> return $ D.Skip (SpliceInitial s)
339− D.Stop -> return $ D.Stop
340−
341− step' gst (SpliceBuffering st buf) = do
342− r <- step gst st
343− case r of
344− D.Yield arr s -> do
345− blen <- byteLength buf
346− alen <- byteLength arr
347− let len = blen + alen
348− if len > n
349− then return $
350− D.Skip (SpliceYielding buf (SpliceBuffering s arr))
351− else do
352− buf' <- spliceTwo buf arr
353− return $ D.Skip (SpliceBuffering s buf')
354− D.Skip s -> return $ D.Skip (SpliceBuffering s buf)
355− D.Stop -> return $ D.Skip (SpliceYielding buf SpliceFinish)
356−
357− step' _ SpliceFinish = return D.Stop
358−
359− step' _ (SpliceYielding arr next) = return $ D.Yield arr next
360−
361−{-# INLINE_NORMAL lpackArraysChunksOf #-}
362−lpackArraysChunksOf ::
363− (MonadIO m, Prim a) => Int -> Fold m (Array a) () -> Fold m (Array a) ()
364−lpackArraysChunksOf n (Fold step1 initial1 extract1) =
365− Fold step initial extract
366−
367− where
368−
369− initial = do
370− when (n <= 0)
371− -- XXX we can pass the module string from the higher level API
372− $ error
373− $ "Streamly.Internal.Data.Array.Foreign.Mut.Type."
374− ++ "packArraysChunksOf: the size of arrays ["
375− ++ show n
376− ++ "] must be a natural number"
377− res <- initial1
378− return $ first (Tuple' Nothing) res
379−
380− extract (Tuple' Nothing r1) = extract1 r1
381− extract (Tuple' (Just buf) r1) = do
382− r <- step1 r1 buf
383− case r of
384− FL.Partial rr -> extract1 rr
385− FL.Done () -> return ()
386−
387− step (Tuple' Nothing r1) arr = do
388− len <- byteLength arr
389− if len >= n
390− then do
391− r <- step1 r1 arr
392− case r of
393− FL.Done () -> return $ FL.Done ()
394− FL.Partial s -> do
395− extract1 s
396− res <- initial1
397− return $ first (Tuple' Nothing) res
398− else return $ FL.Partial $ Tuple' (Just arr) r1
399− step (Tuple' (Just buf) r1) arr = do
400− blen <- byteLength buf
401− alen <- byteLength arr
402− let len = blen + alen
403− buf' <- spliceTwo buf arr
404− if len >= n
405− then do
406− r <- step1 r1 buf'
407− case r of
408− FL.Done () -> return $ FL.Done ()
409− FL.Partial s -> do
410− extract1 s
411− res <- initial1
412− return $ first (Tuple' Nothing) res
413− else return $ FL.Partial $ Tuple' (Just buf') r1
src/Streamly/Internal/Data/Array/Prim/Pinned.hsdeleted−108
@@ -1,108 +0,0 @@
1−#include "inline.hs"
2−
3−-- |
4−-- Module : Streamly.Internal.Data.Array.Prim.Pinned
5−-- Copyright : (c) 2020 Composewell Technologies
6−--
7−-- License : BSD-3-Clause
8−-- Maintainer : streamly@composewell.com
9−-- Stability : experimental
10−-- Portability : GHC
11−--
12−module Streamly.Internal.Data.Array.Prim.Pinned
13− (
14− Array
15−
16− -- * Construction
17−
18− -- Pure List APIs
19− , A.fromListN
20− , A.fromList
21−
22− -- Stream Folds
23− , fromStreamN
24− , fromStream
25−
26− -- Monadic APIs
27− -- , newArray
28− , A.writeN -- drop new
29− , A.write -- full buffer
30−
31− -- * Elimination
32−
33− , A.toList
34− , toStream
35− , toStreamRev
36− , read
37− , unsafeRead
38−
39− -- * Random Access
40− , length
41− , null
42− , last
43− -- , (!!)
44− , readIndex
45− , A.unsafeIndex
46− -- , readIndices
47− -- , readRanges
48−
49− -- , readFrom -- read from a given position to the end of file
50− -- , readFromRev -- read from a given position to the beginning of file
51− -- , readTo -- read from beginning up to the given position
52− -- , readToRev -- read from end to the given position in file
53− -- , readFromTo
54− -- , readFromThenTo
55−
56− -- , readChunksOfFrom
57− -- , ...
58−
59− -- , writeIndex
60− -- , writeFrom -- start writing at the given position
61− -- , writeFromRev
62− -- , writeTo -- write from beginning up to the given position
63− -- , writeToRev
64− -- , writeFromTo
65− -- , writeFromThenTo
66− --
67− -- , writeChunksOfFrom
68− -- , ...
69−
70− -- , writeIndex
71− -- , writeIndices
72− -- , writeRanges
73−
74− -- -- * Search
75− -- , bsearch
76− -- , bsearchIndex
77− -- , find
78− -- , findIndex
79− -- , findIndices
80−
81− -- -- * In-pace mutation (for Mutable Array type)
82− -- , partitionBy
83− -- , shuffleBy
84− -- , foldtWith
85− -- , foldbWith
86−
87− -- * Immutable Transformations
88−-- , streamTransform
89−
90− -- * Folding Arrays
91− , streamFold
92− , fold
93−
94− -- * Folds with Array as the container
95−-- , D.lastN
96−
97− -- * Streaming array operations
98−
99− , concat
100− , compact
101−
102− )
103−where
104−
105−import Streamly.Internal.Data.Array.Prim.Pinned.Type (Array(..), length)
106−import qualified Streamly.Internal.Data.Array.Prim.Pinned.Type as A
107−
108−#include "Streamly/Internal/Data/Array/PrimInclude.hs"
src/Streamly/Internal/Data/Array/Prim/Pinned/Mut/Type.hsdeleted−176
@@ -1,176 +0,0 @@
1−{-# LANGUAGE UnboxedTuples #-}
2−
3−#include "inline.hs"
4−
5−-- |
6−-- Module : Streamly.Internal.Data.Array.Prim.Pinned.Mut.Type
7−-- Copyright : (c) 2020 Composewell Technologies
8−--
9−-- License : BSD-3-Clause
10−-- Maintainer : streamly@composewell.com
11−-- Stability : experimental
12−-- Portability : GHC
13−--
14−module Streamly.Internal.Data.Array.Prim.Pinned.Mut.Type
15− (
16− Array (..)
17−
18− -- * Construction
19− , newArray
20− , newAlignedArray
21− , unsafeWriteIndex
22−
23− , spliceTwo
24− , unsafeCopy
25−
26− , fromListM
27− , fromListNM
28− , fromStreamDN
29− , fromStreamD
30−
31− -- * Streams of arrays
32− , fromStreamDArraysOf
33−
34− , packArraysChunksOf
35− , lpackArraysChunksOf
36−
37−#if !defined(mingw32_HOST_OS)
38−-- , groupIOVecsOf
39−#endif
40−
41− -- * Elimination
42− , unsafeReadIndex
43− , length
44− , byteLength
45−
46− , writeN
47− , ArrayUnsafe(..)
48− , writeNUnsafe
49− , writeNAligned
50− , write
51−
52− -- * Utilities
53− , resizeArray
54− , shrinkArray
55−
56− , touchArray
57− , withArrayAsPtr
58− )
59−where
60−
61−import GHC.IO (IO(..))
62−
63−#include "Streamly/Internal/Data/Array/Prim/MutTypesInclude.hs"
64−
65−-------------------------------------------------------------------------------
66−-- Allocation (Pinned)
67−-------------------------------------------------------------------------------
68−
69−-- XXX we can use a single newArray routine which accepts an allocation
70−-- function which could be newByteArray#, newPinnedByteArray# or
71−-- newAlignedPinnedByteArray#. That function can go in the common include file.
72−--
73−-- | Allocate an array that is pinned and can hold 'count' items. The memory of
74−-- the array is uninitialized.
75−--
76−-- Note that this is internal routine, the reference to this array cannot be
77−-- given out until the array has been written to and frozen.
78−{-# INLINE newArray #-}
79−newArray ::
80− forall m a. (MonadIO m, Prim a)
81− => Int
82− -> m (Array a)
83−newArray (I# n#) =
84− liftIO $ do
85− let bytes = n# *# sizeOf# (undefined :: a)
86− primitive $ \s# ->
87− case newPinnedByteArray# bytes s# of
88− (# s1#, arr# #) -> (# s1#, Array arr# #)
89−
90−-- Change order of args?
91−-- | Allocate a new array aligned to the specified alignment and using pinned
92−-- memory.
93−{-# INLINE newAlignedArray #-}
94−newAlignedArray ::
95− forall m a. (MonadIO m, Prim a)
96− => Int -- size
97− -> Int -- Alignment
98− -> m (Array a)
99−newAlignedArray (I# n#) (I# a#) =
100− liftIO $ do
101− let bytes = n# *# sizeOf# (undefined :: a)
102− primitive $ \s# ->
103− case newAlignedPinnedByteArray# bytes a# s# of
104− (# s1#, arr# #) -> (# s1#, Array arr# #)
105−
106−-- | Resize (pinned) mutable byte array to new specified size (in elem
107−-- count). The returned array is either the original array resized in-place or,
108−-- if not possible, a newly allocated (pinned) array (with the original content
109−-- copied over).
110−{-# INLINE resizeArray #-}
111−resizeArray ::
112− (MonadIO m, Prim a)
113− => Array a
114− -> Int -- ^ new size
115− -> m (Array a)
116−resizeArray arr i = do
117− len <- length arr
118− if len == i
119− then return arr
120− else if i < len
121− then shrinkArray arr i >> return arr
122− else do
123− nArr <- newArray i
124− unsafeCopy nArr 0 arr 0 len
125− return nArr
126−
127−-------------------------------------------------------------------------------
128−-- Aligned Construction
129−-------------------------------------------------------------------------------
130−
131−-- XXX we can also factor out common code in writeN and writeNAligned in the
132−-- same way as suggested above.
133−--
134−{-# INLINE_NORMAL writeNAligned #-}
135−writeNAligned ::
136− (MonadIO m, Prim a)
137− => Int
138− -> Int
139− -> Fold m a (Array a)
140−writeNAligned align limit = Fold step initial extract
141−
142− where
143−
144− initial = do
145− marr <- newAlignedArray limit align
146− return $ FL.Partial $ Tuple' marr 0
147−
148− extract (Tuple' marr len) = shrinkArray marr len >> return marr
149−
150− step s@(Tuple' marr i) x
151− | i == limit = FL.Done <$> extract s
152− | otherwise = do
153− unsafeWriteIndex marr i x
154− return $ FL.Partial $ Tuple' marr (i + 1)
155−
156−-------------------------------------------------------------------------------
157−-- Mutation with pointers
158−-------------------------------------------------------------------------------
159−
160−-- XXX This section can probably go in a common include file for pinned arrays.
161−
162−-- Change name later.
163−{-# INLINE toPtr #-}
164−toPtr :: Array a -> Ptr a
165−toPtr (Array arr#) = Ptr (byteArrayContents# (unsafeCoerce# arr#))
166−
167−{-# INLINE touchArray #-}
168−touchArray :: Array a -> IO ()
169−touchArray arr = IO $ \s -> case touch# arr s of s' -> (# s', () #)
170−
171−{-# INLINE withArrayAsPtr #-}
172−withArrayAsPtr :: Array a -> (Ptr a -> IO b) -> IO b
173−withArrayAsPtr arr f = do
174− r <- f (toPtr arr)
175− touchArray arr
176− return r
src/Streamly/Internal/Data/Array/Prim/Pinned/Type.hsdeleted−127
@@ -1,127 +0,0 @@
1−{-# LANGUAGE UnboxedTuples #-}
2−
3−#include "inline.hs"
4−
5−-- |
6−-- Module : Streamly.Internal.Data.Array.Prim.Pinned.Type
7−-- Copyright : (c) 2020 Composewell Technologies
8−--
9−-- License : BSD-3-Clause
10−-- Maintainer : streamly@composewell.com
11−-- Stability : experimental
12−-- Portability : GHC
13−--
14−module Streamly.Internal.Data.Array.Prim.Pinned.Type
15− (
16− Array (..)
17− , unsafeFreeze
18− , unsafeFreezeWithShrink
19−-- , unsafeThaw
20− , defaultChunkSize
21− , nil
22−
23− -- * Construction
24− , spliceTwo
25−
26− , fromList
27− , fromListN
28− , fromStreamDN
29− , fromStreamD
30−
31− -- * Streams of arrays
32− , fromStreamDArraysOf
33− , FlattenState (..) -- for inspection testing
34− , flattenArrays
35− , flattenArraysRev
36− , SpliceState (..) -- for inspection testing
37− , packArraysChunksOf
38− , lpackArraysChunksOf
39−#if !defined(mingw32_HOST_OS)
40−-- , groupIOVecsOf
41−#endif
42− , splitOn
43− , breakOn
44−
45− -- * Elimination
46− , unsafeIndex
47− , byteLength
48− , length
49−
50− , foldl'
51− , foldr
52− , foldr'
53− , foldlM'
54− , splitAt
55−
56− , toStreamD
57− , toStreamDRev
58− , toStreamK
59− , toStreamKRev
60− , toList
61−-- , toArrayMinChunk
62− , writeN
63− , MA.ArrayUnsafe(..)
64− , writeNUnsafe
65− , write
66−
67− , unlines
68−
69− , toPtr
70−
71− , touchArray
72− , withArrayAsPtr
73− )
74−where
75−
76−import Foreign.C.Types (CSize(..))
77−import GHC.IO (IO(..))
78−import Foreign.Ptr (minusPtr, nullPtr, plusPtr)
79−
80−import qualified Streamly.Internal.Data.Array.Prim.Pinned.Mut.Type as MA
81−
82−#include "Streamly/Internal/Data/Array/Prim/TypesInclude.hs"
83−
84−-------------------------------------------------------------------------------
85−-- Utility functions
86−-------------------------------------------------------------------------------
87−
88−foreign import ccall unsafe "string.h memchr" c_memchr
89− :: Ptr Word8 -> Word8 -> CSize -> IO (Ptr Word8)
90−
91−-------------------------------------------------------------------------------
92−-- Using as a Pointer
93−-------------------------------------------------------------------------------
94−
95−-- Change name later.
96−{-# INLINE toPtr #-}
97−toPtr :: Array a -> Ptr a
98−toPtr (Array arr# off _) = Ptr (byteArrayContents# arr#) `plusPtr` off
99−
100−{-# INLINE touchArray #-}
101−touchArray :: Array a -> IO ()
102−touchArray (Array arr# _ _) = IO $ \s -> case touch# arr# s of s1 -> (# s1, () #)
103−
104−{-# INLINE withArrayAsPtr #-}
105−withArrayAsPtr :: Array a -> (Ptr a -> IO b) -> IO b
106−withArrayAsPtr arr f = do
107− r <- f (toPtr arr)
108− touchArray arr
109− return r
110−
111−-- Drops the separator byte
112−{-# INLINE breakOn #-}
113−breakOn ::
114− MonadIO m
115− => Word8
116− -> Array Word8
117− -> m (Array Word8, Maybe (Array Word8))
118−breakOn sep arr@(Array arr# off len) = do
119− let p = toPtr arr
120− loc = unsafePerformIO $ c_memchr p sep (fromIntegral (byteLength arr))
121− len1 = loc `minusPtr` p
122− len2 = len - len1 - 1
123− return $
124− if loc == nullPtr
125− then (arr, Nothing)
126− else ( Array arr# off len1
127− , Just $ Array arr# (off + len1 + 1) len2)
src/Streamly/Internal/Data/Array/Prim/Type.hsdeleted−98
@@ -1,98 +0,0 @@
1−{-# LANGUAGE UnboxedTuples #-}
2−
3−#include "inline.hs"
4−
5−-- |
6−-- Module : Streamly.Internal.Data.Array.Prim.Type
7−-- Copyright : (c) 2020 Composewell Technologies
8−--
9−-- License : BSD-3-Clause
10−-- Maintainer : streamly@composewell.com
11−-- Stability : experimental
12−-- Portability : GHC
13−--
14−module Streamly.Internal.Data.Array.Prim.Type
15− (
16− Array (..)
17− , unsafeFreeze
18− , unsafeFreezeWithShrink
19−-- , unsafeThaw
20− , defaultChunkSize
21− , nil
22−
23− -- * Construction
24− , spliceTwo
25−
26− , fromList
27− , fromListN
28− , fromStreamDN
29− , fromStreamD
30−
31− -- * Streams of arrays
32− , fromStreamDArraysOf
33− , FlattenState (..) -- for inspection testing
34− , flattenArrays
35− , flattenArraysRev
36− , SpliceState (..) -- for inspection testing
37− , packArraysChunksOf
38− , lpackArraysChunksOf
39−#if !defined(mingw32_HOST_OS)
40−-- , groupIOVecsOf
41−#endif
42− , splitOn
43− , breakOn
44−
45− -- * Elimination
46− , unsafeIndex
47− , byteLength
48− , length
49−
50− , foldl'
51− , foldr
52− , foldr'
53− , foldlM'
54− , splitAt
55−
56− , toStreamD
57− , toStreamDRev
58− , toStreamK
59− , toStreamKRev
60− , toList
61−-- , toArrayMinChunk
62− , writeN
63− , MA.ArrayUnsafe(..)
64− , writeNUnsafe
65− , write
66−
67− , unlines
68− )
69−where
70−
71−import qualified Streamly.Internal.Data.Array.Prim.Mut.Type as MA
72−
73−#include "Streamly/Internal/Data/Array/Prim/TypesInclude.hs"
74−
75−-- Drops the separator byte
76−-- Inefficient compared to Memory Array
77−{-# INLINE breakOn #-}
78−breakOn ::
79− MonadIO m
80− => Word8
81− -> Array Word8
82− -> m (Array Word8, Maybe (Array Word8))
83−breakOn sep arr@(Array arr# off len) =
84− case loc of
85− Left _ -> return (arr, Nothing)
86− Right len1 -> do
87− let len2 = len - len1 - 1
88− return (Array arr# off len1, Just $ Array arr# (off + len1 + 1) len2)
89−
90− where
91−
92− loc = foldl' chk (Left 0) arr
93−
94− chk (Left i) a =
95− if a == sep
96− then Right i
97− else Left (i + 1)
98− chk r _ = r
src/Streamly/Internal/Data/Array/Prim/TypesInclude.hsdeleted−706
@@ -1,706 +0,0 @@
1−-- Copyright : (c) 2020 Composewell Technologies
2−-- License : BSD-3-Clause
3−-- Maintainer : streamly@composewell.com
4−-- Stability : experimental
5−-- Portability : GHC
6−
7−import Control.DeepSeq (NFData(..))
8−import Control.Monad (when)
9−import Control.Monad.IO.Class (MonadIO(..))
10−import Control.Monad.Primitive (PrimMonad(..), primitive_)
11−import Data.Bifunctor (first)
12−import Data.Primitive.Types (Prim(..), sizeOf)
13−#if __GLASGOW_HASKELL__ < 808
14−import Data.Semigroup (Semigroup(..))
15−#endif
16−import Data.Word (Word8)
17−import Streamly.Internal.Data.Tuple.Strict (Tuple3'(..))
18−import Streamly.Internal.Data.Maybe.Strict (Maybe'(..))
19−import Streamly.Internal.Data.Fold.Type (Fold(..))
20−import Streamly.Internal.Data.SVar (adaptState)
21−import System.IO.Unsafe (unsafePerformIO)
22−import Text.Read (readPrec, readListPrec, readListPrecDefault)
23−
24−import qualified GHC.Exts as Exts
25−import qualified Prelude as P
26−import qualified Streamly.Internal.Data.Fold as FL
27−import qualified Streamly.Internal.Data.Stream.StreamD.Type as D
28−import qualified Streamly.Internal.Data.Stream.StreamK.Type as K
29−
30−import GHC.Exts hiding (fromListN, fromList, toList)
31−import Prelude hiding (length, unlines, foldr)
32−
33−-------------------------------------------------------------------------------
34−-- Array Data Type
35−-------------------------------------------------------------------------------
36−
37−data Array a = Array ByteArray# Int Int
38−
39−-------------------------------------------------------------------------------
40−-- Utilities
41−-------------------------------------------------------------------------------
42−
43−-- | Both arrays must fully contain the specified ranges, but this is not
44−-- checked. The two arrays must not be the same array in different states, but
45−-- this is not checked either.
46−{-# INLINE unsafeCopy #-}
47−unsafeCopy ::
48− forall m a. (MonadIO m, Prim a)
49− => MA.Array a -- ^ destination array
50− -> Int -- ^ offset into destination array
51− -> Array a -- ^ source array
52− -> Int -- ^ offset into source array
53− -> Int -- ^ number of elements to copy
54− -> m ()
55−unsafeCopy (MA.Array dst#) (I# doff#) (Array src# (I# off#) _) (I# soff#) (I# n#) =
56− liftIO $ do
57− let toBytes cnt# = cnt# *# (sizeOf# (undefined :: a))
58− primitive_ $
59− copyByteArray#
60− src#
61− (toBytes (off# +# soff#))
62− dst#
63− (toBytes doff#)
64− (toBytes n#)
65−
66−-------------------------------------------------------------------------------
67−-- Basic Byte Array Operations
68−-------------------------------------------------------------------------------
69−
70−{-# INLINE unsafeFreeze #-}
71−unsafeFreeze :: (Prim a, MonadIO m) => MA.Array a -> m (Array a)
72−unsafeFreeze marr@(MA.Array arr#) =
73− liftIO $ do
74− len <- MA.length marr
75− primitive $ \s# ->
76− case unsafeFreezeByteArray# arr# s# of
77− (# s1#, arr1# #) -> (# s1#, Array arr1# 0 len #)
78−
79−{-# INLINE unsafeFreezeWithShrink #-}
80−unsafeFreezeWithShrink ::
81− (Prim a, MonadIO m) => MA.Array a -> Int -> m (Array a)
82−unsafeFreezeWithShrink marr@(MA.Array arr#) n =
83− liftIO $ do
84− MA.shrinkArray marr n
85− len <- MA.length marr
86− primitive $ \s# ->
87− case unsafeFreezeByteArray# arr# s# of
88− (# s1#, arr1# #) -> (# s1#, Array arr1# 0 len #)
89−
90−{-
91−-- Should never be used in general
92−{-# INLINE unsafeThaw #-}
93−unsafeThaw :: MonadIO m => Array a -> m (MA.Array a)
94−unsafeThaw (Array arr#) =
95− primitive $ \s# -> (# s#, MA.Array (unsafeCoerce# arr#) #)
96−-}
97−
98−-- Unsafe because the index bounds are not checked
99−{-# INLINE unsafeIndex #-}
100−unsafeIndex :: Prim a => Array a -> Int -> a
101−unsafeIndex (Array arr# (I# off#) _) (I# i#) = indexByteArray# arr# (off# +# i#)
102−
103−-- unsafe
104−sameByteArray :: ByteArray# -> ByteArray# -> Bool
105−sameByteArray ba1 ba2 =
106− case reallyUnsafePtrEquality#
107− (unsafeCoerce# ba1 :: ())
108− (unsafeCoerce# ba2 :: ()) of
109− r -> isTrue# r
110−
111−-------------------------------------------------------------------------------
112−-- Chunk Size
113−-------------------------------------------------------------------------------
114−
115−-- XXX move this section to mutable array module?
116−
117−mkChunkSizeKB :: Int -> Int
118−mkChunkSizeKB n = n * k
119− where k = 1024
120−
121−-- | Default maximum buffer size in bytes, for reading from and writing to IO
122−-- devices, the value is 32KB minus GHC allocation overhead, which is a few
123−-- bytes, so that the actual allocation is 32KB.
124−defaultChunkSize :: Int
125−defaultChunkSize = mkChunkSizeKB 32
126−
127−-------------------------------------------------------------------------------
128−-- Length
129−-------------------------------------------------------------------------------
130−
131−sizeOfPrimElem :: forall a . (Prim a) => a -> Int
132−sizeOfPrimElem _ = max 1 $ sizeOf (undefined :: a)
133−
134−-- XXX rename to byteCount?
135−{-# INLINE byteLength #-}
136−byteLength :: forall a. Prim a => Array a -> Int
137−byteLength (Array _ _ len) = len * sizeOfPrimElem (undefined :: a)
138−
139−-- XXX Also, rename to elemCount
140−-- XXX I would prefer length to keep the API consistent
141−-- XXX Also, re-export sizeOf from Primitive
142−{-# INLINE length #-}
143−length :: Array a -> Int
144−length (Array _ _ len) = len
145−
146−-------------------------------------------------------------------------------
147−-- Construction
148−-------------------------------------------------------------------------------
149−
150−-- | Use a slice of an array as another array. Note that this is unsafe and does
151−-- not check the bounds
152−slice :: Array a -> Int -> Int -> Array a
153−slice (Array arr# off _) off1 len1 = Array arr# (off + off1) len1
154−
155−nil :: Prim a => Array a
156−nil =
157− unsafePerformIO $ do
158− arr <- MA.newArray 0
159− unsafeFreeze arr
160−
161−-- | Fold the whole input to a single array.
162−--
163−-- /Caution! Do not use this on infinite streams./
164−--
165−-- /Pre-release/
166−{-# INLINE_NORMAL write #-}
167−write :: (MonadIO m, Prim a) => Fold m a (Array a)
168−write = FL.rmapM unsafeFreeze MA.write
169−
170−-- | @writeN n@ folds a maximum of @n@ elements from the input stream to an
171−-- 'Array'.
172−--
173−-- /Pre-release/
174−{-# INLINE_NORMAL writeN #-}
175−writeN :: (MonadIO m, Prim a) => Int -> Fold m a (Array a)
176−writeN limit = FL.rmapM unsafeFreeze (MA.writeN limit)
177−
178−-- | Like 'writeN' but does not check the array bounds when writing. The fold
179−-- driver must not call the step function more than 'n' times otherwise it will
180−-- corrupt the memory and crash. This function exists mainly because any
181−-- conditional in the step function blocks fusion causing 10x performance
182−-- slowdown.
183−--
184−-- /Pre-release/
185−{-# INLINE_NORMAL writeNUnsafe #-}
186−writeNUnsafe :: (MonadIO m, Prim a) => Int -> Fold m a (Array a)
187−writeNUnsafe limit = FL.rmapM unsafeFreeze (MA.writeNUnsafe limit)
188−
189−{-# INLINE_NORMAL fromStreamDN #-}
190−fromStreamDN :: (MonadIO m, Prim a) => Int -> D.Stream m a -> m (Array a)
191−fromStreamDN limit str = MA.fromStreamDN limit str >>= unsafeFreeze
192−
193−{-# INLINE fromStreamD #-}
194−fromStreamD :: (MonadIO m, Prim a) => D.Stream m a -> m (Array a)
195−fromStreamD str = MA.fromStreamD str >>= unsafeFreeze
196−
197−-- | @fromStreamArraysOf n stream@ groups the input stream into a stream of
198−-- arrays of size n.
199−{-# INLINE_NORMAL fromStreamDArraysOf #-}
200−fromStreamDArraysOf ::
201− (MonadIO m, Prim a) => Int -> D.Stream m a -> D.Stream m (Array a)
202−fromStreamDArraysOf n str = D.mapM unsafeFreeze (MA.fromStreamDArraysOf n str)
203−
204−-- XXX derive from MA.fromListN?
205−{-# INLINE fromListN #-}
206−fromListN :: Prim a => Int -> [a] -> Array a
207−fromListN len xs = unsafePerformIO $ MA.fromListNM len xs >>= unsafeFreeze
208−
209−-- XXX derive from MA.fromList?
210−{-# INLINE fromList #-}
211−fromList :: Prim a => [a] -> Array a
212−fromList xs = fromListN (P.length xs) xs
213−
214−-------------------------------------------------------------------------------
215−-- Combining
216−-------------------------------------------------------------------------------
217−
218−-- | Splice two immutable arrays creating a new immutable array.
219−{-# INLINE spliceTwo #-}
220−spliceTwo :: (MonadIO m, Prim a) => Array a -> Array a -> m (Array a)
221−spliceTwo a1 a2 = do
222− let l1 = length a1
223− l2 = length a2
224− a3 <- MA.newArray (l1 + l2)
225− unsafeCopy a3 0 a1 0 l1
226− unsafeCopy a3 l1 a2 0 l2
227− unsafeFreeze a3 -- Use `unsafeFreezeWith off len`?
228−
229−-------------------------------------------------------------------------------
230−-- Elimination
231−-------------------------------------------------------------------------------
232−
233−{-# INLINE_LATE toListFB #-}
234−toListFB :: Prim a => (a -> b -> b) -> b -> Array a -> b
235−toListFB c n arr = go 0
236− where
237− len = length arr
238− go p | p == len = n
239− go p =
240− let !x = unsafeIndex arr p
241− in c x (go (p + 1))
242−
243−-- | Convert an 'Array' into a list.
244−--
245−-- /Pre-release/
246−{-# INLINE toList #-}
247−toList :: Prim a => Array a -> [a]
248−toList s = build (\c n -> toListFB c n s)
249−
250−-------------------------------------------------------------------------------
251−-- Instances
252−-------------------------------------------------------------------------------
253−
254−instance (Eq a, Prim a) => Eq (Array a) where
255− {-# INLINE (==) #-}
256− a1@(Array ba1# _ len1) == a2@(Array ba2# _ len2)
257− | sameByteArray ba1# ba2# = True
258− | len1 /= len2 = False
259− | otherwise = loop (len1 - 1)
260−
261− where
262−
263− loop !i
264− | i < 0 = True
265− | otherwise = unsafeIndex a1 i == unsafeIndex a2 i && loop (i - 1)
266−
267−-- | Lexicographic ordering. Subject to change between major versions.
268−instance (Ord a, Prim a) => Ord (Array a) where
269− {-# INLINE compare #-}
270− compare a1@(Array ba1# _ len1) a2@(Array ba2# _ len2)
271− | sameByteArray ba1# ba2# = EQ
272− | otherwise = loop 0
273−
274− where
275−
276− sz = min len1 len2
277−
278− loop !i
279− | i < sz =
280− compare (unsafeIndex a1 i) (unsafeIndex a2 i) <> loop (i + 1)
281− | otherwise = compare len1 len2
282−
283−instance Prim a => Semigroup (Array a) where
284− -- XXX can't we use runST instead of inlineIO?
285− -- XXX I plan to remove MonadIO and replace it with IO
286− a <> b = unsafePerformIO (spliceTwo a b :: IO (Array a))
287−
288−instance Prim a => Monoid (Array a) where
289− mempty = nil
290− mappend = (<>)
291−
292−instance NFData (Array a) where
293− {-# INLINE rnf #-}
294− rnf _ = ()
295−
296−
297−-- XXX check if this is compatible with Memory.Array?
298−-- XXX It isn't. I might prefer this Show instance though
299−-- XXX Memory.Array: showsPrec _ = shows . toList
300−instance (Show a, Prim a) => Show (Array a) where
301− showsPrec p a =
302− showParen (p > 10) $
303− showString "fromListN "
304− . shows (length a)
305− . showString " "
306− . shows (toList a)
307−
308−instance (a ~ Char) => IsString (Array a) where
309− {-# INLINE fromString #-}
310− fromString = fromList
311−
312−-- GHC versions 8.0 and below cannot derive IsList
313−instance Prim a => IsList (Array a) where
314− type (Item (Array a)) = a
315−
316− {-# INLINE fromList #-}
317− fromList = fromList
318−
319− {-# INLINE fromListN #-}
320− fromListN = fromListN
321−
322− {-# INLINE toList #-}
323− toList = toList
324−
325−instance (Prim a, Read a, Show a) => Read (Array a) where
326− {-# INLINE readPrec #-}
327− readPrec = fromList <$> readPrec
328− readListPrec = readListPrecDefault
329−
330−-- XXX these folds can be made common with mutable arrays by defining a
331−-- unsafeIndex in the specific module?
332−
333−-------------------------------------------------------------------------------
334−-- Folds
335−-------------------------------------------------------------------------------
336−
337−{-# INLINE foldr #-}
338−foldr :: Prim a => (a -> b -> b) -> b -> Array a -> b
339−foldr f z arr = go 0
340−
341− where
342−
343− !len = length arr
344−
345− go !i
346− | len > i = f (unsafeIndex arr i) (go (i + 1))
347− | otherwise = z
348−
349−-- | Strict right-associated fold over the elements of an 'Array'.
350−{-# INLINE foldr' #-}
351−foldr' :: Prim a => (a -> b -> b) -> b -> Array a -> b
352−foldr' f z0 arr = go (length arr - 1) z0
353−
354− where
355−
356− go !i !acc
357− | i < 0 = acc
358− | otherwise = go (i - 1) (f (unsafeIndex arr i) acc)
359−
360−-- | Strict left-associated fold over the elements of an 'Array'.
361−{-# INLINE foldl' #-}
362−foldl' :: Prim a => (b -> a -> b) -> b -> Array a -> b
363−foldl' f z0 arr = go 0 z0
364−
365− where
366−
367− !len = length arr
368−
369− go !i !acc
370− | i < len = go (i + 1) (f acc (unsafeIndex arr i))
371− | otherwise = acc
372−
373−-- | Strict left-associated fold over the elements of an 'Array'.
374−{-# INLINE foldlM' #-}
375−foldlM' :: (Prim a, Monad m) => (b -> a -> m b) -> b -> Array a -> m b
376−foldlM' f z0 arr = go 0 z0
377−
378− where
379−
380− !len = length arr
381−
382− go !i !acc1
383− | i < len = do
384− acc2 <- f acc1 (unsafeIndex arr i)
385− go (i + 1) acc2
386− | otherwise = return acc1
387−
388−-------------------------------------------------------------------------------
389−-- Converting to streams
390−-------------------------------------------------------------------------------
391−
392−{-# INLINE_NORMAL toStreamD #-}
393−toStreamD :: (Prim a, Monad m) => Array a -> D.Stream m a
394−toStreamD arr = D.Stream step 0
395−
396− where
397−
398− {-# INLINE_LATE step #-}
399− step _ i
400− | i == length arr = return D.Stop
401− step _ i = return $ D.Yield (unsafeIndex arr i) (i + 1)
402−
403−{-# INLINE toStreamK #-}
404−toStreamK :: Prim a => Array a -> K.Stream m a
405−toStreamK arr = go 0
406−
407− where
408−
409− len = length arr
410−
411− go p
412− | p == len = K.nil
413− | otherwise =
414− let !x = unsafeIndex arr p
415− in x `K.cons` go (p + 1)
416−
417−{-# INLINE_NORMAL toStreamDRev #-}
418−toStreamDRev :: (Prim a, Monad m) => Array a -> D.Stream m a
419−toStreamDRev arr = D.Stream step (length arr - 1)
420−
421− where
422−
423− {-# INLINE_LATE step #-}
424− step _ i
425− | i < 0 = return D.Stop
426− step _ i = return $ D.Yield (unsafeIndex arr i) (i - 1)
427−
428−{-# INLINE toStreamKRev #-}
429−toStreamKRev :: Prim a => Array a -> K.Stream m a
430−toStreamKRev arr = go (length arr - 1)
431−
432− where
433−
434− go p | p == -1 = K.nil
435− | otherwise =
436− let !x = unsafeIndex arr p
437− in x `K.cons` go (p - 1)
438−
439−-------------------------------------------------------------------------------
440−-- Stream of Arrays
441−-------------------------------------------------------------------------------
442−
443−data FlattenState s a =
444− OuterLoop s
445− | InnerLoop s !(Array a) !Int !Int
446−
447−{-# INLINE_NORMAL flattenArrays #-}
448−flattenArrays :: (MonadIO m, Prim a) => D.Stream m (Array a) -> D.Stream m a
449−flattenArrays (D.Stream step state) = D.Stream step' (OuterLoop state)
450−
451− where
452−
453− {-# INLINE_LATE step' #-}
454− step' gst (OuterLoop st) = do
455− r <- step (adaptState gst) st
456− return $ case r of
457− D.Yield arr s ->
458− let len = length arr
459− in if len == 0
460− then D.Skip (OuterLoop s)
461− else D.Skip (InnerLoop s arr len 0)
462− D.Skip s -> D.Skip (OuterLoop s)
463− D.Stop -> D.Stop
464−
465− step' _ (InnerLoop st _ len i) | i == len =
466− return $ D.Skip $ OuterLoop st
467−
468− step' _ (InnerLoop st arr len i) = do
469− let x = unsafeIndex arr i
470− return $ D.Yield x (InnerLoop st arr len (i + 1))
471−
472−{-# INLINE_NORMAL flattenArraysRev #-}
473−flattenArraysRev :: (MonadIO m, Prim a) => D.Stream m (Array a) -> D.Stream m a
474−flattenArraysRev (D.Stream step state) = D.Stream step' (OuterLoop state)
475−
476− where
477−
478− {-# INLINE_LATE step' #-}
479− step' gst (OuterLoop st) = do
480− r <- step (adaptState gst) st
481− return $ case r of
482− D.Yield arr s ->
483− let len = length arr
484− in if len == 0
485− then D.Skip (OuterLoop s)
486− else D.Skip (InnerLoop s arr len (len - 1))
487− D.Skip s -> D.Skip (OuterLoop s)
488− D.Stop -> D.Stop
489−
490− step' _ (InnerLoop st _ _ i) | i == -1 =
491− return $ D.Skip $ OuterLoop st
492−
493− step' _ (InnerLoop st arr len i) = do
494− let x = unsafeIndex arr i
495− return $ D.Yield x (InnerLoop st arr len (i - 1))
496−
497−{-# INLINE_NORMAL unlines #-}
498−unlines :: (MonadIO m, Prim a) => a -> D.Stream m (Array a) -> D.Stream m a
499−unlines sep (D.Stream step state) = D.Stream step' (OuterLoop state)
500−
501− where
502−
503− {-# INLINE_LATE step' #-}
504− step' gst (OuterLoop st) = do
505− r <- step (adaptState gst) st
506− return $ case r of
507− D.Yield arr s ->
508− let len = length arr
509− in D.Skip (InnerLoop s arr len 0)
510− D.Skip s -> D.Skip (OuterLoop s)
511− D.Stop -> D.Stop
512−
513− step' _ (InnerLoop st _ len i) | i == len =
514− return $ D.Yield sep $ OuterLoop st
515−
516− step' _ (InnerLoop st arr len i) = do
517− let x = unsafeIndex arr i
518− return $ D.Yield x (InnerLoop st arr len (i + 1))
519−
520−-- Splice an array into a pre-reserved mutable array. The user must ensure
521−-- that there is enough space in the mutable array.
522−{-# INLINE spliceInto #-}
523−spliceInto :: (MonadIO m, Prim a) => MA.Array a -> Int -> Array a -> m Int
524−spliceInto dst doff src@(Array _ _ len) = do
525− unsafeCopy dst doff src 0 len
526− return $ doff + len
527−
528−data SpliceState s arr1 arr2
529− = SpliceInitial s
530− | SpliceBuffering s arr2
531− | SpliceYielding arr1 (SpliceState s arr1 arr2)
532− | SpliceFinish
533−
534−-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
535−-- maximum specified size in bytes. Note that if a single array is bigger than
536−-- the specified size we do not split it to fit. When we coalesce multiple
537−-- arrays if the size would exceed the specified size we do not coalesce
538−-- therefore the actual array size may be less than the specified chunk size.
539−--
540−-- /Pre-release/
541−{-# INLINE_NORMAL packArraysChunksOf #-}
542−packArraysChunksOf ::
543− forall m a. (MonadIO m, Prim a)
544− => Int
545− -> D.Stream m (Array a)
546− -> D.Stream m (Array a)
547−packArraysChunksOf n (D.Stream step state) =
548− D.Stream step' (SpliceInitial state)
549−
550− where
551−
552− nElem = n `quot` sizeOfPrimElem (undefined :: a)
553−
554− {-# INLINE_LATE step' #-}
555− step' gst (SpliceInitial st) = do
556− when (n <= 0) $
557− -- XXX we can pass the module string from the higher level API
558− error $ "Streamly.Internal.Data.Array.Foreign.Type.packArraysChunksOf: the size of "
559− ++ "arrays [" ++ show n ++ "] must be a natural number"
560− r <- step gst st
561− case r of
562− D.Yield arr s ->
563− if length arr >= nElem
564− then return $ D.Skip (SpliceYielding arr (SpliceInitial s))
565− else do
566− buf <- MA.newArray nElem
567− noff <- spliceInto buf 0 arr
568− return $ D.Skip (SpliceBuffering s (buf, noff))
569− D.Skip s -> return $ D.Skip (SpliceInitial s)
570− D.Stop -> return $ D.Stop
571−
572− step' gst (SpliceBuffering st arr2@(buf, boff)) = do
573− r <- step gst st
574− case r of
575− D.Yield arr s -> do
576− if boff + length arr > nElem
577− then do
578− nArr <- unsafeFreeze buf
579− return $ D.Skip (SpliceYielding (slice nArr 0 boff) (SpliceBuffering s arr2))
580− else do
581− noff <- spliceInto buf boff arr
582− return $ D.Skip (SpliceBuffering s (buf, noff))
583− D.Skip s -> return $ D.Skip (SpliceBuffering s arr2)
584− D.Stop -> do
585− nArr <- unsafeFreeze buf
586− return $ D.Skip (SpliceYielding (slice nArr 0 boff) SpliceFinish)
587−
588− step' _ SpliceFinish = return D.Stop
589−
590− step' _ (SpliceYielding arr next) = return $ D.Yield arr next
591−
592−{-# INLINE_NORMAL lpackArraysChunksOf #-}
593−lpackArraysChunksOf ::
594− forall m a. (MonadIO m, Prim a)
595− => Int
596− -> Fold m (Array a) ()
597− -> Fold m (Array a) ()
598−lpackArraysChunksOf n (Fold step1 initial1 extract1) =
599− Fold step initial extract
600−
601− where
602−
603− nElem = n `quot` sizeOfPrimElem (undefined :: a)
604−
605− initial = do
606− when (n <= 0) $
607− -- XXX we can pass the module string from the higher level API
608− error $ "Streamly.Internal.Data.Array.Foreign.Type.packArraysChunksOf: the size of "
609− ++ "arrays [" ++ show n ++ "] must be a natural number"
610− res <- initial1
611− return $ first (Tuple3' Nothing' 0) res
612−
613− extract (Tuple3' Nothing' _ r1) = extract1 r1
614− extract (Tuple3' (Just' buf) boff r1) = do
615− nArr <- unsafeFreeze buf
616− r <- step1 r1 (slice nArr 0 boff)
617− case r of
618− FL.Partial rr -> extract1 rr
619− FL.Done _ -> return ()
620−
621− step (Tuple3' Nothing' _ r1) arr =
622− if length arr >= nElem
623− then do
624− r <- step1 r1 arr
625− case r of
626− FL.Done _ -> return $ FL.Done ()
627− FL.Partial s -> do
628− extract1 s
629− res <- initial1
630− return $ first (Tuple3' Nothing' 0) res
631− else do
632− buf <- MA.newArray nElem
633− noff <- spliceInto buf 0 arr
634− return $ FL.Partial $ Tuple3' (Just' buf) noff r1
635−
636− step (Tuple3' (Just' buf) boff r1) arr = do
637− noff <- spliceInto buf boff arr
638−
639− if noff >= nElem
640− then do
641− nArr <- unsafeFreeze buf
642− r <- step1 r1 (slice nArr 0 noff)
643− case r of
644− FL.Done _ -> return $ FL.Done ()
645− FL.Partial s -> do
646− extract1 s
647− res <- initial1
648− return $ first (Tuple3' Nothing' 0) res
649− else return $ FL.Partial $ Tuple3' (Just' buf) noff r1
650−
651−data SplitState s arr
652− = Initial s
653− | Buffering s arr
654− | Splitting s arr
655− | Yielding arr (SplitState s arr)
656− | Finishing
657−
658−-- | Split a stream of arrays on a given separator byte, dropping the separator
659−-- and coalescing all the arrays between two separators into a single array.
660−--
661−-- /Pre-release/
662−{-# INLINE_NORMAL splitOn #-}
663−splitOn ::
664− MonadIO m
665− => Word8
666− -> D.Stream m (Array Word8)
667− -> D.Stream m (Array Word8)
668−splitOn byte (D.Stream step state) = D.Stream step' (Initial state)
669−
670− where
671−
672− {-# INLINE_LATE step' #-}
673− step' gst (Initial st) = do
674− r <- step gst st
675− case r of
676− D.Yield arr s -> do
677− (arr1, marr2) <- breakOn byte arr
678− return $ case marr2 of
679− Nothing -> D.Skip (Buffering s arr1)
680− Just arr2 -> D.Skip (Yielding arr1 (Splitting s arr2))
681− D.Skip s -> return $ D.Skip (Initial s)
682− D.Stop -> return $ D.Stop
683−
684− step' gst (Buffering st buf) = do
685− r <- step gst st
686− case r of
687− D.Yield arr s -> do
688− (arr1, marr2) <- breakOn byte arr
689− buf' <- spliceTwo buf arr1
690− return $ case marr2 of
691− Nothing -> D.Skip (Buffering s buf')
692− Just x -> D.Skip (Yielding buf' (Splitting s x))
693− D.Skip s -> return $ D.Skip (Buffering s buf)
694− D.Stop -> return $
695− if byteLength buf == 0
696− then D.Stop
697− else D.Skip (Yielding buf Finishing)
698−
699− step' _ (Splitting st buf) = do
700− (arr1, marr2) <- breakOn byte buf
701− return $ case marr2 of
702− Nothing -> D.Skip $ Buffering st arr1
703− Just arr2 -> D.Skip $ Yielding arr1 (Splitting st arr2)
704−
705− step' _ (Yielding arr next) = return $ D.Yield arr next
706− step' _ Finishing = return $ D.Stop
src/Streamly/Internal/Data/Array/PrimInclude.hsdeleted−185
@@ -1,185 +0,0 @@
1−-- Copyright : (c) 2020 Composewell Technologies
2−-- License : BSD-3-Clause
3−-- Maintainer : streamly@composewell.com
4−-- Stability : experimental
5−-- Portability : GHC
6−
7−import Control.Monad (when)
8−import Control.Monad.IO.Class (MonadIO(..))
9−import Data.Primitive.Types (Prim(..))
10−import Streamly.Internal.Data.Fold.Type (Fold(..))
11−import Streamly.Internal.Data.Unfold.Type (Unfold(..))
12−import Streamly.Internal.Data.Stream.Serial (SerialT)
13−
14−import qualified Streamly.Internal.Data.Stream.Common as P
15−import qualified Streamly.Internal.Data.Stream.StreamD as D
16−
17−import Prelude hiding (length, null, last, map, (!!), read, concat)
18−import qualified Streamly.Internal.Data.Stream.Type as Stream
19−
20−-------------------------------------------------------------------------------
21−-- Construction
22−-------------------------------------------------------------------------------
23−
24−-- | Create an 'Array' from the first N elements of a stream. The array is
25−-- allocated to size N, if the stream terminates before N elements then the
26−-- array may hold less than N elements.
27−--
28−-- /Pre-release/
29−{-# INLINE fromStreamN #-}
30−fromStreamN :: (MonadIO m, Prim a) => Int -> SerialT m a -> m (Array a)
31−fromStreamN n m = do
32− when (n < 0) $ error "writeN: negative write count specified"
33− A.fromStreamDN n $ D.fromStreamK $ Stream.toStreamK m
34−
35−-- | Create an 'Array' from a stream. This is useful when we want to create a
36−-- single array from a stream of unknown size. 'writeN' is at least twice
37−-- as efficient when the size is already known.
38−--
39−-- Note that if the input stream is too large memory allocation for the array
40−-- may fail. When the stream size is not known, `arraysOf` followed by
41−-- processing of indvidual arrays in the resulting stream should be preferred.
42−--
43−-- /Pre-release/
44−{-# INLINE fromStream #-}
45−fromStream :: (MonadIO m, Prim a) => SerialT m a -> m (Array a)
46−fromStream m = P.fold A.write $ Stream.toStreamK m
47−-- write m = A.fromStreamD $ D.toStreamD m
48−
49−-------------------------------------------------------------------------------
50−-- Elimination
51−-------------------------------------------------------------------------------
52−
53−-- | Convert an 'Array' into a stream.
54−--
55−-- /Pre-release/
56−{-# INLINE_EARLY toStream #-}
57−toStream :: (MonadIO m, Prim a) => Array a -> SerialT m a
58−toStream = Stream.fromStreamK . D.toStreamK . A.toStreamD
59−-- XXX add fallback to StreamK rule
60−-- {-# RULES "Streamly.Array.read fallback to StreamK" [1]
61−-- forall a. S.readK (read a) = K.fromArray a #-}
62−
63−-- | Convert an 'Array' into a stream in reverse order.
64−--
65−-- /Pre-release/
66−{-# INLINE_EARLY toStreamRev #-}
67−toStreamRev :: (MonadIO m, Prim a) => Array a -> SerialT m a
68−toStreamRev = Stream.fromStreamK . D.toStreamK . A.toStreamDRev
69−-- XXX add fallback to StreamK rule
70−-- {-# RULES "Streamly.Array.readRev fallback to StreamK" [1]
71−-- forall a. S.toStreamK (readRev a) = K.revFromArray a #-}
72−
73−-- | Unfold an array into a stream.
74−--
75−-- @since 0.7.0
76−{-# INLINE_NORMAL read #-}
77−read :: (MonadIO m, Prim a) => Unfold m (Array a) a
78−read = Unfold step inject
79− where
80−
81− inject = return
82−
83− {-# INLINE_LATE step #-}
84− step (Array _ _ len) | len == 0 = return D.Stop
85− step arr@(Array arr# off len) =
86− let !x = A.unsafeIndex arr 0
87− in return $ D.Yield x (Array arr# (off + 1) (len - 1))
88−
89−-- | Unfold an array into a stream, does not check the end of the array, the
90−-- user is responsible for terminating the stream within the array bounds. For
91−-- high performance application where the end condition can be determined by
92−-- a terminating fold.
93−--
94−-- The following might not be true, not that the representation changed.
95−-- Written in the hope that it may be faster than "read", however, in the case
96−-- for which this was written, "read" proves to be faster even though the core
97−-- generated with unsafeRead looks simpler.
98−--
99−-- /Pre-release/
100−--
101−{-# INLINE_NORMAL unsafeRead #-}
102−unsafeRead :: (MonadIO m, Prim a) => Unfold m (Array a) a
103−unsafeRead = Unfold step inject
104− where
105−
106− inject = return
107−
108− {-# INLINE_LATE step #-}
109− step arr@(Array arr# off len) =
110− let !x = A.unsafeIndex arr 0
111− in return $ D.Yield x (Array arr# (off + 1) (len - 1))
112−
113−-- | > null arr = length arr == 0
114−--
115−-- /Pre-release/
116−{-# INLINE null #-}
117−null :: Array a -> Bool
118−null arr = length arr == 0
119−
120−-------------------------------------------------------------------------------
121−-- Folds
122−-------------------------------------------------------------------------------
123−
124−-- | Fold an array using a 'Fold'.
125−--
126−-- /Pre-release/
127−{-# INLINE fold #-}
128−fold :: forall m a b. (MonadIO m, Prim a) => Fold m a b -> Array a -> m b
129−fold f arr = P.fold f (Stream.toStreamK (toStream arr))
130−
131−-- | Fold an array using a stream fold operation.
132−--
133−-- /Pre-release/
134−{-# INLINE streamFold #-}
135−streamFold :: (MonadIO m, Prim a) => (SerialT m a -> m b) -> Array a -> m b
136−streamFold f arr = f (toStream arr)
137−
138−-------------------------------------------------------------------------------
139−-- Random reads
140−-------------------------------------------------------------------------------
141−
142−-- | /O(1)/ Lookup the element at the given index, starting from 0.
143−--
144−-- /Pre-release/
145−{-# INLINE readIndex #-}
146−readIndex :: Prim a => Array a -> Int -> Maybe a
147−readIndex arr i =
148− if i < 0 || i > length arr - 1
149− then Nothing
150− else Just $ A.unsafeIndex arr i
151−
152−-- | > last arr = readIndex arr (length arr - 1)
153−--
154−-- /Pre-release/
155−{-# INLINE last #-}
156−last :: Prim a => Array a -> Maybe a
157−last arr = readIndex arr (length arr - 1)
158−
159−-------------------------------------------------------------------------------
160−-- Array stream operations
161−-------------------------------------------------------------------------------
162−
163−-- | Convert a stream of arrays into a stream of their elements.
164−--
165−-- Same as the following but more efficient:
166−--
167−-- > concat = S.concatMap A.read
168−--
169−-- /Pre-release/
170−{-# INLINE concat #-}
171−concat :: (MonadIO m, Prim a) => SerialT m (Array a) -> SerialT m a
172−-- concat m = D.fromStreamD $ A.flattenArrays (D.toStreamD m)
173−-- concat m = D.fromStreamD $ D.concatMap A.toStreamD (D.toStreamD m)
174−concat m =
175− Stream.fromStreamK $ D.toStreamK $ D.unfoldMany read (D.fromStreamK $ Stream.toStreamK m)
176−
177−-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
178−-- maximum specified size in bytes.
179−--
180−-- /Pre-release/
181−{-# INLINE compact #-}
182−compact ::
183− (MonadIO m, Prim a) => Int -> SerialT m (Array a) -> SerialT m (Array a)
184−compact n m =
185− Stream.fromStreamK $ D.toStreamK $ A.packArraysChunksOf n (D.fromStreamK $ Stream.toStreamK m)
src/Streamly/Internal/Unicode/Array/Prim/Pinned.hsdeleted−91
@@ -1,91 +0,0 @@
1−-- |
2−-- Module : Streamly.Internal.Unicode.Array.Prim.Pinned
3−-- Copyright : (c) 2020 Composewell Technologies
4−--
5−-- License : BSD-3-Clause
6−-- Maintainer : streamly@composewell.com
7−-- Stability : experimental
8−-- Portability : GHC
9−--
10−module Streamly.Internal.Unicode.Array.Prim.Pinned
11− (
12− -- * Streams of Strings
13− lines
14− , words
15− , unlines
16− , unwords
17− )
18−where
19−
20−import Control.Monad.IO.Class (MonadIO(..))
21−import Streamly.Prelude (MonadAsync)
22−import Prelude hiding (String, lines, words, unlines, unwords)
23−import Streamly.Internal.Data.Stream.IsStream (IsStream)
24−import Streamly.Internal.Data.Array.Prim.Pinned (Array)
25−
26−import qualified Streamly.Internal.Unicode.Stream as S
27−import qualified Streamly.Internal.Data.Array.Prim.Pinned as A
28−
29−-- $setup
30−-- >>> :m
31−-- >>> :set -XOverloadedStrings
32−-- >>> import qualified Streamly.Prelude as Stream
33−-- >>> import qualified Streamly.Internal.Unicode.Array.Prim.Pinned as Unicode
34−
35−-- | Break a string up into a stream of strings at newline characters.
36−-- The resulting strings do not contain newlines.
37−--
38−-- > lines = S.lines A.write
39−--
40−-- >>> Stream.toList $ Unicode.lines $ Stream.fromList "lines\nthis\nstring\n\n\n"
41−-- [fromListN 5 "lines",fromListN 4 "this",fromListN 6 "string",fromListN 0 "",fromListN 0 ""]
42−--
43−{-# INLINE lines #-}
44−lines :: (MonadIO m, IsStream t) => t m Char -> t m (Array Char)
45−lines = S.lines A.write
46−
47−-- | Break a string up into a stream of strings, which were delimited
48−-- by characters representing white space.
49−--
50−-- > words = S.words A.write
51−--
52−-- >>> Stream.toList $ Unicode.words $ Stream.fromList "A newline\nis considered white space?"
53−-- [fromListN 1 "A",fromListN 7 "newline",fromListN 2 "is",fromListN 10 "considered",fromListN 5 "white",fromListN 6 "space?"]
54−--
55−{-# INLINE words #-}
56−words :: (MonadIO m, IsStream t) => t m Char -> t m (Array Char)
57−words = S.words A.write
58−
59−-- | Flattens the stream of @Array Char@, after appending a terminating
60−-- newline to each string.
61−--
62−-- 'unlines' is an inverse operation to 'lines'.
63−--
64−-- >>> Stream.toList $ Unicode.unlines $ Stream.fromList ["lines", "this", "string"]
65−-- "lines\nthis\nstring\n"
66−--
67−-- > unlines = S.unlines A.read
68−--
69−-- Note that, in general
70−--
71−-- > unlines . lines /= id
72−{-# INLINE unlines #-}
73−unlines :: (MonadAsync m, IsStream t) => t m (Array Char) -> t m Char
74−unlines = S.unlines A.read
75−
76−-- | Flattens the stream of @Array Char@, after appending a separating
77−-- space to each string.
78−--
79−-- 'unwords' is an inverse operation to 'words'.
80−--
81−-- >>> Stream.toList $ Unicode.unwords $ Stream.fromList ["unwords", "this", "string"]
82−-- "unwords this string"
83−--
84−-- > unwords = S.unwords A.read
85−--
86−-- Note that, in general
87−--
88−-- > unwords . words /= id
89−{-# INLINE unwords #-}
90−unwords :: (MonadAsync m, IsStream t) => t m (Array Char) -> t m Char
91−unwords = S.unwords A.read
streamly.cabal−15
@@ -58,8 +58,6 @@ extra-source-files:
5858 benchmark/Streamly/Benchmark/Data/Array/Foreign.hs
5959 benchmark/Streamly/Benchmark/Data/Ring/Unboxed.hs
6060 benchmark/Streamly/Benchmark/Data/Array/Foreign/Mut.hs
61− benchmark/Streamly/Benchmark/Data/Array/Prim.hs
62− benchmark/Streamly/Benchmark/Data/Array/Prim/Pinned.hs
6361 benchmark/Streamly/Benchmark/Data/Array/Stream/Foreign.hs
6462 benchmark/Streamly/Benchmark/Data/Fold/Window.hs
6563 benchmark/Streamly/Benchmark/Data/Parser/*.hs
@@ -87,17 +85,12 @@ extra-source-files:
8785 src/Streamly/Internal/Data/Stream/Instances.hs
8886 src/Streamly/Internal/Data/Array/ArrayMacros.h
8987
90− src/Streamly/Internal/Data/Array/PrimInclude.hs
91− src/Streamly/Internal/Data/Array/Prim/TypesInclude.hs
92− src/Streamly/Internal/Data/Array/Prim/MutTypesInclude.hs
9388 src/Streamly/Internal/FileSystem/Event/Darwin.h
9489 src/config.h.in
9590 src/inline.hs
9691 test/Streamly/Test/Data/*.hs
9792 test/Streamly/Test/Data/Array/CommonImports.hs
9893 test/Streamly/Test/Data/Array/Common.hs
99− test/Streamly/Test/Data/Array/Prim.hs
100− test/Streamly/Test/Data/Array/Prim/Pinned.hs
10194 test/Streamly/Test/Data/Array/Foreign.hs
10295 test/Streamly/Test/Data/Ring/Unboxed.hs
10396 test/Streamly/Test/Data/Array/Stream/Foreign.hs
@@ -441,13 +434,7 @@ library
441434 Streamly.Data.Unfold
442435
443436 -- XXX To be removed or put under dev flag
444− , Streamly.Internal.Data.Array.Prim.Mut.Type
445− , Streamly.Internal.Data.Array.Prim.Type
446− , Streamly.Internal.Data.Array.Prim.Pinned.Mut.Type
447− , Streamly.Internal.Data.Array.Prim.Pinned.Type
448437 , Streamly.Internal.Data.SmallArray.Type
449− , Streamly.Internal.Data.Array.Prim
450− , Streamly.Internal.Data.Array.Prim.Pinned
451438 , Streamly.Internal.Data.SmallArray
452439
453440 -- streamly-concurrent
@@ -494,7 +481,6 @@ library
494481 , Streamly.Internal.Unicode.Char
495482 , Streamly.Internal.Unicode.Char.Parser
496483 , Streamly.Internal.Unicode.Array.Char
497− , Streamly.Internal.Unicode.Array.Prim.Pinned
498484
499485 -- streamly-filesystem
500486 , Streamly.Internal.System.IOVec.Type
@@ -647,7 +633,6 @@ library
647633
648634 other-modules:
649635 Streamly.Data.Array
650− , Streamly.Data.Prim.Array
651636 , Streamly.Data.SmallArray
652637
653638 if os(windows)
test/Streamly/Test/Data/Array/Prim.hsdeleted−55
@@ -1,55 +0,0 @@
1−-- |
2−-- Module : Streamly.Test.Data.Array.Prim
3−-- Copyright : (c) 2020 Composewell Technologies
4−-- License : BSD-3-Clause
5−-- Maintainer : streamly@composewell.com
6−-- Stability : experimental
7−-- Portability : GHC
8−
9−module Streamly.Test.Data.Array.Prim (main) where
10−
11−#include "Streamly/Test/Data/Array/CommonImports.hs"
12−
13−import qualified Streamly.Internal.Data.Fold as Fold
14−import qualified Streamly.Internal.Data.Array.Prim as A
15−import qualified Streamly.Internal.Data.Array.Prim.Type as A
16−type Array = A.Array
17−
18−moduleName :: String
19−moduleName = "Data.Array.Prim"
20−
21−#include "Streamly/Test/Data/Array/Common.hs"
22−
23−testFromStreamToStream :: Property
24−testFromStreamToStream = genericTestFromTo (const A.fromStream) A.toStream (==)
25−
26−testFoldUnfold :: Property
27−testFoldUnfold = genericTestFromTo (const (S.fold A.write)) (S.unfold A.read) (==)
28−
29−testFromList :: Property
30−testFromList =
31− forAll (choose (0, maxArrLen)) $ \len ->
32− forAll (vectorOf len (arbitrary :: Gen Int)) $ \list ->
33− monadicIO $ do
34− let arr = A.fromList list
35− xs <- run $ S.toList $ (S.unfold A.read) arr
36− assert (xs == list)
37−
38−testLengthFromStream :: Property
39−testLengthFromStream = genericTestFrom (const A.fromStream)
40−
41−
42−main :: IO ()
43−main =
44− hspec $
45− H.parallel $
46− modifyMaxSuccess (const maxTestCount) $ do
47− describe moduleName $ do
48− commonMain
49− describe "Construction" $ do
50− prop "length . fromStream === n" testLengthFromStream
51− prop "toStream . fromStream === id" testFromStreamToStream
52− prop "read . write === id" testFoldUnfold
53− prop "fromList" testFromList
54− prop "foldMany with writeNUnsafe concats to original"
55− (foldManyWith (\n -> Fold.take n (A.writeNUnsafe n)))
test/Streamly/Test/Data/Array/Prim/Pinned.hsdeleted−55
@@ -1,55 +0,0 @@
1−-- |
2−-- Module : Streamly.Test.Data.Array.Prim.Pinned
3−-- Copyright : (c) 2020 Composewell Technologies
4−-- License : BSD-3-Clause
5−-- Maintainer : streamly@composewell.com
6−-- Stability : experimental
7−-- Portability : GHC
8−
9−module Streamly.Test.Data.Array.Prim.Pinned (main) where
10−
11−#include "Streamly/Test/Data/Array/CommonImports.hs"
12−
13−import qualified Streamly.Internal.Data.Fold as Fold
14−import qualified Streamly.Internal.Data.Array.Prim as A
15−import qualified Streamly.Internal.Data.Array.Prim.Type as A
16−type Array = A.Array
17−
18−moduleName :: String
19−moduleName = "Data.Array.Prim.Pinned"
20−
21−#include "Streamly/Test/Data/Array/Common.hs"
22−
23−testFromStreamToStream :: Property
24−testFromStreamToStream = genericTestFromTo (const A.fromStream) A.toStream (==)
25−
26−testFoldUnfold :: Property
27−testFoldUnfold = genericTestFromTo (const (S.fold A.write)) (S.unfold A.read) (==)
28−
29−testFromList :: Property
30−testFromList =
31− forAll (choose (0, maxArrLen)) $ \len ->
32− forAll (vectorOf len (arbitrary :: Gen Int)) $ \list ->
33− monadicIO $ do
34− let arr = A.fromList list
35− xs <- run $ S.toList $ (S.unfold A.read) arr
36− assert (xs == list)
37−
38−testLengthFromStream :: Property
39−testLengthFromStream = genericTestFrom (const A.fromStream)
40−
41−
42−main :: IO ()
43−main =
44− hspec $
45− H.parallel $
46− modifyMaxSuccess (const maxTestCount) $ do
47− describe moduleName $ do
48− commonMain
49− describe "Construction" $ do
50− prop "length . fromStream === n" testLengthFromStream
51− prop "toStream . fromStream === id" testFromStreamToStream
52− prop "read . write === id" testFoldUnfold
53− prop "fromList" testFromList
54− prop "foldMany with writeNUnsafe concats to original"
55− (foldManyWith (\n -> Fold.take n (A.writeNUnsafe n)))
test/streamly-tests.cabal−12
@@ -223,18 +223,6 @@ test-suite Data.Array
223223 main-is: Streamly/Test/Data/Array.hs
224224 ghc-options: -main-is Streamly.Test.Data.Array.main
225225
226−test-suite Data.Array.Prim
227− import: test-options
228− type: exitcode-stdio-1.0
229− main-is: Streamly/Test/Data/Array/Prim.hs
230− ghc-options: -main-is Streamly.Test.Data.Array.Prim.main
231−
232−test-suite Data.Array.Prim.Pinned
233− import: test-options
234− type: exitcode-stdio-1.0
235− main-is: Streamly/Test/Data/Array/Prim/Pinned.hs
236− ghc-options: -main-is Streamly.Test.Data.Array.Prim.Pinned.main
237−
238226test-suite Data.Array.Foreign
239227 import: test-options
240228 type: exitcode-stdio-1.0