on 6a56740 help sign in
67 files changed+1970−3616
since splitsnapshots
unifiedsplit
benchmark/Streamly/Benchmark/FileSystem/Handle/Read.hs+8−7 benchmark/Streamly/Benchmark/FileSystem/Handle/ReadWrite.hs+9−8 benchmark/Streamly/Benchmark/Unicode/Stream.hs+3−4 configure+9−9 configure.ac+1−1 core/configure+9−9 core/configure.ac+1−1 core/docs/ApiChangelogs/0.2.0-0.2.2.txt−306 core/docs/Changelog.md+1−3 core/src/DocTestDataArray.hs−3 core/src/DocTestDataStream.hs−2 core/src/DocTestFileSystemHandle.hs+1−1 core/src/Streamly/Data/Array.hs+27−30 core/src/Streamly/Data/Array/Generic.hs+13−16 core/src/Streamly/Data/MutArray.hs+6−12 core/src/Streamly/Data/MutArray/Generic.hs+3−8 core/src/Streamly/Data/Stream.hs+20−129 core/src/Streamly/Internal/Data/Array.hs+94−551 core/src/Streamly/Internal/Data/Array/Generic.hs+6−22 core/src/Streamly/Internal/Data/Array/Stream.hs+474−15 core/src/Streamly/Internal/Data/Array/Type.hs+96−341 core/src/Streamly/Internal/Data/Fold/Combinators.hs+92 core/src/Streamly/Internal/Data/Fold/Type.hs−91 core/src/Streamly/Internal/Data/IsMap.hs−4 core/src/Streamly/Internal/Data/MutArray.hs+15−127 core/src/Streamly/Internal/Data/MutArray/Generic.hs+30−65 core/src/Streamly/Internal/Data/MutArray/Stream.hs+195−11 core/src/Streamly/Internal/Data/MutArray/Type.hs+339−1013 core/src/Streamly/Internal/Data/MutByteArray/Type.hs+16−40 core/src/Streamly/Internal/Data/Serialize/TH.hs+1−5 core/src/Streamly/Internal/Data/Stream/Container.hs+48−56 core/src/Streamly/Internal/Data/Stream/Eliminate.hs+25−33 core/src/Streamly/Internal/Data/Stream/Exception.hs+6−9 core/src/Streamly/Internal/Data/Stream/Generate.hs+12 core/src/Streamly/Internal/Data/Stream/Nesting.hs+139−10 core/src/Streamly/Internal/Data/Stream/Top.hs+115−243 core/src/Streamly/Internal/Data/Stream/Transform.hs+27−53 core/src/Streamly/Internal/Data/Stream/Transformer.hs+1−2 core/src/Streamly/Internal/Data/Stream/Type.hs+3−129 core/src/Streamly/Internal/Data/StreamK.hs+8−19 core/src/Streamly/Internal/Data/StreamK/Type.hs+11−60 core/src/Streamly/Internal/Data/Time/Units.hs+4 core/src/Streamly/Internal/Data/Unbox.hs+1−4 core/src/Streamly/Internal/Data/Unfold.hs+4−6 core/src/Streamly/Internal/FileSystem/File.hs+9−4 core/src/Streamly/Internal/FileSystem/Handle.hs+28−21 core/src/Streamly/Internal/FileSystem/Path.hs+4−36 core/src/Streamly/Internal/Unicode/Stream.hs+2−2 core/src/Streamly/Internal/Unicode/String.hs+7−7 core/streamly-core.cabal+10−14 docs/Developer/optimization-guidelines.md−12 docs/User/Project/Changelog.md+1−1 docs/User/Project/README.md−1 src/Streamly/Internal/Data/IsMap/HashMap.hs−5 src/Streamly/Internal/Data/Stream/IsStream/Common.hs+1−1 src/Streamly/Internal/Data/Stream/IsStream/Expand.hs−5 src/Streamly/Internal/Data/Stream/IsStream/Top.hs+1−1 src/Streamly/Internal/Data/Stream/Serial.hs−5 src/Streamly/Internal/Data/Stream/Zip.hs−5 src/Streamly/Internal/FileSystem/Event.hs−3 src/Streamly/Internal/FileSystem/Event/Darwin.hs+1−1 src/Streamly/Internal/FileSystem/Event/Linux.hs+2−2 src/Streamly/Internal/FileSystem/FD.hs+5−5 src/Streamly/Internal/Network/Inet/TCP.hs+3−3 src/Streamly/Internal/Network/Socket.hs+10−11 streamly.cabal+11−11 test/Streamly/Test/Data/Array.hs+2−2
benchmark/Streamly/Benchmark/FileSystem/Handle/Read.hs+8−7
@@ -33,6 +33,7 @@ import qualified Streamly.Data.Stream as Stream
3333import qualified Streamly.Data.Fold as Fold
3434import qualified Streamly.FileSystem.Handle as FH
3535import qualified Streamly.Internal.Data.Array as A
36+import qualified Streamly.Internal.Data.Array as AT
3637import qualified Streamly.Internal.Data.Fold as FL
3738import qualified Streamly.Internal.Data.Stream as IP
3839import qualified Streamly.Internal.FileSystem.Handle as IFH
@@ -47,7 +48,7 @@ import Streamly.Benchmark.Common.Handle
4748#ifdef INSPECTION
4849import Streamly.Internal.Data.Stream (Step(..), FoldMany)
4950
50−import qualified Streamly.Internal.Data.MutArray as MutArray
51+import qualified Streamly.Internal.Data.MutArray as MA
5152import qualified Streamly.Internal.Data.Stream as D
5253import qualified Streamly.Internal.Data.Unfold as IUF
5354
@@ -68,7 +69,7 @@ readLast = S.fold Fold.last . S.unfold FH.reader
6869inspect $ hasNoTypeClasses 'readLast
6970inspect $ 'readLast `hasNoType` ''Step -- S.unfold
7071inspect $ 'readLast `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
71−inspect $ 'readLast `hasNoType` ''MutArray.ArrayUnsafe -- FH.read/A.read
72+inspect $ 'readLast `hasNoType` ''MA.ArrayUnsafe -- FH.read/A.read
7273#endif
7374
7475-- assert that flattenArrays constructors are not present
@@ -80,7 +81,7 @@ readCountBytes = S.fold Fold.length . S.unfold FH.reader
8081inspect $ hasNoTypeClasses 'readCountBytes
8182inspect $ 'readCountBytes `hasNoType` ''Step -- S.unfold
8283inspect $ 'readCountBytes `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
83−inspect $ 'readCountBytes `hasNoType` ''MutArray.ArrayUnsafe -- FH.read/A.read
84+inspect $ 'readCountBytes `hasNoType` ''MA.ArrayUnsafe -- FH.read/A.read
8485#endif
8586
8687-- | Count the number of lines in a file.
@@ -95,7 +96,7 @@ readCountLines =
9596inspect $ hasNoTypeClasses 'readCountLines
9697inspect $ 'readCountLines `hasNoType` ''Step
9798inspect $ 'readCountLines `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
98−inspect $ 'readCountLines `hasNoType` ''MutArray.ArrayUnsafe -- FH.read/A.read
99+inspect $ 'readCountLines `hasNoType` ''MA.ArrayUnsafe -- FH.read/A.read
99100#endif
100101
101102-- | Count the number of words in a file.
@@ -119,7 +120,7 @@ readSumBytes = S.fold Fold.sum . S.unfold FH.reader
119120inspect $ hasNoTypeClasses 'readSumBytes
120121inspect $ 'readSumBytes `hasNoType` ''Step
121122inspect $ 'readSumBytes `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
122−inspect $ 'readSumBytes `hasNoType` ''MutArray.ArrayUnsafe -- FH.read/A.read
123+inspect $ 'readSumBytes `hasNoType` ''MA.ArrayUnsafe -- FH.read/A.read
123124#endif
124125
125126-- XXX When we mark this with INLINE and we have two benchmarks using S.drain
@@ -235,13 +236,13 @@ groupsOf :: Int -> Handle -> IO Int
235236groupsOf n inh =
236237 -- writeNUnsafe gives 2.5x boost here over writeN.
237238 S.fold Fold.length
238− $ IP.groupsOf n (A.writeNUnsafe n) (S.unfold FH.reader inh)
239+ $ IP.groupsOf n (AT.writeNUnsafe n) (S.unfold FH.reader inh)
239240
240241#ifdef INSPECTION
241242inspect $ hasNoTypeClasses 'groupsOf
242243inspect $ 'groupsOf `hasNoType` ''Step
243244inspect $ 'groupsOf `hasNoType` ''FoldMany
244−inspect $ 'groupsOf `hasNoType` ''MutArray.ArrayUnsafe -- AT.writeNUnsafe
245+inspect $ 'groupsOf `hasNoType` ''AT.ArrayUnsafe -- AT.writeNUnsafe
245246 -- FH.read/A.read
246247inspect $ 'groupsOf `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
247248#endif
benchmark/Streamly/Benchmark/FileSystem/Handle/ReadWrite.hs+9−8
@@ -42,7 +42,8 @@ import Streamly.Internal.Data.Stream (Step(..))
4242
4343import qualified Streamly.Internal.Data.Stream as D
4444import qualified Streamly.Internal.Data.Tuple.Strict as Strict
45−import qualified Streamly.Internal.Data.MutArray as MutArray
45+import qualified Streamly.Internal.Data.MutArray.Stream as MAS
46+import qualified Streamly.Internal.Data.Array as AT
4647
4748import Test.Inspection
4849#endif
@@ -82,7 +83,7 @@ copyStream inh outh = S.fold (FH.write outh) (S.unfold FH.reader inh)
8283inspect $ hasNoTypeClasses 'copyStream
8384inspect $ 'copyStream `hasNoType` ''Step -- S.unfold
8485inspect $ 'copyStream `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
85−inspect $ 'copyStream `hasNoType` ''MutArray.ArrayUnsafe -- FH.write/writeNUnsafe
86+inspect $ 'copyStream `hasNoType` ''AT.ArrayUnsafe -- FH.write/writeNUnsafe
8687 -- FH.read/A.read
8788inspect $ 'copyStream `hasNoType` ''Strict.Tuple3' -- FH.write/chunksOf
8889#endif
@@ -108,8 +109,8 @@ readFromBytesNull inh devNull = IFH.putBytes devNull $ S.unfold FH.reader inh
108109#ifdef INSPECTION
109110inspect $ hasNoTypeClasses 'readFromBytesNull
110111inspect $ 'readFromBytesNull `hasNoType` ''Step
111−inspect $ 'readFromBytesNull `hasNoType` ''MutArray.SpliceState
112−inspect $ 'readFromBytesNull `hasNoType` ''MutArray.ArrayUnsafe -- FH.fromBytes/S.chunksOf
112+inspect $ 'readFromBytesNull `hasNoType` ''MAS.SpliceState
113+inspect $ 'readFromBytesNull `hasNoType` ''AT.ArrayUnsafe -- FH.fromBytes/S.chunksOf
113114inspect $ 'readFromBytesNull `hasNoType` ''D.FoldMany
114115#endif
115116
@@ -122,8 +123,8 @@ readWithFromBytesNull inh devNull =
122123#ifdef INSPECTION
123124inspect $ hasNoTypeClasses 'readWithFromBytesNull
124125inspect $ 'readWithFromBytesNull `hasNoType` ''Step
125−inspect $ 'readWithFromBytesNull `hasNoType` ''MutArray.SpliceState
126−inspect $ 'readWithFromBytesNull `hasNoType` ''MutArray.ArrayUnsafe -- FH.fromBytes/S.chunksOf
126+inspect $ 'readWithFromBytesNull `hasNoType` ''MAS.SpliceState
127+inspect $ 'readWithFromBytesNull `hasNoType` ''AT.ArrayUnsafe -- FH.fromBytes/S.chunksOf
127128inspect $ 'readWithFromBytesNull `hasNoType` ''D.FoldMany
128129#endif
129130
@@ -170,7 +171,7 @@ writeReadWith inh devNull = IUF.fold fld unf (defaultChunkSize, inh)
170171inspect $ hasNoTypeClasses 'writeReadWith
171172inspect $ 'writeReadWith `hasNoType` ''Step
172173inspect $ 'writeReadWith `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
173−inspect $ 'writeReadWith `hasNoType` ''MutArray.ArrayUnsafe -- FH.write/writeNUnsafe
174+inspect $ 'writeReadWith `hasNoType` ''AT.ArrayUnsafe -- FH.write/writeNUnsafe
174175 -- FH.read/A.read
175176#endif
176177
@@ -187,7 +188,7 @@ writeRead inh devNull = IUF.fold fld unf inh
187188inspect $ hasNoTypeClasses 'writeRead
188189inspect $ 'writeRead `hasNoType` ''Step
189190inspect $ 'writeRead `hasNoType` ''IUF.ConcatState -- FH.read/UF.many
190−inspect $ 'writeRead `hasNoType` ''MutArray.ArrayUnsafe -- FH.write/writeNUnsafe
191+inspect $ 'writeRead `hasNoType` ''AT.ArrayUnsafe -- FH.write/writeNUnsafe
191192 -- FH.read/A.read
192193#endif
193194
benchmark/Streamly/Benchmark/Unicode/Stream.hs+3−4
@@ -45,10 +45,9 @@ import Streamly.Benchmark.Common.Handle
4545#ifdef INSPECTION
4646import Streamly.Internal.Data.MutByteArray (Unbox)
4747import Streamly.Internal.Data.Stream (Step(..))
48−import qualified Streamly.Internal.Data.Array as Array
49−import qualified Streamly.Internal.Data.MutArray as MutArray
5048import qualified Streamly.Internal.Data.Fold as Fold
5149import qualified Streamly.Internal.Data.Tuple.Strict as Strict
50+import qualified Streamly.Internal.Data.Array as Array
5251
5352import Test.Inspection
5453#endif
@@ -224,7 +223,7 @@ inspect $ 'copyStreamLatin1' `hasNoType` ''Step
224223inspect $ 'copyStreamLatin1' `hasNoType` ''Unfold.ConcatState -- Handle.read/UF.many
225224
226225inspect $ 'copyStreamLatin1' `hasNoType` ''Fold.Step
227−inspect $ 'copyStreamLatin1' `hasNoType` ''MutArray.ArrayUnsafe -- Handle.write/writeNUnsafe
226+inspect $ 'copyStreamLatin1' `hasNoType` ''Array.ArrayUnsafe -- Handle.write/writeNUnsafe
228227 -- Handle.read/Array.read
229228inspect $ 'copyStreamLatin1' `hasNoType` ''Strict.Tuple3' -- Handle.write/chunksOf
230229#endif
@@ -245,7 +244,7 @@ inspect $ 'copyStreamLatin1 `hasNoType` ''Unfold.ConcatState -- Handle.read/UF.m
245244
246245inspect $ 'copyStreamLatin1 `hasNoType` ''Fold.ManyState
247246inspect $ 'copyStreamLatin1 `hasNoType` ''Fold.Step
248−inspect $ 'copyStreamLatin1 `hasNoType` ''MutArray.ArrayUnsafe -- Handle.write/writeNUnsafe
247+inspect $ 'copyStreamLatin1 `hasNoType` ''Array.ArrayUnsafe -- Handle.write/writeNUnsafe
249248 -- Handle.read/Array.read
250249inspect $ 'copyStreamLatin1 `hasNoType` ''Strict.Tuple3' -- Handle.write/chunksOf
251250#endif
configure+9−9
@@ -1,6 +1,6 @@
11#! /bin/sh
22# Guess values for system-dependent variables and create Makefiles.
3−# Generated by GNU Autoconf 2.71 for streamly 0.10.1.
3+# Generated by GNU Autoconf 2.71 for streamly 0.10.0.
44#
55# Report bugs to <streamly@composewell.com>.
66#
@@ -610,8 +610,8 @@ MAKEFLAGS=
610610# Identity of this package.
611611PACKAGE_NAME='streamly'
612612PACKAGE_TARNAME='streamly'
613−PACKAGE_VERSION='0.10.1'
614−PACKAGE_STRING='streamly 0.10.1'
613+PACKAGE_VERSION='0.10.0'
614+PACKAGE_STRING='streamly 0.10.0'
615615PACKAGE_BUGREPORT='streamly@composewell.com'
616616PACKAGE_URL='https://streamly.composewell.com'
617617
@@ -1224,7 +1224,7 @@ if test "$ac_init_help" = "long"; then
12241224 # Omit some internal or obsolete options to make the list less imposing.
12251225 # This message is too long to be a string in the A/UX 3.1 sh.
12261226 cat <<_ACEOF
1227−\`configure' configures streamly 0.10.1 to adapt to many kinds of systems.
1227+\`configure' configures streamly 0.10.0 to adapt to many kinds of systems.
12281228
12291229Usage: $0 [OPTION]... [VAR=VALUE]...
12301230
@@ -1286,7 +1286,7 @@ fi
12861286
12871287if test -n "$ac_init_help"; then
12881288 case $ac_init_help in
1289− short | recursive ) echo "Configuration of streamly 0.10.1:";;
1289+ short | recursive ) echo "Configuration of streamly 0.10.0:";;
12901290 esac
12911291 cat <<\_ACEOF
12921292
@@ -1372,7 +1372,7 @@ fi
13721372test -n "$ac_init_help" && exit $ac_status
13731373if $ac_init_version; then
13741374 cat <<\_ACEOF
1375−streamly configure 0.10.1
1375+streamly configure 0.10.0
13761376generated by GNU Autoconf 2.71
13771377
13781378Copyright (C) 2021 Free Software Foundation, Inc.
@@ -1500,7 +1500,7 @@ cat >config.log <<_ACEOF
15001500This file contains any messages produced by compilers while
15011501running configure, to aid debugging if configure makes a mistake.
15021502
1503−It was created by streamly $as_me 0.10.1, which was
1503+It was created by streamly $as_me 0.10.0, which was
15041504generated by GNU Autoconf 2.71. Invocation command line was
15051505
15061506 $ $0$ac_configure_args_raw
@@ -3800,7 +3800,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
38003800# report actual input values of CONFIG_FILES etc. instead of their
38013801# values after options handling.
38023802ac_log="
3803−This file was extended by streamly $as_me 0.10.1, which was
3803+This file was extended by streamly $as_me 0.10.0, which was
38043804generated by GNU Autoconf 2.71. Invocation command line was
38053805
38063806 CONFIG_FILES = $CONFIG_FILES
@@ -3856,7 +3856,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
38563856cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
38573857ac_cs_config='$ac_cs_config_escaped'
38583858ac_cs_version="\\
3859−streamly config.status 0.10.1
3859+streamly config.status 0.10.0
38603860configured by $0, generated by GNU Autoconf 2.71,
38613861 with options \\"\$ac_cs_config\\"
38623862
configure.ac+1−1
@@ -3,7 +3,7 @@
33# See https://www.gnu.org/software/autoconf/manual/autoconf.html for help on
44# the macros used in this file.
55
6−AC_INIT([streamly], [0.10.1], [streamly@composewell.com], [streamly], [https://streamly.composewell.com])
6+AC_INIT([streamly], [0.10.0], [streamly@composewell.com], [streamly], [https://streamly.composewell.com])
77
88# To suppress "WARNING: unrecognized options: --with-compiler"
99AC_ARG_WITH([compiler], [GHC])
core/configure+9−9
@@ -1,6 +1,6 @@
11#! /bin/sh
22# Guess values for system-dependent variables and create Makefiles.
3−# Generated by GNU Autoconf 2.71 for streamly-core 0.2.2.
3+# Generated by GNU Autoconf 2.71 for streamly-core 0.2.1.
44#
55# Report bugs to <streamly@composewell.com>.
66#
@@ -610,8 +610,8 @@ MAKEFLAGS=
610610# Identity of this package.
611611PACKAGE_NAME='streamly-core'
612612PACKAGE_TARNAME='streamly-core'
613−PACKAGE_VERSION='0.2.2'
614−PACKAGE_STRING='streamly-core 0.2.2'
613+PACKAGE_VERSION='0.2.1'
614+PACKAGE_STRING='streamly-core 0.2.1'
615615PACKAGE_BUGREPORT='streamly@composewell.com'
616616PACKAGE_URL='https://streamly.composewell.com'
617617
@@ -1256,7 +1256,7 @@ if test "$ac_init_help" = "long"; then
12561256 # Omit some internal or obsolete options to make the list less imposing.
12571257 # This message is too long to be a string in the A/UX 3.1 sh.
12581258 cat <<_ACEOF
1259−\`configure' configures streamly-core 0.2.2 to adapt to many kinds of systems.
1259+\`configure' configures streamly-core 0.2.1 to adapt to many kinds of systems.
12601260
12611261Usage: $0 [OPTION]... [VAR=VALUE]...
12621262
@@ -1318,7 +1318,7 @@ fi
13181318
13191319if test -n "$ac_init_help"; then
13201320 case $ac_init_help in
1321− short | recursive ) echo "Configuration of streamly-core 0.2.2:";;
1321+ short | recursive ) echo "Configuration of streamly-core 0.2.1:";;
13221322 esac
13231323 cat <<\_ACEOF
13241324
@@ -1404,7 +1404,7 @@ fi
14041404test -n "$ac_init_help" && exit $ac_status
14051405if $ac_init_version; then
14061406 cat <<\_ACEOF
1407−streamly-core configure 0.2.2
1407+streamly-core configure 0.2.1
14081408generated by GNU Autoconf 2.71
14091409
14101410Copyright (C) 2021 Free Software Foundation, Inc.
@@ -1622,7 +1622,7 @@ cat >config.log <<_ACEOF
16221622This file contains any messages produced by compilers while
16231623running configure, to aid debugging if configure makes a mistake.
16241624
1625−It was created by streamly-core $as_me 0.2.2, which was
1625+It was created by streamly-core $as_me 0.2.1, which was
16261626generated by GNU Autoconf 2.71. Invocation command line was
16271627
16281628 $ $0$ac_configure_args_raw
@@ -3832,7 +3832,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
38323832# report actual input values of CONFIG_FILES etc. instead of their
38333833# values after options handling.
38343834ac_log="
3835−This file was extended by streamly-core $as_me 0.2.2, which was
3835+This file was extended by streamly-core $as_me 0.2.1, which was
38363836generated by GNU Autoconf 2.71. Invocation command line was
38373837
38383838 CONFIG_FILES = $CONFIG_FILES
@@ -3888,7 +3888,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
38883888cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
38893889ac_cs_config='$ac_cs_config_escaped'
38903890ac_cs_version="\\
3891−streamly-core config.status 0.2.2
3891+streamly-core config.status 0.2.1
38923892configured by $0, generated by GNU Autoconf 2.71,
38933893 with options \\"\$ac_cs_config\\"
38943894
core/configure.ac+1−1
@@ -3,7 +3,7 @@
33# See https://www.gnu.org/software/autoconf/manual/autoconf.html for help on
44# the macros used in this file.
55
6−AC_INIT([streamly-core], [0.2.2], [streamly@composewell.com], [streamly-core], [https://streamly.composewell.com])
6+AC_INIT([streamly-core], [0.2.1], [streamly@composewell.com], [streamly-core], [https://streamly.composewell.com])
77
88# To suppress "WARNING: unrecognized options: --with-compiler"
99AC_ARG_WITH([compiler], [GHC])
core/docs/ApiChangelogs/0.2.0-0.2.2.txtdeleted−306
@@ -1,306 +0,0 @@
1−---------------------------------
2−API Annotations
3−---------------------------------
4−
5−[A] : Added
6−[R] : Removed
7−[C] : Changed
8−[O] : Old definition
9−[N] : New definition
10−[D] : Deprecated
11−
12−---------------------------------
13−API diff
14−---------------------------------
15−
16−[C] Streamly.Data.Stream
17− [A] (FixityR,5)
18− [A] (FixityR,5)
19−[C] Streamly.Data.MutArray.Generic
20− [A] emptyOf :: MonadIO m => Int -> m (MutArray a)
21− [A] createOf :: MonadIO m => Int -> Fold m a (MutArray a)
22− [A] create :: MonadIO m => Fold m a (MutArray a)
23−[C] Streamly.Data.MutArray
24− [A] pinnedEmptyOf :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a)
25− [A] emptyOf :: (MonadIO m, Unbox a) => Int -> m (MutArray a)
26− [A] createOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
27− [A] create :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
28− [A] appendN :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a) -> Fold m a (MutArray a)
29− [A] append :: forall m a. (MonadIO m, Unbox a) => m (MutArray a) -> Fold m a (MutArray a)
30−[C] Streamly.Data.Array.Generic
31− [A] createOf :: MonadIO m => Int -> Fold m a (Array a)
32− [A] create :: MonadIO m => Fold m a (Array a)
33−[C] Streamly.Data.Array
34− [A] class Serialize a
35− [A] serializeAt :: Serialize a => Int -> MutByteArray -> a -> IO Int
36− [A] pinnedSerialize :: Serialize a => a -> Array Word8
37− [A] deserializeAt :: Serialize a => Int -> MutByteArray -> Int -> IO (Int, a)
38− [A] deserialize :: Serialize a => Array Word8 -> a
39− [A] createOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
40− [A] create :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
41− [A] addSizeTo :: Serialize a => Int -> a -> Int
42−
43−---------------------------------
44−Internal API diff
45−---------------------------------
46−
47−[C] Streamly.Internal.Unicode.Stream
48− [A] encodeUtf16le' :: Stream m Char -> Stream m Word16
49− [A] decodeUtf16le' :: Stream m Word16 -> Stream m Char
50−[A] Streamly.Internal.FileSystem.Path
51− [A] class IsPath a
52− [A] Rel
53− [A] File
54− [A] Dir
55− [A] Abs
56− [A] Streamly.Internal.FileSystem.Path.IsPath
57− [A] instance Streamly.Internal.FileSystem.Path.IsPath Streamly.Internal.FileSystem.Path.Path
58− [A] instance Streamly.Internal.FileSystem.Path.IsPath (Streamly.Internal.FileSystem.Path.Rel Streamly.Internal.FileSystem.Path.Path)
59− [A] instance Streamly.Internal.FileSystem.Path.IsPath (Streamly.Internal.FileSystem.Path.Rel (Streamly.Internal.FileSystem.Path.File Streamly.Internal.FileSystem.Path.Path))
60− [A] instance Streamly.Internal.FileSystem.Path.IsPath (Streamly.Internal.FileSystem.Path.Rel (Streamly.Internal.FileSystem.Path.Dir Streamly.Internal.FileSystem.Path.Path))
61− [A] instance Streamly.Internal.FileSystem.Path.IsPath (Streamly.Internal.FileSystem.Path.File Streamly.Internal.FileSystem.Path.Path)
62− [A] instance Streamly.Internal.FileSystem.Path.IsPath (Streamly.Internal.FileSystem.Path.Dir Streamly.Internal.FileSystem.Path.Path)
63− [A] instance Streamly.Internal.FileSystem.Path.IsPath (Streamly.Internal.FileSystem.Path.Abs Streamly.Internal.FileSystem.Path.Path)
64− [A] instance Streamly.Internal.FileSystem.Path.IsPath (Streamly.Internal.FileSystem.Path.Abs (Streamly.Internal.FileSystem.Path.File Streamly.Internal.FileSystem.Path.Path))
65− [A] instance Streamly.Internal.FileSystem.Path.IsPath (Streamly.Internal.FileSystem.Path.Abs (Streamly.Internal.FileSystem.Path.Dir Streamly.Internal.FileSystem.Path.Path))
66− [A] GHC.Show.Show
67− [A] instance GHC.Show.Show Streamly.Internal.FileSystem.Path.PathException
68− [A] GHC.Exception.Type.Exception
69− [A] instance GHC.Exception.Type.Exception Streamly.Internal.FileSystem.Path.PathException
70− [A] GHC.Classes.Eq
71− [A] instance GHC.Classes.Eq Streamly.Internal.FileSystem.Path.PathException
72− [A] Path
73− [A] Path :: Array Word8 -> Path
74− [A] toString :: Path -> [Char]
75− [A] toPath :: IsPath a => a -> Path
76− [A] toChunk :: Path -> Array Word8
77− [A] toChars :: Monad m => Path -> Stream m Char
78− [A] relfile :: QuasiQuoter
79− [A] reldir :: QuasiQuoter
80− [A] rel :: QuasiQuoter
81− [A] primarySeparator :: Char
82− [A] path :: QuasiQuoter
83− [A] mkRelFile :: String -> Q Exp
84− [A] mkRelDir :: String -> Q Exp
85− [A] mkRel :: String -> Q Exp
86− [A] mkPath :: String -> Q Exp
87− [A] mkFile :: String -> Q Exp
88− [A] mkDir :: String -> Q Exp
89− [A] mkAbsFile :: String -> Q Exp
90− [A] mkAbsDir :: String -> Q Exp
91− [A] mkAbs :: String -> Q Exp
92− [A] isSeparator :: Char -> Bool
93− [A] fromString :: MonadThrow m => [Char] -> m Path
94− [A] fromPathUnsafe :: IsPath a => Path -> a
95− [A] fromPath :: (IsPath a, MonadThrow m) => Path -> m a
96− [A] fromChunkUnsafe :: Array Word8 -> Path
97− [A] fromChunk :: MonadThrow m => Array Word8 -> m Path
98− [A] fromChars :: MonadThrow m => Stream Identity Char -> m Path
99− [A] file :: QuasiQuoter
100− [A] extendPath :: Path -> Path -> Path
101− [A] extendDir :: (IsPath (a (Dir Path)), IsPath b, IsPath (a b)) => a (Dir Path) -> Rel b -> a b
102− [A] dir :: QuasiQuoter
103− [A] adaptPath :: (MonadThrow m, IsPath a, IsPath b) => a -> m b
104− [A] absfile :: QuasiQuoter
105− [A] absdir :: QuasiQuoter
106− [A] abs :: QuasiQuoter
107−[C] Streamly.Internal.Data.Stream
108− [A] (FixityR,5)
109− [A] (FixityR,5)
110− [C] splitInnerBySuffix
111− [O] splitInnerBySuffix :: (Monad m, Eq (f a), Monoid (f a)) => (f a -> m (f a, Maybe (f a))) -> (f a -> f a -> m (f a)) -> Stream m (f a) -> Stream m (f a)
112− [N] splitInnerBySuffix :: Monad m => (f a -> Bool) -> (f a -> m (f a, Maybe (f a))) -> (f a -> f a -> m (f a)) -> Stream m (f a) -> Stream m (f a)
113− [D] sliceOnSuffix :: Monad m => (a -> Bool) -> Stream m a -> Stream m (Int, Int)
114− [A] indexOnSuffix :: Monad m => (a -> Bool) -> Stream m a -> Stream m (Int, Int)
115−[C] Streamly.Internal.Data.MutByteArray
116− [A] unsafePinnedAsPtr :: MonadIO m => MutByteArray -> (Ptr a -> m b) -> m b
117− [A] unsafeAsPtr :: MonadIO m => MutByteArray -> (Ptr a -> m b) -> m b
118− [D] nil :: MutByteArray
119− [A] empty :: MutByteArray
120− [D] asPtrUnsafe :: MonadIO m => MutByteArray -> (Ptr a -> m b) -> m b
121−[D] Streamly.Internal.Data.MutArray.Stream
122− [D] writeChunks :: (MonadIO m, Unbox a) => Int -> Fold m a (StreamK n (MutArray a))
123− [D] fromArrayStreamK :: (Unbox a, MonadIO m) => StreamK m (MutArray a) -> m (MutArray a)
124− [D] flattenArraysRev :: forall m a. (MonadIO m, Unbox a) => Stream m (MutArray a) -> Stream m a
125− [D] flattenArrays :: forall m a. (MonadIO m, Unbox a) => Stream m (MutArray a) -> Stream m a
126−[C] Streamly.Internal.Data.MutArray.Generic
127− [D] writeWith :: MonadIO m => Int -> Fold m a (MutArray a)
128− [D] writeNUnsafe :: MonadIO m => Int -> Fold m a (MutArray a)
129− [A] unsafeCreateOf :: MonadIO m => Int -> Fold m a (MutArray a)
130− [A] emptyOf :: MonadIO m => Int -> m (MutArray a)
131− [A] createWith :: MonadIO m => Int -> Fold m a (MutArray a)
132− [A] createOf :: MonadIO m => Int -> Fold m a (MutArray a)
133− [A] create :: MonadIO m => Fold m a (MutArray a)
134−[C] Streamly.Internal.Data.MutArray
135− [A] SpliceState
136− [A] SpliceYielding :: arr -> SpliceState s arr -> SpliceState s arr
137− [A] SpliceInitial :: s -> SpliceState s arr
138− [A] SpliceFinish :: SpliceState s arr
139− [A] SpliceBuffering :: s -> arr -> SpliceState s arr
140− [R] MutByteArray
141− [D] writeWith :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
142− [D] writeRevN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
143− [D] writeNWithUnsafe :: forall m a. (MonadIO m, Unbox a) => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
144− [D] writeNUnsafe :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
145− [D] writeChunks :: (MonadIO m, Unbox a) => Int -> Fold m a (StreamK n (MutArray a))
146− [D] writeAppendWith :: forall m a. (MonadIO m, Unbox a) => (Int -> Int) -> m (MutArray a) -> Fold m a (MutArray a)
147− [D] writeAppendNUnsafe :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a) -> Fold m a (MutArray a)
148− [A] unsafePinnedCreateOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
149− [A] unsafePinnedAsPtr :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
150− [A] unsafeCreateOfWith :: forall m a. (MonadIO m, Unbox a) => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
151− [A] unsafeCreateOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
152− [A] unsafeAsPtr :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
153− [A] unsafeAppendN :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a) -> Fold m a (MutArray a)
154− [A] toStreamWith :: forall m a. (Monad m, Unbox a) => (forall b. IO b -> m b) -> MutArray a -> Stream m a
155− [A] toStreamRevWith :: forall m a. (Monad m, Unbox a) => (forall b. IO b -> m b) -> MutArray a -> Stream m a
156− [R] toStreamDWith :: forall m a. (Monad m, Unbox a) => (forall b. IO b -> m b) -> MutArray a -> Stream m a
157− [R] toStreamDRevWith :: forall m a. (Monad m, Unbox a) => (forall b. IO b -> m b) -> MutArray a -> Stream m a
158− [A] slicerFromLen :: forall m a. (Monad m, Unbox a) => Int -> Int -> Unfold m (MutArray a) (MutArray a)
159− [A] sliceIndexerFromLen :: forall m a. (Monad m, Unbox a) => Int -> Int -> Unfold m (MutArray a) (Int, Int)
160− [A] revCreateOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
161− [D] resizeExp :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m (MutArray a)
162− [D] resize :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m (MutArray a)
163− [A] pokeSkipUnsafe :: Int -> MutArray Word8 -> MutArray Word8
164− [A] pokeAppendMay :: forall m a. (MonadIO m, Unbox a) => MutArray Word8 -> a -> m (Maybe (MutArray Word8))
165− [A] pokeAppend :: forall m a. (MonadIO m, Unbox a) => MutArray Word8 -> a -> m (MutArray Word8)
166− [D] pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
167− [D] pinnedWriteN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
168− [D] pinnedWrite :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
169− [D] pinnedNewBytes :: MonadIO m => Int -> m (MutArray a)
170− [A] pinnedEmptyOf :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a)
171− [A] pinnedCreateOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
172− [A] pinnedCreate :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
173− [A] pinnedCompactLE :: forall m a. (MonadIO m, Unbox a) => Int -> Stream m (MutArray a) -> Stream m (MutArray a)
174− [A] peekUnconsUnsafe :: forall m a. (MonadIO m, Unbox a) => MutArray Word8 -> m (a, MutArray Word8)
175− [A] peekUncons :: forall m a. (MonadIO m, Unbox a) => MutArray Word8 -> m (Maybe a, MutArray Word8)
176− [A] peekSkipUnsafe :: Int -> MutArray Word8 -> MutArray Word8
177− [A] pPinnedCompactLE :: forall m a. (MonadIO m, Unbox a) => Int -> Parser (MutArray a) m (MutArray a)
178− [A] pCompactLE :: forall m a. (MonadIO m, Unbox a) => Int -> Parser (MutArray a) m (MutArray a)
179− [D] nil :: MutArray a
180− [A] lPinnedCompactGE :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m (MutArray a) () -> Fold m (MutArray a) ()
181− [A] lCompactGE :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m (MutArray a) () -> Fold m (MutArray a) ()
182− [A] indexReaderWith :: (Monad m, Unbox a) => (forall b. IO b -> m b) -> Stream m Int -> Unfold m (MutArray a) a
183− [A] indexReader :: (MonadIO m, Unbox a) => Stream m Int -> Unfold m (MutArray a) a
184− [A] growExp :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m (MutArray a)
185− [A] grow :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m (MutArray a)
186− [D] getSlicesFromLen :: forall m a. (Monad m, Unbox a) => Int -> Int -> Unfold m (MutArray a) (MutArray a)
187− [R] getIndicesD :: (Monad m, Unbox a) => (forall b. IO b -> m b) -> Stream m Int -> Unfold m (MutArray a) a
188− [D] getIndices :: (MonadIO m, Unbox a) => Stream m Int -> Unfold m (MutArray a) a
189− [D] genSlicesFromLen :: forall m a. (Monad m, Unbox a) => Int -> Int -> Unfold m (MutArray a) (Int, Int)
190− [A] fromStreamN :: forall m a. (MonadIO m, Unbox a) => Int -> Stream m a -> m (MutArray a)
191− [D] fromStreamDN :: forall m a. (MonadIO m, Unbox a) => Int -> Stream m a -> m (MutArray a)
192− [D] fromStreamD :: (MonadIO m, Unbox a) => Stream m a -> m (MutArray a)
193− [A] fromPureStreamN :: (MonadIO m, Unbox a) => Int -> Stream Identity a -> m (MutArray a)
194− [A] fromPtrN :: MonadIO m => Int -> Ptr Word8 -> m (MutArray Word8)
195− [A] fromChunksRealloced :: forall m a. (MonadIO m, Unbox a) => Stream m (MutArray a) -> m (MutArray a)
196− [A] fromChunksK :: (Unbox a, MonadIO m) => StreamK m (MutArray a) -> m (MutArray a)
197− [A] fromByteStr# :: MonadIO m => Addr# -> m (MutArray Word8)
198− [D] fromArrayStreamK :: (Unbox a, MonadIO m) => StreamK m (MutArray a) -> m (MutArray a)
199− [D] flattenArraysRev :: forall m a. (MonadIO m, Unbox a) => Stream m (MutArray a) -> Stream m a
200− [D] flattenArrays :: forall m a. (MonadIO m, Unbox a) => Stream m (MutArray a) -> Stream m a
201− [A] fPinnedCompactGE :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m (MutArray a) (MutArray a)
202− [A] fCompactGE :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m (MutArray a) (MutArray a)
203− [A] emptyOf :: (MonadIO m, Unbox a) => Int -> m (MutArray a)
204− [A] empty :: MutArray a
205− [A] createWith :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
206− [A] createOfWith :: forall m a. (MonadIO m, Unbox a) => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
207− [A] createOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
208− [A] create :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
209− [A] concatWith :: forall m a. (Monad m, Unbox a) => (forall b. IO b -> m b) -> Stream m (MutArray a) -> Stream m a
210− [A] concatRevWith :: forall m a. (Monad m, Unbox a) => (forall b. IO b -> m b) -> Stream m (MutArray a) -> Stream m a
211− [A] concatRev :: forall m a. (MonadIO m, Unbox a) => Stream m (MutArray a) -> Stream m a
212− [A] concat :: forall m a. (MonadIO m, Unbox a) => Stream m (MutArray a) -> Stream m a
213− [A] compactOnByteSuffix :: MonadIO m => Word8 -> Stream m (MutArray Word8) -> Stream m (MutArray Word8)
214− [A] compactOnByte :: MonadIO m => Word8 -> Stream m (MutArray Word8) -> Stream m (MutArray Word8)
215− [A] compactLeAs :: forall m a. (MonadIO m, Unbox a) => PinnedState -> Int -> Stream m (MutArray a) -> Stream m (MutArray a)
216− [A] compactLE :: (MonadIO m, Unbox a) => Int -> Stream m (MutArray a) -> Stream m (MutArray a)
217− [A] compactGE :: (MonadIO m, Unbox a) => Int -> Stream m (MutArray a) -> Stream m (MutArray a)
218− [A] compactEQ :: Int -> Stream m (MutArray a) -> Stream m (MutArray a)
219− [D] cmp :: MonadIO m => MutArray a -> MutArray a -> m Ordering
220− [A] byteEq :: MonadIO m => MutArray a -> MutArray a -> m Bool
221− [A] byteCmp :: MonadIO m => MutArray a -> MutArray a -> m Ordering
222− [A] buildChunks :: (MonadIO m, Unbox a) => Int -> Fold m a (StreamK n (MutArray a))
223− [D] asPtrUnsafe :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
224− [A] appendWith :: forall m a. (MonadIO m, Unbox a) => (Int -> Int) -> m (MutArray a) -> Fold m a (MutArray a)
225− [A] appendN :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a) -> Fold m a (MutArray a)
226− [A] append :: forall m a. (MonadIO m, Unbox a) => m (MutArray a) -> Fold m a (MutArray a)
227−[D] Streamly.Internal.Data.Array.Stream
228− [C] interposeSuffix
229− [O] interposeSuffix :: (Monad m, Unbox a) => a -> Stream m (Array a) -> Stream m a
230− [N] interposeSuffix :: forall m a. (Monad m, Unbox a) => a -> Stream m (Array a) -> Stream m a
231− [D] flattenArraysRev :: forall m a. (MonadIO m, Unbox a) => Stream m (Array a) -> Stream m a
232− [D] flattenArrays :: forall m a. (MonadIO m, Unbox a) => Stream m (Array a) -> Stream m a
233− [C] concatRev
234− [O] concatRev :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
235− [N] concatRev :: forall m a. (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
236− [D] bufferChunks :: (MonadIO m, Unbox a) => Stream m a -> m (StreamK m (Array a))
237−[C] Streamly.Internal.Data.Array.Generic
238− [A] createOf :: MonadIO m => Int -> Fold m a (Array a)
239− [A] create :: MonadIO m => Fold m a (Array a)
240−[C] Streamly.Internal.Data.Array
241− [R] ArrayUnsafe
242− [D] writeWith :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
243− [D] writeNUnsafe :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
244− [A] unsafePinnedCreateOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
245− [A] unsafePinnedAsPtr :: MonadIO m => Array a -> (Ptr a -> m b) -> m b
246− [A] unsafeCreateOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
247− [D] toStreamDRev :: forall m a. (Monad m, Unbox a) => Array a -> Stream m a
248− [D] toStreamD :: forall m a. (Monad m, Unbox a) => Array a -> Stream m a
249− [C] splice
250− [O] splice :: (MonadIO m, Unbox a) => Array a -> Array a -> m (Array a)
251− [N] splice :: MonadIO m => Array a -> Array a -> m (Array a)
252− [A] slicerFromLen :: forall m a. (Monad m, Unbox a) => Int -> Int -> Unfold m (Array a) (Array a)
253− [A] sliceIndexerFromLen :: forall m a. (Monad m, Unbox a) => Int -> Int -> Unfold m (Array a) (Int, Int)
254− [D] pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
255− [D] pinnedWriteNAligned :: forall m a. (MonadIO m, Unbox a) => Int -> Int -> Fold m a (Array a)
256− [D] pinnedWriteN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
257− [D] pinnedWrite :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
258− [A] pinnedCreateOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
259− [A] pinnedCreate :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
260− [A] pinnedCompactLE :: (MonadIO m, Unbox a) => Int -> Stream m (Array a) -> Stream m (Array a)
261− [A] parseBreakChunksK :: forall m a b. (MonadIO m, Unbox a) => Parser a m b -> StreamK m (Array a) -> m (Either ParseError b, StreamK m (Array a))
262− [D] nil :: Array a
263− [A] lPinnedCompactGE :: (MonadIO m, Unbox a) => Int -> Fold m (Array a) () -> Fold m (Array a) ()
264− [A] lCompactGE :: (MonadIO m, Unbox a) => Int -> Fold m (Array a) () -> Fold m (Array a) ()
265− [A] interposeSuffix :: forall m a. (Monad m, Unbox a) => a -> Stream m (Array a) -> Stream m a
266− [A] interpose :: (Monad m, Unbox a) => a -> Stream m (Array a) -> Stream m a
267− [A] intercalateSuffix :: (Monad m, Unbox a) => Array a -> Stream m (Array a) -> Stream m a
268− [A] indexReaderFromThenTo :: Unfold m (Int, Int, Int, Array a) a
269− [A] indexReader :: (Monad m, Unbox a) => Stream m Int -> Unfold m (Array a) a
270− [A] indexFinder :: (a -> Bool) -> Unfold Identity (Array a) Int
271− [D] getSlicesFromLen :: forall m a. (Monad m, Unbox a) => Int -> Int -> Unfold m (Array a) (Array a)
272− [R] getIndicesFromThenTo :: Unfold m (Int, Int, Int, Array a) a
273− [D] getIndices :: (Monad m, Unbox a) => Stream m Int -> Unfold m (Array a) a
274− [D] genSlicesFromLen :: forall m a. (Monad m, Unbox a) => Int -> Int -> Unfold m (Array a) (Int, Int)
275− [D] fromStreamDN :: forall m a. (MonadIO m, Unbox a) => Int -> Stream m a -> m (Array a)
276− [D] fromStreamD :: forall m a. (MonadIO m, Unbox a) => Stream m a -> m (Array a)
277− [A] fromPureStreamN :: Unbox a => Int -> Stream Identity a -> Array a
278− [A] fromPtrN :: Int -> Ptr Word8 -> Array Word8
279− [A] fromChunksK :: (MonadIO m, Unbox a) => StreamK m (Array a) -> m (Array a)
280− [A] fromChunks :: (MonadIO m, Unbox a) => Stream m (Array a) -> m (Array a)
281− [A] fromByteStr :: Ptr Word8 -> Array Word8
282− [A] foldChunks :: (MonadIO m, Unbox a) => Fold m a b -> Stream m (Array a) -> m b
283− [A] foldBreakChunksK :: forall m a b. (MonadIO m, Unbox a) => Fold m a b -> StreamK m (Array a) -> m (b, StreamK m (Array a))
284− [A] foldBreakChunks :: forall m a b. (MonadIO m, Unbox a) => Fold m a b -> Stream m (Array a) -> m (b, Stream m (Array a))
285− [D] flattenArraysRev :: forall m a. (MonadIO m, Unbox a) => Stream m (Array a) -> Stream m a
286− [D] flattenArrays :: forall m a. (MonadIO m, Unbox a) => Stream m (Array a) -> Stream m a
287− [C] findIndicesOf
288− [O] findIndicesOf :: (a -> Bool) -> Unfold Identity (Array a) Int
289− [N] findIndicesOf :: (a -> Bool) -> Array a -> Stream Identity Int
290− [A] fPinnedCompactGE :: (MonadIO m, Unbox a) => Int -> Fold m (Array a) (Array a)
291− [A] fCompactGE :: (MonadIO m, Unbox a) => Int -> Fold m (Array a) (Array a)
292− [A] empty :: Array a
293− [A] createWith :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
294− [A] createOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
295− [A] create :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
296− [A] concatRev :: forall m a. (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
297− [A] concat :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
298− [A] compactOnByteSuffix :: MonadIO m => Word8 -> Stream m (Array Word8) -> Stream m (Array Word8)
299− [A] compactOnByte :: MonadIO m => Word8 -> Stream m (Array Word8) -> Stream m (Array Word8)
300− [A] compactLE :: (MonadIO m, Unbox a) => Int -> Stream m (Array a) -> Stream m (Array a)
301− [A] compactGE :: (MonadIO m, Unbox a) => Int -> Stream m (Array a) -> Stream m (Array a)
302− [A] byteEq :: Array a -> Array a -> Bool
303− [A] byteCmp :: Array a -> Array a -> Ordering
304− [A] buildChunks :: (MonadIO m, Unbox a) => Stream m a -> m (StreamK m (Array a))
305− [D] bufferChunks :: (MonadIO m, Unbox a) => Stream m a -> m (StreamK m (Array a))
306− [D] asPtrUnsafe :: MonadIO m => Array a -> (Ptr a -> m b) -> m b
core/docs/Changelog.md+1−3
@@ -1,12 +1,10 @@
11# Changelog
22
3−## 0.2.2 (Jan 2024)
3+## Unreleased
44
55* Add fixities `infixr 5` for `cons` and `consM` functions.
66* Fix a bug in Array `Eq` instance when the type is a sum type with
77 differently sized constructors.
8−* lpackArraysChunksOf, compact, writeChunksWith, putChunksWith now take the
9− buffer size in number of array elements instead of bytes.
108
119## 0.2.1 (Dec 2023)
1210
core/src/DocTestDataArray.hs−3
@@ -11,12 +11,9 @@
1111
1212>>> import qualified Streamly.Data.Array as Array
1313>>> import qualified Streamly.Data.Fold as Fold
14−>>> import qualified Streamly.Data.ParserK as ParserK
1514>>> import qualified Streamly.Data.Stream as Stream
16−>>> import qualified Streamly.Data.StreamK as StreamK
1715
1816For APIs that have not been released yet.
1917
2018>>> import qualified Streamly.Internal.Data.Array as Array
21−>>> import qualified Streamly.Internal.Data.Stream as Stream
2219-}
core/src/DocTestDataStream.hs−2
@@ -6,7 +6,6 @@
66>>> import Control.Monad.IO.Class (MonadIO (liftIO))
77>>> import Control.Monad.Trans.Class (lift)
88>>> import Control.Monad.Trans.Identity (runIdentityT)
9−>>> import Data.Char (isSpace)
109>>> import Data.Either (fromLeft, fromRight, isLeft, isRight, either)
1110>>> import Data.Maybe (fromJust, isJust)
1211>>> import Data.Function (fix, (&))
@@ -33,7 +32,6 @@ For APIs that have not been released yet.
3332>>> import qualified Streamly.Internal.Data.Fold as Fold
3433>>> import qualified Streamly.Internal.Data.Parser as Parser
3534>>> import qualified Streamly.Internal.Data.Stream as Stream
36−>>> import qualified Streamly.Internal.Data.StreamK as StreamK
3735>>> import qualified Streamly.Internal.Data.Unfold as Unfold
3836>>> import qualified Streamly.Internal.FileSystem.Dir as Dir
3937-}
core/src/DocTestFileSystemHandle.hs+1−1
@@ -8,7 +8,7 @@
88
99For APIs that have not been released yet.
1010
11−>>> import qualified Streamly.Internal.Data.Array as Array (unsafeCreateOf)
11+>>> import qualified Streamly.Internal.Data.Array as Array (writeNUnsafe)
1212>>> import qualified Streamly.Internal.Data.Unfold as Unfold (first)
1313>>> import qualified Streamly.Internal.FileSystem.Handle as Handle
1414>>> import qualified Streamly.Internal.System.IO as IO (defaultChunkSize)
core/src/Streamly/Data/Array.hs+27−30
@@ -31,42 +31,42 @@ module Streamly.Data.Array
3131 -- * The Array Type
3232 Array
3333
34− -- * Pinning & Unpinning
35− -- | Arrays are created unpinned by default unless pinned versions of
36− -- creation APIs are used. Look for APIs with @pinned@ prefix in
37− -- "Streamly.Internal.Data.Array" for some unreleased pinned creation APIs.
38− -- If an array is to be sent to the OS without any further modification
39− -- then it should be created pinned in the first place instead of pinning
40− -- it later. Pinning an unpinned array has a copy overhead. OS interfacing
41− -- APIs create a pinned array directly or convert an unpinned array to
42− -- pinned array before sending it to the OS.
43− , pin
44− , unpin
45− , isPinned
46−
4734 -- * Construction
4835 -- | When performance matters, the fastest way to generate an array is
49− -- 'createOf'. 'IsList' and 'IsString' instances can be
36+ -- 'writeN'. 'IsList' and 'IsString' instances can be
5037 -- used to conveniently construct arrays from literal values.
5138 -- 'OverloadedLists' extension or 'fromList' can be used to construct an
5239 -- array from a list literal. Similarly, 'OverloadedStrings' extension or
5340 -- 'fromList' can be used to construct an array from a string literal.
5441
55− -- ** From Stream
56− , createOf
57− , create
58− , writeLastN -- drop old (ring buffer)
59−
60− -- ** From List
42+ -- Pure List APIs
6143 , fromListN
6244 , fromList
6345
64− -- * To List
46+ -- Monadic APIs
47+ , writeN -- drop new
48+ , write -- full buffer
49+ , writeLastN -- drop old (ring buffer)
50+
51+ -- * Conversion
6552 -- 'GHC.Exts.toList' from "GHC.Exts" can be used to convert an array to a
6653 -- list.
6754 , toList
6855
69− -- * To Stream
56+ -- * Pinning & Unpinning
57+ -- | Arrays are created unpinned by default unless pinned versions of
58+ -- creation APIs are used. Look for APIs with @pinned@ prefix in
59+ -- "Streamly.Internal.Data.Array" for some unreleased pinned creation APIs.
60+ -- If an array is to be sent to the OS without any further modification
61+ -- then it should be created pinned in the first place instead of pinning
62+ -- it later. Pinning an unpinned array has a copy overhead. OS interfacing
63+ -- APIs create a pinned array directly or convert an unpinned array to
64+ -- pinned array before sending it to the OS.
65+ , pin
66+ , unpin
67+ , isPinned
68+
69+ -- * Streams
7070 , read
7171 , readRev
7272
@@ -90,10 +90,6 @@ module Streamly.Data.Array
9090 -- * Re-exports
9191 , Unbox (..)
9292 , Serialize(..)
93−
94− -- * Deprecated
95− , writeN -- drop new
96− , write -- full buffer
9793 )
9894where
9995
@@ -126,7 +122,7 @@ import Prelude hiding (read, length)
126122--
127123-- Convert array to stream, transform, and fold back to array:
128124--
129−-- >>> amap f arr = Array.read arr & fmap f & Stream.fold (Array.createOf (Array.length arr))
125+-- >>> amap f arr = Array.read arr & fmap f & Stream.fold Array.write
130126-- >>> amap (+1) (Array.fromList [1,2,3::Int])
131127-- fromList [2,3,4]
132128--
@@ -153,11 +149,12 @@ import Prelude hiding (read, length)
153149-- See the 'fromPureStream' unreleased API to generate an array from an
154150-- Identity stream safely without using MonadIO constraint.
155151--
152+--
156153-- Note that 'Identity' streams can be generalized to IO streams:
157154--
158−-- >>> stream = Stream.fromList [1,2,3] :: Stream Identity Int
159−-- >>> pure2IO s = Stream.morphInner (return . runIdentity) s :: Stream IO Int
160−-- >>> Stream.fold Array.create (pure2IO stream)
155+-- >>> pure = Stream.fromList [1,2,3] :: Stream Identity Int
156+-- >>> generally = Stream.morphInner (return . runIdentity)
157+-- >>> Stream.fold Array.write (generally pure :: Stream IO Int)
161158-- fromList [1,2,3]
162159--
163160-- == Programming Tips
core/src/Streamly/Data/Array/Generic.hs+13−16
@@ -15,37 +15,34 @@ module Streamly.Data.Array.Generic
1515 ( Array
1616
1717 -- * Construction
18− , fromListN
19− , fromList
18+ , A.fromListN
19+ , A.fromList
2020
2121 -- MonadicAPIs
22− , createOf
23− , create
22+ , A.writeN
23+ , A.write
2424
2525 -- * Conversion
26− , toList
26+ , A.toList
2727
2828 -- * Streams
29− , read
30− , readRev
29+ , A.read
30+ , A.readRev
3131
3232 -- * Unfolds
33− , reader
33+ , A.reader
3434 -- , A.readerRev
3535
3636 -- * Random Access
37− , length
38− , getIndex
37+ , A.length
38+ , A.getIndex
3939
4040 -- -- * Folding Arrays
4141 -- , A.streamFold
4242 -- , A.fold
43−
44− -- * Deprecated
45− , writeN
46− , write
4743 )
4844where
4945
50−import Streamly.Internal.Data.Array.Generic
51−import Prelude hiding (length, read)
46+import Streamly.Internal.Data.Array.Generic (Array)
47+
48+import qualified Streamly.Internal.Data.Array.Generic as A
core/src/Streamly/Data/MutArray.hs+6−12
@@ -32,14 +32,14 @@ module Streamly.Data.MutArray
3232 -- * Construction
3333
3434 -- Uninitialized Arrays
35− , emptyOf
36− , pinnedEmptyOf
35+ , new
36+ , pinnedNew
3737
3838 -- From containers
3939 , fromListN
4040 , fromList
41− , createOf
42− , create
41+ , writeN -- drop new
42+ , write -- full buffer
4343 -- writeLastN
4444
4545 -- * Pinning & Unpinning
@@ -51,8 +51,8 @@ module Streamly.Data.MutArray
5151 , snoc
5252
5353 -- * Appending streams
54− , appendN
55− , append
54+ , writeAppendN -- XXX Rename to writeSnocN?
55+ , writeAppend -- XXX Rename to writeSnoc?
5656
5757 -- * Inplace mutation
5858 , putIndex
@@ -88,12 +88,6 @@ module Streamly.Data.MutArray
8888
8989 -- * Deprecated
9090 , newPinned
91− , new
92− , pinnedNew
93− , writeN
94− , write
95− , writeAppendN
96− , writeAppend
9791 )
9892where
9993
core/src/Streamly/Data/MutArray/Generic.hs+3−8
@@ -23,11 +23,11 @@ module Streamly.Data.MutArray.Generic
2323 MutArray
2424
2525 -- * Construction
26− , emptyOf
26+ , new
2727 , fromListN
2828 , fromList
29− , createOf
30− , create
29+ , writeN
30+ , write
3131
3232 -- * Appending elements
3333 , snoc
@@ -56,11 +56,6 @@ module Streamly.Data.MutArray.Generic
5656
5757 -- * Size
5858 , length
59−
60− -- * Deprecated
61− , new
62− , writeN
63− , write
6459 )
6560where
6661
core/src/Streamly/Data/Stream.hs+20−129
@@ -70,15 +70,6 @@ module Streamly.Data.Stream
7070
7171 -- ** From Values
7272 -- | Generate a monadic stream from a seed value or values.
73− --
74− -- Non-empty pure streams can be cycled using repeat and unfold:
75− --
76− -- >>> cycle = Stream.unfoldMany Unfold.fromList . Stream.repeat
77− --
78− -- Non-empty StreamK can be cycled using append:
79− --
80− -- >>> cycle xs = let ys = xs `StreamK.append` ys in ys
81− --
8273 , fromPure
8374 , fromEffect
8475 , repeat
@@ -221,57 +212,21 @@ module Streamly.Data.Stream
221212 -- operations like mapping a function over the stream.
222213 , foldrM
223214 , foldr
224− -- foldr1
225215
226216 -- ** Specific Folds
227− -- | Streams are folded using folds in "Streamly.Data.Fold". Here are some
228− -- idioms and equivalents of Data.List APIs using folds:
217+ -- | Usually you can use the folds in "Streamly.Data.Fold". However, some
218+ -- folds that may be commonly used or may have an edge in performance in
219+ -- some cases are provided here.
220+ --
221+ -- Useful idioms:
229222 --
230223 -- >>> foldlM' f a = Stream.fold (Fold.foldlM' f a)
231− -- >>> foldl1' f = Stream.fold (Fold.foldl1' f)
224+ -- >>> foldl1 f = Stream.fold (Fold.foldl1' f)
232225 -- >>> foldl' f a = Stream.fold (Fold.foldl' f a)
233226 -- >>> drain = Stream.fold Fold.drain
234227 -- >>> mapM_ f = Stream.fold (Fold.drainMapM f)
235228 -- >>> length = Stream.fold Fold.length
236− -- >>> genericLength = Stream.fold Fold.lengthGeneric
237229 -- >>> head = Stream.fold Fold.one
238− -- >>> last = Stream.fold Fold.latest
239− -- >>> null = Stream.fold Fold.null
240− -- >>> and = Stream.fold Fold.and
241− -- >>> or = Stream.fold Fold.or
242− -- >>> any p = Stream.fold (Fold.any p)
243− -- >>> all p = Stream.fold (Fold.all p)
244− -- >>> sum = Stream.fold Fold.sum
245− -- >>> product = Stream.fold Fold.product
246− -- >>> maximum = Stream.fold Fold.maximum
247− -- >>> maximumBy cmp = Stream.fold (Fold.maximumBy cmp)
248− -- >>> minimum = Stream.fold Fold.minimum
249− -- >>> minimumBy cmp = Stream.fold (Fold.minimumBy cmp)
250− -- >>> elem x = Stream.fold (Fold.elem x)
251− -- >>> notElem x = Stream.fold (Fold.notElem x)
252− -- >>> lookup x = Stream.fold (Fold.lookup x)
253− -- >>> find p = Stream.fold (Fold.find p)
254− -- >>> (!?) i = Stream.fold (Fold.index i)
255− -- >>> genericIndex i = Stream.fold (Fold.indexGeneric i)
256− -- >>> elemIndex x = Stream.fold (Fold.elemIndex x)
257− -- >>> findIndex p = Stream.fold (Fold.findIndex p)
258− --
259− -- Some equivalents of Data.List APIs from the Stream module:
260− --
261− -- >>> head = fmap (fmap fst) . Stream.uncons
262− -- >>> tail = fmap (fmap snd) . Stream.uncons
263− -- >>> tail = Stream.tail -- unreleased API
264− -- >>> init = Stream.init -- unreleased API
265− --
266− -- A Stream based toList fold implementation is provided below because it
267− -- has a better performance compared to the fold.
268−
269− -- Functions in Data.List, missing here:
270− -- unsnoc = Stream.parseBreak (Parser.init Fold.toList)
271− -- genericTake
272− -- genericDrop
273− -- genericSplitAt
274− -- genericReplicate
275230 , toList
276231
277232 -- * Mapping
@@ -325,15 +280,6 @@ module Streamly.Data.Stream
325280 , scan
326281 , postscan
327282 -- XXX postscan1 can be implemented using Monoids or Refolds.
328− -- The following scans from Data.List are not provided.
329− -- XXX scanl
330− -- XXX scanl1
331− -- XXX scanr
332− -- XXX scanr1
333− -- XXX mapAccumL
334− -- XXX mapAccumR
335− -- XXX inits
336− -- XXX tails
337283
338284 -- ** Specific scans
339285 -- Indexing can be considered as a special type of zipping where we zip a
@@ -342,8 +288,6 @@ module Streamly.Data.Stream
342288
343289 -- * Insertion
344290 -- | Add elements to the stream.
345− --
346− -- >>> insert = Stream.insertBy compare
347291
348292 -- Inserting elements is a special case of interleaving/merging streams.
349293 , insertBy
@@ -379,15 +323,12 @@ module Streamly.Data.Stream
379323 -- "Streamly.Internal.Data.Fold" can be used along with 'scanMaybe' to
380324 -- perform stateful filtering operations in general.
381325 --
382− -- Idioms and equivalents of Data.List APIs:
326+ -- Useful idioms:
383327 --
384328 -- >>> deleteBy cmp x = Stream.scanMaybe (Fold.deleteBy cmp x)
385− -- >>> deleteBy = Stream.deleteBy -- unreleased API
386− -- >>> delete = deleteBy (==)
387329 -- >>> findIndices p = Stream.scanMaybe (Fold.findIndices p)
388330 -- >>> elemIndices a = findIndices (== a)
389331 -- >>> uniq = Stream.scanMaybe (Fold.uniqBy (==))
390− -- >>> partition p = Stream.fold (Fold.partition Fold.toList Fold.toList) . fmap (if p then Left else Right)
391332 , scanMaybe
392333 , take
393334 , takeWhile
@@ -395,8 +336,6 @@ module Streamly.Data.Stream
395336 , drop
396337 , dropWhile
397338 , dropWhileM
398− -- XXX write to an array in reverse and then read in reverse
399− -- > dropWhileEnd = reverse . dropWhile p . reverse
400339
401340 -- XXX These are available as scans in folds. We need to check the
402341 -- performance though. If these are common and we need convenient stream
@@ -433,9 +372,6 @@ module Streamly.Data.Stream
433372 -- >>> s = s1 `Stream.append` s2
434373
435374 -- ** Appending
436− -- | Equivalent of Data.List append:
437− --
438− -- >>> (++) = Stream.append
439375 , append
440376
441377 -- ** Interleaving
@@ -446,14 +382,8 @@ module Streamly.Data.Stream
446382 , mergeByM
447383
448384 -- ** Zipping
449− -- | Idioms and equivalents of Data.List APIs:
450− --
451− -- >>> zip = Stream.zipWith (,)
452− -- >>> unzip = Stream.fold (Fold.unzip Fold.toList Fold.toList)
453385 , zipWith
454386 , zipWithM
455− -- XXX zipWith3,4,5,6,7
456− -- XXX unzip3,4,5,6,7
457387 -- , ZipStream (..)
458388
459389 -- ** Cross Product
@@ -486,89 +416,48 @@ module Streamly.Data.Stream
486416 -- One dimension loops are just a special case of nested loops. For
487417 -- example, 'concatMap' can degenerate to a simple map operation:
488418 --
489− -- >>> map f m = Stream.concatMap (\x -> Stream.fromPure (f x)) m
419+ -- > map f m = S.concatMap (\x -> S.fromPure (f x)) m
490420 --
491421 -- Similarly, 'concatMap' can perform filtering by mapping an element to a
492422 -- 'nil' stream:
493423 --
494− -- >>> filter p m = Stream.concatMap (\x -> if p x then Stream.fromPure x else Stream.nil) m
495− --
496− -- Idioms and equivalents of Data.List APIs:
424+ -- > filter p m = S.concatMap (\x -> if p x then S.fromPure x else S.nil) m
497425 --
498− -- >>> concat = Stream.concatMap id
499− -- >>> unlines = Stream.interposeSuffix '\n'
500− -- >>> unlines = Stream.intercalateSuffix Unfold.fromList "\n"
501− -- >>> unwords = Stream.interpose ' '
502− -- >>> unwords = Stream.intercalate Unfold.fromList " "
503426
504427 , concatEffect
505428 , concatMap
506429 , concatMapM
507430
508431 -- * Repeated Fold
509− -- | Idioms and equivalents of Data.List APIs:
432+ -- | Useful idioms:
510433 --
511− -- >>> groupsOf n = Stream.foldMany (Fold.take n Fold.toList)
512− -- >>> groupBy eq = Stream.groupsWhile eq Fold.toList
513− -- >>> groupBy eq = Stream.parseMany (Parser.groupBy eq Fold.toList)
514− -- >>> groupsByRolling eq = Stream.parseMany (Parser.groupByRolling eq Fold.toList)
515− -- >>> groups = groupBy (==)
434+ -- >>> splitWithSuffix p f = Stream.foldMany (Fold.takeEndBy p f)
435+ -- >>> splitOnSuffix p f = Stream.foldMany (Fold.takeEndBy_ p f)
436+ -- >>> groupsBy eq f = Stream.parseMany (Parser.groupBy eq f)
437+ -- >>> groupsByRolling eq f = Stream.parseMany (Parser.groupByRolling eq f)
438+ -- >>> groupsOf n f = Stream.foldMany (Fold.take n f)
516439 , foldMany -- XXX Rename to foldRepeat
517440 , groupsOf
518441 , parseMany
519442
520443 -- * Splitting
521− -- | Idioms and equivalents of Data.List APIs:
522− --
523− -- >>> splitWithSuffix p f = Stream.foldMany (Fold.takeEndBy p f)
524− -- >>> splitOnSuffix p f = Stream.foldMany (Fold.takeEndBy_ p f)
525− -- >>> lines = splitOnSuffix (== '\n')
526− -- >>> words = Stream.wordsBy isSpace
527− -- >>> splitAt n = Stream.fold (Fold.splitAt n Fold.toList Fold.toList)
528− -- >>> span p = Parser.splitWith (,) (Parser.takeWhile p Fold.toList) (Parser.fromFold Fold.toList)
529− -- >>> break p = span (not . p)
530444 , splitOn
531445 , wordsBy
532446
533447 -- * Buffered Operations
534448 -- | Operations that require buffering of the stream.
535449 -- Reverse is essentially a left fold followed by an unfold.
536− --
537− -- Idioms and equivalents of Data.List APIs:
538− --
539− -- >>> nub = Stream.fold Fold.toList . Stream.scanMaybe Fold.nub
540− -- >>> nub = Stream.ordNub -- unreleased API
541− -- >>> sortBy = StreamK.sortBy
542− -- >>> sortOn f = StreamK.sortOn -- unreleased API
543− -- >>> deleteFirstsBy = Stream.deleteFirstsBy -- unreleased
544− -- >>> (\\) = Stream.deleteFirstsBy (==) -- unreleased
545− -- >>> intersectBy = Stream.intersectBy -- unreleased
546− -- >>> intersect = Stream.intersectBy (==) -- unreleased
547− -- >>> unionBy = Stream.unionBy -- unreleased
548− -- >>> union = Stream.unionBy (==) -- unreleased
549− --
550450 , reverse
551− -- XXX transpose: write the streams to arrays and then stream transposed.
552− -- XXX subsequences
553− -- XXX permutations
554− -- , nub
555− -- , ordNub
556− -- , nubBy
557451
558452 -- * Multi-Stream folds
559453 -- | Operations that consume multiple streams at the same time.
560454 , eqBy
561455 , cmpBy
562456 , isPrefixOf
563− , isInfixOf
564− -- , isSuffixOf
565− -- , isSuffixOfUnbox
566457 , isSubsequenceOf
567458
568459 -- trimming sequences
569− -- , stripPrefix
570− -- , stripSuffix
571− -- , stripSuffixUnbox
460+ , stripPrefix
572461
573462 -- Exceptions and resource management depend on the "exceptions" package
574463 -- XXX We can have IO Stream operations not depending on "exceptions"
@@ -632,8 +521,10 @@ where
632521import Streamly.Internal.Data.Stream
633522import Prelude
634523 hiding (filter, drop, dropWhile, take, takeWhile, zipWith, foldr,
635− mapM, sequence, reverse, iterate, foldr1, repeat, replicate,
636− concatMap)
524+ foldl, map, mapM, mapM_, sequence, all, any, sum, product, elem,
525+ notElem, maximum, minimum, head, last, tail, length, null,
526+ reverse, iterate, init, and, or, lookup, foldr1, (!!),
527+ scanl, scanl1, repeat, replicate, concatMap, span)
637528
638529import qualified Streamly.Internal.Data.Array.Type as Array
639530
core/src/Streamly/Internal/Data/Array.hs+94−551
@@ -2,6 +2,7 @@
22-- |
33-- Module : Streamly.Internal.Data.Array
44-- Copyright : (c) 2019 Composewell Technologies
5+--
56-- License : BSD3
67-- Maintainer : streamly@composewell.com
78-- Stability : experimental
@@ -22,18 +23,23 @@ module Streamly.Internal.Data.Array
2223 -- Monadic Folds
2324 , writeLastN
2425
26+ -- * Unfolds
27+ , reader
28+ , readerUnsafe
29+ , producer -- experimental
30+
2531 -- * Random Access
2632 -- , (!!)
2733 , getIndex
2834 , getIndexRev
29− , last -- XXX getLastIndex?
35+ , last -- XXX getIndexLast?
36+ , getIndices
37+ , getIndicesFromThenTo
3038 -- , getIndicesFrom -- read from a given position to the end of file
3139 -- , getIndicesUpto -- read from beginning up to the given position
3240 -- , getIndicesFromTo
3341 -- , getIndicesFromRev -- read from a given position to the beginning of file
3442 -- , getIndicesUptoRev -- read from end to the given position in file
35− , indexReader
36− , indexReaderFromThenTo
3743
3844 -- * Size
3945 , null
@@ -41,8 +47,6 @@ module Streamly.Internal.Data.Array
4147 -- * Search
4248 , binarySearch
4349 , findIndicesOf
44− -- getIndicesOf
45− , indexFinder -- see splitOn
4650 -- , findIndexOf
4751 -- , find
4852
@@ -55,8 +59,8 @@ module Streamly.Internal.Data.Array
5559 -- * Subarrays
5660 , getSliceUnsafe
5761 -- , getSlice
58− , sliceIndexerFromLen
59− , slicerFromLen
62+ , genSlicesFromLen
63+ , getSlicesFromLen
6064 , splitOn
6165
6266 -- * Streaming Operations
@@ -66,34 +70,11 @@ module Streamly.Internal.Data.Array
6670 , streamFold
6771 , fold
6872
69− -- * Stream of Arrays
70−
71− -- XXX these are probably not very useful to have in this module as we can
72− -- express these idiomatically using streams.
73− , interpose
74− , interposeSuffix
75− , intercalateSuffix
76−
77− , compactLE
78− , pinnedCompactLE
79− , compactOnByte
80− , compactOnByteSuffix
81−
82− , foldBreakChunks
83− , foldChunks
84− , foldBreakChunksK
85− , parseBreakChunksK
86−
8773 -- * Serialization
8874 , encodeAs
8975 , serialize
9076 , pinnedSerialize
9177 , deserialize
92−
93− -- * Deprecated
94− , genSlicesFromLen
95− , getSlicesFromLen
96− , getIndices
9778 )
9879where
9980
@@ -102,42 +83,35 @@ where
10283#include "ArrayMacros.h"
10384
10485import Control.Monad.IO.Class (MonadIO(..))
105−-- import Data.Bifunctor (first)
106−-- import Data.Either (fromRight)
10786import Data.Functor.Identity (Identity)
10887import Data.Proxy (Proxy(..))
10988import Data.Word (Word8)
11089import Foreign.C.String (CString)
11190import Foreign.Ptr (castPtr)
11291import Foreign.Storable (Storable)
113−import GHC.Types (SPEC(..))
11492import Streamly.Internal.Data.Unbox (Unbox(..))
11593import Prelude hiding (length, null, last, map, (!!), read, concat)
11694
117−import Streamly.Internal.Data.MutByteArray.Type (PinnedState(..), MutByteArray)
95+import Streamly.Internal.Data.MutByteArray.Type (PinnedState(..))
11896import Streamly.Internal.Data.Serialize.Type (Serialize)
11997import Streamly.Internal.Data.Fold.Type (Fold(..))
120−import Streamly.Internal.Data.Parser (Parser(..), Initial(..), ParseError(..))
121−import Streamly.Internal.Data.Stream (Stream(..))
122−import Streamly.Internal.Data.StreamK (StreamK)
123−import Streamly.Internal.Data.SVar.Type (adaptState, defState)
124−import Streamly.Internal.Data.Tuple.Strict (Tuple'(..), Tuple3Fused'(..))
98+import Streamly.Internal.Data.Producer.Type (Producer(..))
99+import Streamly.Internal.Data.Stream (Stream)
100+import Streamly.Internal.Data.Tuple.Strict (Tuple3Fused'(..))
125101import Streamly.Internal.Data.Unfold.Type (Unfold(..))
126102import Streamly.Internal.System.IO (unsafeInlineIO)
127103
128−import qualified Streamly.Internal.Data.Fold.Type as Fold
129104import qualified Streamly.Internal.Data.Serialize.Type as Serialize
130105import qualified Streamly.Internal.Data.MutByteArray.Type as MBA
131106import qualified Streamly.Internal.Data.MutArray as MA
107+import qualified Streamly.Internal.Data.Array.Type as A
132108import qualified Streamly.Internal.Data.Fold as FL
109+import qualified Streamly.Internal.Data.Producer.Type as Producer
110+import qualified Streamly.Internal.Data.Producer as Producer
133111import qualified Streamly.Internal.Data.Ring as RB
134−import qualified Streamly.Internal.Data.Parser as Parser
135−-- import qualified Streamly.Internal.Data.ParserK as ParserK
136112import qualified Streamly.Internal.Data.Stream as D
137113import qualified Streamly.Internal.Data.Stream as Stream
138−import qualified Streamly.Internal.Data.StreamK as StreamK
139114import qualified Streamly.Internal.Data.Unfold as Unfold
140−import qualified Prelude
141115
142116import Streamly.Internal.Data.Array.Type
143117
@@ -170,6 +144,49 @@ import Streamly.Internal.Data.Array.Type
170144-- Elimination
171145-------------------------------------------------------------------------------
172146
147+{-# INLINE_NORMAL producer #-}
148+producer :: forall m a. (Monad m, Unbox a) => Producer m (Array a) a
149+producer =
150+ Producer.translate A.unsafeThaw A.unsafeFreeze
151+ $ MA.producerWith (return . unsafeInlineIO)
152+
153+-- | Unfold an array into a stream.
154+--
155+{-# INLINE_NORMAL reader #-}
156+reader :: forall m a. (Monad m, Unbox a) => Unfold m (Array a) a
157+reader = Producer.simplify producer
158+
159+-- | Unfold an array into a stream, does not check the end of the array, the
160+-- user is responsible for terminating the stream within the array bounds. For
161+-- high performance application where the end condition can be determined by
162+-- a terminating fold.
163+--
164+-- Written in the hope that it may be faster than "read", however, in the case
165+-- for which this was written, "read" proves to be faster even though the core
166+-- generated with unsafeRead looks simpler.
167+--
168+-- /Pre-release/
169+--
170+{-# INLINE_NORMAL readerUnsafe #-}
171+readerUnsafe :: forall m a. (Monad m, Unbox a) => Unfold m (Array a) a
172+readerUnsafe = Unfold step inject
173+ where
174+
175+ inject (Array contents start end) =
176+ return (ArrayUnsafe contents end start)
177+
178+ {-# INLINE_LATE step #-}
179+ step (ArrayUnsafe contents end p) = do
180+ -- unsafeInlineIO allows us to run this in Identity monad for pure
181+ -- toList/foldr case which makes them much faster due to not
182+ -- accumulating the list and fusing better with the pure consumers.
183+ --
184+ -- This should be safe as the array contents are guaranteed to be
185+ -- evaluated/written to before we peek at them.
186+ let !x = unsafeInlineIO $ peekAt p contents
187+ let !p1 = INDEX_NEXT(p,a)
188+ return $ D.Yield x (ArrayUnsafe contents end p1)
189+
173190-- |
174191--
175192-- >>> null arr = Array.byteLength arr == 0
@@ -177,7 +194,7 @@ import Streamly.Internal.Data.Array.Type
177194-- /Pre-release/
178195{-# INLINE null #-}
179196null :: Array a -> Bool
180−null arr = byteLength arr == 0
197+null arr = A.byteLength arr == 0
181198
182199-- | Like 'getIndex' but indexes the array in reverse from the end.
183200--
@@ -205,8 +222,6 @@ last = getIndexRev 0
205222-- Folds with Array as the container
206223-------------------------------------------------------------------------------
207224
208−-- XXX We should generate this from Ring.
209−
210225-- | @writeLastN n@ folds a maximum of @n@ elements from the end of the input
211226-- stream to an 'Array'.
212227--
@@ -215,7 +230,7 @@ writeLastN ::
215230 (Storable a, Unbox a, MonadIO m) => Int -> Fold m a (Array a)
216231writeLastN n
217232 | n <= 0 = fmap (const mempty) FL.drain
218− | otherwise = unsafeFreeze <$> Fold step initial done done
233+ | otherwise = A.unsafeFreeze <$> Fold step initial done done
219234
220235 where
221236
@@ -228,9 +243,11 @@ writeLastN n
228243 in fmap f $ liftIO $ RB.new n
229244
230245 done (Tuple3Fused' rb rh i) = do
231− arr <- MA.new n
232− -- XXX We should write a read unfold for ring.
233− foldFunc i rh MA.snocUnsafe arr rb
246+ arr <- liftIO $ MA.new n
247+ foldFunc i rh snoc' arr rb
248+
249+ -- XXX We should write a read unfold for ring.
250+ snoc' b a = liftIO $ MA.snocUnsafe b a
234251
235252 foldFunc i
236253 | i < n = RB.unsafeFoldRingM
@@ -256,26 +273,19 @@ binarySearch = undefined
256273-- compared to streams by using SIMD instructions.
257274-- We can also return a bit array instead.
258275
259−-- Can use SIMD.
260−
261276-- | Perform a linear search to find all the indices where a given element is
262277-- present in an array.
263278--
264279-- /Unimplemented/
265−indexFinder :: (a -> Bool) -> Unfold Identity (Array a) Int
266−indexFinder = undefined
267−
268−-- |
269−-- /Unimplemented/
270−findIndicesOf :: (a -> Bool) -> Array a -> Stream Identity Int
271−findIndicesOf p = Stream.unfold (indexFinder p)
280+findIndicesOf :: (a -> Bool) -> Unfold Identity (Array a) Int
281+findIndicesOf = undefined
272282
273283{-
274284findIndexOf :: (a -> Bool) -> Array a -> Maybe Int
275−findIndexOf p = Unfold.fold Fold.one . Stream.unfold (indexFinder p)
285+findIndexOf p = Unfold.fold Fold.one . Stream.unfold (findIndicesOf p)
276286
277287find :: (a -> Bool) -> Array a -> Bool
278−find = Unfold.fold Fold.null . Stream.unfold (indexFinder p)
288+find = Unfold.fold Fold.null . Stream.unfold (findIndicesOf p)
279289-}
280290
281291-------------------------------------------------------------------------------
@@ -317,45 +327,29 @@ splitOn :: (Monad m, Unbox a) =>
317327 (a -> Bool) -> Array a -> Stream m (Array a)
318328splitOn predicate arr =
319329 fmap (\(i, len) -> getSliceUnsafe i len arr)
320− $ D.indexOnSuffix predicate (read arr)
330+ $ D.sliceOnSuffix predicate (A.toStreamD arr)
321331
322−{-# INLINE sliceIndexerFromLen #-}
323−sliceIndexerFromLen :: forall m a. (Monad m, Unbox a)
324− => Int -- ^ from index
325− -> Int -- ^ length of the slice
326− -> Unfold m (Array a) (Int, Int)
327−sliceIndexerFromLen from len =
328− Unfold.lmap unsafeThaw (MA.sliceIndexerFromLen from len)
329−
330−{-# DEPRECATED genSlicesFromLen "Please use sliceIndexerFromLen instead." #-}
331332{-# INLINE genSlicesFromLen #-}
332333genSlicesFromLen :: forall m a. (Monad m, Unbox a)
333334 => Int -- ^ from index
334335 -> Int -- ^ length of the slice
335336 -> Unfold m (Array a) (Int, Int)
336−genSlicesFromLen = sliceIndexerFromLen
337+genSlicesFromLen from len =
338+ Unfold.lmap A.unsafeThaw (MA.genSlicesFromLen from len)
337339
338340-- | Generate a stream of slices of specified length from an array, starting
339341-- from the supplied array index. The last slice may be shorter than the
340342-- requested length.
341343--
342344-- /Pre-release//
343−{-# INLINE slicerFromLen #-}
344−slicerFromLen :: forall m a. (Monad m, Unbox a)
345− => Int -- ^ from index
346− -> Int -- ^ length of the slice
347− -> Unfold m (Array a) (Array a)
348−slicerFromLen from len =
349− fmap unsafeFreeze
350− $ Unfold.lmap unsafeThaw (MA.slicerFromLen from len)
351−
352−{-# DEPRECATED getSlicesFromLen "Please use slicerFromLen instead." #-}
353345{-# INLINE getSlicesFromLen #-}
354346getSlicesFromLen :: forall m a. (Monad m, Unbox a)
355347 => Int -- ^ from index
356348 -> Int -- ^ length of the slice
357349 -> Unfold m (Array a) (Array a)
358−getSlicesFromLen = slicerFromLen
350+getSlicesFromLen from len =
351+ fmap A.unsafeFreeze
352+ $ Unfold.lmap A.unsafeThaw (MA.getSlicesFromLen from len)
359353
360354-------------------------------------------------------------------------------
361355-- Random reads and writes
@@ -385,25 +379,19 @@ getIndex i arr =
385379-- @
386380-- read =
387381-- let u = lmap (\arr -> (0, length arr - 1)) Unfold.enumerateFromTo
388−-- in Unfold.lmap f (indexReader arr)
382+-- in Unfold.lmap f (getIndices arr)
389383--
390384-- readRev =
391385-- let i = length arr - 1
392−-- in Unfold.lmap f (indexReaderFromThenTo i (i - 1) 0)
386+-- in Unfold.lmap f (getIndicesFromThenTo i (i - 1) 0)
393387-- @
394388--
395389-- /Pre-release/
396−{-# INLINE indexReader #-}
397−indexReader :: (Monad m, Unbox a) => Stream m Int -> Unfold m (Array a) a
398−indexReader m =
399− let unf = MA.indexReaderWith (return . unsafeInlineIO) m
400− in Unfold.lmap unsafeThaw unf
401−
402−-- XXX DO NOT REMOVE, change the signature to use Stream instead of unfold
403−{-# DEPRECATED getIndices "Please use getIndices instead." #-}
404390{-# INLINE getIndices #-}
405391getIndices :: (Monad m, Unbox a) => Stream m Int -> Unfold m (Array a) a
406−getIndices = indexReader
392+getIndices m =
393+ let unf = MA.getIndicesD (return . unsafeInlineIO) m
394+ in Unfold.lmap A.unsafeThaw unf
407395
408396-- | Unfolds @(from, then, to, array)@ generating a finite stream whose first
409397-- element is the array value from the index @from@ and the successive elements
@@ -419,9 +407,9 @@ getIndices = indexReader
419407-- @
420408--
421409-- /Unimplemented/
422−{-# INLINE indexReaderFromThenTo #-}
423−indexReaderFromThenTo :: Unfold m (Int, Int, Int, Array a) a
424−indexReaderFromThenTo = undefined
410+{-# INLINE getIndicesFromThenTo #-}
411+getIndicesFromThenTo :: Unfold m (Int, Int, Int, Array a) a
412+getIndicesFromThenTo = undefined
425413
426414-------------------------------------------------------------------------------
427415-- Transform via stream operations
@@ -438,7 +426,7 @@ indexReaderFromThenTo = undefined
438426{-# INLINE runPipe #-}
439427runPipe :: (MonadIO m, Unbox a, Unbox b)
440428 => Pipe m a b -> Array a -> m (Array b)
441−runPipe f arr = P.runPipe (toArrayMinChunk (length arr)) $ f (read arr)
429+runPipe f arr = P.runPipe (toArrayMinChunk (length arr)) $ f (A.read arr)
442430-}
443431
444432-- XXX For transformations that cannot change the number of elements e.g. "map"
@@ -452,7 +440,7 @@ runPipe f arr = P.runPipe (toArrayMinChunk (length arr)) $ f (read arr)
452440streamTransform :: forall m a b. (MonadIO m, Unbox a, Unbox b)
453441 => (Stream m a -> Stream m b) -> Array a -> m (Array b)
454442streamTransform f arr =
455− Stream.fold (createWith (length arr)) $ f (read arr)
443+ Stream.fold (A.writeWith (length arr)) $ f (A.read arr)
456444
457445-------------------------------------------------------------------------------
458446-- Casts
@@ -486,7 +474,7 @@ asBytes = castUnsafe
486474--
487475cast :: forall a b. (Unbox b) => Array a -> Maybe (Array b)
488476cast arr =
489− let len = byteLength arr
477+ let len = A.byteLength arr
490478 r = len `mod` SIZE_OF(b)
491479 in if r /= 0
492480 then Nothing
@@ -504,9 +492,9 @@ cast arr =
504492--
505493asCStringUnsafe :: Array a -> (CString -> IO b) -> IO b
506494asCStringUnsafe arr act = do
507− let arr1 = asBytes arr <> fromList [0]
508− -- unsafePinnedAsPtr makes sure the array is pinned
509− unsafePinnedAsPtr arr1 $ \ptr -> act (castPtr ptr)
495+ let arr1 = asBytes arr <> A.fromList [0]
496+ -- asPtrUnsafe makes sure the array is pinned
497+ asPtrUnsafe arr1 $ \ptr -> act (castPtr ptr)
510498
511499-------------------------------------------------------------------------------
512500-- Folds
@@ -519,14 +507,14 @@ asCStringUnsafe arr act = do
519507-- /Pre-release/
520508{-# INLINE fold #-}
521509fold :: forall m a b. (Monad m, Unbox a) => Fold m a b -> Array a -> m b
522−fold f arr = Stream.fold f (read arr)
510+fold f arr = Stream.fold f (A.read arr)
523511
524512-- | Fold an array using a stream fold operation.
525513--
526514-- /Pre-release/
527515{-# INLINE streamFold #-}
528516streamFold :: (Monad m, Unbox a) => (Stream m a -> m b) -> Array a -> m b
529−streamFold f arr = f (read arr)
517+streamFold f arr = f (A.read arr)
530518
531519--------------------------------------------------------------------------------
532520-- Serialization
@@ -571,448 +559,3 @@ deserialize arr@(Array {..}) = unsafeInlineIO $ do
571559 Serialize.deserializeAt arrStart arrContents (arrStart + lenArr)
572560 assertM(off == arrStart + lenArr)
573561 pure val
574−
575−-------------------------------------------------------------------------------
576−-- Streams of Arrays
577−-------------------------------------------------------------------------------
578−
579−-- TODO: efficiently compare two streams of arrays. Two streams can have chunks
580−-- of different sizes, we can handle that in the stream comparison abstraction.
581−-- This could be useful e.g. to fast compare whether two files differ.
582−
583−-- | Insert the given element between arrays and flatten.
584−--
585−-- >>> interpose x = Stream.interpose x Array.reader
586−--
587−{-# INLINE interpose #-}
588−interpose :: (Monad m, Unbox a) => a -> Stream m (Array a) -> Stream m a
589−interpose x = D.interpose x reader
590−
591−data FlattenState s =
592− OuterLoop s
593− | InnerLoop s !MutByteArray !Int !Int
594−
595−-- | Insert the given element after each array and flatten. This is similar to
596−-- unlines.
597−--
598−-- >>> interposeSuffix x = Stream.interposeSuffix x Array.reader
599−--
600−{-# INLINE_NORMAL interposeSuffix #-}
601−interposeSuffix :: forall m a. (Monad m, Unbox a)
602− => a -> Stream m (Array a) -> Stream m a
603−-- This does not require MonadIO constraint.
604−-- interposeSuffix x = D.interposeSuffix x reader
605−interposeSuffix sep (D.Stream step state) = D.Stream step' (OuterLoop state)
606−
607− where
608−
609− {-# INLINE_LATE step' #-}
610− step' gst (OuterLoop st) = do
611− r <- step (adaptState gst) st
612− return $ case r of
613− D.Yield Array{..} s ->
614− D.Skip (InnerLoop s arrContents arrStart arrEnd)
615− D.Skip s -> D.Skip (OuterLoop s)
616− D.Stop -> D.Stop
617−
618− step' _ (InnerLoop st _ p end) | p == end =
619− return $ D.Yield sep $ OuterLoop st
620−
621− step' _ (InnerLoop st contents p end) = do
622− x <- pure $ unsafeInlineIO $ peekAt p contents
623− return $ D.Yield x (InnerLoop st contents (INDEX_NEXT(p,a)) end)
624−
625−-- | Insert the given array after each array and flatten.
626−--
627−-- >>> intercalateSuffix = Stream.intercalateSuffix Array.reader
628−--
629−{-# INLINE intercalateSuffix #-}
630−intercalateSuffix :: (Monad m, Unbox a)
631− => Array a -> Stream m (Array a) -> Stream m a
632−intercalateSuffix = D.intercalateSuffix reader
633−
634−-- | @compactLE n@ coalesces adjacent arrays in the input stream
635−-- only if the combined size would be less than or equal to n.
636−--
637−-- Generates unpinned arrays irrespective of the pinning status of input
638−-- arrays.
639−{-# INLINE_NORMAL compactLE #-}
640−compactLE :: (MonadIO m, Unbox a)
641− => Int -> Stream m (Array a) -> Stream m (Array a)
642−compactLE n stream =
643− D.map unsafeFreeze $ MA.compactLE n $ D.map unsafeThaw stream
644−
645−-- | Pinned version of 'compactLE'.
646−{-# INLINE_NORMAL pinnedCompactLE #-}
647−pinnedCompactLE :: (MonadIO m, Unbox a)
648− => Int -> Stream m (Array a) -> Stream m (Array a)
649−pinnedCompactLE n stream =
650− D.map unsafeFreeze $ MA.pinnedCompactLE n $ D.map unsafeThaw stream
651−
652−-- | Split a stream of arrays on a given separator byte, dropping the separator
653−-- and coalescing all the arrays between two separators into a single array.
654−--
655−{-# INLINE compactOnByte #-}
656−compactOnByte
657− :: (MonadIO m)
658− => Word8
659− -> Stream m (Array Word8)
660− -> Stream m (Array Word8)
661−compactOnByte byte =
662− fmap unsafeFreeze . MA.compactOnByte byte . fmap unsafeThaw
663−
664−-- | Like 'compactOnByte' considers the separator in suffix position instead of
665−-- infix position.
666−{-# INLINE compactOnByteSuffix #-}
667−compactOnByteSuffix
668− :: (MonadIO m)
669− => Word8
670− -> Stream m (Array Word8)
671− -> Stream m (Array Word8)
672−compactOnByteSuffix byte =
673− fmap unsafeFreeze . MA.compactOnByteSuffix byte . fmap unsafeThaw
674−
675−-------------------------------------------------------------------------------
676−-- Folding Streams of Arrays
677−-------------------------------------------------------------------------------
678−
679−-- XXX This should not be used for breaking a stream as the D.cons used in
680−-- reconstructing the stream could be very bad for performance. This can only
681−-- be useful in folding without breaking.
682−{-# INLINE_NORMAL foldBreakChunks #-}
683−foldBreakChunks :: forall m a b. (MonadIO m, Unbox a) =>
684− Fold m a b -> Stream m (Array a) -> m (b, Stream m (Array a))
685−foldBreakChunks (Fold fstep initial _ final) stream@(Stream step state) = do
686− res <- initial
687− case res of
688− Fold.Partial fs -> go SPEC state fs
689− Fold.Done fb -> return $! (fb, stream)
690−
691− where
692−
693− {-# INLINE go #-}
694− go !_ st !fs = do
695− r <- step defState st
696− case r of
697− Stream.Yield (Array contents start end) s ->
698− let fp = Tuple' end contents
699− in goArray SPEC s fp start fs
700− Stream.Skip s -> go SPEC s fs
701− Stream.Stop -> do
702− b <- final fs
703− return (b, D.nil)
704−
705− goArray !_ s (Tuple' end _) !cur !fs
706− | cur == end = do
707− go SPEC s fs
708− goArray !_ st fp@(Tuple' end contents) !cur !fs = do
709− x <- liftIO $ peekAt cur contents
710− res <- fstep fs x
711− let next = INDEX_NEXT(cur,a)
712− case res of
713− Fold.Done b -> do
714− let arr = Array contents next end
715− return $! (b, D.cons arr (D.Stream step st))
716− Fold.Partial fs1 -> goArray SPEC st fp next fs1
717−
718−-- This may be more robust wrt fusion compared to unfoldMany?
719−
720−-- | Fold a stream of arrays using a 'Fold'. This is equivalent to the
721−-- following:
722−--
723−-- >>> foldChunks f = Stream.fold f . Stream.unfoldMany Array.reader
724−--
725−foldChunks :: (MonadIO m, Unbox a) => Fold m a b -> Stream m (Array a) -> m b
726−foldChunks f s = fmap fst (foldBreakChunks f s)
727−-- foldStream f = Stream.fold f . Stream.unfoldMany reader
728−
729−-- | Fold a stream of arrays using a 'Fold' and return the remaining stream.
730−--
731−-- The following alternative to this function allows composing the fold using
732−-- the parser Monad:
733−--
734−-- @
735−-- foldBreakStreamK f s =
736−-- fmap (first (fromRight undefined))
737−-- $ StreamK.parseBreakChunks (ParserK.adaptC (Parser.fromFold f)) s
738−-- @
739−--
740−-- We can compare perf and remove this one or define it in terms of that.
741−--
742−foldBreakChunksK :: forall m a b. (MonadIO m, Unbox a) =>
743− Fold m a b -> StreamK m (Array a) -> m (b, StreamK m (Array a))
744−{-
745−foldBreakChunksK f s =
746− fmap (first (fromRight undefined))
747− $ StreamK.parseBreakChunks (ParserK.adaptC (Parser.fromFold f)) s
748−-}
749−foldBreakChunksK (Fold fstep initial _ final) stream = do
750− res <- initial
751− case res of
752− Fold.Partial fs -> go fs stream
753− Fold.Done fb -> return (fb, stream)
754−
755− where
756−
757− {-# INLINE go #-}
758− go !fs st = do
759− let stop = (, StreamK.nil) <$> final fs
760− single a = yieldk a StreamK.nil
761− yieldk (Array contents start end) r =
762− let fp = Tuple' end contents
763− in goArray fs r fp start
764− in StreamK.foldStream defState yieldk single stop st
765−
766− goArray !fs st (Tuple' end _) !cur
767− | cur == end = do
768− go fs st
769− goArray !fs st fp@(Tuple' end contents) !cur = do
770− x <- liftIO $ peekAt cur contents
771− res <- fstep fs x
772− let next = INDEX_NEXT(cur,a)
773− case res of
774− Fold.Done b -> do
775− let arr = Array contents next end
776− return $! (b, StreamK.cons arr st)
777− Fold.Partial fs1 -> goArray fs1 st fp next
778−
779−{-
780−-- This can be generalized to any type provided it can be unfolded to a stream
781−-- and it can be combined using a semigroup operation.
782−--
783−{-# INLINE_NORMAL parseBreakD #-}
784−parseBreakD ::
785− forall m a b. (MonadIO m, MonadThrow m, Unbox a)
786− => PRD.Parser a m b
787− -> D.Stream m (Array.Array a)
788− -> m (b, D.Stream m (Array.Array a))
789−parseBreakD
790− (PRD.Parser pstep initial extract) stream@(D.Stream step state) = do
791−
792− res <- initial
793− case res of
794− PRD.IPartial s -> go SPEC state (List []) s
795− PRD.IDone b -> return (b, stream)
796− PRD.IError err -> throwM $ ParseError err
797−
798− where
799−
800− -- "backBuf" contains last few items in the stream that we may have to
801− -- backtrack to.
802− --
803− -- XXX currently we are using a dumb list based approach for backtracking
804− -- buffer. This can be replaced by a sliding/ring buffer using Data.Array.
805− -- That will allow us more efficient random back and forth movement.
806− go !_ st backBuf !pst = do
807− r <- step defState st
808− case r of
809− D.Yield (Array contents start end) s ->
810− gobuf SPEC s backBuf
811− (Tuple' end contents) start pst
812− D.Skip s -> go SPEC s backBuf pst
813− D.Stop -> do
814− b <- extract pst
815− return (b, D.nil)
816−
817− -- Use strictness on "cur" to keep it unboxed
818− gobuf !_ s backBuf (Tuple' end _) !cur !pst
819− | cur == end = do
820− go SPEC s backBuf pst
821− gobuf !_ s backBuf fp@(Tuple' end contents) !cur !pst = do
822− x <- liftIO $ peekByteIndex contents cur
823− pRes <- pstep pst x
824− let next = INDEX_NEXT(cur,a)
825− case pRes of
826− PR.Partial 0 pst1 ->
827− gobuf SPEC s (List []) fp next pst1
828− PR.Partial n pst1 -> do
829− assert (n <= Prelude.length (x:getList backBuf)) (return ())
830− let src0 = Prelude.take n (x:getList backBuf)
831− arr0 = A.fromListN n (Prelude.reverse src0)
832− arr1 = Array contents next end
833− src = arr0 <> arr1
834− let !(Array cont1 start end1) = src
835− fp1 = Tuple' end1 cont1
836− gobuf SPEC s (List []) fp1 start pst1
837− PR.Continue 0 pst1 ->
838− gobuf SPEC s (List (x:getList backBuf)) fp next pst1
839− PR.Continue n pst1 -> do
840− assert (n <= Prelude.length (x:getList backBuf)) (return ())
841− let (src0, buf1) = splitAt n (x:getList backBuf)
842− arr0 = A.fromListN n (Prelude.reverse src0)
843− arr1 = Array contents next end
844− src = arr0 <> arr1
845− let !(Array cont1 start end1) = src
846− fp1 = Tuple' end1 cont1
847− gobuf SPEC s (List buf1) fp1 start pst1
848− PR.Done 0 b -> do
849− let arr = Array contents next end
850− return (b, D.cons arr (D.Stream step s))
851− PR.Done n b -> do
852− assert (n <= Prelude.length (x:getList backBuf)) (return ())
853− let src0 = Prelude.take n (x:getList backBuf)
854− -- XXX create the array in reverse instead
855− arr0 = A.fromListN n (Prelude.reverse src0)
856− arr1 = Array contents next end
857− -- XXX Use StreamK to avoid adding arbitrary layers of
858− -- constructors every time.
859− str = D.cons arr0 (D.cons arr1 (D.Stream step s))
860− return (b, str)
861− PR.Error err -> throwM $ ParseError err
862−-}
863−
864−-- | Parse an array stream using the supplied 'Parser'. Returns the parse
865−-- result and the unconsumed stream. Throws 'ParseError' if the parse fails.
866−--
867−-- The following alternative to this function allows composing the parser using
868−-- the parser Monad:
869−--
870−-- >>> parseBreakStreamK p = StreamK.parseBreakChunks (ParserK.adaptC p)
871−--
872−-- We can compare perf and remove this one or define it in terms of that.
873−--
874−-- /Internal/
875−--
876−{-# INLINE_NORMAL parseBreakChunksK #-}
877−parseBreakChunksK ::
878− forall m a b. (MonadIO m, Unbox a)
879− => Parser a m b
880− -> StreamK m (Array a)
881− -> m (Either ParseError b, StreamK m (Array a))
882−-- parseBreakStreamK p = StreamK.parseBreakChunks (ParserK.adaptC p)
883−parseBreakChunksK (Parser pstep initial extract) stream = do
884− res <- initial
885− case res of
886− IPartial s -> go s stream []
887− IDone b -> return (Right b, stream)
888− IError err -> return (Left (ParseError err), stream)
889−
890− where
891−
892− -- "backBuf" contains last few items in the stream that we may have to
893− -- backtrack to.
894− --
895− -- XXX currently we are using a dumb list based approach for backtracking
896− -- buffer. This can be replaced by a sliding/ring buffer using Data.Array.
897− -- That will allow us more efficient random back and forth movement.
898− go !pst st backBuf = do
899− let stop = goStop pst backBuf -- (, K.nil) <$> extract pst
900− single a = yieldk a StreamK.nil
901− yieldk arr r = goArray pst backBuf r arr
902− in StreamK.foldStream defState yieldk single stop st
903−
904− -- Use strictness on "cur" to keep it unboxed
905− goArray !pst backBuf st (Array _ cur end) | cur == end = go pst st backBuf
906− goArray !pst backBuf st (Array contents cur end) = do
907− x <- liftIO $ peekAt cur contents
908− pRes <- pstep pst x
909− let next = INDEX_NEXT(cur,a)
910− case pRes of
911− Parser.Partial 0 s ->
912− goArray s [] st (Array contents next end)
913− Parser.Partial n s -> do
914− assert (n <= Prelude.length (x:backBuf)) (return ())
915− let src0 = Prelude.take n (x:backBuf)
916− arr0 = fromListN n (Prelude.reverse src0)
917− arr1 = Array contents next end
918− src = arr0 <> arr1
919− goArray s [] st src
920− Parser.Continue 0 s ->
921− goArray s (x:backBuf) st (Array contents next end)
922− Parser.Continue n s -> do
923− assert (n <= Prelude.length (x:backBuf)) (return ())
924− let (src0, buf1) = Prelude.splitAt n (x:backBuf)
925− arr0 = fromListN n (Prelude.reverse src0)
926− arr1 = Array contents next end
927− src = arr0 <> arr1
928− goArray s buf1 st src
929− Parser.Done 0 b -> do
930− let arr = Array contents next end
931− return (Right b, StreamK.cons arr st)
932− Parser.Done n b -> do
933− assert (n <= Prelude.length (x:backBuf)) (return ())
934− let src0 = Prelude.take n (x:backBuf)
935− -- XXX Use fromListRevN once implemented
936− -- arr0 = A.fromListRevN n src0
937− arr0 = fromListN n (Prelude.reverse src0)
938− arr1 = Array contents next end
939− str = StreamK.cons arr0 (StreamK.cons arr1 st)
940− return (Right b, str)
941− Parser.Error err -> do
942− let n = Prelude.length backBuf
943− arr0 = fromListN n (Prelude.reverse backBuf)
944− arr1 = Array contents cur end
945− str = StreamK.cons arr0 (StreamK.cons arr1 stream)
946− return (Left (ParseError err), str)
947−
948− -- This is a simplified goArray
949− goExtract !pst backBuf (Array _ cur end)
950− | cur == end = goStop pst backBuf
951− goExtract !pst backBuf (Array contents cur end) = do
952− x <- liftIO $ peekAt cur contents
953− pRes <- pstep pst x
954− let next = INDEX_NEXT(cur,a)
955− case pRes of
956− Parser.Partial 0 s ->
957− goExtract s [] (Array contents next end)
958− Parser.Partial n s -> do
959− assert (n <= Prelude.length (x:backBuf)) (return ())
960− let src0 = Prelude.take n (x:backBuf)
961− arr0 = fromListN n (Prelude.reverse src0)
962− arr1 = Array contents next end
963− src = arr0 <> arr1
964− goExtract s [] src
965− Parser.Continue 0 s ->
966− goExtract s backBuf (Array contents next end)
967− Parser.Continue n s -> do
968− assert (n <= Prelude.length (x:backBuf)) (return ())
969− let (src0, buf1) = Prelude.splitAt n (x:backBuf)
970− arr0 = fromListN n (Prelude.reverse src0)
971− arr1 = Array contents next end
972− src = arr0 <> arr1
973− goExtract s buf1 src
974− Parser.Done 0 b -> do
975− let arr = Array contents next end
976− return (Right b, StreamK.fromPure arr)
977− Parser.Done n b -> do
978− assert (n <= Prelude.length backBuf) (return ())
979− let src0 = Prelude.take n backBuf
980− -- XXX Use fromListRevN once implemented
981− -- arr0 = A.fromListRevN n src0
982− arr0 = fromListN n (Prelude.reverse src0)
983− arr1 = Array contents next end
984− str = StreamK.cons arr0 (StreamK.fromPure arr1)
985− return (Right b, str)
986− Parser.Error err -> do
987− let n = Prelude.length backBuf
988− arr0 = fromListN n (Prelude.reverse backBuf)
989− arr1 = Array contents cur end
990− str = StreamK.cons arr0 (StreamK.cons arr1 stream)
991− return (Left (ParseError err), str)
992−
993− -- This is a simplified goExtract
994− {-# INLINE goStop #-}
995− goStop !pst backBuf = do
996− pRes <- extract pst
997− case pRes of
998− Parser.Partial _ _ -> error "Bug: parseBreak: Partial in extract"
999− Parser.Continue 0 s ->
1000− goStop s backBuf
1001− Parser.Continue n s -> do
1002− assert (n <= Prelude.length backBuf) (return ())
1003− let (src0, buf1) = Prelude.splitAt n backBuf
1004− arr = fromListN n (Prelude.reverse src0)
1005− goExtract s buf1 arr
1006− Parser.Done 0 b ->
1007− return (Right b, StreamK.nil)
1008− Parser.Done n b -> do
1009− assert (n <= Prelude.length backBuf) (return ())
1010− let src0 = Prelude.take n backBuf
1011− -- XXX Use fromListRevN once implemented
1012− -- arr0 = A.fromListRevN n src0
1013− arr0 = fromListN n (Prelude.reverse src0)
1014− return (Right b, StreamK.fromPure arr0)
1015− Parser.Error err -> do
1016− let n = Prelude.length backBuf
1017− arr0 = fromListN n (Prelude.reverse backBuf)
1018− return (Left (ParseError err), StreamK.fromPure arr0)
core/src/Streamly/Internal/Data/Array/Generic.hs+6−22
@@ -11,8 +11,8 @@ module Streamly.Internal.Data.Array.Generic
1111
1212 -- * Construction
1313 , nil
14− , createOf
15− , create
14+ , writeN
15+ , write
1616 , writeWith
1717 , writeLastN
1818
@@ -44,10 +44,6 @@ module Streamly.Internal.Data.Array.Generic
4444 , getIndex
4545 , getSliceUnsafe
4646 , strip
47−
48− -- * Deprecated
49− , writeN
50− , write
5147 )
5248where
5349
@@ -108,33 +104,21 @@ nil = unsafePerformIO $ unsafeFreeze <$> MArray.nil
108104-- Construction - Folds
109105-------------------------------------------------------------------------------
110106
111−{-# INLINE_NORMAL createOf #-}
112−createOf :: MonadIO m => Int -> Fold m a (Array a)
113−createOf = fmap unsafeFreeze <$> MArray.createOf
114−
115−-- XXX Deprecate in major
116−-- {-# DEPRECATED writeN "Please use createOf instead." #-}
117−{-# INLINE writeN #-}
107+{-# INLINE_NORMAL writeN #-}
118108writeN :: MonadIO m => Int -> Fold m a (Array a)
119−writeN = createOf
109+writeN = fmap unsafeFreeze <$> MArray.writeN
120110
121111{-# INLINE_NORMAL writeWith #-}
122112writeWith :: MonadIO m => Int -> Fold m a (Array a)
123−writeWith elemCount = unsafeFreeze <$> MArray.createWith elemCount
113+writeWith elemCount = unsafeFreeze <$> MArray.writeWith elemCount
124114
125115-- | Fold the whole input to a single array.
126116--
127117-- /Caution! Do not use this on infinite streams./
128118--
129−{-# INLINE create #-}
130−create :: MonadIO m => Fold m a (Array a)
131−create = fmap unsafeFreeze MArray.create
132−
133−-- XXX Deprecate in major
134−-- {-# DEPRECATED write "Please use create instead." #-}
135119{-# INLINE write #-}
136120write :: MonadIO m => Fold m a (Array a)
137−write = create
121+write = fmap unsafeFreeze MArray.write
138122
139123fromPureStream :: Stream Identity a -> Array a
140124fromPureStream x =
core/src/Streamly/Internal/Data/Array/Stream.hs+474−15
@@ -12,7 +12,6 @@
1212-- keep this as a separate module and release it.
1313--
1414module Streamly.Internal.Data.Array.Stream
15−{-# DEPRECATED "Please use \"Streamly.Internal.Data.Array\" instead." #-}
1615 (
1716 -- * Creation
1817 Array.chunksOf
@@ -20,13 +19,13 @@ module Streamly.Internal.Data.Array.Stream
2019 , Array.bufferChunks
2120
2221 -- * Flattening to elements
23− , Array.concat
22+ , concat
2423 , Array.flattenArrays
25− , Array.concatRev
24+ , concatRev
2625 , Array.flattenArraysRev
27− , Array.interpose
28− , Array.interposeSuffix
29− , Array.intercalateSuffix
26+ , interpose
27+ , interposeSuffix
28+ , intercalateSuffix
3029 , unlines
3130
3231 -- * Elimination
@@ -96,9 +95,14 @@ import Streamly.Internal.Data.Parser (ParseError(..))
9695import Streamly.Internal.Data.Stream (Stream)
9796import Streamly.Internal.Data.StreamK (StreamK, fromStream, toStream)
9897import Streamly.Internal.Data.SVar.Type (adaptState, defState)
98+import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
9999
100+import qualified Streamly.Data.Fold as FL
100101import qualified Streamly.Internal.Data.Array as A
101102import qualified Streamly.Internal.Data.Array as Array
103+import qualified Streamly.Internal.Data.MutArray.Type as MA
104+import qualified Streamly.Internal.Data.MutArray.Stream as AS
105+import qualified Streamly.Internal.Data.Fold.Type as FL (Fold(..), Step(..))
102106import qualified Streamly.Internal.Data.Parser as PR
103107import qualified Streamly.Internal.Data.Parser as PRD
104108 (Parser(..), Initial(..))
@@ -109,19 +113,110 @@ import qualified Streamly.Internal.Data.StreamK as K
109113-- XXX Since these are immutable arrays MonadIO constraint can be removed from
110114-- most places.
111115
116+-------------------------------------------------------------------------------
117+-- Append
118+-------------------------------------------------------------------------------
119+
120+-- XXX efficiently compare two streams of arrays. Two streams can have chunks
121+-- of different sizes, we can handle that in the stream comparison abstraction.
122+-- This could be useful e.g. to fast compare whether two files differ.
123+
124+-- | Convert a stream of arrays into a stream of their elements.
125+--
126+-- Same as the following:
127+--
128+-- > concat = Stream.unfoldMany Array.read
129+--
130+-- @since 0.7.0
131+{-# INLINE concat #-}
132+concat :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
133+-- concat m = fromStreamD $ A.flattenArrays (toStreamD m)
134+-- concat m = fromStreamD $ D.concatMap A.toStreamD (toStreamD m)
135+concat = D.unfoldMany A.reader
136+
137+-- | Convert a stream of arrays into a stream of their elements reversing the
138+-- contents of each array before flattening.
139+--
140+-- > concatRev = Stream.unfoldMany Array.readerRev
141+--
142+-- @since 0.7.0
143+{-# INLINE concatRev #-}
144+concatRev :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
145+-- concatRev m = fromStreamD $ A.flattenArraysRev (toStreamD m)
146+concatRev = D.unfoldMany A.readerRev
147+
112148-------------------------------------------------------------------------------
113149-- Intersperse and append
114150-------------------------------------------------------------------------------
115151
152+-- | Flatten a stream of arrays after inserting the given element between
153+-- arrays.
154+--
155+-- /Pre-release/
156+{-# INLINE interpose #-}
157+interpose :: (Monad m, Unbox a) => a -> Stream m (Array a) -> Stream m a
158+interpose x = D.interpose x A.reader
159+
160+{-# INLINE intercalateSuffix #-}
161+intercalateSuffix :: (Monad m, Unbox a)
162+ => Array a -> Stream m (Array a) -> Stream m a
163+intercalateSuffix = D.intercalateSuffix A.reader
164+
165+-- | Flatten a stream of arrays appending the given element after each
166+-- array.
167+--
168+-- @since 0.7.0
169+{-# INLINE interposeSuffix #-}
170+interposeSuffix :: (Monad m, Unbox a)
171+ => a -> Stream m (Array a) -> Stream m a
172+-- interposeSuffix x = fromStreamD . A.unlines x . toStreamD
173+interposeSuffix x = D.interposeSuffix x A.reader
174+
175+data FlattenState s =
176+ OuterLoop s
177+ | InnerLoop s !MA.MutableByteArray !Int !Int
178+
179+-- XXX This is a special case of interposeSuffix, can be removed.
180+-- XXX Remove monadIO constraint
116181{-# INLINE_NORMAL unlines #-}
117182unlines :: forall m a. (MonadIO m, Unbox a)
118183 => a -> D.Stream m (Array a) -> D.Stream m a
119−unlines = Array.interposeSuffix
184+unlines sep (D.Stream step state) = D.Stream step' (OuterLoop state)
185+ where
186+ {-# INLINE_LATE step' #-}
187+ step' gst (OuterLoop st) = do
188+ r <- step (adaptState gst) st
189+ return $ case r of
190+ D.Yield Array{..} s ->
191+ D.Skip (InnerLoop s arrContents arrStart arrEnd)
192+ D.Skip s -> D.Skip (OuterLoop s)
193+ D.Stop -> D.Stop
194+
195+ step' _ (InnerLoop st _ p end) | p == end =
196+ return $ D.Yield sep $ OuterLoop st
197+
198+ step' _ (InnerLoop st contents p end) = do
199+ x <- liftIO $ peekByteIndex p contents
200+ return $ D.Yield x (InnerLoop st contents (INDEX_NEXT(p,a)) end)
120201
121202-------------------------------------------------------------------------------
122203-- Compact
123204-------------------------------------------------------------------------------
124205
206+-- XXX These would not be needed once we implement compactLEFold, see
207+-- module Streamly.Internal.Data.Stream.MutChunked
208+--
209+-- XXX Note that this thaws immutable arrays for appending, that may be
210+-- problematic if multiple users do the same thing, however, immutable arrays
211+-- would usually have no capacity to append, therefore, a copy will be forced
212+-- anyway. Confirm this. We can forcefully trim the array capacity before thaw
213+-- to ensure this.
214+{-# INLINE_NORMAL packArraysChunksOf #-}
215+packArraysChunksOf :: (MonadIO m, Unbox a)
216+ => Int -> D.Stream m (Array a) -> D.Stream m (Array a)
217+packArraysChunksOf n str =
218+ D.map A.unsafeFreeze $ AS.packArraysChunksOf n $ D.map A.unsafeThaw str
219+
125220-- XXX instead of writing two different versions of this operation, we should
126221-- write it as a pipe.
127222--
@@ -129,7 +224,8 @@ unlines = Array.interposeSuffix
129224{-# INLINE_NORMAL lpackArraysChunksOf #-}
130225lpackArraysChunksOf :: (MonadIO m, Unbox a)
131226 => Int -> Fold m (Array a) () -> Fold m (Array a) ()
132−lpackArraysChunksOf = Array.lCompactGE
227+lpackArraysChunksOf n fld =
228+ FL.lmap A.unsafeThaw $ AS.lpackArraysChunksOf n (FL.lmap A.unsafeFreeze fld)
133229
134230-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
135231-- maximum specified size in bytes.
@@ -138,7 +234,7 @@ lpackArraysChunksOf = Array.lCompactGE
138234{-# INLINE compact #-}
139235compact :: (MonadIO m, Unbox a)
140236 => Int -> Stream m (Array a) -> Stream m (Array a)
141−compact = Array.compactLE
237+compact = packArraysChunksOf
142238
143239-- | Given a stream of arrays, splice them all together to generate a single
144240-- array. The stream must be /finite/.
@@ -146,12 +242,71 @@ compact = Array.compactLE
146242-- @since 0.7.0
147243{-# INLINE toArray #-}
148244toArray :: (MonadIO m, Unbox a) => Stream m (Array a) -> m (Array a)
149−toArray = Array.fromChunks
245+toArray s =
246+ fmap A.unsafeFreeze $ MA.fromChunksRealloced (fmap A.unsafeThaw s)
150247
151248-------------------------------------------------------------------------------
152249-- Split
153250-------------------------------------------------------------------------------
154251
252+data SplitState s arr
253+ = Initial s
254+ | Buffering s arr
255+ | Splitting s arr
256+ | Yielding arr (SplitState s arr)
257+ | Finishing
258+
259+-- | Split a stream of arrays on a given separator byte, dropping the separator
260+-- and coalescing all the arrays between two separators into a single array.
261+--
262+-- @since 0.7.0
263+{-# INLINE_NORMAL _splitOn #-}
264+_splitOn
265+ :: MonadIO m
266+ => Word8
267+ -> D.Stream m (Array Word8)
268+ -> D.Stream m (Array Word8)
269+_splitOn byte (D.Stream step state) = D.Stream step' (Initial state)
270+
271+ where
272+
273+ {-# INLINE_LATE step' #-}
274+ step' gst (Initial st) = do
275+ r <- step gst st
276+ case r of
277+ D.Yield arr s -> do
278+ (arr1, marr2) <- A.breakOn byte arr
279+ return $ case marr2 of
280+ Nothing -> D.Skip (Buffering s arr1)
281+ Just arr2 -> D.Skip (Yielding arr1 (Splitting s arr2))
282+ D.Skip s -> return $ D.Skip (Initial s)
283+ D.Stop -> return D.Stop
284+
285+ step' gst (Buffering st buf) = do
286+ r <- step gst st
287+ case r of
288+ D.Yield arr s -> do
289+ (arr1, marr2) <- A.breakOn byte arr
290+ -- XXX Should use MutArray.splice
291+ buf' <- A.splice buf arr1
292+ return $ case marr2 of
293+ Nothing -> D.Skip (Buffering s buf')
294+ Just x -> D.Skip (Yielding buf' (Splitting s x))
295+ D.Skip s -> return $ D.Skip (Buffering s buf)
296+ D.Stop -> return $
297+ if A.byteLength buf == 0
298+ then D.Stop
299+ else D.Skip (Yielding buf Finishing)
300+
301+ step' _ (Splitting st buf) = do
302+ (arr1, marr2) <- A.breakOn byte buf
303+ return $ case marr2 of
304+ Nothing -> D.Skip $ Buffering st arr1
305+ Just arr2 -> D.Skip $ Yielding arr1 (Splitting st arr2)
306+
307+ step' _ (Yielding arr next) = return $ D.Yield arr next
308+ step' _ Finishing = return D.Stop
309+
155310-- XXX Remove MonadIO constraint.
156311-- | Split a stream of arrays on a given separator byte, dropping the separator
157312-- and coalescing all the arrays between two separators into a single array.
@@ -163,7 +318,11 @@ splitOn
163318 => Word8
164319 -> Stream m (Array Word8)
165320 -> Stream m (Array Word8)
166−splitOn = Array.compactOnByte
321+splitOn byte =
322+ fmap A.unsafeFreeze
323+ -- XXX use spliceExp and rightSize?
324+ . D.splitInnerBy (MA.breakOn byte) MA.splice
325+ . fmap A.unsafeThaw
167326
168327{-# INLINE splitOnSuffix #-}
169328splitOnSuffix
@@ -171,7 +330,13 @@ splitOnSuffix
171330 => Word8
172331 -> Stream m (Array Word8)
173332 -> Stream m (Array Word8)
174−splitOnSuffix = Array.compactOnByteSuffix
333+-- splitOn byte s = fromStreamD $ A.splitOn byte $ toStreamD s
334+splitOnSuffix byte =
335+ fmap A.unsafeFreeze
336+ -- XXX use spliceExp and rightSize?
337+ . D.splitInnerBySuffix
338+ (\arr -> MA.byteLength arr == 0) (MA.breakOn byte) MA.splice
339+ . fmap A.unsafeThaw
175340
176341-------------------------------------------------------------------------------
177342-- Elimination - Running folds
@@ -180,7 +345,71 @@ splitOnSuffix = Array.compactOnByteSuffix
180345{-# INLINE_NORMAL foldBreakD #-}
181346foldBreakD :: forall m a b. (MonadIO m, Unbox a) =>
182347 Fold m a b -> D.Stream m (Array a) -> m (b, D.Stream m (Array a))
183−foldBreakD = Array.foldBreakChunks
348+foldBreakD (FL.Fold fstep initial _ final) stream@(D.Stream step state) = do
349+ res <- initial
350+ case res of
351+ FL.Partial fs -> go SPEC state fs
352+ FL.Done fb -> return $! (fb, stream)
353+
354+ where
355+
356+ {-# INLINE go #-}
357+ go !_ st !fs = do
358+ r <- step defState st
359+ case r of
360+ D.Yield (Array contents start end) s ->
361+ let fp = Tuple' end contents
362+ in goArray SPEC s fp start fs
363+ D.Skip s -> go SPEC s fs
364+ D.Stop -> do
365+ b <- final fs
366+ return (b, D.nil)
367+
368+ goArray !_ s (Tuple' end _) !cur !fs
369+ | cur == end = do
370+ go SPEC s fs
371+ goArray !_ st fp@(Tuple' end contents) !cur !fs = do
372+ x <- liftIO $ peekByteIndex cur contents
373+ res <- fstep fs x
374+ let next = INDEX_NEXT(cur,a)
375+ case res of
376+ FL.Done b -> do
377+ let arr = Array contents next end
378+ return $! (b, D.cons arr (D.Stream step st))
379+ FL.Partial fs1 -> goArray SPEC st fp next fs1
380+
381+{-# INLINE_NORMAL foldBreakK #-}
382+foldBreakK :: forall m a b. (MonadIO m, Unbox a) =>
383+ Fold m a b -> K.StreamK m (Array a) -> m (b, K.StreamK m (Array a))
384+foldBreakK (FL.Fold fstep initial _ final) stream = do
385+ res <- initial
386+ case res of
387+ FL.Partial fs -> go fs stream
388+ FL.Done fb -> return (fb, stream)
389+
390+ where
391+
392+ {-# INLINE go #-}
393+ go !fs st = do
394+ let stop = (, K.nil) <$> final fs
395+ single a = yieldk a K.nil
396+ yieldk (Array contents start end) r =
397+ let fp = Tuple' end contents
398+ in goArray fs r fp start
399+ in K.foldStream defState yieldk single stop st
400+
401+ goArray !fs st (Tuple' end _) !cur
402+ | cur == end = do
403+ go fs st
404+ goArray !fs st fp@(Tuple' end contents) !cur = do
405+ x <- liftIO $ peekByteIndex cur contents
406+ res <- fstep fs x
407+ let next = INDEX_NEXT(cur,a)
408+ case res of
409+ FL.Done b -> do
410+ let arr = Array contents next end
411+ return $! (b, K.cons arr st)
412+ FL.Partial fs1 -> goArray fs1 st fp next
184413
185414-- | Fold an array stream using the supplied 'Fold'. Returns the fold result
186415-- and the unconsumed stream.
@@ -206,7 +435,7 @@ foldBreak ::
206435 => Fold m a b
207436 -> StreamK m (A.Array a)
208437 -> m (b, StreamK m (A.Array a))
209−foldBreak = Array.foldBreakChunksK
438+foldBreak = foldBreakK
210439--
211440-- foldBreak f s = fmap fromStreamD <$> foldBreakD f (toStreamD s)
212441--
@@ -270,6 +499,236 @@ splitAtArrayListRev n ls
270499{-# ANN type List NoSpecConstr #-}
271500newtype List a = List {getList :: [a]}
272501
502+{-
503+-- This can be generalized to any type provided it can be unfolded to a stream
504+-- and it can be combined using a semigroup operation.
505+--
506+-- XXX This should be written using CPS (as parseK) if we want it to scale wrt
507+-- to the number of times it can be called on the same stream.
508+{-# INLINE_NORMAL parseBreakD #-}
509+parseBreakD ::
510+ forall m a b. (MonadIO m, MonadThrow m, Unbox a)
511+ => PRD.Parser a m b
512+ -> D.Stream m (Array.Array a)
513+ -> m (b, D.Stream m (Array.Array a))
514+parseBreakD
515+ (PRD.Parser pstep initial extract) stream@(D.Stream step state) = do
516+
517+ res <- initial
518+ case res of
519+ PRD.IPartial s -> go SPEC state (List []) s
520+ PRD.IDone b -> return (b, stream)
521+ PRD.IError err -> throwM $ ParseError err
522+
523+ where
524+
525+ -- "backBuf" contains last few items in the stream that we may have to
526+ -- backtrack to.
527+ --
528+ -- XXX currently we are using a dumb list based approach for backtracking
529+ -- buffer. This can be replaced by a sliding/ring buffer using Data.Array.
530+ -- That will allow us more efficient random back and forth movement.
531+ go !_ st backBuf !pst = do
532+ r <- step defState st
533+ case r of
534+ D.Yield (Array contents start end) s ->
535+ gobuf SPEC s backBuf
536+ (Tuple' end contents) start pst
537+ D.Skip s -> go SPEC s backBuf pst
538+ D.Stop -> do
539+ b <- extract pst
540+ return (b, D.nil)
541+
542+ -- Use strictness on "cur" to keep it unboxed
543+ gobuf !_ s backBuf (Tuple' end _) !cur !pst
544+ | cur == end = do
545+ go SPEC s backBuf pst
546+ gobuf !_ s backBuf fp@(Tuple' end contents) !cur !pst = do
547+ x <- liftIO $ peekByteIndex contents cur
548+ pRes <- pstep pst x
549+ let next = INDEX_NEXT(cur,a)
550+ case pRes of
551+ PR.Partial 0 pst1 ->
552+ gobuf SPEC s (List []) fp next pst1
553+ PR.Partial n pst1 -> do
554+ assert (n <= Prelude.length (x:getList backBuf)) (return ())
555+ let src0 = Prelude.take n (x:getList backBuf)
556+ arr0 = A.fromListN n (Prelude.reverse src0)
557+ arr1 = Array contents next end
558+ src = arr0 <> arr1
559+ let !(Array cont1 start end1) = src
560+ fp1 = Tuple' end1 cont1
561+ gobuf SPEC s (List []) fp1 start pst1
562+ PR.Continue 0 pst1 ->
563+ gobuf SPEC s (List (x:getList backBuf)) fp next pst1
564+ PR.Continue n pst1 -> do
565+ assert (n <= Prelude.length (x:getList backBuf)) (return ())
566+ let (src0, buf1) = splitAt n (x:getList backBuf)
567+ arr0 = A.fromListN n (Prelude.reverse src0)
568+ arr1 = Array contents next end
569+ src = arr0 <> arr1
570+ let !(Array cont1 start end1) = src
571+ fp1 = Tuple' end1 cont1
572+ gobuf SPEC s (List buf1) fp1 start pst1
573+ PR.Done 0 b -> do
574+ let arr = Array contents next end
575+ return (b, D.cons arr (D.Stream step s))
576+ PR.Done n b -> do
577+ assert (n <= Prelude.length (x:getList backBuf)) (return ())
578+ let src0 = Prelude.take n (x:getList backBuf)
579+ -- XXX create the array in reverse instead
580+ arr0 = A.fromListN n (Prelude.reverse src0)
581+ arr1 = Array contents next end
582+ -- XXX Use StreamK to avoid adding arbitrary layers of
583+ -- constructors every time.
584+ str = D.cons arr0 (D.cons arr1 (D.Stream step s))
585+ return (b, str)
586+ PR.Error err -> throwM $ ParseError err
587+-}
588+
589+{-# INLINE_NORMAL parseBreakK #-}
590+parseBreakK ::
591+ forall m a b. (MonadIO m, Unbox a)
592+ => PRD.Parser a m b
593+ -> K.StreamK m (Array.Array a)
594+ -> m (Either ParseError b, K.StreamK m (Array.Array a))
595+parseBreakK (PRD.Parser pstep initial extract) stream = do
596+ res <- initial
597+ case res of
598+ PRD.IPartial s -> go s stream []
599+ PRD.IDone b -> return (Right b, stream)
600+ PRD.IError err -> return (Left (ParseError err), stream)
601+
602+ where
603+
604+ -- "backBuf" contains last few items in the stream that we may have to
605+ -- backtrack to.
606+ --
607+ -- XXX currently we are using a dumb list based approach for backtracking
608+ -- buffer. This can be replaced by a sliding/ring buffer using Data.Array.
609+ -- That will allow us more efficient random back and forth movement.
610+ go !pst st backBuf = do
611+ let stop = goStop pst backBuf -- (, K.nil) <$> extract pst
612+ single a = yieldk a K.nil
613+ yieldk arr r = goArray pst backBuf r arr
614+ in K.foldStream defState yieldk single stop st
615+
616+ -- Use strictness on "cur" to keep it unboxed
617+ goArray !pst backBuf st (Array _ cur end) | cur == end = go pst st backBuf
618+ goArray !pst backBuf st (Array contents cur end) = do
619+ x <- liftIO $ peekByteIndex cur contents
620+ pRes <- pstep pst x
621+ let next = INDEX_NEXT(cur,a)
622+ case pRes of
623+ PR.Partial 0 s ->
624+ goArray s [] st (Array contents next end)
625+ PR.Partial n s -> do
626+ assert (n <= Prelude.length (x:backBuf)) (return ())
627+ let src0 = Prelude.take n (x:backBuf)
628+ arr0 = A.fromListN n (Prelude.reverse src0)
629+ arr1 = Array contents next end
630+ src = arr0 <> arr1
631+ goArray s [] st src
632+ PR.Continue 0 s ->
633+ goArray s (x:backBuf) st (Array contents next end)
634+ PR.Continue n s -> do
635+ assert (n <= Prelude.length (x:backBuf)) (return ())
636+ let (src0, buf1) = splitAt n (x:backBuf)
637+ arr0 = A.fromListN n (Prelude.reverse src0)
638+ arr1 = Array contents next end
639+ src = arr0 <> arr1
640+ goArray s buf1 st src
641+ PR.Done 0 b -> do
642+ let arr = Array contents next end
643+ return (Right b, K.cons arr st)
644+ PR.Done n b -> do
645+ assert (n <= Prelude.length (x:backBuf)) (return ())
646+ let src0 = Prelude.take n (x:backBuf)
647+ -- XXX Use fromListRevN once implemented
648+ -- arr0 = A.fromListRevN n src0
649+ arr0 = A.fromListN n (Prelude.reverse src0)
650+ arr1 = Array contents next end
651+ str = K.cons arr0 (K.cons arr1 st)
652+ return (Right b, str)
653+ PR.Error err -> do
654+ let n = Prelude.length backBuf
655+ arr0 = A.fromListN n (Prelude.reverse backBuf)
656+ arr1 = Array contents cur end
657+ str = K.cons arr0 (K.cons arr1 stream)
658+ return (Left (ParseError err), str)
659+
660+ -- This is a simplified goArray
661+ goExtract !pst backBuf (Array _ cur end)
662+ | cur == end = goStop pst backBuf
663+ goExtract !pst backBuf (Array contents cur end) = do
664+ x <- liftIO $ peekByteIndex cur contents
665+ pRes <- pstep pst x
666+ let next = INDEX_NEXT(cur,a)
667+ case pRes of
668+ PR.Partial 0 s ->
669+ goExtract s [] (Array contents next end)
670+ PR.Partial n s -> do
671+ assert (n <= Prelude.length (x:backBuf)) (return ())
672+ let src0 = Prelude.take n (x:backBuf)
673+ arr0 = A.fromListN n (Prelude.reverse src0)
674+ arr1 = Array contents next end
675+ src = arr0 <> arr1
676+ goExtract s [] src
677+ PR.Continue 0 s ->
678+ goExtract s backBuf (Array contents next end)
679+ PR.Continue n s -> do
680+ assert (n <= Prelude.length (x:backBuf)) (return ())
681+ let (src0, buf1) = splitAt n (x:backBuf)
682+ arr0 = A.fromListN n (Prelude.reverse src0)
683+ arr1 = Array contents next end
684+ src = arr0 <> arr1
685+ goExtract s buf1 src
686+ PR.Done 0 b -> do
687+ let arr = Array contents next end
688+ return (Right b, K.fromPure arr)
689+ PR.Done n b -> do
690+ assert (n <= Prelude.length backBuf) (return ())
691+ let src0 = Prelude.take n backBuf
692+ -- XXX Use fromListRevN once implemented
693+ -- arr0 = A.fromListRevN n src0
694+ arr0 = A.fromListN n (Prelude.reverse src0)
695+ arr1 = Array contents next end
696+ str = K.cons arr0 (K.fromPure arr1)
697+ return (Right b, str)
698+ PR.Error err -> do
699+ let n = Prelude.length backBuf
700+ arr0 = A.fromListN n (Prelude.reverse backBuf)
701+ arr1 = Array contents cur end
702+ str = K.cons arr0 (K.cons arr1 stream)
703+ return (Left (ParseError err), str)
704+
705+ -- This is a simplified goExtract
706+ {-# INLINE goStop #-}
707+ goStop !pst backBuf = do
708+ pRes <- extract pst
709+ case pRes of
710+ PR.Partial _ _ -> error "Bug: parseBreak: Partial in extract"
711+ PR.Continue 0 s ->
712+ goStop s backBuf
713+ PR.Continue n s -> do
714+ assert (n <= Prelude.length backBuf) (return ())
715+ let (src0, buf1) = splitAt n backBuf
716+ arr = A.fromListN n (Prelude.reverse src0)
717+ goExtract s buf1 arr
718+ PR.Done 0 b ->
719+ return (Right b, K.nil)
720+ PR.Done n b -> do
721+ assert (n <= Prelude.length backBuf) (return ())
722+ let src0 = Prelude.take n backBuf
723+ -- XXX Use fromListRevN once implemented
724+ -- arr0 = A.fromListRevN n src0
725+ arr0 = A.fromListN n (Prelude.reverse src0)
726+ return (Right b, K.fromPure arr0)
727+ PR.Error err -> do
728+ let n = Prelude.length backBuf
729+ arr0 = A.fromListN n (Prelude.reverse backBuf)
730+ return (Left (ParseError err), K.fromPure arr0)
731+
273732-- | Parse an array stream using the supplied 'Parser'. Returns the parse
274733-- result and the unconsumed stream. Throws 'ParseError' if the parse fails.
275734--
@@ -293,7 +752,7 @@ parseBreak ::
293752parseBreak p s =
294753 fmap fromStreamD <$> parseBreakD (PRD.fromParserK p) (toStreamD s)
295754-}
296−parseBreak = Array.parseBreakChunksK
755+parseBreak = parseBreakK
297756-- parseBreak p = K.parseBreakChunks (ParserK.adaptC p)
298757
299758-------------------------------------------------------------------------------
core/src/Streamly/Internal/Data/Array/Type.hs+96−341
@@ -1,11 +1,8 @@
11{-# LANGUAGE CPP #-}
2−{-# LANGUAGE TypeFamilies #-}
3−-- Must come after TypeFamilies, otherwise it is re-enabled.
4−-- MonoLocalBinds enabled by TypeFamilies causes perf regressions in general.
5−{-# LANGUAGE NoMonoLocalBinds #-}
62-- |
73-- Module : Streamly.Internal.Data.Array.Type
84-- Copyright : (c) 2020 Composewell Technologies
5+--
96-- License : BSD3-3-Clause
107-- Maintainer : streamly@composewell.com
118-- Stability : experimental
@@ -13,57 +10,33 @@
1310--
1411-- See notes in "Streamly.Internal.Data.MutArray.Type"
1512--
16−
1713module Streamly.Internal.Data.Array.Type
1814 (
1915 -- ** Type
2016 -- $arrayNotes
2117 Array (..)
18+ , asPtrUnsafe
19+ , nil
2220
23− -- ** Conversion
24− -- *** Mutable and Immutable
21+ -- ** Freezing and Thawing
2522 , unsafeFreeze
2623 , unsafeFreezeWithShrink
2724 , unsafeThaw
2825
29− -- *** Pinned and Unpinned
26+ -- ** Pinning and Unpinning
3027 , pin
3128 , unpin
3229 , isPinned
3330
34− -- *** Casting
35− , unsafePinnedAsPtr
36−
3731 -- ** Construction
38− , empty
39−
40− -- *** Cloning
41− -- XXX Why would we clone an immutable array?
42− , clone
43− , pinnedClone
32+ , splice
4433
45− -- *** Slicing
46− -- | Get a subarray without copying
47− , splitAt
48− , breakOn -- XXX requires MonadIO
49−
50− -- *** Stream Folds
51− , unsafeMakePure
52− , createOf
53− , pinnedCreateOf
54− , unsafeCreateOf
55− , unsafePinnedCreateOf
56− , create
57− , pinnedCreate
58− , createWith
59−
60− -- *** From containers
61− , fromListN
62− , pinnedFromListN
6334 , fromList
6435 , pinnedFromList
65− , fromListRevN
36+ , fromListN
37+ , pinnedFromListN
6638 , fromListRev
39+ , fromListRevN
6740 , fromStreamN
6841 , fromStream
6942 , fromPureStreamN
@@ -71,68 +44,58 @@ module Streamly.Internal.Data.Array.Type
7144 , fromByteStr#
7245 , fromByteStr
7346 , fromPtrN
74− , fromChunks
7547 , fromChunksK
7648
77− -- ** Reading
78−
79− -- *** Indexing
80− , unsafeIndexIO -- XXX unsafeGetIndexIO
81− , getIndexUnsafe -- XXX unsafeGetIndex
82−
83− -- *** To Streams
84− , read
85− , readRev
86− , toStreamK
87− , toStreamKRev
49+ -- ** Split
50+ , breakOn
8851
89− -- *** To Containers
90− , toList
91−
92− -- *** Unfolds
93− , producer -- experimental
94− , readerUnsafe
95− , reader
96− , readerRev
52+ -- ** Cloning arrays
53+ , clone
54+ , pinnedClone
9755
98− -- *** Size
99− , length
56+ -- ** Elimination
57+ , unsafeIndexIO
58+ , getIndexUnsafe
10059 , byteLength
60+ , length
10161
102− -- ** Folding
10362 , foldl'
10463 , foldr
64+ , splitAt
65+
66+ , toStreamD
67+ , toStreamDRev
68+ , toStreamK
69+ , toStreamKRev
70+ , toStream
71+ , toStreamRev
72+ , read
73+ , readRev
74+ , readerRev
75+ , toList
76+
77+ -- ** Folds
78+ , writeWith
79+ , writeN
80+ , pinnedWriteN
81+ , writeNUnsafe
82+ , pinnedWriteNUnsafe
83+ , MA.ArrayUnsafe (..)
84+ , pinnedWriteNAligned
85+ , write
86+ , pinnedWrite
87+ , unsafeMakePure
10588 , byteCmp
10689 , byteEq
10790
108− -- ** Appending
109− , splice -- XXX requires MonadIO
110−
11191 -- ** Streams of arrays
112− -- *** Chunk
113− -- | Group a stream into arrays.
11492 , chunksOf
11593 , pinnedChunksOf
11694 , buildChunks
117−
118− -- *** Split
119− -- | Split an array into slices.
120−
121− -- *** Concat
122− -- | Append the arrays in a stream to form a stream of elements.
123− , concat
124− , concatRev
125−
126− -- *** Compact
127− -- | Append the arrays in a stream to form a stream of larger arrays.
128− , fCompactGE
129− , fPinnedCompactGE
130− , lCompactGE
131− , lPinnedCompactGE
132− , compactGE
95+ , concatChunks
96+ , concatChunksRev
13397
13498 -- ** Deprecated
135− , asPtrUnsafe
13699 , unsafeIndex
137100 , bufferChunks
138101 , flattenArrays
@@ -140,19 +103,6 @@ module Streamly.Internal.Data.Array.Type
140103 , fromArrayStreamK
141104 , fromStreamDN
142105 , fromStreamD
143− , toStreamD
144− , toStreamDRev
145− , toStream
146− , toStreamRev
147− , nil
148− , writeWith
149− , writeN
150− , pinnedWriteN
151− , writeNUnsafe
152− , pinnedWriteNUnsafe
153− , pinnedWriteNAligned
154− , write
155− , pinnedWrite
156106 )
157107where
158108
@@ -171,9 +121,7 @@ import GHC.Exts (IsList, IsString(..), Addr#)
171121
172122import GHC.IO (unsafePerformIO)
173123import GHC.Ptr (Ptr(..))
174−import Streamly.Internal.Data.Producer.Type (Producer(..))
175−import Streamly.Internal.Data.MutArray.Type (MutArray(..))
176−import Streamly.Internal.Data.MutByteArray.Type (MutByteArray)
124+import Streamly.Internal.Data.MutArray.Type (MutArray(..), MutByteArray)
177125import Streamly.Internal.Data.Fold.Type (Fold(..))
178126import Streamly.Internal.Data.Stream.Type (Stream)
179127import Streamly.Internal.Data.StreamK.Type (StreamK)
@@ -181,15 +129,13 @@ import Streamly.Internal.Data.Unbox (Unbox(..))
181129import Streamly.Internal.Data.Unfold.Type (Unfold(..))
182130import Text.Read (readPrec)
183131
184−import Prelude hiding (Foldable(..), concat, read, unlines, splitAt)
132+import Prelude hiding (Foldable(..), read, unlines, splitAt)
185133
186134import qualified GHC.Exts as Exts
187−import qualified Streamly.Internal.Data.Fold.Type as Fold
188135import qualified Streamly.Internal.Data.MutArray.Type as MA
189136import qualified Streamly.Internal.Data.Stream.Type as D
190137import qualified Streamly.Internal.Data.StreamK.Type as K
191138import qualified Streamly.Internal.Data.MutByteArray.Type as Unboxed
192−import qualified Streamly.Internal.Data.Producer as Producer
193139import qualified Streamly.Internal.Data.Unfold.Type as Unfold
194140import qualified Text.ParserCombinators.ReadPrec as ReadPrec
195141
@@ -243,20 +189,15 @@ data Array a =
243189
244190-- | Use an @Array a@ as @Ptr a@.
245191--
246−-- See 'MA.unsafePinnedAsPtr' in the Mutable array module for more details.
192+-- See 'MA.asPtrUnsafe' in the Mutable array module for more details.
247193--
248194-- /Unsafe/
249195--
250196-- /Pre-release/
251197--
252−{-# INLINE unsafePinnedAsPtr #-}
253−unsafePinnedAsPtr :: MonadIO m => Array a -> (Ptr a -> m b) -> m b
254−unsafePinnedAsPtr arr = MA.unsafePinnedAsPtr (unsafeThaw arr)
255−
256−{-# DEPRECATED asPtrUnsafe "Please use unsafePinnedAsPtr instead." #-}
257198{-# INLINE asPtrUnsafe #-}
258199asPtrUnsafe :: MonadIO m => Array a -> (Ptr a -> m b) -> m b
259−asPtrUnsafe = unsafePinnedAsPtr
200+asPtrUnsafe arr = MA.asPtrUnsafe (unsafeThaw arr)
260201
261202-------------------------------------------------------------------------------
262203-- Freezing and Thawing
@@ -472,100 +413,37 @@ pinnedChunksOf :: forall m a. (MonadIO m, Unbox a)
472413 => Int -> D.Stream m a -> D.Stream m (Array a)
473414pinnedChunksOf n str = D.map unsafeFreeze $ MA.pinnedChunksOf n str
474415
475−-- | Convert a stream of arrays into a stream of their elements.
416+-- | Use the "reader" unfold instead.
476417--
477−-- >>> concat = Stream.unfoldMany Array.reader
418+-- @concatChunks = unfoldMany reader@
478419--
479−{-# INLINE_NORMAL concat #-}
480−concat :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
481−-- XXX this requires MonadIO whereas the unfoldMany version does not
482−concat = MA.concatWith (pure . unsafeInlineIO) . D.map unsafeThaw
483−-- concat = D.unfoldMany reader
420+-- We can try this if there are any fusion issues in the unfold.
421+--
422+{-# INLINE_NORMAL concatChunks #-}
423+concatChunks :: forall m a. (MonadIO m, Unbox a)
424+ => D.Stream m (Array a) -> D.Stream m a
425+concatChunks = MA.concatChunks . D.map unsafeThaw
484426
485427{-# DEPRECATED flattenArrays "Please use \"unfoldMany reader\" instead." #-}
486−{-# INLINE flattenArrays #-}
487428flattenArrays :: forall m a. (MonadIO m, Unbox a)
488429 => D.Stream m (Array a) -> D.Stream m a
489−flattenArrays = concat
430+flattenArrays = concatChunks
490431
491−-- | Convert a stream of arrays into a stream of their elements reversing the
492−-- contents of each array before flattening.
432+-- | Use the "readerRev" unfold instead.
433+--
434+-- @concatChunksRev = unfoldMany readerRev@
493435--
494−-- >>> concatRev = Stream.unfoldMany Array.readerRev
436+-- We can try this if there are any fusion issues in the unfold.
495437--
496−{-# INLINE_NORMAL concatRev #-}
497−concatRev :: forall m a. (Monad m, Unbox a)
438+{-# INLINE_NORMAL concatChunksRev #-}
439+concatChunksRev :: forall m a. (MonadIO m, Unbox a)
498440 => D.Stream m (Array a) -> D.Stream m a
499−-- XXX this requires MonadIO whereas the unfoldMany version does not
500−concatRev = MA.concatRevWith (pure . unsafeInlineIO) . D.map unsafeThaw
501−-- concatRev = D.unfoldMany readerRev
441+concatChunksRev = MA.concatChunksRev . D.map unsafeThaw
502442
503443{-# DEPRECATED flattenArraysRev "Please use \"unfoldMany readerRev\" instead." #-}
504−{-# INLINE flattenArraysRev #-}
505444flattenArraysRev :: forall m a. (MonadIO m, Unbox a)
506445 => D.Stream m (Array a) -> D.Stream m a
507−flattenArraysRev = concatRev
508−
509−-------------------------------------------------------------------------------
510−-- Compact
511−-------------------------------------------------------------------------------
512−
513−-- XXX Note that this thaws immutable arrays for appending, that may be
514−-- problematic if multiple users do the same thing, however, thawed immutable
515−-- arrays would have no capacity to append, therefore, a copy will be forced
516−-- anyway.
517−
518−-- | Fold @fCompactGE n@ coalesces adjacent arrays in the input stream
519−-- until the size becomes greater than or equal to n.
520−--
521−-- Generates unpinned arrays irrespective of the pinning status of input
522−-- arrays.
523−{-# INLINE_NORMAL fCompactGE #-}
524−fCompactGE :: (MonadIO m, Unbox a) => Int -> Fold m (Array a) (Array a)
525−fCompactGE n = fmap unsafeFreeze $ Fold.lmap unsafeThaw $ MA.fCompactGE n
526−
527−-- | PInned version of 'fCompactGE'.
528−{-# INLINE_NORMAL fPinnedCompactGE #-}
529−fPinnedCompactGE :: (MonadIO m, Unbox a) => Int -> Fold m (Array a) (Array a)
530−fPinnedCompactGE n =
531− fmap unsafeFreeze $ Fold.lmap unsafeThaw $ MA.fPinnedCompactGE n
532−
533−-- | @compactGE n stream@ coalesces adjacent arrays in the @stream@ until
534−-- the size becomes greater than or equal to @n@.
535−--
536−-- >>> compactGE n = Stream.foldMany (Array.fCompactGE n)
537−--
538−-- Generates unpinned arrays irrespective of the pinning status of input
539−-- arrays.
540−{-# INLINE compactGE #-}
541−compactGE ::
542− (MonadIO m, Unbox a)
543− => Int -> Stream m (Array a) -> Stream m (Array a)
544−compactGE n stream =
545− D.map unsafeFreeze $ MA.compactGE n $ D.map unsafeThaw stream
546−
547−-- | Like 'compactGE' but for transforming folds instead of stream.
548−--
549−-- >>> lCompactGE n = Fold.many (Array.fCompactGE n)
550−--
551−-- Generates unpinned arrays irrespective of the pinning status of input
552−-- arrays.
553−{-# INLINE_NORMAL lCompactGE #-}
554−lCompactGE :: (MonadIO m, Unbox a)
555− => Int -> Fold m (Array a) () -> Fold m (Array a) ()
556−lCompactGE n fld =
557− Fold.lmap unsafeThaw $ MA.lCompactGE n (Fold.lmap unsafeFreeze fld)
558−
559−-- | Pinned version of 'lCompactGE'.
560−{-# INLINE_NORMAL lPinnedCompactGE #-}
561−lPinnedCompactGE :: (MonadIO m, Unbox a)
562− => Int -> Fold m (Array a) () -> Fold m (Array a) ()
563−lPinnedCompactGE n fld =
564− Fold.lmap unsafeThaw $ MA.lPinnedCompactGE n (Fold.lmap unsafeFreeze fld)
565−
566−-------------------------------------------------------------------------------
567−-- Splitting
568−-------------------------------------------------------------------------------
446+flattenArraysRev = concatChunksRev
569447
570448-- Drops the separator byte
571449{-# INLINE breakOn #-}
@@ -609,68 +487,24 @@ byteLength = MA.byteLength . unsafeThaw
609487length :: Unbox a => Array a -> Int
610488length arr = MA.length (unsafeThaw arr)
611489
612−{-# INLINE_NORMAL producer #-}
613−producer :: forall m a. (Monad m, Unbox a) => Producer m (Array a) a
614−producer =
615− Producer.translate unsafeThaw unsafeFreeze
616− $ MA.producerWith (return . unsafeInlineIO)
617−
618−-- | Unfold an array into a stream.
619−--
620−{-# INLINE_NORMAL reader #-}
621−reader :: forall m a. (Monad m, Unbox a) => Unfold m (Array a) a
622−reader = Producer.simplify producer
623−
624−-- | Unfold an array into a stream, does not check the end of the array, the
625−-- user is responsible for terminating the stream within the array bounds. For
626−-- high performance application where the end condition can be determined by
627−-- a terminating fold.
628−--
629−-- Written in the hope that it may be faster than "read", however, in the case
630−-- for which this was written, "read" proves to be faster even though the core
631−-- generated with unsafeRead looks simpler.
632−--
633−-- /Pre-release/
634−--
635−{-# INLINE_NORMAL readerUnsafe #-}
636−readerUnsafe :: forall m a. (Monad m, Unbox a) => Unfold m (Array a) a
637−readerUnsafe = Unfold step inject
638− where
639−
640− inject (Array contents start end) =
641− return (MA.ArrayUnsafe contents end start)
642−
643− {-# INLINE_LATE step #-}
644− step (MA.ArrayUnsafe contents end p) = do
645− -- unsafeInlineIO allows us to run this in Identity monad for pure
646− -- toList/foldr case which makes them much faster due to not
647− -- accumulating the list and fusing better with the pure consumers.
648− --
649− -- This should be safe as the array contents are guaranteed to be
650− -- evaluated/written to before we peek at them.
651− let !x = unsafeInlineIO $ peekAt p contents
652− let !p1 = INDEX_NEXT(p,a)
653− return $ D.Yield x (MA.ArrayUnsafe contents end p1)
654−
655490-- | Unfold an array into a stream in reverse order.
656491--
657492{-# INLINE_NORMAL readerRev #-}
658493readerRev :: forall m a. (Monad m, Unbox a) => Unfold m (Array a) a
659494readerRev = Unfold.lmap unsafeThaw $ MA.readerRevWith (return . unsafeInlineIO)
660495
661−{-# DEPRECATED toStreamD "Please use 'read' instead." #-}
662496{-# INLINE_NORMAL toStreamD #-}
663497toStreamD :: forall m a. (Monad m, Unbox a) => Array a -> D.Stream m a
664−toStreamD = read
498+toStreamD arr = MA.toStreamDWith (return . unsafeInlineIO) (unsafeThaw arr)
665499
666500{-# INLINE toStreamK #-}
667501toStreamK :: forall m a. (Monad m, Unbox a) => Array a -> K.StreamK m a
668502toStreamK arr = MA.toStreamKWith (return . unsafeInlineIO) (unsafeThaw arr)
669503
670−{-# DEPRECATED toStreamDRev "Please use 'readRev' instead." #-}
671504{-# INLINE_NORMAL toStreamDRev #-}
672505toStreamDRev :: forall m a. (Monad m, Unbox a) => Array a -> D.Stream m a
673−toStreamDRev = readRev
506+toStreamDRev arr =
507+ MA.toStreamDRevWith (return . unsafeInlineIO) (unsafeThaw arr)
674508
675509{-# INLINE toStreamKRev #-}
676510toStreamKRev :: forall m a. (Monad m, Unbox a) => Array a -> K.StreamK m a
@@ -682,7 +516,7 @@ toStreamKRev arr =
682516-- /Pre-release/
683517{-# INLINE_EARLY read #-}
684518read :: (Monad m, Unbox a) => Array a -> Stream m a
685−read arr = MA.toStreamWith (return . unsafeInlineIO) (unsafeThaw arr)
519+read = toStreamD
686520
687521-- | Same as 'read'
688522--
@@ -699,7 +533,7 @@ toStream = read
699533-- /Pre-release/
700534{-# INLINE_EARLY readRev #-}
701535readRev :: (Monad m, Unbox a) => Array a -> Stream m a
702−readRev arr = MA.toStreamRevWith (return . unsafeInlineIO) (unsafeThaw arr)
536+readRev = toStreamDRev
703537
704538-- | Same as 'readRev'
705539--
@@ -723,7 +557,6 @@ foldr f z arr = runIdentity $ D.foldr f z $ toStreamD arr
723557-- | Create two slices of an array without copying the original array. The
724558-- specified index @i@ is the first index of the second slice.
725559--
726−{-# INLINE splitAt #-}
727560splitAt :: Unbox a => Int -> Array a -> (Array a, Array a)
728561splitAt i arr = (unsafeFreeze a, unsafeFreeze b)
729562 where
@@ -757,28 +590,17 @@ toList s = build (\c n -> toListFB c n s)
757590-- Folds
758591-------------------------------------------------------------------------------
759592
760−-- | @createOf n@ folds a maximum of @n@ elements from the input stream to an
593+-- | @writeN n@ folds a maximum of @n@ elements from the input stream to an
761594-- 'Array'.
762595--
763−{-# INLINE_NORMAL createOf #-}
764−createOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
765−createOf = fmap unsafeFreeze . MA.createOf
766−
767−-- XXX Deprecate in major
768−-- {-# DEPRECATED writeN "Please use createOf instead." #-}
769−{-# INLINE writeN #-}
596+{-# INLINE_NORMAL writeN #-}
770597writeN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
771−writeN = createOf
772−
773−-- | Like 'createOf' but creates a pinned array.
774−{-# INLINE_NORMAL pinnedCreateOf #-}
775−pinnedCreateOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
776−pinnedCreateOf = fmap unsafeFreeze . MA.pinnedCreateOf
598+writeN = fmap unsafeFreeze . MA.writeN
777599
778−{-# DEPRECATED pinnedWriteN "Please use pinnedCreateOf instead." #-}
779−{-# INLINE pinnedWriteN #-}
600+-- | Like 'fromListN' but creates a pinned array.
601+{-# INLINE_NORMAL pinnedWriteN #-}
780602pinnedWriteN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
781−pinnedWriteN = pinnedCreateOf
603+pinnedWriteN = fmap unsafeFreeze . MA.pinnedWriteN
782604
783605-- | @pinnedWriteNAligned alignment n@ folds a maximum of @n@ elements from the input
784606-- stream to an 'Array' aligned to the given size.
@@ -786,74 +608,44 @@ pinnedWriteN = pinnedCreateOf
786608-- /Pre-release/
787609--
788610{-# INLINE_NORMAL pinnedWriteNAligned #-}
789−{-# DEPRECATED pinnedWriteNAligned "To be removed." #-}
790611pinnedWriteNAligned :: forall m a. (MonadIO m, Unbox a)
791612 => Int -> Int -> Fold m a (Array a)
792613pinnedWriteNAligned alignSize = fmap unsafeFreeze . MA.pinnedWriteNAligned alignSize
793614
794−-- | Like 'createOf' but does not check the array bounds when writing. The fold
615+-- | Like 'writeN' but does not check the array bounds when writing. The fold
795616-- driver must not call the step function more than 'n' times otherwise it will
796617-- corrupt the memory and crash. This function exists mainly because any
797618-- conditional in the step function blocks fusion causing 10x performance
798619-- slowdown.
799620--
800−{-# INLINE_NORMAL unsafeCreateOf #-}
801−unsafeCreateOf :: forall m a. (MonadIO m, Unbox a)
802− => Int -> Fold m a (Array a)
803−unsafeCreateOf n = unsafeFreeze <$> MA.unsafeCreateOf n
804−
805−{-# DEPRECATED writeNUnsafe "Please use unsafeCreateOf instead." #-}
806−{-# INLINE writeNUnsafe #-}
621+{-# INLINE_NORMAL writeNUnsafe #-}
807622writeNUnsafe :: forall m a. (MonadIO m, Unbox a)
808623 => Int -> Fold m a (Array a)
809−writeNUnsafe = unsafeCreateOf
810−
811−{-# INLINE_NORMAL unsafePinnedCreateOf #-}
812−unsafePinnedCreateOf :: forall m a. (MonadIO m, Unbox a)
813− => Int -> Fold m a (Array a)
814−unsafePinnedCreateOf n = unsafeFreeze <$> MA.unsafePinnedCreateOf n
624+writeNUnsafe n = unsafeFreeze <$> MA.writeNUnsafe n
815625
816−{-# DEPRECATED pinnedWriteNUnsafe "Please use unsafePinnedCreateOf instead." #-}
817−{-# INLINE pinnedWriteNUnsafe #-}
626+{-# INLINE_NORMAL pinnedWriteNUnsafe #-}
818627pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a)
819628 => Int -> Fold m a (Array a)
820−pinnedWriteNUnsafe = unsafePinnedCreateOf
629+pinnedWriteNUnsafe n = unsafeFreeze <$> MA.pinnedWriteNUnsafe n
821630
822−{-# INLINE_NORMAL createWith #-}
823−createWith :: forall m a. (MonadIO m, Unbox a)
824− => Int -> Fold m a (Array a)
825−-- createWith n = FL.rmapM spliceArrays $ toArraysOf n
826−createWith elemCount = unsafeFreeze <$> MA.createWith elemCount
827−
828−{-# DEPRECATED writeWith "Please use createWith instead." #-}
829−{-# INLINE writeWith #-}
631+{-# INLINE_NORMAL writeWith #-}
830632writeWith :: forall m a. (MonadIO m, Unbox a)
831633 => Int -> Fold m a (Array a)
832−writeWith = createWith
634+-- writeWith n = FL.rmapM spliceArrays $ toArraysOf n
635+writeWith elemCount = unsafeFreeze <$> MA.writeWith elemCount
833636
834637-- | Fold the whole input to a single array.
835638--
836639-- /Caution! Do not use this on infinite streams./
837640--
838−{-# INLINE create #-}
839−create :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
840−create = fmap unsafeFreeze MA.create
841−
842−-- XXX Deprecate in major
843−-- {-# DEPRECATED write "Please use create instead." #-}
844641{-# INLINE write #-}
845642write :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
846−write = create
847−
848−-- | Like 'create' but creates a pinned array.
849−{-# INLINE pinnedCreate #-}
850−pinnedCreate :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
851−pinnedCreate = fmap unsafeFreeze MA.pinnedCreate
643+write = fmap unsafeFreeze MA.write
852644
853−{-# DEPRECATED pinnedWrite "Please use pinnedCreate instead." #-}
645+-- | Like 'write' but creates a pinned array.
854646{-# INLINE pinnedWrite #-}
855647pinnedWrite :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
856−pinnedWrite = pinnedCreate
648+pinnedWrite = fmap unsafeFreeze MA.pinnedWrite
857649
858650-- | Fold "step" has a dependency on "initial", and each step is dependent on
859651-- the previous invocation of step due to state passing, finally extract
@@ -901,19 +693,13 @@ fromPureStream x = unsafePerformIO $ fmap (unsafeFreeze) (MA.fromPureStream x)
901693-- fromPureStream = runIdentity . D.fold (unsafeMakePure write)
902694-- fromPureStream = fromList . runIdentity . D.toList
903695
904−-- XXX This should be monadic.
905−
906696-- | Copy an immutable 'Ptr Word8' sequence into an array.
907697--
908698-- /Unsafe:/ The caller is responsible for safe addressing.
909699--
910−-- Note that this should be evaluated strictly to ensure that we do not hold
911−-- the reference to the pointer in a lazy thunk.
912700fromPtrN :: Int -> Ptr Word8 -> Array Word8
913701fromPtrN n addr = unsafePerformIO $ fmap unsafeFreeze (MA.fromPtrN n addr)
914702
915−-- XXX This should be monadic.
916−
917703-- | Copy a null terminated immutable 'Addr#' Word8 sequence into an array.
918704--
919705-- /Unsafe:/ The caller is responsible for safe addressing.
@@ -924,15 +710,9 @@ fromPtrN n addr = unsafePerformIO $ fmap unsafeFreeze (MA.fromPtrN n addr)
924710-- >>> Array.toList $ Array.fromByteStr# "\1\2\3\0"#
925711-- [1,2,3]
926712--
927−-- Note that this should be evaluated strictly to ensure that we do not hold
928−-- the reference to the pointer in a lazy thunk.
929713fromByteStr# :: Addr# -> Array Word8
930714fromByteStr# addr = unsafePerformIO $ fmap unsafeFreeze (MA.fromByteStr# addr)
931715
932−-- XXX This should be monadic.
933−
934−-- | Note that this should be evaluated strictly to ensure that we do not hold
935−-- the reference to the pointer in a lazy thunk.
936716fromByteStr :: Ptr Word8 -> Array Word8
937717fromByteStr (Ptr addr#) = fromByteStr# addr#
938718
@@ -942,29 +722,14 @@ fromByteStr (Ptr addr#) = fromByteStr# addr#
942722-- that is double the size of the array stream.
943723--
944724{-# INLINE fromChunksK #-}
945−fromChunksK :: (MonadIO m, Unbox a) => StreamK m (Array a) -> m (Array a)
725+fromChunksK :: (Unbox a, MonadIO m) => StreamK m (Array a) -> m (Array a)
946726fromChunksK stream =
947− -- We buffer the entire stream and then allocate the target array of the
948− -- same size, thus requiring double the memory.
949727 fmap unsafeFreeze $ MA.fromChunksK $ fmap unsafeThaw stream
950728
951729{-# DEPRECATED fromArrayStreamK "Please use fromChunksK instead." #-}
952730fromArrayStreamK :: (Unbox a, MonadIO m) => StreamK m (Array a) -> m (Array a)
953731fromArrayStreamK = fromChunksK
954732
955−-- | Given a stream of arrays, splice them all together to generate a single
956−-- array. The stream must be /finite/.
957−--
958−{-# INLINE fromChunks #-}
959−fromChunks :: (MonadIO m, Unbox a) => Stream m (Array a) -> m (Array a)
960−fromChunks s =
961− -- XXX Check which implementation is better
962− -- This may also require double the memory as we double the space every
963− -- time, when copying the last array we may have reallocated almost double
964− -- the space required before we right size it.
965− fmap unsafeFreeze $ MA.fromChunksRealloced (fmap unsafeThaw s)
966− -- fromChunkStreamK $ D.toStreamK s
967−
968733-------------------------------------------------------------------------------
969734-- Instances
970735-------------------------------------------------------------------------------
@@ -1007,7 +772,6 @@ instance Unbox a => IsList (Array a) where
1007772{-# INLINE byteCmp #-}
1008773byteCmp :: Array a -> Array a -> Ordering
1009774byteCmp arr1 arr2 =
1010− -- unsafePerformIO?
1011775 unsafeInlineIO $! unsafeThaw arr1 `MA.byteCmp` unsafeThaw arr2
1012776
1013777-- | Byte equality of two arrays.
@@ -1029,21 +793,20 @@ MK_EQ_INSTANCE(Char)
1029793MK_EQ_INSTANCE(Word8)
1030794MK_EQ_INSTANCE(Word16)
1031795MK_EQ_INSTANCE(Word32)
1032−
1033−-- XXX The Word64 default instance should be as fast because we are comparing
1034−-- 64-bit at a time.
1035796MK_EQ_INSTANCE(Word64)
1036797MK_EQ_INSTANCE(Int)
1037798MK_EQ_INSTANCE(Int8)
1038799MK_EQ_INSTANCE(Int16)
1039800MK_EQ_INSTANCE(Int32)
1040−
1041−-- XXX The Int64 default instance should be as fast.
1042801MK_EQ_INSTANCE(Int64)
1043802
1044−-- | If the type allows a byte-by-byte comparison this instance can be
1045−-- overlapped by a more specific instance that uses 'byteCmp'. Byte comparison
1046−-- can be significantly faster.
803+-- | If the type allows a byte-by-byte comparison (see 'byteCmp') this instance
804+-- can be overlapped by a more specific instance that uses a byte comparison.
805+-- Byte comparison can be significantly faster.
806+--
807+-- For example:
808+--
809+-- >>> (==) = byteCmp
1047810--
1048811instance {-# OVERLAPPABLE #-} (Unbox a, Eq a) => Eq (Array a) where
1049812 {-# INLINE (==) #-}
@@ -1128,20 +891,12 @@ instance Foldable Array where
1128891instance Unbox a => Semigroup (Array a) where
1129892 arr1 <> arr2 = unsafePerformIO $ splice arr1 arr2
1130893
1131−empty ::
1132−#ifdef DEVBUILD
1133− Unbox a =>
1134−#endif
1135− Array a
1136−empty = Array Unboxed.empty 0 0
1137−
1138−{-# DEPRECATED nil "Please use empty instead." #-}
1139894nil ::
1140895#ifdef DEVBUILD
1141896 Unbox a =>
1142897#endif
1143898 Array a
1144−nil = empty
899+nil = Array Unboxed.nil 0 0
1145900
1146901instance Unbox a => Monoid (Array a) where
1147902 mempty = nil
core/src/Streamly/Internal/Data/Fold/Combinators.hs+92
@@ -30,6 +30,8 @@ module Streamly.Internal.Data.Fold.Combinators
3030 -- *** Reducers
3131 , drainMapM
3232 , the
33+ , length
34+ , lengthGeneric
3335 , mean
3436 , rollingHash
3537 , defaultSalt
@@ -164,6 +166,8 @@ module Streamly.Internal.Data.Fold.Combinators
164166 -- ** Trimming
165167
166168 -- By elements
169+ , takeEndBy
170+ , takeEndBy_
167171 , takeEndBySeq
168172 , takeEndBySeq_
169173 {-
@@ -705,6 +709,30 @@ the = foldt' step initial id
705709-- To Summary
706710------------------------------------------------------------------------------
707711
712+-- | Like 'length', except with a more general 'Num' return value
713+--
714+-- Definition:
715+--
716+-- >>> lengthGeneric = fmap getSum $ Fold.foldMap (Sum . const 1)
717+-- >>> lengthGeneric = Fold.foldl' (\n _ -> n + 1) 0
718+--
719+-- /Pre-release/
720+{-# INLINE lengthGeneric #-}
721+lengthGeneric :: (Monad m, Num b) => Fold m a b
722+lengthGeneric = foldl' (\n _ -> n + 1) 0
723+
724+-- | Determine the length of the input stream.
725+--
726+-- Definition:
727+--
728+-- >>> length = Fold.lengthGeneric
729+-- >>> length = fmap getSum $ Fold.foldMap (Sum . const 1)
730+--
731+{-# INLINE length #-}
732+length :: Monad m => Fold m a Int
733+length = lengthGeneric
734+
735+
708736-- | Determine the sum of all elements of a stream of numbers. Returns additive
709737-- identity (@0@) when the stream is empty. Note that this is not numerically
710738-- stable for floating point numbers.
@@ -1482,6 +1510,70 @@ droppingWhileM p = Fold step initial extract extract
14821510droppingWhile :: Monad m => (a -> Bool) -> Fold m a (Maybe a)
14831511droppingWhile p = droppingWhileM (return . p)
14841512
1513+-- Note: Keep this consistent with S.splitOn. In fact we should eliminate
1514+-- S.splitOn in favor of the fold.
1515+--
1516+-- XXX Use Fold.many instead once it is fixed.
1517+-- > Stream.splitOnSuffix p f = Stream.foldMany (Fold.takeEndBy_ p f)
1518+
1519+-- | Like 'takeEndBy' but drops the element on which the predicate succeeds.
1520+--
1521+-- Example:
1522+--
1523+-- >>> input = Stream.fromList "hello\nthere\n"
1524+-- >>> line = Fold.takeEndBy_ (== '\n') Fold.toList
1525+-- >>> Stream.fold line input
1526+-- "hello"
1527+--
1528+-- >>> Stream.fold Fold.toList $ Stream.foldMany line input
1529+-- ["hello","there"]
1530+--
1531+{-# INLINE takeEndBy_ #-}
1532+takeEndBy_ :: Monad m => (a -> Bool) -> Fold m a b -> Fold m a b
1533+-- takeEndBy_ predicate = scanMaybe (takingEndBy_ predicate)
1534+takeEndBy_ predicate (Fold fstep finitial fextract ffinal) =
1535+ Fold step finitial fextract ffinal
1536+
1537+ where
1538+
1539+ step s a =
1540+ if not (predicate a)
1541+ then fstep s a
1542+ else Done <$> ffinal s
1543+
1544+-- Note:
1545+-- > Stream.splitWithSuffix p f = Stream.foldMany (Fold.takeEndBy p f)
1546+
1547+-- | Take the input, stop when the predicate succeeds taking the succeeding
1548+-- element as well.
1549+--
1550+-- Example:
1551+--
1552+-- >>> input = Stream.fromList "hello\nthere\n"
1553+-- >>> line = Fold.takeEndBy (== '\n') Fold.toList
1554+-- >>> Stream.fold line input
1555+-- "hello\n"
1556+--
1557+-- >>> Stream.fold Fold.toList $ Stream.foldMany line input
1558+-- ["hello\n","there\n"]
1559+--
1560+{-# INLINE takeEndBy #-}
1561+takeEndBy :: Monad m => (a -> Bool) -> Fold m a b -> Fold m a b
1562+-- takeEndBy predicate = scanMaybe (takingEndBy predicate)
1563+takeEndBy predicate (Fold fstep finitial fextract ffinal) =
1564+ Fold step finitial fextract ffinal
1565+
1566+ where
1567+
1568+ step s a = do
1569+ res <- fstep s a
1570+ if not (predicate a)
1571+ then return res
1572+ else do
1573+ case res of
1574+ Partial s1 -> Done <$> ffinal s1
1575+ Done b -> return $ Done b
1576+
14851577------------------------------------------------------------------------------
14861578-- Binary splitting on a separator
14871579------------------------------------------------------------------------------
core/src/Streamly/Internal/Data/Fold/Type.hs−91
@@ -367,8 +367,6 @@ module Streamly.Internal.Data.Fold.Type
367367 , toList
368368 , toStreamK
369369 , toStreamKRev
370− , lengthGeneric
371− , length
372370
373371 -- * Combinators
374372
@@ -393,8 +391,6 @@ module Streamly.Internal.Data.Fold.Type
393391 -- ** Trimming
394392 , take
395393 , taking
396− , takeEndBy_
397− , takeEndBy
398394 , dropping
399395
400396 -- ** Sequential application
@@ -771,29 +767,6 @@ toStreamKRev = foldl' (flip K.cons) K.nil
771767toStreamK :: Monad m => Fold m a (K.StreamK n a)
772768toStreamK = foldr K.cons K.nil
773769
774−-- | Like 'length', except with a more general 'Num' return value
775−--
776−-- Definition:
777−--
778−-- >>> lengthGeneric = fmap getSum $ Fold.foldMap (Sum . const 1)
779−-- >>> lengthGeneric = Fold.foldl' (\n _ -> n + 1) 0
780−--
781−-- /Pre-release/
782−{-# INLINE lengthGeneric #-}
783−lengthGeneric :: (Monad m, Num b) => Fold m a b
784−lengthGeneric = foldl' (\n _ -> n + 1) 0
785−
786−-- | Determine the length of the input stream.
787−--
788−-- Definition:
789−--
790−-- >>> length = Fold.lengthGeneric
791−-- >>> length = fmap getSum $ Fold.foldMap (Sum . const 1)
792−--
793−{-# INLINE length #-}
794−length :: Monad m => Fold m a Int
795−length = lengthGeneric
796−
797770------------------------------------------------------------------------------
798771-- Instances
799772------------------------------------------------------------------------------
@@ -1544,70 +1517,6 @@ take n (Fold fstep finitial fextract ffinal) = Fold step initial extract final
15441517
15451518 final (Tuple'Fused _ r) = ffinal r
15461519
1547−-- Note: Keep this consistent with S.splitOn. In fact we should eliminate
1548−-- S.splitOn in favor of the fold.
1549−--
1550−-- XXX Use Fold.many instead once it is fixed.
1551−-- > Stream.splitOnSuffix p f = Stream.foldMany (Fold.takeEndBy_ p f)
1552−
1553−-- | Like 'takeEndBy' but drops the element on which the predicate succeeds.
1554−--
1555−-- Example:
1556−--
1557−-- >>> input = Stream.fromList "hello\nthere\n"
1558−-- >>> line = Fold.takeEndBy_ (== '\n') Fold.toList
1559−-- >>> Stream.fold line input
1560−-- "hello"
1561−--
1562−-- >>> Stream.fold Fold.toList $ Stream.foldMany line input
1563−-- ["hello","there"]
1564−--
1565−{-# INLINE takeEndBy_ #-}
1566−takeEndBy_ :: Monad m => (a -> Bool) -> Fold m a b -> Fold m a b
1567−-- takeEndBy_ predicate = scanMaybe (takingEndBy_ predicate)
1568−takeEndBy_ predicate (Fold fstep finitial fextract ffinal) =
1569− Fold step finitial fextract ffinal
1570−
1571− where
1572−
1573− step s a =
1574− if not (predicate a)
1575− then fstep s a
1576− else Done <$> ffinal s
1577−
1578−-- Note:
1579−-- > Stream.splitWithSuffix p f = Stream.foldMany (Fold.takeEndBy p f)
1580−
1581−-- | Take the input, stop when the predicate succeeds taking the succeeding
1582−-- element as well.
1583−--
1584−-- Example:
1585−--
1586−-- >>> input = Stream.fromList "hello\nthere\n"
1587−-- >>> line = Fold.takeEndBy (== '\n') Fold.toList
1588−-- >>> Stream.fold line input
1589−-- "hello\n"
1590−--
1591−-- >>> Stream.fold Fold.toList $ Stream.foldMany line input
1592−-- ["hello\n","there\n"]
1593−--
1594−{-# INLINE takeEndBy #-}
1595−takeEndBy :: Monad m => (a -> Bool) -> Fold m a b -> Fold m a b
1596−-- takeEndBy predicate = scanMaybe (takingEndBy predicate)
1597−takeEndBy predicate (Fold fstep finitial fextract ffinal) =
1598− Fold step finitial fextract ffinal
1599−
1600− where
1601−
1602− step s a = do
1603− res <- fstep s a
1604− if not (predicate a)
1605− then return res
1606− else do
1607− case res of
1608− Partial s1 -> Done <$> ffinal s1
1609− Done b -> return $ Done b
1610−
16111520------------------------------------------------------------------------------
16121521-- Nesting
16131522------------------------------------------------------------------------------
core/src/Streamly/Internal/Data/IsMap.hs−4
@@ -1,7 +1,3 @@
1−{-# LANGUAGE TypeFamilies #-}
2−-- Must come after TypeFamilies, otherwise it is re-enabled.
3−-- MonoLocalBinds enabled by TypeFamilies causes perf regressions in general.
4−{-# LANGUAGE NoMonoLocalBinds #-}
51-- |
62-- Module : Streamly.Internal.Data.IsMap
73-- Copyright : (c) 2022 Composewell Technologies
core/src/Streamly/Internal/Data/MutArray.hs+15−127
@@ -11,16 +11,14 @@ module Streamly.Internal.Data.MutArray
1111 -- * MutArray.Type module
1212 module Streamly.Internal.Data.MutArray.Type
1313 -- * MutArray module
14+ , splitOn
1415 , sliceIndexerFromLen
1516 , slicerFromLen
16− , compactLE
17− , pinnedCompactLE
18− , compactOnByte
19− , compactOnByteSuffix
2017 -- * Unboxed IORef
2118 , module Streamly.Internal.Data.IORef.Unboxed
2219
2320 -- * Deprecated
21+ , splitOn
2422 , genSlicesFromLen
2523 , getSlicesFromLen
2624 )
@@ -29,21 +27,28 @@ where
2927#include "inline.hs"
3028
3129import Control.Monad.IO.Class (MonadIO(..))
32−import Data.Word (Word8)
33−import Streamly.Internal.Data.MutByteArray.Type (PinnedState(..))
34−import Streamly.Internal.Data.Stream.Type (Stream)
3530import Streamly.Internal.Data.Unbox (Unbox)
31+import Streamly.Internal.Data.Stream (Stream)
3632import Streamly.Internal.Data.Unfold.Type (Unfold(..))
3733
38−import qualified Streamly.Internal.Data.Stream.Type as Stream
39−import qualified Streamly.Internal.Data.Stream.Nesting as Stream
40−-- import qualified Streamly.Internal.Data.Stream.Transform as Stream
34+import qualified Streamly.Internal.Data.Stream as D
4135import qualified Streamly.Internal.Data.Unfold as Unfold
4236
4337import Prelude hiding (foldr, length, read, splitAt)
4438import Streamly.Internal.Data.MutArray.Type
4539import Streamly.Internal.Data.IORef.Unboxed
4640
41+-- | Split the array into a stream of slices using a predicate. The element
42+-- matching the predicate is dropped.
43+--
44+-- /Pre-release/
45+{-# INLINE splitOn #-}
46+splitOn :: (MonadIO m, Unbox a) =>
47+ (a -> Bool) -> MutArray a -> Stream m (MutArray a)
48+splitOn predicate arr =
49+ fmap (\(i, len) -> getSliceUnsafe i len arr)
50+ $ D.sliceOnSuffix predicate (read arr)
51+
4752-- | Generate a stream of array slice descriptors ((index, len)) of specified
4853-- length from an array, starting from the supplied array index. The last slice
4954-- may be shorter than the requested length depending on the array length.
@@ -88,120 +93,3 @@ getSlicesFromLen :: forall m a. (Monad m, Unbox a)
8893 -> Int -- ^ length of the slice
8994 -> Unfold m (MutArray a) (MutArray a)
9095getSlicesFromLen = slicerFromLen
91−
92−-------------------------------------------------------------------------------
93−-- Compacting Streams of Arrays
94−-------------------------------------------------------------------------------
95−
96−-- | @compactLE maxElems@ coalesces adjacent arrays in the input stream
97−-- only if the combined size would be less than or equal to @maxElems@
98−-- elements. Note that it won't split an array if the original array is already
99−-- larger than maxElems.
100−--
101−-- @maxElems@ must be greater than 0.
102−--
103−-- Generates unpinned arrays irrespective of the pinning status of input
104−-- arrays.
105−{-# INLINE compactLE #-}
106−compactLE :: (MonadIO m, Unbox a) =>
107− Int -> Stream m (MutArray a) -> Stream m (MutArray a)
108−-- XXX compactLE can be moved to MutArray/Type if we are not using the parser
109−-- to implement it.
110−compactLE = compactLeAs Unpinned
111−-- The parser version turns out to be a little bit slower.
112−-- compactLE n = Stream.catRights . Stream.parseManyD (pCompactLE n)
113−
114−-- | Pinned version of 'compactLE'.
115−{-# INLINE pinnedCompactLE #-}
116−pinnedCompactLE :: forall m a. (MonadIO m, Unbox a)
117− => Int -> Stream m (MutArray a) -> Stream m (MutArray a)
118−pinnedCompactLE = compactLeAs Pinned
119−-- pinnedCompactLE n = Stream.catRights . Stream.parseManyD (pPinnedCompactLE n)
120−
121−data SplitState s arr
122− = Initial s
123− | Buffering s arr
124− | Splitting s arr
125− | Yielding arr (SplitState s arr)
126− | Finishing
127−
128−-- | Split a stream of arrays on a given separator byte, dropping the separator
129−-- and coalescing all the arrays between two separators into a single array.
130−--
131−{-# INLINE_NORMAL _compactOnByteCustom #-}
132−_compactOnByteCustom
133− :: MonadIO m
134− => Word8
135− -> Stream m (MutArray Word8)
136− -> Stream m (MutArray Word8)
137−_compactOnByteCustom byte (Stream.Stream step state) =
138− Stream.Stream step' (Initial state)
139−
140− where
141−
142− {-# INLINE_LATE step' #-}
143− step' gst (Initial st) = do
144− r <- step gst st
145− case r of
146− Stream.Yield arr s -> do
147− (arr1, marr2) <- breakOn byte arr
148− return $ case marr2 of
149− Nothing -> Stream.Skip (Buffering s arr1)
150− Just arr2 -> Stream.Skip (Yielding arr1 (Splitting s arr2))
151− Stream.Skip s -> return $ Stream.Skip (Initial s)
152− Stream.Stop -> return Stream.Stop
153−
154− step' gst (Buffering st buf) = do
155− r <- step gst st
156− case r of
157− Stream.Yield arr s -> do
158− (arr1, marr2) <- breakOn byte arr
159− -- XXX Use spliceExp instead and then rightSize?
160− buf1 <- splice buf arr1
161− return $ case marr2 of
162− Nothing -> Stream.Skip (Buffering s buf1)
163− Just x -> Stream.Skip (Yielding buf1 (Splitting s x))
164− Stream.Skip s -> return $ Stream.Skip (Buffering s buf)
165− Stream.Stop -> return $
166− if byteLength buf == 0
167− then Stream.Stop
168− else Stream.Skip (Yielding buf Finishing)
169−
170− step' _ (Splitting st buf) = do
171− (arr1, marr2) <- breakOn byte buf
172− return $ case marr2 of
173− Nothing -> Stream.Skip $ Buffering st arr1
174− Just arr2 -> Stream.Skip $ Yielding arr1 (Splitting st arr2)
175−
176− step' _ (Yielding arr next) = return $ Stream.Yield arr next
177− step' _ Finishing = return Stream.Stop
178−
179−-- XXX implement predicate based version of this
180−-- XXX Naming of predicate based vs custom version
181−
182−-- | Split a stream of arrays on a given separator byte, dropping the separator
183−-- and coalescing all the arrays between two separators into a single array.
184−--
185−{-# INLINE compactOnByte #-}
186−compactOnByte
187− :: (MonadIO m)
188− => Word8
189− -> Stream m (MutArray Word8)
190− -> Stream m (MutArray Word8)
191−-- XXX compare perf of custom vs idiomatic version
192−-- compactOnByte = _compactOnByteCustom
193−-- XXX use spliceExp and rightSize?
194−compactOnByte byte = Stream.splitInnerBy (breakOn byte) splice
195−
196−-- | Like 'compactOnByte' considers the separator in suffix position instead of
197−-- infix position.
198−{-# INLINE compactOnByteSuffix #-}
199−compactOnByteSuffix
200− :: (MonadIO m)
201− => Word8
202− -> Stream m (MutArray Word8)
203− -> Stream m (MutArray Word8)
204−compactOnByteSuffix byte =
205− -- XXX use spliceExp and rightSize?
206− Stream.splitInnerBySuffix
207− (\arr -> byteLength arr == 0) (breakOn byte) splice
core/src/Streamly/Internal/Data/MutArray/Generic.hs+30−65
@@ -19,14 +19,14 @@ module Streamly.Internal.Data.MutArray.Generic
1919 , nil
2020
2121 -- *** Uninitialized Arrays
22− , emptyOf
22+ , new
2323 -- , newArrayWith
2424
2525 -- *** From streams
26− , unsafeCreateOf
27− , createOf
28− , createWith -- createOfMin/createMin/createGE?
29− , create
26+ , writeNUnsafe
27+ , writeN
28+ , writeWith
29+ , write
3030 , fromStreamN
3131 , fromStream
3232 , fromPureStream
@@ -160,13 +160,6 @@ module Streamly.Internal.Data.MutArray.Generic
160160 -- , appendSliceFrom
161161
162162 , clone
163−
164− -- * Deprecated
165− , new
166− , writeNUnsafe
167− , writeN
168− , writeWith
169− , write
170163 )
171164where
172165
@@ -243,13 +236,13 @@ bottomElement =
243236-- XXX Would be nice if GHC can provide something like newUninitializedArray# so
244237-- that we do not have to write undefined or error in the whole array.
245238
246−-- | @emptyOf count@ allocates a zero length array that can be extended to hold
239+-- | @new count@ allocates a zero length array that can be extended to hold
247240-- up to 'count' items without reallocating.
248241--
249242-- /Pre-release/
250−{-# INLINE emptyOf #-}
251−emptyOf :: MonadIO m => Int -> m (MutArray a)
252−emptyOf n@(I# n#) =
243+{-# INLINE new #-}
244+new :: MonadIO m => Int -> m (MutArray a)
245+new n@(I# n#) =
253246 liftIO
254247 $ IO
255248 $ \s# ->
@@ -258,12 +251,6 @@ emptyOf n@(I# n#) =
258251 let ma = MutArray arr# 0 0 n
259252 in (# s1#, ma #)
260253
261−-- XXX Deprecate in major
262−-- {-# DEPRECATED new "Please use emptyOf instead." #-}
263−{-# INLINE new #-}
264−new :: MonadIO m => Int -> m (MutArray a)
265−new = emptyOf
266−
267254-- XXX This could be pure?
268255
269256-- |
@@ -331,7 +318,7 @@ putIndices arr = FL.foldlM' step (return ())
331318
332319 where
333320
334− step () (i, x) = putIndex i arr x
321+ step () (i, x) = liftIO (putIndex i arr x)
335322
336323-- | Modify a given index of an array using a modifier function without checking
337324-- the bounds.
@@ -602,16 +589,16 @@ readRev arr@MutArray{..} =
602589arrayChunkSize :: Int
603590arrayChunkSize = 1024
604591
605−-- | Like 'createOf' but does not check the array bounds when writing. The fold
592+-- | Like 'writeN' but does not check the array bounds when writing. The fold
606593-- driver must not call the step function more than 'n' times otherwise it will
607594-- corrupt the memory and crash. This function exists mainly because any
608595-- conditional in the step function blocks fusion causing 10x performance
609596-- slowdown.
610597--
611598-- /Pre-release/
612−{-# INLINE_NORMAL unsafeCreateOf #-}
613−unsafeCreateOf :: MonadIO m => Int -> Fold m a (MutArray a)
614−unsafeCreateOf n = Fold step initial return return
599+{-# INLINE_NORMAL writeNUnsafe #-}
600+writeNUnsafe :: MonadIO m => Int -> Fold m a (MutArray a)
601+writeNUnsafe n = Fold step initial return return
615602
616603 where
617604
@@ -619,81 +606,59 @@ unsafeCreateOf n = Fold step initial return return
619606
620607 step arr x = FL.Partial <$> snocUnsafe arr x
621608
622−{-# DEPRECATED writeNUnsafe "Please use unsafeCreateOf instead." #-}
623−{-# INLINE writeNUnsafe #-}
624−writeNUnsafe :: MonadIO m => Int -> Fold m a (MutArray a)
625−writeNUnsafe = unsafeCreateOf
626−
627−-- | @createOf n@ folds a maximum of @n@ elements from the input stream to an
609+-- | @writeN n@ folds a maximum of @n@ elements from the input stream to an
628610-- 'Array'.
629611--
630−-- >>> createOf n = Fold.take n (MutArray.unsafeCreateOf n)
612+-- >>> writeN n = Fold.take n (MutArray.writeNUnsafe n)
631613--
632614-- /Pre-release/
633−{-# INLINE_NORMAL createOf #-}
634−createOf :: MonadIO m => Int -> Fold m a (MutArray a)
635−createOf n = FL.take n $ unsafeCreateOf n
636−
637−-- XXX Deprecate in major
638−-- {-# DEPRECATED writeN "Please use createOf instead." #-}
639−{-# INLINE writeN #-}
615+{-# INLINE_NORMAL writeN #-}
640616writeN :: MonadIO m => Int -> Fold m a (MutArray a)
641−writeN = createOf
617+writeN n = FL.take n $ writeNUnsafe n
642618
643619-- >>> f n = MutArray.writeAppendWith (* 2) (MutArray.pinnedNew n)
644620-- >>> writeWith n = Fold.rmapM MutArray.rightSize (f n)
645621-- >>> writeWith n = Fold.rmapM MutArray.fromArrayStreamK (MutArray.writeChunks n)
646622
647−-- | @createWith minCount@ folds the whole input to a single array. The array
623+-- | @writeWith minCount@ folds the whole input to a single array. The array
648624-- starts at a size big enough to hold minCount elements, the size is doubled
649625-- every time the array needs to be grown.
650626--
651627-- /Caution! Do not use this on infinite streams./
652628--
653629-- /Pre-release/
654−{-# INLINE_NORMAL createWith #-}
655−createWith :: MonadIO m => Int -> Fold m a (MutArray a)
630+{-# INLINE_NORMAL writeWith #-}
631+writeWith :: MonadIO m => Int -> Fold m a (MutArray a)
656632-- writeWith n = FL.rmapM rightSize $ writeAppendWith (* 2) (pinnedNew n)
657−createWith elemCount = FL.rmapM extract $ FL.foldlM' step initial
633+writeWith elemCount = FL.rmapM extract $ FL.foldlM' step initial
658634
659635 where
660636
661637 initial = do
662− when (elemCount < 0) $ error "createWith: elemCount is negative"
663− new elemCount
638+ when (elemCount < 0) $ error "writeWith: elemCount is negative"
639+ liftIO $ new elemCount
664640
665641 step arr@(MutArray _ start end bound) x
666642 | end == bound = do
667643 let oldSize = end - start
668644 newSize = max (oldSize * 2) 1
669− arr1 <- realloc newSize arr
645+ arr1 <- liftIO $ realloc newSize arr
670646 snocUnsafe arr1 x
671647 step arr x = snocUnsafe arr x
672648
673− -- extract = rightSize
649+ -- extract = liftIO . rightSize
674650 extract = return
675651
676−{-# DEPRECATED writeWith "Please use createWith instead." #-}
677−{-# INLINE writeWith #-}
678−writeWith :: MonadIO m => Int -> Fold m a (MutArray a)
679−writeWith = createWith
680−
681652-- | Fold the whole input to a single array.
682653--
683−-- Same as 'createWith' using an initial array size of 'arrayChunkSize' bytes
654+-- Same as 'writeWith' using an initial array size of 'arrayChunkSize' bytes
684655-- rounded up to the element size.
685656--
686657-- /Caution! Do not use this on infinite streams./
687658--
688−{-# INLINE create #-}
689−create :: MonadIO m => Fold m a (MutArray a)
690−create = writeWith arrayChunkSize
691−
692−-- XXX Deprecate in major
693−-- {-# DEPRECATED write "Please use create instead." #-}
694659{-# INLINE write #-}
695660write :: MonadIO m => Fold m a (MutArray a)
696−write = create
661+write = writeWith arrayChunkSize
697662
698663-- | Create a 'MutArray' from the first @n@ elements of a stream. The
699664-- array is allocated to size @n@, if the stream terminates before @n@
@@ -718,7 +683,7 @@ fromList xs = fromStream $ D.fromList xs
718683{-# INLINABLE fromPureStream #-}
719684fromPureStream :: MonadIO m => Stream Identity a -> m (MutArray a)
720685fromPureStream xs =
721− D.fold write $ D.morphInner (return . runIdentity) xs
686+ liftIO $ D.fold write $ D.morphInner (return . runIdentity) xs
722687
723688-------------------------------------------------------------------------------
724689-- Chunking
@@ -850,7 +815,7 @@ putSliceUnsafe src srcStart dst dstStart len = liftIO $ do
850815
851816{-# INLINE clone #-}
852817clone :: MonadIO m => MutArray a -> m (MutArray a)
853−clone src = do
818+clone src = liftIO $ do
854819 let len = arrLen src
855820 dst <- new len
856821 putSliceUnsafe src 0 dst 0 len
core/src/Streamly/Internal/Data/MutArray/Stream.hs+195−11
@@ -12,7 +12,6 @@
1212-- keep this as a separate module and release it.
1313--
1414module Streamly.Internal.Data.MutArray.Stream
15−{-# DEPRECATED "Please use \"Streamly.Internal.Data.MutArray\" instead." #-}
1615 (
1716 -- * Generation
1817 MArray.chunksOf
@@ -22,7 +21,7 @@ module Streamly.Internal.Data.MutArray.Stream
2221
2322 -- * Compaction
2423 , packArraysChunksOf
25− , MArray.SpliceState (..)
24+ , SpliceState (..)
2625 , lpackArraysChunksOf
2726 , compact -- chunksCompact
2827 , compactLE
@@ -36,12 +35,19 @@ module Streamly.Internal.Data.MutArray.Stream
3635 )
3736where
3837
38+#include "inline.hs"
39+#include "ArrayMacros.h"
40+
3941import Control.Monad.IO.Class (MonadIO(..))
40−import Streamly.Internal.Data.Unbox (Unbox)
42+import Control.Monad (when)
43+import Data.Bifunctor (first)
44+import Data.Proxy (Proxy(..))
45+import Streamly.Internal.Data.Unbox (Unbox, sizeOf)
4146import Streamly.Internal.Data.MutArray.Type (MutArray(..))
4247import Streamly.Internal.Data.Fold.Type (Fold(..))
4348import Streamly.Internal.Data.Parser (ParseError)
4449import Streamly.Internal.Data.Stream.Type (Stream)
50+import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
4551
4652import qualified Streamly.Internal.Data.MutArray as MArray
4753import qualified Streamly.Internal.Data.Fold.Type as FL
@@ -52,6 +58,12 @@ import qualified Streamly.Internal.Data.Stream as D
5258-- Compact
5359-------------------------------------------------------------------------------
5460
61+data SpliceState s arr
62+ = SpliceInitial s
63+ | SpliceBuffering s arr
64+ | SpliceYielding arr (SpliceState s arr)
65+ | SpliceFinish
66+
5567-- XXX This can be removed once compactLEFold/compactLE are implemented.
5668--
5769-- | This mutates the first array (if it has space) to append values from the
@@ -66,18 +78,117 @@ import qualified Streamly.Internal.Data.Stream as D
6678-- actual array size may be less than the specified chunk size.
6779--
6880-- @since 0.7.0
69−{-# INLINE packArraysChunksOf #-}
81+{-# INLINE_NORMAL packArraysChunksOf #-}
7082packArraysChunksOf :: (MonadIO m, Unbox a)
7183 => Int -> D.Stream m (MutArray a) -> D.Stream m (MutArray a)
72−packArraysChunksOf = MArray.compactLE
84+packArraysChunksOf n (D.Stream step state) =
85+ D.Stream step' (SpliceInitial state)
86+
87+ where
88+
89+ {-# INLINE_LATE step' #-}
90+ step' gst (SpliceInitial st) = do
91+ when (n <= 0) $
92+ -- XXX we can pass the module string from the higher level API
93+ error $ "Streamly.Internal.Data.MutArray.Type.packArraysChunksOf: the size of "
94+ ++ "arrays [" ++ show n ++ "] must be a natural number"
95+ r <- step gst st
96+ case r of
97+ D.Yield arr s -> return $
98+ let len = MArray.byteLength arr
99+ in if len >= n
100+ then D.Skip (SpliceYielding arr (SpliceInitial s))
101+ else D.Skip (SpliceBuffering s arr)
102+ D.Skip s -> return $ D.Skip (SpliceInitial s)
103+ D.Stop -> return D.Stop
104+
105+ step' gst (SpliceBuffering st buf) = do
106+ r <- step gst st
107+ case r of
108+ D.Yield arr s -> do
109+ let len = MArray.byteLength buf + MArray.byteLength arr
110+ if len > n
111+ then return $
112+ D.Skip (SpliceYielding buf (SpliceBuffering s arr))
113+ else do
114+ buf' <- if MArray.byteCapacity buf < n
115+ then liftIO $ MArray.realloc n buf
116+ else return buf
117+ buf'' <- MArray.spliceUnsafe buf' arr
118+ return $ D.Skip (SpliceBuffering s buf'')
119+ D.Skip s -> return $ D.Skip (SpliceBuffering s buf)
120+ D.Stop -> return $ D.Skip (SpliceYielding buf SpliceFinish)
121+
122+ step' _ SpliceFinish = return D.Stop
123+
124+ step' _ (SpliceYielding arr next) = return $ D.Yield arr next
73125
74126-- XXX Remove this once compactLEFold is implemented
75127-- lpackArraysChunksOf = Fold.many compactLEFold
76128--
77−{-# INLINE lpackArraysChunksOf #-}
129+{-# INLINE_NORMAL lpackArraysChunksOf #-}
78130lpackArraysChunksOf :: (MonadIO m, Unbox a)
79131 => Int -> Fold m (MutArray a) () -> Fold m (MutArray a) ()
80−lpackArraysChunksOf = MArray.lCompactGE
132+lpackArraysChunksOf n (Fold step1 initial1 _ final1) =
133+ Fold step initial extract final
134+
135+ where
136+
137+ initial = do
138+ when (n <= 0) $
139+ -- XXX we can pass the module string from the higher level API
140+ error $ "Streamly.Internal.Data.MutArray.Type.packArraysChunksOf: the size of "
141+ ++ "arrays [" ++ show n ++ "] must be a natural number"
142+
143+ r <- initial1
144+ return $ first (Tuple' Nothing) r
145+
146+ step (Tuple' Nothing r1) arr =
147+ let len = MArray.byteLength arr
148+ in if len >= n
149+ then do
150+ r <- step1 r1 arr
151+ case r of
152+ FL.Done _ -> return $ FL.Done ()
153+ FL.Partial s -> do
154+ _ <- final1 s
155+ res <- initial1
156+ return $ first (Tuple' Nothing) res
157+ else return $ FL.Partial $ Tuple' (Just arr) r1
158+
159+ step (Tuple' (Just buf) r1) arr = do
160+ let len = MArray.byteLength buf + MArray.byteLength arr
161+ buf' <- if MArray.byteCapacity buf < len
162+ then liftIO $ MArray.realloc (max n len) buf
163+ else return buf
164+ buf'' <- MArray.spliceUnsafe buf' arr
165+
166+ -- XXX this is common in both the equations of step
167+ if len >= n
168+ then do
169+ r <- step1 r1 buf''
170+ case r of
171+ FL.Done _ -> return $ FL.Done ()
172+ FL.Partial s -> do
173+ _ <- final1 s
174+ res <- initial1
175+ return $ first (Tuple' Nothing) res
176+ else return $ FL.Partial $ Tuple' (Just buf'') r1
177+
178+ -- XXX Several folds do extract >=> final, therefore, we need to make final
179+ -- return "m b" rather than using extract post it if we want extract to be
180+ -- partial.
181+ --
182+ -- extract forces the pending buffer to be sent to the fold which is not
183+ -- what we want.
184+ extract _ = error "lpackArraysChunksOf: not designed for scanning"
185+
186+ final (Tuple' Nothing r1) = final1 r1
187+ final (Tuple' (Just buf) r1) = do
188+ r <- step1 r1 buf
189+ case r of
190+ FL.Partial rr -> final1 rr
191+ FL.Done _ -> return ()
81192
82193-- XXX Same as compactLE, to be removed once that is implemented.
83194--
@@ -97,11 +208,48 @@ compact = packArraysChunksOf
97208-- actual array size may be less than the specified chunk size.
98209--
99210-- /Internal/
100−{-# INLINE compactLEParserD #-}
211+{-# INLINE_NORMAL compactLEParserD #-}
101212compactLEParserD ::
102213 forall m a. (MonadIO m, Unbox a)
103214 => Int -> ParserD.Parser (MutArray a) m (MutArray a)
104−compactLEParserD = MArray.pCompactLE
215+compactLEParserD n = ParserD.Parser step initial extract
216+
217+ where
218+
219+ nBytes = n * SIZE_OF(a)
220+
221+ initial =
222+ return
223+ $ if n <= 0
224+ then error
225+ $ functionPath
226+ ++ ": the size of arrays ["
227+ ++ show n ++ "] must be a natural number"
228+ else ParserD.IPartial Nothing
229+
230+ step Nothing arr =
231+ return
232+ $ let len = MArray.byteLength arr
233+ in if len >= nBytes
234+ then ParserD.Done 0 arr
235+ else ParserD.Partial 0 (Just arr)
236+ step (Just buf) arr =
237+ let len = MArray.byteLength buf + MArray.byteLength arr
238+ in if len > nBytes
239+ then return $ ParserD.Done 1 buf
240+ else do
241+ buf1 <-
242+ if MArray.byteCapacity buf < nBytes
243+ then liftIO $ MArray.realloc nBytes buf
244+ else return buf
245+ buf2 <- MArray.spliceUnsafe buf1 arr
246+ return $ ParserD.Partial 0 (Just buf2)
247+
248+ extract Nothing = return $ ParserD.Done 0 MArray.nil
249+ extract (Just buf) = return $ ParserD.Done 0 buf
250+
251+ functionPath =
252+ "Streamly.Internal.Data.Stream.MutChunked.compactLEParserD"
105253
106254-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
107255-- minimum specified size. Note that if all the arrays in the stream together
@@ -110,11 +258,47 @@ compactLEParserD = MArray.pCompactLE
110258-- the specified size we stop coalescing further.
111259--
112260-- /Internal/
113−{-# INLINE compactGEFold #-}
261+{-# INLINE_NORMAL compactGEFold #-}
114262compactGEFold ::
115263 forall m a. (MonadIO m, Unbox a)
116264 => Int -> FL.Fold m (MutArray a) (MutArray a)
117−compactGEFold = MArray.fCompactGE
265+compactGEFold n = Fold step initial extract extract
266+
267+ where
268+
269+ nBytes = n * SIZE_OF(a)
270+
271+ initial =
272+ return
273+ $ if n < 0
274+ then error
275+ $ functionPath
276+ ++ ": the size of arrays ["
277+ ++ show n ++ "] must be a natural number"
278+ else FL.Partial Nothing
279+
280+ step Nothing arr =
281+ return
282+ $ let len = MArray.byteLength arr
283+ in if len >= nBytes
284+ then FL.Done arr
285+ else FL.Partial (Just arr)
286+ step (Just buf) arr = do
287+ let len = MArray.byteLength buf + MArray.byteLength arr
288+ buf1 <-
289+ if MArray.byteCapacity buf < len
290+ then liftIO $ MArray.realloc (max len nBytes) buf
291+ else return buf
292+ buf2 <- MArray.spliceUnsafe buf1 arr
293+ if len >= n
294+ then return $ FL.Done buf2
295+ else return $ FL.Partial (Just buf2)
296+
297+ extract Nothing = return MArray.nil
298+ extract (Just buf) = return buf
299+
300+ functionPath =
301+ "Streamly.Internal.Data.Stream.MutChunked.compactGEFold"
118302
119303-- | Coalesce adjacent arrays in incoming stream to form bigger arrays of a
120304-- maximum specified size in bytes.
core/src/Streamly/Internal/Data/MutArray/Type.hs+339−1013
@@ -31,57 +31,39 @@ module Streamly.Internal.Data.MutArray.Type
3131 -- ** Type
3232 -- $arrayNotes
3333 MutArray (..)
34−
35− -- ** Conversion
36− -- *** Pinned and Unpinned
34+ , MutByteArray
35+ , MutableByteArray
3736 , pin
3837 , unpin
3938 , isPinned
4039
41− -- ** Casting
42− , cast
43− , castUnsafe -- XXX unsafeCast
44− , asBytes
45− , unsafePinnedAsPtr
46− , unsafeAsPtr
47−
40+ -- -- * Constructing and Writing
4841 -- ** Construction
49− , empty
50−
51− -- *** New
52− -- | New arrays are always empty arrays with some reserve capacity to
53− -- extend the length without reallocating.
54− , emptyOf
55− , newArrayWith -- emptyAlignedWith
56− , pinnedEmptyOf
57− , pinnedNewAligned -- XXX not required
58− -- , new -- uninitialized array of specified length
59−
60− -- *** Cloning
61− , clone
62− , pinnedClone
42+ , nil
6343
64− -- *** Slicing
65− -- | Get a subarray without copying
66− , getSliceUnsafe -- XXX unsafeGetSlice
67− , getSlice
68− , splitAt -- XXX should be able to express using getSlice
69− , breakOn
44+ -- *** Uninitialized Arrays
45+ , pinnedNew
46+ , pinnedNewBytes
47+ , pinnedNewAligned
48+ , new
49+ , newArrayWith
7050
71− -- *** Stream Folds
51+ -- *** From streams
7252 , ArrayUnsafe (..)
73− , unsafeCreateOfWith
74− , unsafeCreateOf
75− , unsafePinnedCreateOf
76− , pinnedCreateOf
77− , createOfWith
78− , createOf
79− , revCreateOf
80−
81− , pinnedCreate
82− , createWith
83− , create
84− -- , revCreate
53+ , writeNWithUnsafe
54+ , writeNWith
55+ , writeNUnsafe
56+ , pinnedWriteNUnsafe
57+ , writeN
58+ , pinnedWriteN
59+ , pinnedWriteNAligned
60+
61+ , writeWith
62+ , write
63+ , pinnedWrite
64+
65+ , writeRevN
66+ -- , writeRev
8567
8668 -- *** From containers
8769 , fromListN
@@ -97,11 +79,11 @@ module Streamly.Internal.Data.MutArray.Type
9779 , fromByteStr#
9880 , fromPtrN
9981 , fromChunksK
100− , fromChunksRealloced -- fromSmallChunks
82+ , fromChunksRealloced
10183
10284 -- ** Random writes
10385 , putIndex
104− , putIndexUnsafe -- XXX unsafePutIndex
86+ , putIndexUnsafe
10587 , putIndices
10688 -- , putFromThenTo
10789 -- , putFrom -- start writing at the given position
@@ -109,69 +91,76 @@ module Streamly.Internal.Data.MutArray.Type
10991 -- , putFromTo
11092 -- , putFromRev
11193 -- , putUptoRev
112− , modifyIndexUnsafe -- XXX unsafeModifyIndex
94+ , modifyIndexUnsafe
11395 , modifyIndex
11496 , modifyIndices
11597 , modify
11698 , swapIndices
11799 , unsafeSwapIndices
118100
119− -- ** Reading
101+ -- ** Growing and Shrinking
102+ -- | Arrays grow only at the end, though it is possible to grow on both sides
103+ -- and therefore have a cons as well as snoc. But that will require two
104+ -- bounds in the array representation.
120105
121− -- *** Indexing
122− , getIndex
123− , getIndexUnsafe -- XXX unsafeGetIndex
124− -- , getFromThenTo
125− , getIndexRev -- getRevIndex?
126− , indexReader
127− , indexReaderWith
106+ -- *** Appending elements
107+ , snocWith
108+ , snoc
109+ , snocLinear
110+ , snocMay
111+ , snocUnsafe
112+
113+ -- *** Appending streams
114+ , writeAppendNUnsafe
115+ , writeAppendN
116+ , writeAppendWith
117+ , writeAppend
118+
119+ -- ** Eliminating and Reading
120+
121+ -- *** To streams
122+ , reader
123+ , readerRevWith
124+ , readerRev
128125
129− -- *** To Streams
126+ -- *** To containers
127+ , toStreamDWith
128+ , toStreamDRevWith
129+ , toStreamKWith
130+ , toStreamKRevWith
130131 , read
131132 , readRev
132− , toStreamWith
133− , toStreamRevWith
134133 , toStreamK
135− , toStreamKWith
136134 , toStreamKRev
137− , toStreamKRevWith
138−
139− -- *** To Containers
140135 , toList
141136
142− -- *** Unfolds
143137 -- experimental
144138 , producerWith
145139 , producer
146140
147− , reader
148− , readerRevWith
149− , readerRev
150−
151− -- ** Size and Capacity
152− -- *** Size
153− , length
154− , byteLength
155−
156− -- *** Capacity
157− -- , capacity
158− , byteCapacity
159− , bytesFree
141+ -- *** Random reads
142+ , getIndex
143+ , getIndexUnsafe
144+ , getIndices
145+ , getIndicesD
146+ -- , getFromThenTo
147+ , getIndexRev
160148
161− -- *** Capacity Management
149+ -- ** Memory Management
162150 , blockSize
163151 , arrayChunkBytes
164152 , allocBytesToElemCount
165− , realloc -- this is "resize"
166− , grow
167− , growExp
153+ , realloc
154+ , resize
155+ , resizeExp
168156 , rightSize
169157
170− -- ** Folding
171− , foldl'
172− , foldr
173− , byteCmp
174− , byteEq
158+ -- ** Size
159+ , length
160+ , byteLength
161+ -- , capacity
162+ , byteCapacity
163+ , bytesFree
175164
176165 -- ** In-place Mutation Algorithms
177166 , strip
@@ -183,82 +172,58 @@ module Streamly.Internal.Data.MutArray.Type
183172 , mergeBy
184173 , bubble
185174
186− -- ** Growing and Shrinking
187− -- | Arrays grow only at the end, though it is possible to grow on both
188− -- sides and therefore have a cons as well as snoc. But that will require
189− -- both lower and upper bound in the array representation.
190−
191− -- *** Appending elements
192− , snocWith
193− , snoc
194− , snocLinear
195− , snocMay
196− , snocUnsafe -- XXX unsafeSnoc
197−
198− -- *** Appending streams
199− , unsafeAppendN
200− , appendN
201− , appendWith
202− , append
203−
204− -- *** Appending arrays
205− , spliceCopy
206− , spliceWith
207− , splice
208− , spliceExp
209− , spliceUnsafe -- XXX unsafeSplice
210− -- , putSlice
211− -- , appendSlice
212− -- , appendSliceFrom
213−
214− -- ** Serialization using Unbox
215− , pokeAppend
216− , pokeAppendMay
217− , pokeSkipUnsafe -- unsafePokeSkip
175+ -- ** Casting
176+ , cast
177+ , castUnsafe
178+ , asBytes
179+ , asPtrUnsafe
180+ , asUnpinnedPtrUnsafe
218181
219− -- ** Deserialization using Unbox
220− , peekUncons
221− , peekUnconsUnsafe -- unsafePeekUncons
222− , peekSkipUnsafe -- unsafePeekSkip
182+ -- ** Folding
183+ , foldl'
184+ , foldr
185+ , cmp
186+ , byteCmp
187+ , byteEq
223188
224− -- Arrays of arrays
189+ -- ** Arrays of arrays
225190 -- We can add dimensionality parameter to the array type to get
226191 -- multidimensional arrays. Multidimensional arrays would just be a
227192 -- convenience wrapper on top of single dimensional arrays.
228193
229− -- ** Streams of Arrays
230− -- *** Chunk
231− -- | Group a stream into arrays.
194+ -- | Operations dealing with multiple arrays, streams of arrays or
195+ -- multidimensional array representations.
196+
197+ -- *** Construct from streams
232198 , chunksOf
233199 , pinnedChunksOf
234200 , buildChunks
235201
236− -- *** Split
237− -- | Split an array into slices.
202+ -- *** Eliminate to streams
203+ , concatChunks
204+ , concatChunksRev
238205
206+ -- *** Construct from arrays
207+ -- get chunks without copying
208+ , getSliceUnsafe
209+ , getSlice
239210 -- , getSlicesFromLenN
240− , splitOn
241− -- , slicesOf
242−
243− -- *** Concat
244− -- | Append the arrays in a stream to form a stream of elements.
245− , concatWith
246− , concatRevWith
247− , concat
248− , concatRev
249−
250− -- *** Compact
251− -- | Append the arrays in a stream to form a stream of larger arrays.
252− , SpliceState (..)
253− , pCompactLE
254− , pPinnedCompactLE
255− , compactLeAs
256− , fCompactGE
257− , fPinnedCompactGE
258− , lCompactGE
259− , lPinnedCompactGE
260− , compactGE
261− , compactEQ
211+ , splitAt -- XXX should be able to express using getSlice
212+ , breakOn
213+
214+ -- ** Cloning arrays
215+ , clone
216+ , pinnedClone
217+
218+ -- ** Appending arrays
219+ , spliceCopy
220+ , spliceWith
221+ , splice
222+ , spliceExp
223+ , spliceUnsafe
224+ -- , putSlice
225+ -- , appendSlice
226+ -- , appendSliceFrom
262227
263228 -- ** Utilities
264229 , roundUpToPower2
@@ -267,37 +232,12 @@ module Streamly.Internal.Data.MutArray.Type
267232 , c_memchr
268233
269234 -- * Deprecated
270− , asPtrUnsafe
271235 , writeChunks
272236 , flattenArrays
273237 , flattenArraysRev
274238 , fromArrayStreamK
275239 , fromStreamDN
276240 , fromStreamD
277− , cmp
278− , getIndices
279− , getIndicesWith
280− , resize
281− , resizeExp
282− , nil
283− , new
284− , pinnedNew
285− , pinnedNewBytes
286− , writeAppendNUnsafe
287− , writeAppendN
288− , writeAppendWith
289− , writeAppend
290− , writeNWithUnsafe
291− , writeNWith
292− , writeNUnsafe
293− , pinnedWriteNUnsafe
294− , writeN
295− , pinnedWriteN
296− , pinnedWriteNAligned -- XXX not required
297− , writeWith
298− , write
299− , pinnedWrite
300− , writeRevN
301241 )
302242where
303243
@@ -308,7 +248,6 @@ where
308248
309249import Control.Monad (when, void)
310250import Control.Monad.IO.Class (MonadIO(..))
311−import Data.Bifunctor (first)
312251import Data.Bits (shiftR, (.|.), (.&.))
313252import Data.Functor.Identity (Identity(..))
314253import Data.Proxy (Proxy(..))
@@ -317,6 +256,7 @@ import Foreign.C.Types (CSize(..), CInt(..))
317256import Foreign.Ptr (plusPtr, minusPtr, nullPtr)
318257import Streamly.Internal.Data.MutByteArray.Type
319258 ( MutByteArray(..)
259+ , MutableByteArray
320260 , PinnedState(..)
321261 , getMutableByteArray#
322262 , putSliceUnsafe
@@ -335,17 +275,13 @@ import GHC.Ptr (Ptr(..))
335275import Streamly.Internal.Data.Fold.Type (Fold(..))
336276import Streamly.Internal.Data.Producer.Type (Producer (..))
337277import Streamly.Internal.Data.Stream.Type (Stream)
338−import Streamly.Internal.Data.Parser.Type (Parser (..))
339278import Streamly.Internal.Data.StreamK.Type (StreamK)
340279import Streamly.Internal.Data.SVar.Type (adaptState, defState)
341−import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
342280import Streamly.Internal.Data.Unfold.Type (Unfold(..))
343281import Streamly.Internal.System.IO (arrayPayloadSize, defaultChunkSize)
344282
345283import qualified Streamly.Internal.Data.Fold.Type as FL
346284import 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
349285import qualified Streamly.Internal.Data.Producer as Producer
350286import qualified Streamly.Internal.Data.Stream.Type as D
351287import qualified Streamly.Internal.Data.Stream.Lift as D
@@ -353,7 +289,7 @@ import qualified Streamly.Internal.Data.StreamK.Type as K
353289import qualified Prelude
354290
355291import Prelude hiding
356− (Foldable(..), concat, read, unlines, splitAt, reverse, truncate)
292+ (Foldable(..), read, unlines, splitAt, reverse, truncate)
357293
358294#include "DocTestDataMutArray.hs"
359295
@@ -479,8 +415,6 @@ isPinned MutArray{..} = Unboxed.isPinned arrContents
479415-- we need more than that. See stg_pinnedNewAlignedByteArrayzh and
480416-- allocatePinned in GHC source.
481417
482−-- XXX Rename to emptyAlignedWith, alignSize should be first arg.
483−
484418-- | @newArrayWith allocator alignment count@ allocates a new array of zero
485419-- length and with a capacity to hold @count@ elements, using @allocator
486420-- size alignment@ as the memory allocator function.
@@ -504,25 +438,12 @@ newArrayWith alloc alignSize count = do
504438 , arrBound = size
505439 }
506440
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.
510−
511−-- | Create an empty array.
512−empty ::
513−#ifdef DEVBUILD
514− Unbox a =>
515−#endif
516− MutArray a
517−empty = MutArray Unboxed.empty 0 0 0
518−
519−{-# DEPRECATED nil "Please use empty instead." #-}
520441nil ::
521442#ifdef DEVBUILD
522443 Unbox a =>
523444#endif
524445 MutArray a
525−nil = empty
446+nil = MutArray Unboxed.nil 0 0 0
526447
527448{-# INLINE newBytesAs #-}
528449newBytesAs :: MonadIO m =>
@@ -539,13 +460,12 @@ newBytesAs ps bytes = do
539460 , arrBound = bytes
540461 }
541462
542−-- | Allocates a pinned empty array that with a reserved capacity of bytes.
543−-- The memory of the array is uninitialized and the allocation is aligned as
544−-- per the 'Unboxed' instance of the type.
463+-- | Allocates a pinned empty array that can hold 'count' items. The memory of
464+-- the array is uninitialized and the allocation is aligned as per the
465+-- 'Unboxed' instance of the type.
545466--
546467-- /Pre-release/
547468{-# INLINE pinnedNewBytes #-}
548−{-# DEPRECATED pinnedNewBytes "Please use pinnedEmptyOf with appropriate calculation" #-}
549469pinnedNewBytes :: MonadIO m =>
550470#ifdef DEVBUILD
551471 Unbox a =>
@@ -570,31 +490,21 @@ newAs ps =
570490 (error "new: alignment is not used in unpinned arrays.")
571491
572492-- XXX can unaligned allocation be more efficient when alignment is not needed?
573−
574−-- | Allocates a pinned array of zero length but growable to the specified
575−-- capacity without reallocation.
576−{-# INLINE pinnedEmptyOf #-}
577−pinnedEmptyOf :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a)
578−pinnedEmptyOf = newAs Pinned
579−
580−-- XXX Deprecate in major
581−-- {-# DEPRECATED pinnedNew "Please use pinnedEmptyOf instead." #-}
493+--
494+-- | Allocates an empty pinned array that can hold 'count' items. The memory of
495+-- the array is uninitialized and the allocation is aligned as per the 'Unboxed'
496+-- instance of the type.
497+--
582498{-# INLINE pinnedNew #-}
583499pinnedNew :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a)
584−pinnedNew = pinnedEmptyOf
500+pinnedNew = newAs Pinned
585501
586−-- | Allocates an unpinned array of zero length but growable to the specified
587−-- capacity without reallocation.
502+-- | Allocates an empty unpinned array that can hold 'count' items. The memory
503+-- of the array is uninitialized.
588504--
589−{-# INLINE emptyOf #-}
590−emptyOf :: (MonadIO m, Unbox a) => Int -> m (MutArray a)
591−emptyOf = newAs Unpinned
592−
593−-- XXX Deprecate in major
594−-- {-# DEPRECATED new "Please use emptyOf instead." #-}
595505{-# INLINE new #-}
596506new :: (MonadIO m, Unbox a) => Int -> m (MutArray a)
597−new = emptyOf
507+new = newAs Unpinned
598508
599509-------------------------------------------------------------------------------
600510-- Random writes
@@ -642,7 +552,7 @@ putIndices arr = FL.foldlM' step (return ())
642552
643553 where
644554
645− step () (i, x) = putIndex i arr x
555+ step () (i, x) = liftIO (putIndex i arr x)
646556
647557-- | Modify a given index of an array using a modifier function.
648558--
@@ -838,19 +748,22 @@ arrayChunkBytes = 1024
838748roundDownTo :: Int -> Int -> Int
839749roundDownTo elemSize size = size - (size `mod` elemSize)
840750
751+-- XXX See if resizing can be implemented by reading the old array as a stream
752+-- and then using writeN to the new array.
753+--
841754-- NOTE: we are passing elemSize explicitly to avoid an Unboxed constraint.
842755-- Since this is not inlined Unboxed consrraint leads to dictionary passing
843756-- which complicates some inspection tests.
844757--
845−{-# NOINLINE reallocExplicitAs #-}
846−reallocExplicitAs :: PinnedState -> Int -> Int -> MutArray a -> IO (MutArray a)
847−reallocExplicitAs ps elemSize newCapacityInBytes MutArray{..} = do
758+{-# NOINLINE reallocExplicit #-}
759+reallocExplicit :: Int -> Int -> MutArray a -> IO (MutArray a)
760+reallocExplicit elemSize newCapacityInBytes MutArray{..} = do
848761 assertM(arrEnd <= arrBound)
849762
850763 -- Allocate new array
851764 let newCapMaxInBytes = roundUpLargeArray newCapacityInBytes
852765 contents <-
853− if ps == Pinned
766+ if Unboxed.isPinned arrContents
854767 then Unboxed.pinnedNew newCapMaxInBytes
855768 else Unboxed.new newCapMaxInBytes
856769 let !(MutByteArray mbarrFrom#) = arrContents
@@ -875,10 +788,6 @@ reallocExplicitAs ps elemSize newCapacityInBytes MutArray{..} = do
875788 , arrBound = newCapInBytes
876789 }
877790
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.
881−
882791-- | @realloc newCapacity array@ reallocates the array to the specified
883792-- capacity in bytes.
884793--
@@ -890,12 +799,7 @@ reallocExplicitAs ps elemSize newCapacityInBytes MutArray{..} = do
890799-- If the original array is pinned, the newly allocated array is also pinned.
891800{-# INLINABLE realloc #-}
892801realloc :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m (MutArray a)
893−realloc bytes arr =
894− let ps =
895− if isPinned arr
896− then Pinned
897− else Unpinned
898− in liftIO $ reallocExplicitAs ps (SIZE_OF(a)) bytes arr
802+realloc bytes arr = liftIO $ reallocExplicit (SIZE_OF(a)) bytes arr
899803
900804-- | @reallocWith label capSizer minIncrBytes array@. The label is used
901805-- in error messages and the capSizer is used to determine the capacity of the
@@ -918,14 +822,14 @@ reallocWith label capSizer minIncrBytes arr = do
918822 where
919823
920824 badSize newSize =
921− Prelude.concat
825+ concat
922826 [ label
923827 , ": new array size (in bytes) is less than required size "
924828 , show newSize
925829 , ". Please check the sizing function passed."
926830 ]
927831
928−-- | @grow newCapacity array@ changes the total capacity of the array so that
832+-- | @resize newCapacity array@ changes the total capacity of the array so that
929833-- it is enough to hold the specified number of elements. Nothing is done if
930834-- the specified capacity is less than the length of the array.
931835--
@@ -933,46 +837,34 @@ reallocWith label capSizer minIncrBytes arr = do
933837-- the block size (4K).
934838--
935839-- /Pre-release/
936−{-# INLINE grow #-}
937−grow :: forall m a. (MonadIO m, Unbox a) =>
840+{-# INLINE resize #-}
841+resize :: forall m a. (MonadIO m, Unbox a) =>
938842 Int -> MutArray a -> m (MutArray a)
939−grow nElems arr@MutArray{..} = do
843+resize nElems arr@MutArray{..} = do
940844 let req = SIZE_OF(a) * nElems
941− cap = arrBound - arrStart
942− if req < cap
845+ len = arrEnd - arrStart
846+ if req < len
943847 then return arr
944848 else realloc req arr
945849
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)
950−resize = grow
951−
952−-- | Like 'grow' but if the requested byte capacity is more than
953−-- 'largeObjectThreshold' then it is rounded up to the closest power of 2.
850+-- | Like 'resize' but if the byte capacity is more than 'largeObjectThreshold'
851+-- then it is rounded up to the closest power of 2.
954852--
955853-- /Pre-release/
956−{-# INLINE growExp #-}
957−growExp :: forall m a. (MonadIO m, Unbox a) =>
854+{-# INLINE resizeExp #-}
855+resizeExp :: forall m a. (MonadIO m, Unbox a) =>
958856 Int -> MutArray a -> m (MutArray a)
959−growExp nElems arr@MutArray{..} = do
857+resizeExp nElems arr@MutArray{..} = do
960858 let req = roundUpLargeArray (SIZE_OF(a) * nElems)
961859 req1 =
962860 if req > largeObjectThreshold
963861 then roundUpToPower2 req
964862 else req
965− cap = arrBound - arrStart
966− if req1 < cap
863+ len = arrEnd - arrStart
864+ if req1 < len
967865 then return arr
968866 else realloc req1 arr
969867
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)
974−resizeExp = growExp
975−
976868-- | Resize the allocated memory to drop any reserved free space at the end of
977869-- the array and reallocate it to reduce wastage.
978870--
@@ -1037,7 +929,7 @@ snocUnsafe arr@MutArray{..} = snocNewEnd (INDEX_NEXT(arrEnd,a)) arr
1037929{-# INLINE snocMay #-}
1038930snocMay :: forall m a. (MonadIO m, Unbox a) =>
1039931 MutArray a -> a -> m (Maybe (MutArray a))
1040−snocMay arr@MutArray{..} x = do
932+snocMay arr@MutArray{..} x = liftIO $ do
1041933 let newEnd = INDEX_NEXT(arrEnd,a)
1042934 if newEnd <= arrBound
1043935 then Just <$> snocNewEnd newEnd arr x
@@ -1051,7 +943,7 @@ snocWithRealloc :: forall m a. (MonadIO m, Unbox a) =>
1051943 -> a
1052944 -> m (MutArray a)
1053945snocWithRealloc sizer arr x = do
1054− arr1 <- reallocWith "snocWith" sizer (SIZE_OF(a)) arr
946+ arr1 <- liftIO $ reallocWith "snocWith" sizer (SIZE_OF(a)) arr
1055947 snocUnsafe arr1 x
1056948
1057949-- | @snocWith sizer arr elem@ mutates @arr@ to append @elem@. The length of
@@ -1073,7 +965,7 @@ snocWith :: forall m a. (MonadIO m, Unbox a) =>
1073965 -> MutArray a
1074966 -> a
1075967 -> m (MutArray a)
1076−snocWith allocSize arr x = do
968+snocWith allocSize arr x = liftIO $ do
1077969 let newEnd = INDEX_NEXT(arrEnd arr,a)
1078970 if newEnd <= arrBound arr
1079971 then snocNewEnd newEnd arr x
@@ -1117,126 +1009,6 @@ snoc = snocWith f
11171009 then oldSize * 2
11181010 else roundUpToPower2 oldSize * 2
11191011
1120−-------------------------------------------------------------------------------
1121−-- Serialization/Deserialization
1122−-------------------------------------------------------------------------------
1123−
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}
1131−
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
1135−-- element.
1136−--
1137−-- /Internal/
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
1142−
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})
1150−
1151−-- | Like 'pokeAppend' but does not grow the array when pre-allocated array
1152−-- capacity becomes full.
1153−--
1154−-- /Internal/
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
1163−
1164−{-# NOINLINE pokeWithRealloc #-}
1165−pokeWithRealloc :: forall m a. (MonadIO m, Unbox a) =>
1166− (Int -> Int)
1167− -> MutArray Word8
1168− -> 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
1173−
1174−{-# INLINE pokeAppendWith #-}
1175−pokeAppendWith :: forall m a. (MonadIO m, Unbox a) =>
1176− (Int -> Int)
1177− -> MutArray Word8
1178− -> 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
1185−
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.
1188−--
1189−-- Definition:
1190−--
1191−-- >>> pokeAppend arr x = MutArray.castUnsafe <$> MutArray.snoc (MutArray.castUnsafe arr) x
1192−--
1193−{-# INLINE pokeAppend #-}
1194−pokeAppend :: forall m a. (MonadIO m, Unbox a) =>
1195− MutArray Word8 -> a -> m (MutArray Word8)
1196−pokeAppend = pokeAppendWith f
1197−
1198− where
1199−
1200− f oldSize =
1201− if isPower2 oldSize
1202− then oldSize * 2
1203− else roundUpToPower2 oldSize * 2
1204−
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.
1208−--
1209−-- /Internal/
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 ())
1216− liftIO $ do
1217− r <- peekAt arrStart arrContents
1218− return (r, MutArray arrContents start1 arrEnd arrBound)
1219−
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)
1226−
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)
1234− if start1 > arrEnd
1235− then return (Nothing, arr)
1236− else liftIO $ do
1237− r <- peekAt arrStart arrContents
1238− return (Just r, MutArray arrContents start1 arrEnd arrBound)
1239−
12401012-------------------------------------------------------------------------------
12411013-- Random reads
12421014-------------------------------------------------------------------------------
@@ -1279,10 +1051,15 @@ getIndexRev i MutArray{..} = do
12791051data GetIndicesState contents start end st =
12801052 GetIndicesState contents start end st
12811053
1282−{-# INLINE indexReaderWith #-}
1283−indexReaderWith :: (Monad m, Unbox a) =>
1054+-- | Given an unfold that generates array indices, read the elements on those
1055+-- indices from the supplied MutArray. An error is thrown if an index is out of
1056+-- bounds.
1057+--
1058+-- /Pre-release/
1059+{-# INLINE getIndicesD #-}
1060+getIndicesD :: (Monad m, Unbox a) =>
12841061 (forall b. IO b -> m b) -> D.Stream m Int -> Unfold m (MutArray a) a
1285−indexReaderWith liftio (D.Stream stepi sti) = Unfold step inject
1062+getIndicesD liftio (D.Stream stepi sti) = Unfold step inject
12861063
12871064 where
12881065
@@ -1301,26 +1078,9 @@ indexReaderWith liftio (D.Stream stepi sti) = Unfold step inject
13011078 D.Skip s -> return $ D.Skip (GetIndicesState contents start end s)
13021079 D.Stop -> return D.Stop
13031080
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
1309−
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
1312−-- bounds.
1313−--
1314−-- /Pre-release/
1315−{-# INLINE indexReader #-}
1316−indexReader :: (MonadIO m, Unbox a) => Stream m Int -> Unfold m (MutArray a) a
1317−indexReader = indexReaderWith liftIO
1318−
1319−-- XXX DO NOT REMOVE, change the signature to use Stream instead of unfold
1320−{-# DEPRECATED getIndices "Please use indexReader instead." #-}
13211081{-# INLINE getIndices #-}
13221082getIndices :: (MonadIO m, Unbox a) => Stream m Int -> Unfold m (MutArray a) a
1323−getIndices = indexReader
1083+getIndices = getIndicesD liftIO
13241084
13251085-------------------------------------------------------------------------------
13261086-- Subarrays
@@ -1615,7 +1375,7 @@ chunksOfAs ps n (D.Stream step state) =
16151375--
16161376-- Same as the following but may be more efficient:
16171377--
1618−-- >>> chunksOf n = Stream.foldMany (MutArray.createOf n)
1378+-- >>> chunksOf n = Stream.foldMany (MutArray.writeN n)
16191379--
16201380-- /Pre-release/
16211381{-# INLINE_NORMAL chunksOf #-}
@@ -1624,14 +1384,14 @@ chunksOf :: forall m a. (MonadIO m, Unbox a)
16241384-- XXX the idiomatic implementation leads to large regression in the D.reverse'
16251385-- benchmark. It seems it has difficulty producing optimized code when
16261386-- converting to StreamK. Investigate GHC optimizations.
1627−-- chunksOf n = D.foldMany (createOf n)
1387+-- chunksOf n = D.foldMany (writeN n)
16281388chunksOf = chunksOfAs Unpinned
16291389
16301390-- | Like 'chunksOf' but creates pinned arrays.
16311391{-# INLINE_NORMAL pinnedChunksOf #-}
16321392pinnedChunksOf :: forall m a. (MonadIO m, Unbox a)
16331393 => Int -> D.Stream m a -> D.Stream m (MutArray a)
1634−-- pinnedChunksOf n = D.foldMany (pinnedCreateOf n)
1394+-- pinnedChunksOf n = D.foldMany (pinnedWriteN n)
16351395pinnedChunksOf = chunksOfAs Pinned
16361396
16371397-- | When we are buffering a stream of unknown size into an array we do not
@@ -1664,10 +1424,16 @@ data FlattenState s contents a =
16641424 OuterLoop s
16651425 | InnerLoop s contents !Int !Int
16661426
1667−{-# INLINE_NORMAL concatWith #-}
1668−concatWith :: forall m a. (Monad m, Unbox a)
1669− => (forall b. IO b -> m b) -> D.Stream m (MutArray a) -> D.Stream m a
1670−concatWith liftio (D.Stream step state) = D.Stream step' (OuterLoop state)
1427+-- | Use the "reader" unfold instead.
1428+--
1429+-- @concatChunks = unfoldMany reader@
1430+--
1431+-- We can try this if there are any fusion issues in the unfold.
1432+--
1433+{-# INLINE_NORMAL concatChunks #-}
1434+concatChunks :: forall m a. (MonadIO m, Unbox a)
1435+ => D.Stream m (MutArray a) -> D.Stream m a
1436+concatChunks (D.Stream step state) = D.Stream step' (OuterLoop state)
16711437
16721438 where
16731439
@@ -1684,30 +1450,24 @@ concatWith liftio (D.Stream step state) = D.Stream step' (OuterLoop state)
16841450 return $ D.Skip $ OuterLoop st
16851451
16861452 step' _ (InnerLoop st contents p end) = do
1687− x <- liftio $ peekAt p contents
1453+ x <- liftIO $ peekAt p contents
16881454 return $ D.Yield x (InnerLoop st contents (INDEX_NEXT(p,a)) end)
16891455
1690−-- | Use the "reader" unfold instead.
1456+{-# DEPRECATED flattenArrays "Please use \"unfoldMany reader\" instead." #-}
1457+flattenArrays :: forall m a. (MonadIO m, Unbox a)
1458+ => D.Stream m (MutArray a) -> D.Stream m a
1459+flattenArrays = concatChunks
1460+
1461+-- | Use the "readerRev" unfold instead.
16911462--
1692−-- @concat = unfoldMany reader@
1463+-- @concatChunks = unfoldMany readerRev@
16931464--
16941465-- We can try this if there are any fusion issues in the unfold.
16951466--
1696−{-# INLINE_NORMAL concat #-}
1697−concat :: forall m a. (MonadIO m, Unbox a)
1467+{-# INLINE_NORMAL concatChunksRev #-}
1468+concatChunksRev :: forall m a. (MonadIO m, Unbox a)
16981469 => D.Stream m (MutArray a) -> D.Stream m a
1699−concat = concatWith liftIO
1700−
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
1706−
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
1710−concatRevWith liftio (D.Stream step state) = D.Stream step' (OuterLoop state)
1470+concatChunksRev (D.Stream step state) = D.Stream step' (OuterLoop state)
17111471
17121472 where
17131473
@@ -1725,26 +1485,14 @@ concatRevWith liftio (D.Stream step state) = D.Stream step' (OuterLoop state)
17251485 return $ D.Skip $ OuterLoop st
17261486
17271487 step' _ (InnerLoop st contents p start) = do
1728− x <- liftio $ peekAt p contents
1488+ x <- liftIO $ peekAt p contents
17291489 let cur = INDEX_PREV(p,a)
17301490 return $ D.Yield x (InnerLoop st contents cur start)
17311491
1732−-- | Use the "readerRev" unfold instead.
1733−--
1734−-- @concat = unfoldMany readerRev@
1735−--
1736−-- We can try this if there are any fusion issues in the unfold.
1737−--
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
1742−
17431492{-# DEPRECATED flattenArraysRev "Please use \"unfoldMany readerRev\" instead." #-}
1744−{-# INLINE flattenArraysRev #-}
17451493flattenArraysRev :: forall m a. (MonadIO m, Unbox a)
17461494 => D.Stream m (MutArray a) -> D.Stream m a
1747−flattenArraysRev = concatRev
1495+flattenArraysRev = concatChunksRev
17481496
17491497-------------------------------------------------------------------------------
17501498-- Unfolds
@@ -1863,11 +1611,11 @@ toList MutArray{..} = liftIO $ go arrStart
18631611 x <- peekAt p arrContents
18641612 (:) x <$> go (INDEX_NEXT(p,a))
18651613
1866−{-# INLINE_NORMAL toStreamWith #-}
1867−toStreamWith ::
1614+{-# INLINE_NORMAL toStreamDWith #-}
1615+toStreamDWith ::
18681616 forall m a. (Monad m, Unbox a)
18691617 => (forall b. IO b -> m b) -> MutArray a -> D.Stream m a
1870−toStreamWith liftio MutArray{..} = D.Stream step arrStart
1618+toStreamDWith liftio MutArray{..} = D.Stream step arrStart
18711619
18721620 where
18731621
@@ -1883,7 +1631,7 @@ toStreamWith liftio MutArray{..} = D.Stream step arrStart
18831631--
18841632{-# INLINE_NORMAL read #-}
18851633read :: forall m a. (MonadIO m, Unbox a) => MutArray a -> D.Stream m a
1886−read = toStreamWith liftIO
1634+read = toStreamDWith liftIO
18871635
18881636{-# INLINE toStreamKWith #-}
18891637toStreamKWith ::
@@ -1902,11 +1650,11 @@ toStreamKWith liftio MutArray{..} = go arrStart
19021650toStreamK :: forall m a. (MonadIO m, Unbox a) => MutArray a -> StreamK m a
19031651toStreamK = toStreamKWith liftIO
19041652
1905−{-# INLINE_NORMAL toStreamRevWith #-}
1906−toStreamRevWith ::
1653+{-# INLINE_NORMAL toStreamDRevWith #-}
1654+toStreamDRevWith ::
19071655 forall m a. (Monad m, Unbox a)
19081656 => (forall b. IO b -> m b) -> MutArray a -> D.Stream m a
1909−toStreamRevWith liftio MutArray{..} =
1657+toStreamDRevWith liftio MutArray{..} =
19101658 let p = INDEX_PREV(arrEnd,a)
19111659 in D.Stream step p
19121660
@@ -1924,7 +1672,7 @@ toStreamRevWith liftio MutArray{..} =
19241672--
19251673{-# INLINE_NORMAL readRev #-}
19261674readRev :: forall m a. (MonadIO m, Unbox a) => MutArray a -> D.Stream m a
1927−readRev = toStreamRevWith liftIO
1675+readRev = toStreamDRevWith liftIO
19281676
19291677{-# INLINE toStreamKRevWith #-}
19301678toStreamKRevWith ::
@@ -1973,7 +1721,7 @@ foldr f z arr = D.foldr f z $ read arr
19731721
19741722-- XXX Keep the bound intact to not lose any free space? Perf impact?
19751723
1976−-- | @unsafeAppendN n arr@ appends up to @n@ input items to the supplied
1724+-- | @writeAppendNUnsafe n arr@ appends up to @n@ input items to the supplied
19771725-- array.
19781726--
19791727-- Unsafe: Do not drive the fold beyond @n@ elements, it will lead to memory
@@ -1982,12 +1730,13 @@ foldr f z arr = D.foldr f z $ read arr
19821730-- Any free space left in the array after appending @n@ elements is lost.
19831731--
19841732-- /Internal/
1985−{-# INLINE_NORMAL unsafeAppendN #-}
1986−unsafeAppendN :: forall m a. (MonadIO m, Unbox a) =>
1733+{-# INLINE_NORMAL writeAppendNUnsafe #-}
1734+writeAppendNUnsafe :: forall m a. (MonadIO m, Unbox a) =>
19871735 Int
19881736 -> m (MutArray a)
19891737 -> Fold m a (MutArray a)
1990−unsafeAppendN n action = fmap fromArrayUnsafe $ FL.foldlM' step initial
1738+writeAppendNUnsafe n action =
1739+ fmap fromArrayUnsafe $ FL.foldlM' step initial
19911740
19921741 where
19931742
@@ -2000,7 +1749,7 @@ unsafeAppendN n action = fmap fromArrayUnsafe $ FL.foldlM' step initial
20001749 -- otherwise we lose that space.
20011750 arr1 <-
20021751 if free < needed
2003− then noinline reallocWith "unsafeAppendN" (+ needed) needed arr
1752+ then noinline reallocWith "writeAppendNUnsafeWith" (+ needed) needed arr
20041753 else return arr
20051754 return $ toArrayUnsafe arr1
20061755
@@ -2008,51 +1757,30 @@ unsafeAppendN n action = fmap fromArrayUnsafe $ FL.foldlM' step initial
20081757 liftIO $ pokeAt end contents x
20091758 return $ ArrayUnsafe contents start (INDEX_NEXT(end,a))
20101759
2011−{-# DEPRECATED writeAppendNUnsafe "Please use unsafeAppendN instead." #-}
2012−{-# INLINE writeAppendNUnsafe #-}
2013−writeAppendNUnsafe :: forall m a. (MonadIO m, Unbox a) =>
2014− Int
2015− -> m (MutArray a)
2016− -> Fold m a (MutArray a)
2017−writeAppendNUnsafe = unsafeAppendN
2018−
20191760-- | Append @n@ elements to an existing array. Any free space left in the array
20201761-- after appending @n@ elements is lost.
20211762--
2022−-- >>> appendN n initial = Fold.take n (MutArray.unsafeAppendN n initial)
1763+-- >>> writeAppendN n initial = Fold.take n (MutArray.writeAppendNUnsafe n initial)
20231764--
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)
2028−
2029−-- XXX Deprecate in major
2030−-- {-# DEPRECATED writeAppendN "Please use appendN instead." #-}
2031−{-# INLINE writeAppendN #-}
1765+{-# INLINE_NORMAL writeAppendN #-}
20321766writeAppendN :: forall m a. (MonadIO m, Unbox a) =>
20331767 Int -> m (MutArray a) -> Fold m a (MutArray a)
2034−writeAppendN = appendN
1768+writeAppendN n initial = FL.take n (writeAppendNUnsafe n initial)
20351769
2036−-- | @appendWith realloc action@ mutates the array generated by @action@ to
1770+-- | @writeAppendWith realloc action@ mutates the array generated by @action@ to
20371771-- append the input stream. If there is no reserved space available in the
20381772-- array it is reallocated to a size in bytes determined by @realloc oldSize@,
20391773-- where @oldSize@ is the current size of the array in bytes.
20401774--
20411775-- Note that the returned array may be a mutated version of original array.
20421776--
2043−-- >>> appendWith sizer = Fold.foldlM' (MutArray.snocWith sizer)
1777+-- >>> writeAppendWith sizer = Fold.foldlM' (MutArray.snocWith sizer)
20441778--
20451779-- /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)
2050−
2051−{-# DEPRECATED writeAppendWith "Please use appendWith instead." #-}
20521780{-# INLINE writeAppendWith #-}
20531781writeAppendWith :: forall m a. (MonadIO m, Unbox a) =>
20541782 (Int -> Int) -> m (MutArray a) -> Fold m a (MutArray a)
2055−writeAppendWith = appendWith
1783+writeAppendWith sizer = FL.foldlM' (snocWith sizer)
20561784
20571785-- | @append action@ mutates the array generated by @action@ to append the
20581786-- input stream. If there is no reserved space available in the array it is
@@ -2060,33 +1788,26 @@ writeAppendWith = appendWith
20601788--
20611789-- Note that the returned array may be a mutated version of original array.
20621790--
2063−-- >>> append = MutArray.appendWith (* 2)
1791+-- >>> writeAppend = MutArray.writeAppendWith (* 2)
20641792--
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)
2069−
2070−-- XXX Deprecate in major
2071−-- {-# DEPRECATED writeAppend "Please use append instead." #-}
20721793{-# INLINE writeAppend #-}
20731794writeAppend :: forall m a. (MonadIO m, Unbox a) =>
20741795 m (MutArray a) -> Fold m a (MutArray a)
2075−writeAppend = append
1796+writeAppend = writeAppendWith (* 2)
20761797
20771798-- XXX We can carry bound as well in the state to make sure we do not lose the
20781799-- remaining capacity. Need to check perf impact.
20791800--
2080−-- | Like 'unsafeCreateOf' but takes a new array allocator @alloc size@
2081−-- function as argument.
1801+-- | Like 'writeNUnsafe' but takes a new array allocator @alloc size@ function
1802+-- as argument.
20821803--
2083−-- >>> unsafeCreateOfWith alloc n = MutArray.unsafeAppendN (alloc n) n
1804+-- >>> writeNWithUnsafe alloc n = MutArray.writeAppendNUnsafe (alloc n) n
20841805--
20851806-- /Pre-release/
2086−{-# INLINE_NORMAL unsafeCreateOfWith #-}
2087−unsafeCreateOfWith :: forall m a. (MonadIO m, Unbox a)
1807+{-# INLINE_NORMAL writeNWithUnsafe #-}
1808+writeNWithUnsafe :: forall m a. (MonadIO m, Unbox a)
20881809 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
2089−unsafeCreateOfWith alloc n = fromArrayUnsafe <$> FL.foldlM' step initial
1810+writeNWithUnsafe alloc n = fromArrayUnsafe <$> FL.foldlM' step initial
20901811
20911812 where
20921813
@@ -2097,64 +1818,40 @@ unsafeCreateOfWith alloc n = fromArrayUnsafe <$> FL.foldlM' step initial
20971818 return
20981819 $ ArrayUnsafe contents start (INDEX_NEXT(end,a))
20991820
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
2105−
21061821{-# INLINE_NORMAL writeNUnsafeAs #-}
21071822writeNUnsafeAs :: forall m a. (MonadIO m, Unbox a)
21081823 => PinnedState -> Int -> Fold m a (MutArray a)
2109−writeNUnsafeAs ps = unsafeCreateOfWith (newAs ps)
1824+writeNUnsafeAs ps = writeNWithUnsafe (newAs ps)
21101825
2111−-- | Like 'createOf' but does not check the array bounds when writing. The fold
1826+-- | Like 'writeN' but does not check the array bounds when writing. The fold
21121827-- driver must not call the step function more than 'n' times otherwise it will
21131828-- corrupt the memory and crash. This function exists mainly because any
21141829-- conditional in the step function blocks fusion causing 10x performance
21151830-- slowdown.
21161831--
2117−-- >>> unsafeCreateOf = MutArray.unsafeCreateOfWith MutArray.emptyOf
1832+-- >>> writeNUnsafe = MutArray.writeNWithUnsafe MutArray.new
21181833--
2119−{-# INLINE_NORMAL unsafeCreateOf #-}
2120−unsafeCreateOf :: forall m a. (MonadIO m, Unbox a)
2121− => Int -> Fold m a (MutArray a)
2122−unsafeCreateOf = writeNUnsafeAs Unpinned
2123−
2124−{-# DEPRECATED writeNUnsafe "Please use unsafeCreateOf instead." #-}
2125−{-# INLINE writeNUnsafe #-}
1834+{-# INLINE_NORMAL writeNUnsafe #-}
21261835writeNUnsafe :: forall m a. (MonadIO m, Unbox a)
21271836 => Int -> Fold m a (MutArray a)
2128−writeNUnsafe = unsafeCreateOf
2129−
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
1837+writeNUnsafe = writeNUnsafeAs Unpinned
21351838
2136−{-# DEPRECATED pinnedWriteNUnsafe "Please use unsafePinnedCreateOf instead." #-}
2137−{-# INLINE pinnedWriteNUnsafe #-}
1839+-- | Like 'writeNUnsafe' but creates a pinned array.
1840+{-# INLINE_NORMAL pinnedWriteNUnsafe #-}
21381841pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a)
21391842 => Int -> Fold m a (MutArray a)
2140−pinnedWriteNUnsafe = unsafePinnedCreateOf
1843+pinnedWriteNUnsafe = writeNUnsafeAs Pinned
21411844
2142−-- | @createOfWith alloc n@ folds a maximum of @n@ elements into an array
1845+-- | @writeNWith alloc n@ folds a maximum of @n@ elements into an array
21431846-- allocated using the @alloc@ function.
21441847--
2145−-- >>> createOfWith alloc n = Fold.take n (MutArray.unsafeCreateOfWith alloc n)
2146−-- >>> createOfWith alloc n = MutArray.appendN (alloc n) n
1848+-- >>> writeNWith alloc n = Fold.take n (MutArray.writeNWithUnsafe alloc n)
1849+-- >>> writeNWith alloc n = MutArray.writeAppendN (alloc n) n
21471850--
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)
2152−
2153−-- {-# DEPRECATED writeNWith "Please use createOfWith instead." #-}
2154−{-# INLINE writeNWith #-}
1851+{-# INLINE_NORMAL writeNWith #-}
21551852writeNWith :: forall m a. (MonadIO m, Unbox a)
21561853 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
2157−writeNWith = createOfWith
1854+writeNWith alloc n = FL.take n (writeNWithUnsafe alloc n)
21581855
21591856{-# INLINE_NORMAL writeNAs #-}
21601857writeNAs ::
@@ -2162,42 +1859,28 @@ writeNAs ::
21621859 => PinnedState
21631860 -> Int
21641861 -> Fold m a (MutArray a)
2165−writeNAs ps = createOfWith (newAs ps)
1862+writeNAs ps = writeNWith (newAs ps)
21661863
2167−-- | @createOf n@ folds a maximum of @n@ elements from the input stream to an
1864+-- | @writeN n@ folds a maximum of @n@ elements from the input stream to an
21681865-- 'MutArray'.
21691866--
2170−-- >>> createOf = MutArray.createOfWith MutArray.new
2171−-- >>> createOf n = Fold.take n (MutArray.unsafeCreateOf n)
2172−-- >>> createOf n = MutArray.appendN n (MutArray.emptyOf n)
1867+-- >>> writeN = MutArray.writeNWith MutArray.new
1868+-- >>> writeN n = Fold.take n (MutArray.writeNUnsafe n)
1869+-- >>> writeN n = MutArray.writeAppendN n (MutArray.new n)
21731870--
2174−{-# INLINE_NORMAL createOf #-}
2175−createOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
2176−createOf = writeNAs Unpinned
2177−
2178−-- XXX Deprecate in major
2179−-- {-# DEPRECATED writeN "Please use createOf instead." #-}
2180−{-# INLINE writeN #-}
1871+{-# INLINE_NORMAL writeN #-}
21811872writeN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
2182−writeN = createOf
1873+writeN = writeNAs Unpinned
21831874
2184−-- | Like 'createOf' but creates a pinned array.
2185−{-# INLINE_NORMAL pinnedCreateOf #-}
2186−pinnedCreateOf ::
2187− forall m a. (MonadIO m, Unbox a)
2188− => Int
2189− -> Fold m a (MutArray a)
2190−pinnedCreateOf = writeNAs Pinned
2191−
2192−{-# DEPRECATED pinnedWriteN "Please use pinnedCreateOf instead." #-}
2193−{-# INLINE pinnedWriteN #-}
1875+-- | Like 'writeN' but creates a pinned array.
1876+{-# INLINE_NORMAL pinnedWriteN #-}
21941877pinnedWriteN ::
21951878 forall m a. (MonadIO m, Unbox a)
21961879 => Int
21971880 -> Fold m a (MutArray a)
2198−pinnedWriteN = pinnedCreateOf
1881+pinnedWriteN = writeNAs Pinned
21991882
2200−-- | Like unsafeCreateOfWith but writes the array in reverse order.
1883+-- | Like writeNWithUnsafe but writes the array in reverse order.
22011884--
22021885-- /Internal/
22031886{-# INLINE_NORMAL writeRevNWithUnsafe #-}
@@ -2218,7 +1901,7 @@ writeRevNWithUnsafe alloc n = fromArrayUnsafe <$> FL.foldlM' step initial
22181901 return
22191902 $ ArrayUnsafe contents ptr end
22201903
2221−-- | Like createOfWith but writes the array in reverse order.
1904+-- | Like writeNWith but writes the array in reverse order.
22221905--
22231906-- /Internal/
22241907{-# INLINE_NORMAL writeRevNWith #-}
@@ -2226,36 +1909,31 @@ writeRevNWith :: forall m a. (MonadIO m, Unbox a)
22261909 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
22271910writeRevNWith alloc n = FL.take n (writeRevNWithUnsafe alloc n)
22281911
2229−-- | Like 'createOf' but writes the array in reverse order.
1912+-- | Like writeN but writes the array in reverse order.
22301913--
22311914-- /Pre-release/
2232−{-# INLINE_NORMAL revCreateOf #-}
2233−revCreateOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
2234−revCreateOf = writeRevNWith new
2235−
2236−{-# DEPRECATED writeRevN "Please use revCreateOf instead." #-}
2237−{-# INLINE writeRevN #-}
1915+{-# INLINE_NORMAL writeRevN #-}
22381916writeRevN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
2239−writeRevN = revCreateOf
1917+writeRevN = writeRevNWith new
22401918
22411919-- | @pinnedWriteNAligned align n@ folds a maximum of @n@ elements from the
22421920-- input stream to a 'MutArray' aligned to the given size.
22431921--
2244−-- >>> pinnedWriteNAligned align = MutArray.createOfWith (MutArray.pinnedNewAligned align)
2245−-- >>> pinnedWriteNAligned align n = MutArray.appendN n (MutArray.pinnedNewAligned align n)
1922+-- >>> pinnedWriteNAligned align = MutArray.writeNWith (MutArray.pinnedNewAligned align)
1923+-- >>> pinnedWriteNAligned align n = MutArray.writeAppendN n (MutArray.pinnedNewAligned align n)
22461924--
22471925-- /Pre-release/
22481926--
22491927{-# INLINE_NORMAL pinnedWriteNAligned #-}
22501928pinnedWriteNAligned :: forall m a. (MonadIO m, Unbox a)
22511929 => Int -> Int -> Fold m a (MutArray a)
2252−pinnedWriteNAligned align = createOfWith (pinnedNewAligned align)
1930+pinnedWriteNAligned align = writeNWith (pinnedNewAligned align)
22531931
22541932-- XXX Buffer to a list instead?
22551933
22561934-- | Buffer a stream into a stream of arrays.
22571935--
2258−-- >>> buildChunks n = Fold.many (MutArray.createOf n) Fold.toStreamK
1936+-- >>> buildChunks n = Fold.many (MutArray.writeN n) Fold.toStreamK
22591937--
22601938-- Breaking an array into an array stream can be useful to consume a large
22611939-- array sequentially such that memory of the array is released incrementatlly.
@@ -2267,10 +1945,9 @@ pinnedWriteNAligned align = createOfWith (pinnedNewAligned align)
22671945{-# INLINE_NORMAL buildChunks #-}
22681946buildChunks :: (MonadIO m, Unbox a) =>
22691947 Int -> Fold m a (StreamK n (MutArray a))
2270−buildChunks n = FL.many (createOf n) FL.toStreamK
1948+buildChunks n = FL.many (writeN n) FL.toStreamK
22711949
22721950{-# DEPRECATED writeChunks "Please use buildChunks instead." #-}
2273−{-# INLINE writeChunks #-}
22741951writeChunks :: (MonadIO m, Unbox a) =>
22751952 Int -> Fold m a (StreamK n (MutArray a))
22761953writeChunks = buildChunks
@@ -2278,29 +1955,29 @@ writeChunks = buildChunks
22781955{-# INLINE_NORMAL writeWithAs #-}
22791956writeWithAs :: forall m a. (MonadIO m, Unbox a)
22801957 => PinnedState -> Int -> Fold m a (MutArray a)
2281−-- writeWithAs ps n = FL.rmapM rightSize $ appendWith (* 2) (newAs ps n)
1958+-- writeWithAs ps n = FL.rmapM rightSize $ writeAppendWith (* 2) (newAs ps n)
22821959writeWithAs ps elemCount =
22831960 FL.rmapM extract $ FL.foldlM' step initial
22841961
22851962 where
22861963
22871964 initial = do
2288− when (elemCount < 0) $ error "createWith: elemCount is negative"
2289− newAs ps elemCount
1965+ when (elemCount < 0) $ error "writeWith: elemCount is negative"
1966+ liftIO $ newAs ps elemCount
22901967
22911968 step arr@(MutArray _ start end bound) x
22921969 | INDEX_NEXT(end,a) > bound = do
22931970 let oldSize = end - start
22941971 newSize = max (oldSize * 2) 1
2295− arr1 <- liftIO $ reallocExplicitAs ps (SIZE_OF(a)) newSize arr
1972+ arr1 <- liftIO $ reallocExplicit (SIZE_OF(a)) newSize arr
22961973 snocUnsafe arr1 x
22971974 step arr x = snocUnsafe arr x
22981975
22991976 extract = liftIO . rightSize
23001977
2301−-- XXX Compare createWith with fromStreamD which uses an array of streams
1978+-- XXX Compare writeWith with fromStreamD which uses an array of streams
23021979-- implementation. We can write this using buildChunks above if that is faster.
2303−-- If createWith is faster then we should use that to implement
1980+-- If writeWith is faster then we should use that to implement
23041981-- fromStreamD.
23051982--
23061983-- XXX The realloc based implementation needs to make one extra copy if we use
@@ -2315,56 +1992,39 @@ writeWithAs ps elemCount =
23151992-- XXX check if GHC's memory allocator is efficient enough. We can try the C
23161993-- malloc to compare against.
23171994
2318−-- | @createWith minCount@ folds the whole input to a single array. The array
1995+-- | @writeWith minCount@ folds the whole input to a single array. The array
23191996-- starts at a size big enough to hold minCount elements, the size is doubled
23201997-- every time the array needs to be grown.
23211998--
23221999-- /Caution! Do not use this on infinite streams./
23232000--
2324−-- >>> f n = MutArray.appendWith (* 2) (MutArray.emptyOf n)
2325−-- >>> createWith n = Fold.rmapM MutArray.rightSize (f n)
2326−-- >>> createWith n = Fold.rmapM MutArray.fromChunksK (MutArray.buildChunks n)
2001+-- >>> f n = MutArray.writeAppendWith (* 2) (MutArray.new n)
2002+-- >>> writeWith n = Fold.rmapM MutArray.rightSize (f n)
2003+-- >>> writeWith n = Fold.rmapM MutArray.fromChunksK (MutArray.buildChunks n)
23272004--
23282005-- /Pre-release/
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
2334−
2335−{-# DEPRECATED writeWith "Please use createWith instead." #-}
2336−{-# INLINE writeWith #-}
2006+{-# INLINE_NORMAL writeWith #-}
23372007writeWith :: forall m a. (MonadIO m, Unbox a)
23382008 => Int -> Fold m a (MutArray a)
2339−writeWith = createWith
2009+-- writeWith n = FL.rmapM rightSize $ writeAppendWith (* 2) (new n)
2010+writeWith = writeWithAs Unpinned
23402011
23412012-- | Fold the whole input to a single array.
23422013--
2343−-- Same as 'createWith' using an initial array size of 'arrayChunkBytes' bytes
2014+-- Same as 'writeWith' using an initial array size of 'arrayChunkBytes' bytes
23442015-- rounded up to the element size.
23452016--
23462017-- /Caution! Do not use this on infinite streams./
23472018--
2348−{-# INLINE create #-}
2349−create :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
2350−create = createWith (allocBytesToElemCount (undefined :: a) arrayChunkBytes)
2351−
2352−-- XXX Deprecate in major
2353−-- {-# DEPRECATED write "Please use create instead." #-}
23542019{-# INLINE write #-}
23552020write :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
2356−write = create
2021+write = writeWith (allocBytesToElemCount (undefined :: a) arrayChunkBytes)
23572022
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)
2361−pinnedCreate =
2362− writeWithAs Pinned (allocBytesToElemCount (undefined :: a) arrayChunkBytes)
2363−
2364−{-# DEPRECATED pinnedWrite "Please use pinnedCreate instead." #-}
2023+-- | Like 'write' but creates a pinned array.
23652024{-# INLINE pinnedWrite #-}
23662025pinnedWrite :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
2367−pinnedWrite = pinnedCreate
2026+pinnedWrite =
2027+ writeWithAs Pinned (allocBytesToElemCount (undefined :: a) arrayChunkBytes)
23682028
23692029-------------------------------------------------------------------------------
23702030-- construct from streams, known size
@@ -2374,7 +2034,7 @@ pinnedWrite = pinnedCreate
23742034fromStreamDNAs :: forall m a. (MonadIO m, Unbox a)
23752035 => PinnedState -> Int -> D.Stream m a -> m (MutArray a)
23762036fromStreamDNAs ps limit str = do
2377− (arr :: MutArray a) <- newAs ps limit
2037+ (arr :: MutArray a) <- liftIO $ newAs ps limit
23782038 end <- D.foldlM' (fwrite (arrContents arr)) (return $ arrEnd arr) $ D.take limit str
23792039 return $ arr {arrEnd = end}
23802040
@@ -2384,18 +2044,17 @@ fromStreamDNAs ps limit str = do
23842044 liftIO $ pokeAt ptr arrContents x
23852045 return $ INDEX_NEXT(ptr,a)
23862046
2387−-- | Use the 'createOf' fold instead.
2047+-- | Use the 'writeN' fold instead.
23882048--
2389−-- >>> fromStreamN n = Stream.fold (MutArray.createOf n)
2049+-- >>> fromStreamN n = Stream.fold (MutArray.writeN n)
23902050--
23912051{-# INLINE_NORMAL fromStreamN #-}
23922052fromStreamN :: forall m a. (MonadIO m, Unbox a)
23932053 => Int -> D.Stream m a -> m (MutArray a)
2394−-- fromStreamDN n = D.fold (createOf n)
2054+-- fromStreamDN n = D.fold (writeN n)
23952055fromStreamN = fromStreamDNAs Unpinned
23962056
23972057{-# DEPRECATED fromStreamDN "Please use fromStreamN instead." #-}
2398−{-# INLINE fromStreamDN #-}
23992058fromStreamDN :: forall m a. (MonadIO m, Unbox a)
24002059 => Int -> D.Stream m a -> m (MutArray a)
24012060fromStreamDN = fromStreamN
@@ -2418,20 +2077,20 @@ pinnedFromListN n xs = fromStreamDNAs Pinned n $ D.fromList xs
24182077-- /Pre-release/
24192078{-# INLINE fromListRevN #-}
24202079fromListRevN :: (MonadIO m, Unbox a) => Int -> [a] -> m (MutArray a)
2421−fromListRevN n xs = D.fold (revCreateOf n) $ D.fromList xs
2080+fromListRevN n xs = D.fold (writeRevN n) $ D.fromList xs
24222081
24232082-- | Convert a pure stream in Identity monad to a mutable array.
24242083{-# INLINABLE fromPureStreamN #-}
24252084fromPureStreamN :: (MonadIO m, Unbox a) =>
24262085 Int -> Stream Identity a -> m (MutArray a)
24272086fromPureStreamN n xs =
2428− D.fold (createOf n) $ D.morphInner (return . runIdentity) xs
2087+ liftIO $ D.fold (writeN n) $ D.morphInner (return . runIdentity) xs
24292088
24302089-- | Convert a pure stream in Identity monad to a mutable array.
24312090{-# INLINABLE fromPureStream #-}
24322091fromPureStream :: (MonadIO m, Unbox a) => Stream Identity a -> m (MutArray a)
24332092fromPureStream xs =
2434− D.fold create $ D.morphInner (return . runIdentity) xs
2093+ liftIO $ D.fold write $ D.morphInner (return . runIdentity) xs
24352094
24362095{-# INLINABLE fromPtrN #-}
24372096fromPtrN :: MonadIO m => Int -> Ptr Word8 -> m (MutArray Word8)
@@ -2440,7 +2099,7 @@ fromPtrN len addr = do
24402099 -- XXX We can implement a stream copy in a similar way by streaming Word64
24412100 -- first and then remaining Word8.
24422101 arr <- new len
2443− _ <- unsafeAsPtr arr
2102+ _ <- asUnpinnedPtrUnsafe arr
24442103 (\ptr -> liftIO $ c_memcpy ptr addr (fromIntegral len))
24452104 return (arr {arrEnd = len})
24462105
@@ -2456,7 +2115,7 @@ fromByteStr# addr = do
24562115 len <- liftIO $ c_strlen (Ptr addr)
24572116 let lenInt = fromIntegral len
24582117 arr <- new lenInt
2459− _ <- unsafeAsPtr arr (\ptr -> liftIO $ c_memcpy ptr (Ptr addr) len)
2118+ _ <- asUnpinnedPtrUnsafe arr (\ptr -> liftIO $ c_memcpy ptr (Ptr addr) len)
24602119 return (arr {arrEnd = lenInt})
24612120
24622121-------------------------------------------------------------------------------
@@ -2477,7 +2136,7 @@ fromChunksRealloced s = do
24772136 arr <- D.foldlM' spliceExp (pure a) strm
24782137 -- Reallocation is exponential so there may be 50% empty space in
24792138 -- worst case. One more reallocation to reclaim the space.
2480− rightSize arr
2139+ liftIO $ rightSize arr
24812140 Nothing -> pure nil
24822141
24832142-------------------------------------------------------------------------------
@@ -2515,7 +2174,6 @@ fromChunksK :: (Unbox a, MonadIO m) =>
25152174fromChunksK = fromChunkskAs Unpinned
25162175
25172176{-# DEPRECATED fromArrayStreamK "Please use fromChunksK instead." #-}
2518−{-# INLINE fromArrayStreamK #-}
25192177fromArrayStreamK :: (Unbox a, MonadIO m) =>
25202178 StreamK m (MutArray a) -> m (MutArray a)
25212179fromArrayStreamK = fromChunksK
@@ -2527,7 +2185,7 @@ fromStreamDAs ps m =
25272185 arrayStreamKFromStreamDAs Unpinned m >>= fromChunkskAs ps
25282186
25292187-- | 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
2188+-- single array from a stream of unknown size. 'writeN' is at least twice
25312189-- as efficient when the size is already known.
25322190--
25332191-- Note that if the input stream is too large memory allocation for the array
@@ -2539,19 +2197,19 @@ fromStreamDAs ps m =
25392197fromStream :: (MonadIO m, Unbox a) => Stream m a -> m (MutArray a)
25402198fromStream = fromStreamDAs Unpinned
25412199
2542−-- fromStream (Stream m) = P.fold create m
2200+-- fromStream (Stream m) = P.fold write m
25432201-- CAUTION: a very large number (millions) of arrays can degrade performance
25442202-- due to GC overhead because we need to buffer the arrays before we flatten
25452203-- all the arrays.
25462204--
2547−-- XXX Compare if this is faster or "fold create".
2205+-- XXX Compare if this is faster or "fold write".
25482206--
25492207-- | We could take the approach of doubling the memory allocation on each
25502208-- overflow. This would result in more or less the same amount of copying as in
25512209-- the chunking approach. However, if we have to shrink in the end then it may
25522210-- result in an extra copy of the entire data.
25532211--
2554−-- >>> fromStreamD = StreamD.fold MutArray.create
2212+-- >>> fromStreamD = StreamD.fold MutArray.write
25552213--
25562214{-# INLINE fromStreamD #-}
25572215{-# DEPRECATED fromStreamD "Please use fromStream instead." #-}
@@ -2581,10 +2239,6 @@ fromListRev xs = fromListRevN (Prelude.length xs) xs
25812239-- Cloning
25822240-------------------------------------------------------------------------------
25832241
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.
2587−
25882242{-# INLINE cloneAs #-}
25892243cloneAs ::
25902244 ( MonadIO m
@@ -2594,7 +2248,7 @@ cloneAs ::
25942248 )
25952249 => PinnedState -> MutArray a -> m (MutArray a)
25962250cloneAs ps src =
2597− do
2251+ liftIO $ do
25982252 let startSrc = arrStart src
25992253 srcLen = arrEnd src - startSrc
26002254 newArrContents <-
@@ -2633,16 +2287,17 @@ spliceCopy :: forall m a. MonadIO m =>
26332287 Unbox a =>
26342288#endif
26352289 MutArray a -> MutArray a -> m (MutArray a)
2636−spliceCopy arr1 arr2 = do
2290+spliceCopy arr1 arr2 = liftIO $ do
26372291 let start1 = arrStart arr1
26382292 start2 = arrStart arr2
26392293 len1 = arrEnd arr1 - start1
26402294 len2 = arrEnd arr2 - start2
2641− let len = len1 + len2
2295+ let newLen = len1 + len2
26422296 newArrContents <-
26432297 if Unboxed.isPinned (arrContents arr1)
2644− then liftIO $ Unboxed.pinnedNew len
2645− else liftIO $ Unboxed.new len
2298+ then Unboxed.pinnedNew newLen
2299+ else Unboxed.new newLen
2300+ let len = len1 + len2
26462301 putSliceUnsafe (arrContents arr1) start1 newArrContents 0 len1
26472302 putSliceUnsafe (arrContents arr2) start2 newArrContents len1 len2
26482303 return $ MutArray newArrContents 0 len len
@@ -2654,7 +2309,7 @@ spliceCopy arr1 arr2 = do
26542309spliceUnsafe :: MonadIO m =>
26552310 MutArray a -> MutArray a -> m (MutArray a)
26562311spliceUnsafe dst src =
2657− do
2312+ liftIO $ do
26582313 let startSrc = arrStart src
26592314 srcLen = arrEnd src - startSrc
26602315 endDst = arrEnd dst
@@ -2676,7 +2331,7 @@ spliceWith :: forall m a. (MonadIO m, Unbox a) =>
26762331 (Int -> Int -> Int) -> MutArray a -> MutArray a -> m (MutArray a)
26772332spliceWith sizer dst@(MutArray _ start end bound) src = do
26782333{-
2679− let f = appendWith (`sizer` byteLength src) (return dst)
2334+ let f = writeAppendWith (`sizer` byteLength src) (return dst)
26802335 in D.fold f (toStreamD src)
26812336-}
26822337 assert (end <= bound) (return ())
@@ -2692,7 +2347,7 @@ spliceWith sizer dst@(MutArray _ start end bound) src = do
26922347 $ "splice: newSize is less than the total size "
26932348 ++ "of arrays being appended. Please check the "
26942349 ++ "sizer function passed."
2695− realloc newSizeInBytes dst
2350+ liftIO $ realloc newSizeInBytes dst
26962351 else return dst
26972352 spliceUnsafe dst1 src
26982353
@@ -2729,22 +2384,11 @@ spliceExp = spliceWith (\l1 l2 -> max (l1 * 2) (l1 + l2))
27292384-- Splitting
27302385-------------------------------------------------------------------------------
27312386
2732−-- | Generate a stream of array slices using a predicate. The array element
2733−-- matching the predicate is dropped.
2734−--
2735−-- /Pre-release/
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)
2742−
27432387-- | Drops the separator byte
27442388{-# INLINE breakOn #-}
27452389breakOn :: MonadIO m
27462390 => Word8 -> MutArray Word8 -> m (MutArray Word8, Maybe (MutArray Word8))
2747−breakOn sep arr@MutArray{..} = unsafeAsPtr arr $ \p -> liftIO $ do
2391+breakOn sep arr@MutArray{..} = asUnpinnedPtrUnsafe arr $ \p -> liftIO $ do
27482392 -- XXX We do not need memchr here, we can use a Haskell equivalent.
27492393 -- Need efficient stream based primitives that work on Word64.
27502394 loc <- c_memchr p sep (fromIntegral $ byteLength arr)
@@ -2767,41 +2411,32 @@ breakOn sep arr@MutArray{..} = unsafeAsPtr arr $ \p -> liftIO $ do
27672411 }
27682412 )
27692413
2770−-- | Like 'splitAt' but does not check whether the index is valid.
2771−--
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)
2777− p = arrStart + off
2778− in ( MutArray
2779− { arrContents = arrContents
2780− , arrStart = arrStart
2781− , arrEnd = p
2782− , arrBound = p
2783− }
2784− , MutArray
2785− { arrContents = arrContents
2786− , arrStart = p
2787− , arrEnd = arrEnd
2788− , arrBound = arrBound
2789− }
2790− )
2791−
27922414-- | Create two slices of an array without copying the original array. The
27932415-- specified index @i@ is the first index of the second slice.
27942416--
2795−{-# INLINE splitAt #-}
27962417splitAt :: forall a. Unbox a => Int -> MutArray a -> (MutArray a, MutArray a)
2797−splitAt i arr =
2418+splitAt i arr@MutArray{..} =
27982419 let maxIndex = length arr - 1
27992420 in if i < 0
28002421 then error "sliceAt: negative array index"
28012422 else if i > maxIndex
28022423 then error $ "sliceAt: specified array index " ++ show i
28032424 ++ " is beyond the maximum index " ++ show maxIndex
2804− else unsafeSplitAt i arr
2425+ else let off = i * SIZE_OF(a)
2426+ p = arrStart + off
2427+ in ( MutArray
2428+ { arrContents = arrContents
2429+ , arrStart = arrStart
2430+ , arrEnd = p
2431+ , arrBound = p
2432+ }
2433+ , MutArray
2434+ { arrContents = arrContents
2435+ , arrStart = p
2436+ , arrEnd = arrEnd
2437+ , arrBound = arrBound
2438+ }
2439+ )
28052440
28062441-------------------------------------------------------------------------------
28072442-- Casting
@@ -2851,13 +2486,9 @@ cast arr =
28512486-- guarantees that unsafe calls will be performed in the calling thread. Making
28522487-- it safe to pass heap-allocated objects to unsafe functions.
28532488
2854−-- XXX Should we just name it asPtr, the unsafety is implicit for any pointer
2489+-- Should we just name it asPtr, the unsafety is implicit for any pointer
28552490-- operations. And we are safe from Haskell perspective because we will be
28562491-- pinning the memory.
2857−--
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.
28612492
28622493-- | Use a @MutArray a@ as @Ptr a@. This is useful when we want to pass an
28632494-- array as a pointer to some operating system call or to a "safe" FFI call.
@@ -2875,21 +2506,16 @@ cast arr =
28752506--
28762507-- /Pre-release/
28772508--
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))
2883−
2884−{-# DEPRECATED asPtrUnsafe "Please use unsafePinnedAsPtr instead." #-}
28852509{-# INLINE asPtrUnsafe #-}
28862510asPtrUnsafe :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
2887−asPtrUnsafe = unsafePinnedAsPtr
2511+asPtrUnsafe arr f =
2512+ Unboxed.asPtrUnsafe
2513+ (arrContents arr) (\ptr -> f (ptr `plusPtr` arrStart arr))
28882514
2889−{-# INLINE unsafeAsPtr #-}
2890−unsafeAsPtr :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
2891−unsafeAsPtr arr f =
2892− Unboxed.unsafeAsPtr
2515+{-# INLINE asUnpinnedPtrUnsafe #-}
2516+asUnpinnedPtrUnsafe :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
2517+asUnpinnedPtrUnsafe arr f =
2518+ Unboxed.asUnpinnedPtrUnsafe
28932519 (arrContents arr) (\ptr -> f (ptr `plusPtr` arrStart arr))
28942520
28952521-------------------------------------------------------------------------------
@@ -2907,26 +2533,28 @@ unsafeAsPtr arr f =
29072533-- /Pre-release/
29082534{-# INLINE byteCmp #-}
29092535byteCmp :: 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
2917− EQ -> do
2918− r <- liftIO $ IO $ \s# ->
2919− let res =
2920− I#
2921− (compareByteArrays#
2922− (unsafeCoerce# marr1)
2923− st1#
2924− (unsafeCoerce# marr2)
2925− st2#
2926− len#)
2927− in (# s#, res #)
2928− return $ compare r 0
2929− x -> return x
2536+byteCmp arr1 arr2 =
2537+ liftIO
2538+ $ do
2539+ let marr1 = getMutableByteArray# (arrContents arr1)
2540+ marr2 = getMutableByteArray# (arrContents arr2)
2541+ !(I# st1#) = arrStart arr1
2542+ !(I# st2#) = arrStart arr2
2543+ !(I# len#) = byteLength arr1
2544+ case compare (byteLength arr1) (byteLength arr2) of
2545+ EQ -> do
2546+ r <- liftIO $ IO $ \s# ->
2547+ let res =
2548+ I#
2549+ (compareByteArrays#
2550+ (unsafeCoerce# marr1)
2551+ st1#
2552+ (unsafeCoerce# marr2)
2553+ st2#
2554+ len#)
2555+ in (# s#, res #)
2556+ return $ compare r 0
2557+ x -> return x
29302558
29312559{-# INLINE cmp #-}
29322560{-# DEPRECATED cmp "Please use byteCmp instead." #-}
@@ -2943,309 +2571,7 @@ byteEq :: MonadIO m => MutArray a -> MutArray a -> m Bool
29432571byteEq arr1 arr2 = fmap (EQ ==) $ byteCmp arr1 arr2
29442572
29452573-------------------------------------------------------------------------------
2946−-- Compact
2947−-------------------------------------------------------------------------------
2948−
2949−-- Note: LE versions avoid an extra copy compared to GE. LE parser trades
2950−-- backtracking one array in lieu of avoiding a copy. However, LE and GE both
2951−-- can leave some memory unused. They can split the last array to fit it
2952−-- exactly in the space.
2953−
2954−{-# INLINE_NORMAL pCompactLeAs #-}
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
2959−
2960− where
2961−
2962− maxBytes = maxElems * SIZE_OF(a)
2963−
2964− functionName = "Streamly.Internal.Data.MutArray.pCompactLE"
2965−
2966− initial =
2967− return
2968− $ if maxElems <= 0
2969− then error
2970− $ functionName
2971− ++ ": the size of arrays ["
2972− ++ show maxElems ++ "] must be a natural number"
2973− else Parser.IPartial Nothing
2974−
2975− step Nothing arr =
2976− return
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
2986− else do
2987− buf1 <-
2988− if byteCapacity buf < maxBytes
2989− then liftIO $ reallocExplicitAs
2990− ps (SIZE_OF(a)) maxBytes buf
2991− else return buf
2992− buf2 <- spliceUnsafe buf1 arr
2993− return $ Parser.Partial 0 (Just buf2)
2994−
2995− extract Nothing = return $ Parser.Done 0 nil
2996− extract (Just buf) = return $ Parser.Done 0 buf
2997−
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.
3002−--
3003−-- @maxElems@ must be greater than 0.
3004−--
3005−-- Generates unpinned arrays irrespective of the pinning status of input
3006−-- arrays.
3007−--
3008−-- /Internal/
3009−{-# INLINE pCompactLE #-}
3010−pCompactLE ::
3011− forall m a. (MonadIO m, Unbox a)
3012− => Int -> Parser (MutArray a) m (MutArray a)
3013−pCompactLE = pCompactLeAs Unpinned
3014−
3015−-- | Pinned version of 'pCompactLE'.
3016−{-# INLINE pPinnedCompactLE #-}
3017−pPinnedCompactLE ::
3018− forall m a. (MonadIO m, Unbox a)
3019− => Int -> Parser (MutArray a) m (MutArray a)
3020−pPinnedCompactLE = pCompactLeAs Pinned
3021−
3022−data SpliceState s arr
3023− = SpliceInitial s
3024− | SpliceBuffering s arr
3025− | SpliceYielding arr (SpliceState s arr)
3026− | SpliceFinish
3027−
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.
3032−
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)
3038−
3039− where
3040−
3041− maxBytes = maxElems * SIZE_OF(a)
3042−
3043− functionName = "Streamly.Internal.Data.MutArray.rCompactLE"
3044−
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"
3051− r <- step gst st
3052− case r of
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
3060−
3061− -- XXX Split the last array to use the space more compactly.
3062− step' gst (SpliceBuffering st buf) = do
3063− r <- step gst st
3064− case r of
3065− D.Yield arr s -> do
3066− let len = byteLength buf + byteLength arr
3067− if len > maxBytes
3068− then return $
3069− D.Skip (SpliceYielding buf (SpliceBuffering s arr))
3070− else do
3071− buf1 <- if byteCapacity buf < maxBytes
3072− then liftIO $ reallocExplicitAs
3073− ps (SIZE_OF(a)) maxBytes buf
3074− else return 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)
3079−
3080− step' _ SpliceFinish = return D.Stop
3081−
3082− step' _ (SpliceYielding arr next) = return $ D.Yield arr next
3083−
3084−
3085−{-# INLINE_NORMAL fCompactGeAs #-}
3086−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
3090−
3091− where
3092−
3093− minBytes = minElems * SIZE_OF(a)
3094−
3095− functionName = "Streamly.Internal.Data.MutArray.fCompactGE"
3096−
3097− initial =
3098− return
3099− $ if minElems < 0
3100− then error
3101− $ functionName
3102− ++ ": the size of arrays ["
3103− ++ show minElems ++ "] must be a natural number"
3104− else FL.Partial Nothing
3105−
3106− step Nothing arr =
3107− return
3108− $ let len = byteLength arr
3109− in if len >= minBytes
3110− then FL.Done arr
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
3115− buf1 <-
3116− if byteCapacity buf < len
3117− then liftIO $ reallocExplicitAs
3118− ps (SIZE_OF(a)) (max minBytes len) buf
3119− else return buf
3120− buf2 <- spliceUnsafe buf1 arr
3121− if len >= minBytes
3122− then return $ FL.Done buf2
3123− else return $ FL.Partial (Just buf2)
3124−
3125− extract Nothing = return nil
3126− extract (Just buf) = return buf
3127−
3128−-- | Fold @fCompactGE minElems@ coalesces adjacent arrays in the input stream
3129−-- until the size becomes greater than or equal to @minElems@.
3130−--
3131−-- Generates unpinned arrays irrespective of the pinning status of input
3132−-- arrays.
3133−{-# INLINE fCompactGE #-}
3134−fCompactGE ::
3135− forall m a. (MonadIO m, Unbox a)
3136− => Int -> FL.Fold m (MutArray a) (MutArray a)
3137−fCompactGE = fCompactGeAs Unpinned
3138−
3139−-- | Pinned version of 'fCompactGE'.
3140−{-# INLINE fPinnedCompactGE #-}
3141−fPinnedCompactGE ::
3142− forall m a. (MonadIO m, Unbox a)
3143− => Int -> FL.Fold m (MutArray a) (MutArray a)
3144−fPinnedCompactGE = fCompactGeAs Pinned
3145−
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
3153−
3154− where
3155−
3156− minBytes = minElems * SIZE_OF(a)
3157−
3158− functionName = "Streamly.Internal.Data.MutArray.lCompactGE"
3159−
3160− initial = do
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"
3165−
3166− r <- initial1
3167− return $ first (Tuple' Nothing) r
3168−
3169− {-# INLINE runInner #-}
3170− runInner len acc buf =
3171− if len >= minBytes
3172− then do
3173− r <- step1 acc buf
3174− case r of
3175− FL.Done _ -> return $ FL.Done ()
3176− FL.Partial s -> do
3177− _ <- final1 s
3178− res <- initial1
3179− return $ first (Tuple' Nothing) res
3180− else return $ FL.Partial $ Tuple' (Just buf) acc
3181−
3182− step (Tuple' Nothing r1) arr =
3183− runInner (byteLength arr) r1 arr
3184−
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
3191− else return buf
3192− buf2 <- spliceUnsafe buf1 arr
3193− runInner len r1 buf2
3194−
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
3197− -- partial.
3198− --
3199− -- extract forces the pending buffer to be sent to the fold which is not
3200− -- what we want.
3201− extract _ = error "lCompactGE: not designed for scanning"
3202−
3203− final (Tuple' Nothing r1) = final1 r1
3204− final (Tuple' (Just buf) r1) = do
3205− r <- step1 r1 buf
3206− case r of
3207− FL.Partial rr -> final1 rr
3208− FL.Done _ -> return ()
3209−
3210−-- | Like 'compactGE' but for transforming folds instead of stream.
3211−--
3212−-- >>> lCompactGE n = Fold.many (MutArray.fCompactGE n)
3213−--
3214−-- Generates unpinned arrays irrespective of the pinning status of input
3215−-- arrays.
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
3220−
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
3226−
3227−-- | @compactGE n stream@ coalesces adjacent arrays in the @stream@ until
3228−-- the size becomes greater than or equal to @n@.
3229−--
3230−-- >>> compactGE n = Stream.foldMany (MutArray.fCompactGE n)
3231−--
3232−{-# INLINE compactGE #-}
3233−compactGE ::
3234− (MonadIO m, Unbox a)
3235− => Int -> Stream m (MutArray a) -> Stream m (MutArray a)
3236−compactGE n = D.foldMany (fCompactGE n)
3237−
3238−-- | 'compactEQ n' coalesces adajacent arrays in the input stream to
3239−-- arrays of exact size @n@.
3240−--
3241−-- /Unimplemented/
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)
3246−
3247−-------------------------------------------------------------------------------
3248−-- In-place mutation algorithms
2574+-- NFData
32492575-------------------------------------------------------------------------------
32502576
32512577-- | Strip elements which match with predicate from both ends.
core/src/Streamly/Internal/Data/MutByteArray/Type.hs+16−40
@@ -13,7 +13,7 @@ module Streamly.Internal.Data.MutByteArray.Type
1313 -- ** MutByteArray
1414 MutByteArray(..)
1515 , MutableByteArray
16− , getMutableByteArray# -- XXX getMutByteArray#
16+ , getMutableByteArray#
1717
1818 -- ** Pinning
1919 , PinnedState(..)
@@ -22,24 +22,20 @@ module Streamly.Internal.Data.MutByteArray.Type
2222 , unpin
2323
2424 -- ** Allocation
25− , empty
26− , newBytesAs -- XXX should be removed
25+ , nil
26+ , newBytesAs
2727 , new
2828 , pinnedNew
29− , pinnedNewAlignedBytes -- XXX should be removed
29+ , pinnedNewAlignedBytes
3030
3131 -- ** Access
32− , sizeOfMutableByteArray -- XXX length
32+ , sizeOfMutableByteArray
3333 , putSliceUnsafe
3434 , cloneSliceUnsafeAs
3535 , cloneSliceUnsafe
3636 , pinnedCloneSliceUnsafe
37− , unsafePinnedAsPtr
38− , unsafeAsPtr
39−
40− -- ** Deprecated
4137 , asPtrUnsafe
42− , nil
38+ , asUnpinnedPtrUnsafe
4339 ) where
4440
4541import Control.Monad.IO.Class (MonadIO(..))
@@ -58,7 +54,7 @@ import GHC.Exts
5854
5955data PinnedState
6056 = Pinned
61− | Unpinned deriving (Show, Eq)
57+ | Unpinned
6258
6359-- XXX can use UnliftedNewtypes
6460
@@ -87,9 +83,6 @@ touch :: MutByteArray -> IO ()
8783touch (MutByteArray contents) =
8884 IO $ \s -> case touch# contents s of s' -> (# s', () #)
8985
90−-- XXX Some functions in this module are "IO" and others are "m", we need to
91−-- make it consistent.
92−
9386-- XXX We can provide another API for "unsafe" FFI calls passing an unlifted
9487-- pointer to the FFI call. For unsafe calls we do not need to pin the array.
9588-- We can pass an unlifted pointer to the FFI routine to avoid GC kicking in
@@ -118,9 +111,9 @@ touch (MutByteArray contents) =
118111--
119112-- /Pre-release/
120113--
121−{-# INLINE unsafePinnedAsPtr #-}
122−unsafePinnedAsPtr :: MonadIO m => MutByteArray -> (Ptr a -> m b) -> m b
123−unsafePinnedAsPtr arr f = do
114+{-# INLINE asPtrUnsafe #-}
115+asPtrUnsafe :: MonadIO m => MutByteArray -> (Ptr a -> m b) -> m b
116+asPtrUnsafe arr f = do
124117 contents <- liftIO $ pin arr
125118 let !ptr = Ptr (byteArrayContents#
126119 (unsafeCoerce# (getMutableByteArray# contents)))
@@ -128,15 +121,10 @@ unsafePinnedAsPtr arr f = do
128121 liftIO $ touch contents
129122 return r
130123
131−{-# DEPRECATED asPtrUnsafe "Please use unsafePinnedAsPtr instead." #-}
132−{-# INLINE asPtrUnsafe #-}
133−asPtrUnsafe :: MonadIO m => MutByteArray -> (Ptr a -> m b) -> m b
134−asPtrUnsafe = unsafePinnedAsPtr
135−
136124-- | For use with unsafe FFI functions. Does not force pin the array memory.
137−{-# INLINE unsafeAsPtr #-}
138−unsafeAsPtr :: MonadIO m => MutByteArray -> (Ptr a -> m b) -> m b
139−unsafeAsPtr arr f = do
125+{-# INLINE asUnpinnedPtrUnsafe #-}
126+asUnpinnedPtrUnsafe :: MonadIO m => MutByteArray -> (Ptr a -> m b) -> m b
127+asUnpinnedPtrUnsafe arr f = do
140128 let !ptr = Ptr (byteArrayContents#
141129 (unsafeCoerce# (getMutableByteArray# arr)))
142130 r <- f ptr
@@ -147,16 +135,10 @@ unsafeAsPtr arr f = do
147135-- Creation
148136--------------------------------------------------------------------------------
149137
150−{-# NOINLINE empty #-}
151−empty :: MutByteArray
152−empty = unsafePerformIO $ new 0
153−
154−{-# DEPRECATED nil "Please use empty instead" #-}
138+{-# NOINLINE nil #-}
155139nil :: MutByteArray
156−nil = empty
140+nil = unsafePerformIO $ new 0
157141
158−-- XXX add "newRounded" to round up the large size to the next page boundary
159−-- and return the allocated size.
160142{-# INLINE new #-}
161143new :: Int -> IO MutByteArray
162144new nbytes | nbytes < 0 =
@@ -170,7 +152,7 @@ new (I# nbytes) = IO $ \s ->
170152{-# INLINE pinnedNew #-}
171153pinnedNew :: Int -> IO MutByteArray
172154pinnedNew nbytes | nbytes < 0 =
173− errorWithoutStackTrace "pinnedNew: size must be >= 0"
155+ errorWithoutStackTrace "pinnedNewByteArray: size must be >= 0"
174156pinnedNew (I# nbytes) = IO $ \s ->
175157 case newPinnedByteArray# nbytes s of
176158 (# s', mbarr# #) ->
@@ -196,12 +178,6 @@ newBytesAs Pinned = pinnedNew
196178-- Copying
197179-------------------------------------------------------------------------------
198180
199−-- Note: Array copy is more efficient than streaming copy.
200−-- CopyMutableByteArray# translates to genMemcpy in GHC/CmmToAsm/X86/CodeGen.hs
201−-- glibc memcpy copies bytes/words/pages - unrolls the loops:
202−-- https://github.com/bminor/glibc/blob/4290aed05135ae4c0272006442d147f2155e70d7/string/memcpy.c
203−-- https://github.com/bminor/glibc/blob/4290aed05135ae4c0272006442d147f2155e70d7/string/wordcopy.c
204−
205181-- | Put a sub range of a source array into a subrange of a destination array.
206182-- This is not safe as it does not check the bounds of neither the src array
207183-- nor the destination array.
core/src/Streamly/Internal/Data/Serialize/TH.hs+1−5
@@ -7,11 +7,7 @@
77-- Maintainer : streamly@composewell.com
88-- Stability : experimental
99-- Portability : GHC
10−
11−-- XXX Instead of applying the product constructor in one go can we apply it
12−-- one at a time in case of too many arguments, compiler may not have to save
13−-- them in local vars.
14−
10+--
1511module Streamly.Internal.Data.Serialize.TH
1612 (
1713 -- Deriving
core/src/Streamly/Internal/Data/Stream/Container.hs+48−56
@@ -11,17 +11,16 @@
1111
1212module Streamly.Internal.Data.Stream.Container
1313 (
14− -- * Deduplication
15− ordNub
14+ nub
1615
17− -- * Joins
18− , leftJoin
19− , outerJoin
16+ -- * Joins for unconstrained types
17+ , joinLeftGeneric
18+ , joinOuterGeneric
2019
21− -- * Ord Joins
22− , innerOrdJoin
23− , leftOrdJoin
24− , outerOrdJoin
20+ -- * Joins with Ord constraint
21+ , joinInner
22+ , joinLeft
23+ , joinOuter
2524 )
2625where
2726
@@ -48,15 +47,12 @@ import qualified Streamly.Internal.Data.Stream.Transformer as Stream
4847
4948#include "DocTestDataStream.hs"
5049
51−-- | @nub@ specialized to 'Ord' types for better performance. Returns a
52−-- subsequence of the stream removing any duplicate elements.
53−--
54−-- The memory used is proportional to the number of unique elements in the
55−-- stream. One way to limit the memory is to use @take@ on the resulting
56−-- stream to limit the unique elements in the stream.
57−{-# INLINE_NORMAL ordNub #-}
58−ordNub :: (Monad m, Ord a) => Stream m a -> Stream m a
59−ordNub (Stream step1 state1) = Stream step (Set.empty, state1)
50+-- | The memory used is proportional to the number of unique elements in the
51+-- stream. If we want to limit the memory we can just use "take" to limit the
52+-- uniq elements in the stream.
53+{-# INLINE_NORMAL nub #-}
54+nub :: (Monad m, Ord a) => Stream m a -> Stream m a
55+nub (Stream step1 state1) = Stream step (Set.empty, state1)
6056
6157 where
6258
@@ -82,8 +78,8 @@ toMap =
8278--
8379-- XXX An IntMap may be faster when the keys are Int.
8480-- XXX Use hashmap instead of map?
85−
86−-- | 'innerJoin' specialized to 'Ord' types for better performance.
81+--
82+-- | Like 'joinInner' but uses a 'Map' for efficiency.
8783--
8884-- If the input streams have duplicate keys, the behavior is undefined.
8985--
@@ -94,10 +90,10 @@ toMap =
9490-- Time: O(m + n)
9591--
9692-- /Pre-release/
97−{-# INLINE innerOrdJoin #-}
98−innerOrdJoin :: (Monad m, Ord k) =>
93+{-# INLINE joinInner #-}
94+joinInner :: (Monad m, Ord k) =>
9995 Stream m (k, a) -> Stream m (k, b) -> Stream m (k, a, b)
100−innerOrdJoin s1 s2 =
96+joinInner s1 s2 =
10197 Stream.concatEffect $ do
10298 km <- toMap s2
10399 pure $ Stream.mapMaybe (joinAB km) s1
@@ -110,33 +106,32 @@ innerOrdJoin s1 s2 =
110106 Nothing -> Nothing
111107
112108-- XXX We can do this concurrently.
113−-- XXX Check performance of StreamD vs StreamK
114109-- XXX If the second stream is sorted and passed as an Array or a seek capable
115110-- stream then we could use binary search if we have an Ord instance or
116111-- Ordering returning function. The time complexity would then become (m x log
117112-- n).
118113
119−-- | Like 'innerJoin' but emits @(a, Just b)@ whenever a and b are equal, for
120−-- those @a@'s that are not equal to any @b@ emits @(a, Nothing)@.
121−--
122−-- This is a generalization of 'innerJoin' to include all elements from the
123−-- left stream and not just those which have an equal in the right stream. This
124−-- is not a commutative operation, the order of the stream arguments matters.
114+-- XXX Check performance of StreamD vs StreamK
115+
116+-- | Like 'joinInner' but emit @(a, Just b)@, and additionally, for those @a@'s
117+-- that are not equal to any @b@ emit @(a, Nothing)@.
125118--
126−-- All the caveats mentioned in 'innerJoin' apply here as well. Right join is
127−-- not provided because it is just a flipped left join:
119+-- The second stream is evaluated multiple times. If the stream is a
120+-- consume-once stream then the caller should cache it in an 'Data.Array.Array'
121+-- before calling this function. Caching may also improve performance if the
122+-- stream is expensive to evaluate.
128123--
129−-- >>> rightJoin eq = flip (Stream.leftJoin eq)
124+-- >>> joinRightGeneric eq = flip (Stream.joinLeftGeneric eq)
130125--
131126-- Space: O(n) assuming the second stream is cached in memory.
132127--
133128-- Time: O(m x n)
134129--
135130-- /Unimplemented/
136−{-# INLINE leftJoin #-}
137−leftJoin :: Monad m =>
131+{-# INLINE joinLeftGeneric #-}
132+joinLeftGeneric :: Monad m =>
138133 (a -> b -> Bool) -> Stream m a -> Stream m b -> Stream m (a, Maybe b)
139−leftJoin eq s1 s2 = Stream.evalStateT (return False) $ unCross $ do
134+joinLeftGeneric eq s1 s2 = Stream.evalStateT (return False) $ unCross $ do
140135 a <- mkCross (Stream.liftInner s1)
141136 -- XXX should we use StreamD monad here?
142137 -- XXX Is there a better way to perform some action at the end of a loop
@@ -157,17 +152,19 @@ leftJoin eq s1 s2 = Stream.evalStateT (return False) $ unCross $ do
157152 else mkCross Stream.nil
158153 Nothing -> return (a, Nothing)
159154
160−-- | 'leftJoin' specialized to 'Ord' types for better performance.
155+-- XXX rename to joinLeftOrd?
156+
157+-- | A more efficient 'joinLeft' using a hashmap for efficiency.
161158--
162159-- Space: O(n)
163160--
164161-- Time: O(m + n)
165162--
166163-- /Pre-release/
167−{-# INLINE leftOrdJoin #-}
168−leftOrdJoin :: (Ord k, Monad m) =>
164+{-# INLINE joinLeft #-}
165+joinLeft :: (Ord k, Monad m) =>
169166 Stream m (k, a) -> Stream m (k, b) -> Stream m (k, a, Maybe b)
170−leftOrdJoin s1 s2 =
167+joinLeft s1 s2 =
171168 Stream.concatEffect $ do
172169 km <- toMap s2
173170 return $ fmap (joinAB km) s1
@@ -180,19 +177,14 @@ leftOrdJoin s1 s2 =
180177 Nothing -> (k, a, Nothing)
181178
182179-- XXX We can do this concurrently.
183−-- XXX Check performance of StreamD vs StreamK cross operation.
184180
185−-- | Like 'leftJoin' but emits a @(Just a, Just b)@. Like 'leftJoin', for those
181+-- XXX Check performance of StreamD vs StreamK
182+
183+-- | Like 'joinLeft' but emits a @(Just a, Just b)@. Like 'joinLeft', for those
186184-- @a@'s that are not equal to any @b@ emit @(Just a, Nothing)@, but
187185-- additionally, for those @b@'s that are not equal to any @a@ emit @(Nothing,
188186-- Just b)@.
189187--
190−-- This is a generalization of left join to include all the elements from the
191−-- right stream as well, in other words it is a combination of left and right
192−-- joins. This is a commutative operation. The order of stream arguments can be
193−-- changed without affecting results, except for the ordering of elements in
194−-- the resulting tuple.
195−--
196188-- For space efficiency use the smaller stream as the second stream.
197189--
198190-- Space: O(n)
@@ -200,15 +192,15 @@ leftOrdJoin s1 s2 =
200192-- Time: O(m x n)
201193--
202194-- /Pre-release/
203−{-# INLINE outerJoin #-}
204−outerJoin :: MonadIO m =>
195+{-# INLINE joinOuterGeneric #-}
196+joinOuterGeneric :: MonadIO m =>
205197 (a -> b -> Bool)
206198 -> Stream m a
207199 -> Stream m b
208200 -> Stream m (Maybe a, Maybe b)
209−outerJoin eq s1 s2 =
201+joinOuterGeneric eq s1 s =
210202 Stream.concatEffect $ do
211− inputArr <- Array.fromStream s2
203+ inputArr <- Array.fromStream s
212204 let len = Array.length inputArr
213205 foundArr <-
214206 Stream.fold
@@ -262,18 +254,18 @@ outerJoin eq s1 s2 =
262254-- a flag. At the end go through @Stream m b@ and find those that are not in that
263255-- hash to return (Nothing, b).
264256
265−-- | 'outerJoin' specialized to 'Ord' types for better performance.
257+-- | Like 'joinOuter' but uses a 'Map' for efficiency.
266258--
267259-- Space: O(m + n)
268260--
269261-- Time: O(m + n)
270262--
271263-- /Pre-release/
272−{-# INLINE outerOrdJoin #-}
273−outerOrdJoin ::
264+{-# INLINE joinOuter #-}
265+joinOuter ::
274266 (Ord k, MonadIO m) =>
275267 Stream m (k, a) -> Stream m (k, b) -> Stream m (k, Maybe a, Maybe b)
276−outerOrdJoin s1 s2 =
268+joinOuter s1 s2 =
277269 Stream.concatEffect $ do
278270 km1 <- kvFold s1
279271 km2 <- kvFold s2
core/src/Streamly/Internal/Data/Stream/Eliminate.hs+25−33
@@ -13,24 +13,36 @@
1313--
1414module Streamly.Internal.Data.Stream.Eliminate
1515 (
16− -- * Running a Parser
17− parse
16+ -- * Running a 'Fold'
17+ fold
18+
19+ -- -- * Running a 'Parser'
20+ , parse
1821 , parseD
1922 , parseBreak
2023 , parseBreakD
2124
22− -- * Deconstruction
25+ -- * Stream Deconstruction
2326 , uncons
2427
2528 -- * Right Folds
29+ , foldrM
30+ , foldr
31+ , foldrMx
2632 , foldr1
2733
34+ -- * Left Folds
35+ , foldlM'
36+ , foldl'
37+ , foldlMx'
38+ , foldlx'
39+
2840 -- * Specific Fold Functions
41+ , drain
2942 , mapM_ -- Map and Fold
3043 , null
3144 , head
3245 , headElse
33− , init
3446 , tail
3547 , last
3648 , elem
@@ -48,9 +60,16 @@ module Streamly.Internal.Data.Stream.Eliminate
4860 , the
4961
5062 -- * To containers
63+ , toList
5164 , toListRev
5265
5366 -- * Multi-Stream Folds
67+ -- ** Comparisons
68+ -- | These should probably be expressed using zipping operations.
69+ , eqBy
70+ , cmpBy
71+
72+ -- ** Substreams
5473 -- | These should probably be expressed using parsers.
5574 , isPrefixOf
5675 , isInfixOf
@@ -71,7 +90,7 @@ import Foreign.Storable (Storable)
7190import GHC.Exts (SpecConstrAnnotation(..))
7291import GHC.Types (SPEC(..))
7392import Streamly.Internal.Data.Parser (ParseError(..))
74−import Streamly.Internal.Data.SVar.Type (adaptState, defState)
93+import Streamly.Internal.Data.SVar.Type (defState)
7594import Streamly.Internal.Data.Unbox (Unbox)
7695
7796import Streamly.Internal.Data.Maybe.Strict (Maybe'(..))
@@ -86,7 +105,7 @@ import qualified Streamly.Internal.Data.Stream.Transform as StreamD
86105
87106import Prelude hiding
88107 ( Foldable(..), all, any, head, last, lookup, mapM, mapM_
89− , notElem, splitAt, init, tail, (!!))
108+ , notElem, splitAt, tail, (!!))
90109import Data.Foldable (length)
91110import Streamly.Internal.Data.Stream.Type
92111
@@ -372,35 +391,9 @@ head = foldrM (\x _ -> return (Just x)) (return Nothing)
372391headElse :: Monad m => a -> Stream m a -> m a
373392headElse a = foldrM (\x _ -> return x) (return a)
374393
375−{-# INLINE_NORMAL init #-}
376−init :: Monad m => Stream m a -> m (Maybe (Stream m a))
377−init stream = do
378− r <- uncons stream
379− case r of
380− Nothing -> return Nothing
381− Just (h, Stream step1 state1) ->
382− return $ Just $ Stream step (h, state1)
383−
384− where
385−
386− step gst (a, s1) = do
387− res <- step1 (adaptState gst) s1
388− return $
389− case res of
390− Yield x s -> Yield a (x, s)
391− Skip s -> Skip (a, s)
392− Stop -> Stop
393−
394−-- | Same as:
395−--
396−-- >>> tail = fmap (fmap snd) . Stream.uncons
397−--
398394-- Does not fuse, has the same performance as the StreamK version.
399−--
400395{-# INLINE_NORMAL tail #-}
401396tail :: Monad m => Stream m a -> m (Maybe (Stream m a))
402−tail = fmap (fmap snd) . uncons
403−{-
404397tail (UnStream step state) = go SPEC state
405398 where
406399 go !_ st = do
@@ -409,7 +402,6 @@ tail (UnStream step state) = go SPEC state
409402 Yield _ s -> return (Just $ Stream step s)
410403 Skip s -> go SPEC s
411404 Stop -> return Nothing
412−-}
413405
414406-- XXX will it fuse? need custom impl?
415407{-# INLINE_NORMAL last #-}
core/src/Streamly/Internal/Data/Stream/Exception.hs+6−9
@@ -9,20 +9,17 @@
99
1010module Streamly.Internal.Data.Stream.Exception
1111 (
12− -- * Resources
13− before
14− , afterIO
15− , afterUnsafe
16− , finallyIO
17− , finallyUnsafe
18− , gbracket_
12+ gbracket_
1913 , gbracket
14+ , before
15+ , afterUnsafe
16+ , afterIO
2017 , bracketUnsafe
2118 , bracketIO3
2219 , bracketIO
23−
24− -- * Exceptions
2520 , onException
21+ , finallyUnsafe
22+ , finallyIO
2623 , ghandle
2724 , handle
2825 )
core/src/Streamly/Internal/Data/Stream/Generate.hs+12
@@ -16,13 +16,20 @@ module Streamly.Internal.Data.Stream.Generate
1616 (
1717 -- * Primitives
1818 nil
19+ , nilM
1920 , cons
21+ , consM
22+
23+ -- * From 'Unfold'
24+ , unfold
2025
2126 -- * Unfolding
2227 , unfoldr
2328 , unfoldrM
2429
2530 -- * From Values
31+ , fromPure
32+ , fromEffect
2633 , repeat
2734 , repeatM
2835 , replicate
@@ -88,6 +95,7 @@ module Streamly.Internal.Data.Stream.Generate
8895 -- * From Containers
8996 -- | Transform an input structure into a stream.
9097
98+ , fromList
9199 , fromListM
92100 , fromFoldable
93101 , fromFoldableM
@@ -96,6 +104,10 @@ module Streamly.Internal.Data.Stream.Generate
96104 , fromPtr
97105 , fromPtrN
98106 , fromByteStr#
107+
108+ -- * Conversions
109+ , fromStreamK
110+ , toStreamK
99111 )
100112where
101113
core/src/Streamly/Internal/Data/Stream/Nesting.hs+139−10
@@ -55,6 +55,11 @@ module Streamly.Internal.Data.Stream.Nesting
5555 -- yields an element. A special case of unfoldRoundRobin.
5656 , roundRobin -- interleaveFair?/ParallelFair
5757
58+ -- *** Zipping
59+ -- | Zip corresponding elements of two streams.
60+ , zipWith
61+ , zipWithM
62+
5863 -- *** Merging
5964 -- | Interleave elements from two streams based on a condition.
6065 , mergeBy
@@ -71,10 +76,17 @@ module Streamly.Internal.Data.Stream.Nesting
7176 -- unfoldMany: Unfold m a b -> t m a -> t m b
7277 -- @
7378
79+ -- *** ConcatMap
80+ -- | Generate streams by mapping a stream generator on each element of an
81+ -- input stream, append the resulting streams and flatten.
82+ , concatMap
83+ , concatMapM
84+
7485 -- *** ConcatUnfold
7586 -- | Generate streams by using an unfold on each element of an input
7687 -- stream, append the resulting streams and flatten. A special case of
7788 -- gintercalate.
89+ , unfoldMany
7890 , ConcatUnfoldInterleaveState (..)
7991 , unfoldInterleave
8092 , unfoldRoundRobin
@@ -106,8 +118,11 @@ module Streamly.Internal.Data.Stream.Nesting
106118
107119 -- ** Folding
108120 -- | Apply folds on a stream.
121+ , foldMany
122+ , refoldMany
109123 , foldSequence
110124 , foldIterateM
125+ , refoldIterateM
111126
112127 -- ** Parsing
113128 -- | Parsing is opposite to flattening. 'parseMany' is dual to concatMap or
@@ -124,6 +139,7 @@ module Streamly.Internal.Data.Stream.Nesting
124139
125140 -- ** Grouping
126141 -- | Group segments of a stream and fold. Special case of parsing.
142+ , groupsOf
127143 , groupsBy
128144 , groupsWhile
129145 , groupsRollingBy
@@ -131,8 +147,9 @@ module Streamly.Internal.Data.Stream.Nesting
131147 -- ** Splitting
132148 -- | A special case of parsing.
133149 , wordsBy
134− , splitOnSeq -- XXX splitOnSeg
135− , splitOnSuffixSeq -- XXX splitOnSegSuffix, splitOnTrailer
150+ , splitOnSeq
151+ , splitOnSuffixSeq
152+ , sliceOnSuffix
136153
137154 -- XXX Implement these as folds or parsers instead.
138155 , splitOnSuffixSeqAny
@@ -141,8 +158,9 @@ module Streamly.Internal.Data.Stream.Nesting
141158
142159 -- * Transform (Nested Containers)
143160 -- | Opposite to compact in ArrayStream
144− , splitInnerBy -- XXX innerSplitOn
145− , splitInnerBySuffix -- XXX innerSplitOnSuffix
161+ , splitInnerBy
162+ , splitInnerBySuffix
163+ , intersectBySorted
146164
147165 -- * Reduce By Streams
148166 , dropPrefix
@@ -164,9 +182,12 @@ import Fusion.Plugin.Types (Fuse(..))
164182import GHC.Types (SPEC(..))
165183
166184import Streamly.Internal.Data.Array.Type (Array(..))
185+import Streamly.Internal.Data.Fold.Step (Step(..))
167186import Streamly.Internal.Data.Fold.Type (Fold(..))
168187import Streamly.Internal.Data.Parser (ParseError(..))
188+import Streamly.Internal.Data.Refold.Type (Refold(..))
169189import Streamly.Internal.Data.SVar.Type (adaptState)
190+import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
170191import Streamly.Internal.Data.Unbox (Unbox, sizeOf)
171192import Streamly.Internal.Data.Unfold.Type (Unfold(..))
172193
@@ -592,6 +613,49 @@ mergeFstBy :: -- Monad m =>
592613mergeFstBy _f _m1 _m2 = undefined
593614 -- fromStreamK $ D.mergeFstBy f (toStreamD m1) (toStreamD m2)
594615
616+-------------------------------------------------------------------------------
617+-- Intersection of sorted streams
618+-------------------------------------------------------------------------------
619+
620+-- Assuming the streams are sorted in ascending order
621+{-# INLINE_NORMAL intersectBySorted #-}
622+intersectBySorted :: Monad m
623+ => (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
624+intersectBySorted cmp (Stream stepa ta) (Stream stepb tb) =
625+ Stream step
626+ ( ta -- left stream state
627+ , tb -- right stream state
628+ , Nothing -- left value
629+ , Nothing -- right value
630+ )
631+
632+ where
633+
634+ {-# INLINE_LATE step #-}
635+ -- step 1, fetch the first value
636+ step gst (sa, sb, Nothing, b) = do
637+ r <- stepa gst sa
638+ return $ case r of
639+ Yield a sa' -> Skip (sa', sb, Just a, b) -- step 2/3
640+ Skip sa' -> Skip (sa', sb, Nothing, b)
641+ Stop -> Stop
642+
643+ -- step 2, fetch the second value
644+ step gst (sa, sb, a@(Just _), Nothing) = do
645+ r <- stepb gst sb
646+ return $ case r of
647+ Yield b sb' -> Skip (sa, sb', a, Just b) -- step 3
648+ Skip sb' -> Skip (sa, sb', a, Nothing)
649+ Stop -> Stop
650+
651+ -- step 3, compare the two values
652+ step _ (sa, sb, Just a, Just b) = do
653+ let res = cmp a b
654+ return $ case res of
655+ GT -> Skip (sa, sb, Just a, Nothing) -- step 2
656+ LT -> Skip (sa, sb, Nothing, Just b) -- step 1
657+ EQ -> Yield a (sa, sb, Nothing, Just b) -- step 1
658+
595659------------------------------------------------------------------------------
596660-- Combine N Streams - unfoldMany
597661------------------------------------------------------------------------------
@@ -1230,6 +1294,77 @@ foldIterateM func seed0 (Stream step state) =
12301294 stepOuter _ (FIterYield a next) = return $ Yield a next
12311295 stepOuter _ FIterStop = return Stop
12321296
1297+{-# ANN type CIterState Fuse #-}
1298+data CIterState s f fs b
1299+ = CIterInit s f
1300+ | CIterConsume s fs
1301+ | CIterYield b (CIterState s f fs b)
1302+ | CIterStop
1303+
1304+-- | Like 'foldIterateM' but using the 'Refold' type instead. This could be
1305+-- much more efficient due to stream fusion.
1306+--
1307+-- /Internal/
1308+{-# INLINE_NORMAL refoldIterateM #-}
1309+refoldIterateM ::
1310+ Monad m => Refold m b a b -> m b -> Stream m a -> Stream m b
1311+refoldIterateM (Refold fstep finject fextract) initial (Stream step state) =
1312+ Stream stepOuter (CIterInit state initial)
1313+
1314+ where
1315+
1316+ {-# INLINE iterStep #-}
1317+ iterStep st action = do
1318+ res <- action
1319+ return
1320+ $ Skip
1321+ $ case res of
1322+ FL.Partial fs -> CIterConsume st fs
1323+ FL.Done fb -> CIterYield fb $ CIterInit st (return fb)
1324+
1325+ {-# INLINE_LATE stepOuter #-}
1326+ stepOuter _ (CIterInit st action) = do
1327+ iterStep st (action >>= finject)
1328+ stepOuter gst (CIterConsume st fs) = do
1329+ r <- step (adaptState gst) st
1330+ case r of
1331+ Yield x s -> iterStep s (fstep fs x)
1332+ Skip s -> return $ Skip $ CIterConsume s fs
1333+ Stop -> do
1334+ b <- fextract fs
1335+ return $ Skip $ CIterYield b CIterStop
1336+ stepOuter _ (CIterYield a next) = return $ Yield a next
1337+ stepOuter _ CIterStop = return Stop
1338+
1339+-- "n" elements at the end are dropped by the fold.
1340+{-# INLINE sliceBy #-}
1341+sliceBy :: Monad m => Fold m a Int -> Int -> Refold m (Int, Int) a (Int, Int)
1342+sliceBy (Fold step1 initial1 extract1 _final) n = Refold step inject extract
1343+
1344+ where
1345+
1346+ inject (i, len) = do
1347+ r <- initial1
1348+ return $ case r of
1349+ Partial s -> Partial $ Tuple' (i + len + n) s
1350+ Done l -> Done (i, l)
1351+
1352+ step (Tuple' i s) x = do
1353+ r <- step1 s x
1354+ return $ case r of
1355+ Partial s1 -> Partial $ Tuple' i s1
1356+ Done len -> Done (i, len)
1357+
1358+ extract (Tuple' i s) = (i,) <$> extract1 s
1359+
1360+{-# INLINE sliceOnSuffix #-}
1361+sliceOnSuffix :: Monad m => (a -> Bool) -> Stream m a -> Stream m (Int, Int)
1362+sliceOnSuffix predicate =
1363+ -- Scan the stream with the given refold
1364+ refoldIterateM
1365+ (sliceBy (FL.takeEndBy_ predicate FL.length) 1)
1366+ (return (-1, 0))
1367+
12331368------------------------------------------------------------------------------
12341369-- Parsing
12351370------------------------------------------------------------------------------
@@ -2986,8 +3121,6 @@ splitInnerBySuffix isEmpty splitter joiner (Stream step1 state1) =
29863121--
29873122-- Space: @O(1)@
29883123--
2989−-- See also stripPrefix.
2990−--
29913124-- /Unimplemented/
29923125{-# INLINE dropPrefix #-}
29933126dropPrefix ::
@@ -3000,8 +3133,6 @@ dropPrefix = error "Not implemented yet!"
30003133--
30013134-- Space: @O(n)@ where n is the length of the infix.
30023135--
3003−-- See also stripInfix.
3004−--
30053136-- /Unimplemented/
30063137{-# INLINE dropInfix #-}
30073138dropInfix ::
@@ -3014,8 +3145,6 @@ dropInfix = error "Not implemented yet!"
30143145--
30153146-- Space: @O(n)@ where n is the length of the suffix.
30163147--
3017−-- See also stripSuffix.
3018−--
30193148-- /Unimplemented/
30203149{-# INLINE dropSuffix #-}
30213150dropSuffix ::
core/src/Streamly/Internal/Data/Stream/Top.hs+115−243
@@ -8,73 +8,38 @@
88-- Portability : GHC
99--
1010-- Top level module that can depend on all other lower level Stream modules.
11−--
12−-- Design notes:
13−--
14−-- The order of arguments in the join operations should ideally be opposite. It
15−-- should be such that the infinite stream is the last one. The transformation
16−-- should be on the last argument, so if you curry the functions with all other
17−-- arguments we get a @Stream -> Stream@ function. The first stream argument
18−-- may be considered as a config or modifier for the operation.
19−--
20−-- Benefit of changing the order is that we get a more intuitive Stream ->
21−-- Stream transformation after currying all other arguments. The inner loop
22−-- streams become arguments for the transformation, more like local modifiers
23−-- for the global outer stream as the last argument. Thus we can continue using
24−-- transformations on the outer stream in a composed pipeline. Otherwise we can
25−-- use flip to flip the order.
26−--
27−-- The fact that the inner stream can be used in the loop multiple times also
28−-- tells that this is not the real effectful stream, it is more like a pure
29−-- stream or an array. In fact we may consider using an Identity streams as
30−-- inner streams in which case these functions will not look nice.
31−--
32−-- Downsides:
33−--
34−-- * Maybe less intuitive to think about, because we usually think the first
35−-- stream as the outer loop and second as the inner.
36−-- * Zip and merge operations will continue using the opposite order.
37−-- * Need to change the order of cross, crossWith operations as well
38−-- * It will be inconsistent with Data.List. The functions cannot be used as
39−-- intuitive operators.
40−--
41−-- The choice is similar to concatMap vs bind. concatMap is pipeline
42−-- composition friendly but bind is user intuition friendly. Another option is
43−-- to have other functions with a different argument order e.g. flippedCross
44−-- instead of cross.
45−--
46−-- If we change the order we have to make sure that we have a consistent
47−-- convention for set-like and the cross join operations.
4811
4912module Streamly.Internal.Data.Stream.Top
5013 (
51− -- * Sampling
14+ -- * Transformation
15+ -- ** Sampling
5216 -- | Value agnostic filtering.
5317 strideFromThen
5418
55− -- * Straight Joins
56− -- | These are set-like operations but not exactly set operations because
57− -- streams are not necessarily sets, they may have duplicated elements.
58− -- These operations are generic i.e. they work on streams of unconstrained
59− -- types, therefore, they have quadratic performance characterstics. For
60− -- better performance using Set or Map structures see the
61− -- Streamly.Internal.Data.Stream.Container module.
62− , intersectBy
63− , deleteFirstsBy
64− , unionBy
65−
66− -- Set like operations on sorted streams
67− , sortedIntersectBy
68− , sortedDeleteFirstsBy
69− , sortedUnionBy
70−
71− -- * Cross Joins
72− , innerJoin
73−
74− -- Joins on sorted stream
75− , innerSortedJoin
76− , leftSortedJoin
77− , outerSortedJoin
19+ -- * Nesting
20+ -- ** Set like operations
21+ -- | These are not exactly set operations because streams are not
22+ -- necessarily sets, they may have duplicated elements. These operations
23+ -- are generic i.e. they work on streams of unconstrained types, therefore,
24+ -- they have quadratic performance characterstics. For better performance
25+ -- using Set structures see the Streamly.Internal.Data.Stream.Container
26+ -- module.
27+ , filterInStreamGenericBy
28+ , deleteInStreamGenericBy
29+ , unionWithStreamGenericBy
30+
31+ -- ** Set like operations on sorted streams
32+ , filterInStreamAscBy
33+ , deleteInStreamAscBy
34+ , unionWithStreamAscBy
35+
36+ -- ** Join operations
37+ , joinInnerGeneric
38+
39+ -- * Joins on sorted stream
40+ , joinInnerAscBy
41+ , joinLeftAscBy
42+ , joinOuterAscBy
7843 )
7944where
8045
@@ -83,7 +48,7 @@ where
8348import Control.Monad.IO.Class (MonadIO(..))
8449import Data.IORef (newIORef, readIORef, modifyIORef')
8550import Streamly.Internal.Data.Fold.Type (Fold)
86−import Streamly.Internal.Data.Stream.Type (Stream(..), Step(..), cross)
51+import Streamly.Internal.Data.Stream.Type (Stream, cross)
8752
8853import qualified Data.List as List
8954import qualified Streamly.Internal.Data.Fold as Fold
@@ -145,40 +110,29 @@ strideFromThen offset stride =
145110-- binary search if we have an Ord instance or Ordering returning function. The
146111-- time complexity would then become (m x log n).
147112
148−-- | Like 'cross' but emits only those tuples where @a == b@ using the supplied
149−-- equality predicate. This is essentially a @cross intersection@ of two
150−-- streams.
113+-- | Like 'cross' but emits only those tuples where @a == b@ using the
114+-- supplied equality predicate.
151115--
152116-- Definition:
153117--
154−-- >>> innerJoin eq s1 s2 = Stream.filter (\(a, b) -> a `eq` b) $ Stream.cross s1 s2
155−--
156−-- The second (inner) stream must be finite. Moreover, it must be either pure
157−-- or capable of multiple evaluations. If not then the caller should cache it
158−-- in an 'Data.Array.Array', if the type does not have an 'Unbox' instance then
159−-- use the Generic 'Data.Array.Generic.Array'. Convert the array to stream
160−-- before calling this function. Caching may also improve performance if the
161−-- stream is expensive to evaluate.
118+-- >>> joinInnerGeneric eq s1 s2 = Stream.filter (\(a, b) -> a `eq` b) $ Stream.cross s1 s2
162119--
163−-- If you care about performance this function should be your last choice among
164−-- all inner joins. 'Streamly.Internal.Data.Unfold.innerJoin' is a much faster
165−-- fused alternative. 'innerSortedJoin' is a faster alternative when streams
166−-- are sorted. 'innerOrdJoin' is an order of magnitude faster alternative when
167−-- the type has an 'Ord' instance.
120+-- You should almost always prefer @joinInnerOrd@ over 'joinInnerGeneric' if
121+-- possible. @joinInnerOrd@ is an order of magnitude faster but may take more
122+-- space for caching the second stream.
168123--
169−-- Note: Conceptually, this is a commutative operation. Result includes all the
170−-- elements from the left and the right stream. The order of streams can be
171−-- changed without affecting results, except for the ordering within the tuple.
124+-- See 'Streamly.Internal.Data.Unfold.joinInnerGeneric' for a much faster fused
125+-- alternative.
172126--
173127-- Time: O(m x n)
174128--
175129-- /Pre-release/
176−{-# INLINE innerJoin #-}
177−innerJoin :: Monad m =>
130+{-# INLINE joinInnerGeneric #-}
131+joinInnerGeneric :: Monad m =>
178132 (a -> b -> Bool) -> Stream m a -> Stream m b -> Stream m (a, b)
179−innerJoin eq s1 s2 = Stream.filter (\(a, b) -> a `eq` b) $ cross s1 s2
133+joinInnerGeneric eq s1 s2 = Stream.filter (\(a, b) -> a `eq` b) $ cross s1 s2
180134{-
181−innerJoin eq s1 s2 = do
135+joinInnerGeneric eq s1 s2 = do
182136 -- ConcatMap works faster than bind
183137 Stream.concatMap (\a ->
184138 Stream.concatMap (\b ->
@@ -189,44 +143,44 @@ innerJoin eq s1 s2 = do
189143 ) s1
190144-}
191145
192−-- | A more efficient 'innerJoin' for sorted streams.
146+-- | A more efficient 'joinInner' for sorted streams.
193147--
194148-- Space: O(1)
195149--
196150-- Time: O(m + n)
197151--
198152-- /Unimplemented/
199−{-# INLINE innerSortedJoin #-}
200−innerSortedJoin ::
153+{-# INLINE joinInnerAscBy #-}
154+joinInnerAscBy ::
201155 (a -> b -> Ordering) -> Stream m a -> Stream m b -> Stream m (a, b)
202−innerSortedJoin = undefined
156+joinInnerAscBy = undefined
203157
204−-- | A more efficient 'leftJoin' for sorted streams.
158+-- | A more efficient 'joinLeft' for sorted streams.
205159--
206160-- Space: O(1)
207161--
208162-- Time: O(m + n)
209163--
210164-- /Unimplemented/
211−{-# INLINE leftSortedJoin #-}
212−leftSortedJoin :: -- Monad m =>
165+{-# INLINE joinLeftAscBy #-}
166+joinLeftAscBy :: -- Monad m =>
213167 (a -> b -> Ordering) -> Stream m a -> Stream m b -> Stream m (a, Maybe b)
214−leftSortedJoin _eq _s1 _s2 = undefined
168+joinLeftAscBy _eq _s1 _s2 = undefined
215169
216−-- | A more efficient 'outerJoin' for sorted streams.
170+-- | A more efficient 'joinOuter' for sorted streams.
217171--
218172-- Space: O(1)
219173--
220174-- Time: O(m + n)
221175--
222176-- /Unimplemented/
223−{-# INLINE outerSortedJoin #-}
224−outerSortedJoin :: -- Monad m =>
177+{-# INLINE joinOuterAscBy #-}
178+joinOuterAscBy :: -- Monad m =>
225179 (a -> b -> Ordering)
226180 -> Stream m a
227181 -> Stream m b
228182 -> Stream m (Maybe a, Maybe b)
229−outerSortedJoin _eq _s1 _s2 = undefined
183+joinOuterAscBy _eq _s1 _s2 = undefined
230184
231185------------------------------------------------------------------------------
232186-- Set operations (special joins)
@@ -236,8 +190,8 @@ outerSortedJoin _eq _s1 _s2 = undefined
236190-- the best would be to use an Array with linear search. If the second stream
237191-- is sorted we can also use a binary search, using Ord constraint.
238192
239−-- | Keep only those elements in the first stream that are present in the
240−-- second stream too. The second stream is folded to a container using the
193+-- | Keep only those elements in the second stream that are present in the
194+-- first stream too. The first stream is folded to a container using the
241195-- supplied fold and then the elements in the container are looked up using the
242196-- supplied lookup function.
243197--
@@ -252,30 +206,23 @@ filterStreamWith :: Monad m =>
252206filterStreamWith fld member s1 s2 =
253207 Stream.concatEffect
254208 $ do
255− xs <- Stream.fold fld s2
256− return $ Stream.filter (`member` xs) s1
257−
258−-- XXX instead of folding the second stream to a list we could use it directly.
259−-- If the user wants they can generate the stream from an array and also call
260−-- uniq or nub on it. We can provide a convenience Stream -> Stream to cache
261−-- a finite stream in an array and serve it from the cache. The user can decide
262−-- what is best based on the context. They can also choose to use a boxed or
263−-- unboxed array for caching. To force caching we can make the second stream
264−-- monad type Identity. But that may be less flexible. One option is to use
265−-- cachedIntersectBy etc for automatic caching.
209+ xs <- Stream.fold fld s1
210+ return $ Stream.filter (`member` xs) s2
266211
267−-- | 'intersectBy' returns a subsequence of the first stream which intersects
268−-- with the second stream. Note that this is not a commutative operation unlike
269−-- a set intersection, because of duplicate elements in the stream the order of
270−-- the streams matters. This is similar to 'Data.List.intersectBy'. Note that
271−-- intersectBy is a special case of 'innerJoin'.
212+-- | 'filterInStreamGenericBy' retains only those elements in the second stream that
213+-- are present in the first stream.
272214--
273−-- >>> f s1 s2 = Stream.fold Fold.toList $ Stream.intersectBy (==) (Stream.fromList s1) (Stream.fromList s2)
274−-- >>> f [1,3,4,4,5]) [2,3,4,5,5]
275−-- [3,4,4,5]
215+-- >>> Stream.fold Fold.toList $ Stream.filterInStreamGenericBy (==) (Stream.fromList [1,2,2,4]) (Stream.fromList [2,1,1,3])
216+-- [2,1,1]
276217--
277−-- First stream can be infinite, the second stream must be finite and must be
278−-- capable of multiple evaluations.
218+-- >>> Stream.fold Fold.toList $ Stream.filterInStreamGenericBy (==) (Stream.fromList [2,1,1,3]) (Stream.fromList [1,2,2,4])
219+-- [1,2,2]
220+--
221+-- Similar to the list intersectBy operation but with the stream argument order
222+-- flipped.
223+--
224+-- The first stream must be finite and must not block. Second stream is
225+-- processed only after the first stream is fully realized.
279226--
280227-- Space: O(n) where @n@ is the number of elements in the second stream.
281228--
@@ -283,87 +230,46 @@ filterStreamWith fld member s1 s2 =
283230-- @n@ is the number of elements in the second stream.
284231--
285232-- /Pre-release/
286−{-# INLINE intersectBy #-}
287−intersectBy :: Monad m =>
233+{-# INLINE filterInStreamGenericBy #-}
234+filterInStreamGenericBy :: Monad m =>
288235 (a -> a -> Bool) -> Stream m a -> Stream m a -> Stream m a
289−intersectBy eq =
236+filterInStreamGenericBy eq =
290237 -- XXX Use an (unboxed) array instead.
291238 filterStreamWith
292239 (Fold.scanMaybe (Fold.uniqBy eq) Fold.toListRev)
293240 (List.any . eq)
294241
295−-------------------------------------------------------------------------------
296−-- Intersection of sorted streams
297−-------------------------------------------------------------------------------
298−
299−-- XXX The sort order is not important as long both the streams have the same
300−-- sort order. We need to move only in one direction in each stream.
301−-- XXX Fix the argument order to use the same behavior as intersectBy.
302−
303−-- | Like 'intersectBy' but assumes that the input streams are sorted in
242+-- | Like 'filterInStreamGenericBy' but assumes that the input streams are sorted in
304243-- ascending order. To use it on streams sorted in descending order pass an
305244-- inverted comparison function returning GT for less than and LT for greater
306245-- than.
307246--
308−-- Both streams can be infinite.
309−--
310247-- Space: O(1)
311248--
312249-- Time: O(m+n)
313250--
314251-- /Pre-release/
315−{-# INLINE_NORMAL sortedIntersectBy #-}
316−sortedIntersectBy :: Monad m =>
252+{-# INLINE filterInStreamAscBy #-}
253+filterInStreamAscBy :: Monad m =>
317254 (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
318−sortedIntersectBy cmp (Stream stepa ta) (Stream stepb tb) =
319− Stream step
320− ( ta -- left stream state
321− , tb -- right stream state
322− , Nothing -- left value
323− , Nothing -- right value
324− )
325−
326− where
255+filterInStreamAscBy eq s1 s2 = Stream.intersectBySorted eq s2 s1
327256
328− {-# INLINE_LATE step #-}
329− -- step 1, fetch the first value
330− step gst (sa, sb, Nothing, b) = do
331− r <- stepa gst sa
332− return $ case r of
333− Yield a sa' -> Skip (sa', sb, Just a, b) -- step 2/3
334− Skip sa' -> Skip (sa', sb, Nothing, b)
335− Stop -> Stop
336−
337− -- step 2, fetch the second value
338− step gst (sa, sb, a@(Just _), Nothing) = do
339− r <- stepb gst sb
340− return $ case r of
341− Yield b sb' -> Skip (sa, sb', a, Just b) -- step 3
342− Skip sb' -> Skip (sa, sb', a, Nothing)
343− Stop -> Stop
344−
345− -- step 3, compare the two values
346− step _ (sa, sb, Just a, Just b) = do
347− let res = cmp a b
348− return $ case res of
349− GT -> Skip (sa, sb, Just a, Nothing) -- step 2
350− LT -> Skip (sa, sb, Nothing, Just b) -- step 1
351− EQ -> Yield a (sa, sb, Nothing, Just b) -- step 1
352−
353−-- | Returns a subsequence of the first stream, deleting first occurrences of
354−-- those elements that are present in the second stream. Note that this is not
355−-- a commutative operation. This is similar to the 'Data.List.deleteFirstsBy'.
257+-- | Delete all elements of the first stream from the seconds stream. If an
258+-- element occurs multiple times in the first stream as many occurrences of it
259+-- are deleted from the second stream.
356260--
357−-- >>> f xs ys = Stream.fold Fold.toList $ Stream.deleteFirstsBy (==) (Stream.fromList xs) (Stream.fromList ys)
358−-- >>> f [1,2,2,3,3,5] [1,2,2,3,4]
359−-- [2,3,5]
261+-- >>> Stream.fold Fold.toList $ Stream.deleteInStreamGenericBy (==) (Stream.fromList [1,2,3]) (Stream.fromList [1,2,2])
262+-- [2]
360263--
361−-- The following holds:
264+-- The following laws hold:
362265--
363−-- > deleteFirstsBy (==) (Stream.nub s2 `append` s1) s2 === s1
364−-- > deleteFirstsBy (==) (Stream.nub s2 `interleave` s1) s2 === s1
266+-- > deleteInStreamGenericBy (==) s1 (s1 `append` s2) === s2
267+-- > deleteInStreamGenericBy (==) s1 (s1 `interleave` s2) === s2
365268--
366−-- First stream can be infinite, second stream must be finite.
269+-- Same as the list 'Data.List.//' operation but with argument order flipped.
270+--
271+-- The first stream must be finite and must not block. Second stream is
272+-- processed only after the first stream is fully realized.
367273--
368274-- Space: O(m) where @m@ is the number of elements in the first stream.
369275--
@@ -371,83 +277,58 @@ sortedIntersectBy cmp (Stream stepa ta) (Stream stepb tb) =
371277-- @n@ is the number of elements in the second stream.
372278--
373279-- /Pre-release/
374−{-# INLINE deleteFirstsBy #-}
375−deleteFirstsBy :: Monad m =>
280+{-# INLINE deleteInStreamGenericBy #-}
281+deleteInStreamGenericBy :: Monad m =>
376282 (a -> a -> Bool) -> Stream m a -> Stream m a -> Stream m a
377−deleteFirstsBy eq s2 s1 =
378− -- XXX s2 can be a sorted mutable array and we can use binary
379− -- search to find. Mark the element deleted, count the deletions
380− -- and reconsolidate the array when a min number of elements is
381− -- deleted.
382−
383− -- XXX Use StreamK or list as second argument instead of Stream to avoid
384− -- concatEffect?
385− Stream.concatEffect $ do
386− xs <- Stream.toList s1
387− -- It reverses the list but that is fine.
388− let del x =
389− List.foldl' (\(ys,res) y ->
390− if x `eq` y
391− then (ys, True)
392− else (x:ys, res)) ([], False)
393− g (ys,_) x =
394− let (ys1, deleted) = del x ys
395− in if deleted
396− then (ys1, Nothing)
397− else (ys1, Just x)
398− in return
399− $ Stream.catMaybes
400− $ fmap snd
401− $ Stream.postscanl' g (xs, Nothing) s2
283+deleteInStreamGenericBy eq s1 s2 =
284+ Stream.concatEffect
285+ $ do
286+ -- This may work well if s1 is small
287+ -- If s1 is big we can go through s1, deleting elements from s2 and
288+ -- not emitting an element if it was successfully deleted from s2.
289+ -- we will need a deleteBy that can return whether the element was
290+ -- deleted or not.
291+ xs <- Stream.fold Fold.toList s2
292+ let f = Fold.foldl' (flip (List.deleteBy eq)) xs
293+ fmap Stream.fromList $ Stream.fold f s1
402294
403−-- | A more efficient 'deleteFirstsBy' for streams sorted in ascending order.
404−--
405−-- Both streams can be infinite.
295+-- | A more efficient 'deleteInStreamGenericBy' for streams sorted in ascending order.
406296--
407297-- Space: O(1)
408298--
409299-- /Unimplemented/
410−{-# INLINE sortedDeleteFirstsBy #-}
411−sortedDeleteFirstsBy :: -- (Monad m) =>
300+{-# INLINE deleteInStreamAscBy #-}
301+deleteInStreamAscBy :: -- (Monad m) =>
412302 (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
413−sortedDeleteFirstsBy _eq _s1 _s2 = undefined
303+deleteInStreamAscBy _eq _s1 _s2 = undefined
414304
415305-- XXX Remove the MonadIO constraint. We can just cache one stream and then
416306-- implement using differenceEqBy.
417307
418−-- | Returns the first stream appended with those unique elements from the
419−-- second stream that are not already present in the first stream. Note that
420−-- this is not a commutative operation unlike a set union, argument order
421−-- matters. The behavior is similar to the 'Data.List.unionBy'.
308+-- | This essentially appends to the second stream all the occurrences of
309+-- elements in the first stream that are not already present in the second
310+-- stream.
422311--
423312-- Equivalent to the following except that @s2@ is evaluated only once:
424313--
425−-- >>> unionBy eq s1 s2 = s1 `Stream.append` Stream.deleteFirstsBy eq s1 (Stream.nub s2)
314+-- >>> unionWithStreamGenericBy eq s1 s2 = s2 `Stream.append` (Stream.deleteInStreamGenericBy eq s2 s1)
426315--
427316-- Example:
428317--
429−-- >>> f s1 s2 = Stream.fold Fold.toList $ Stream.unionBy (==) (Stream.fromList s1) (Stream.fromList s2)
430−-- >>> f [1,2,2,4] [1,1,2,3,3]
318+-- >>> Stream.fold Fold.toList $ Stream.unionWithStreamGenericBy (==) (Stream.fromList [1,1,2,3]) (Stream.fromList [1,2,2,4])
431319-- [1,2,2,4,3]
432320--
433−-- First stream can be infinite, but second stream must be finite. Note that if
434−-- the first stream is infinite the union means just the first stream. Thus
435−-- union is useful only when both streams are finite. See 'sortedUnionBy' where
436−-- union can work on infinite streams if they are sorted.
437−--
438321-- Space: O(n)
439322--
440323-- Time: O(m x n)
441324--
442325-- /Pre-release/
443−{-# INLINE unionBy #-}
444−unionBy :: MonadIO m =>
326+{-# INLINE unionWithStreamGenericBy #-}
327+unionWithStreamGenericBy :: MonadIO m =>
445328 (a -> a -> Bool) -> Stream m a -> Stream m a -> Stream m a
446−unionBy eq s2 s1 =
329+unionWithStreamGenericBy eq s1 s2 =
447330 Stream.concatEffect
448331 $ do
449− -- XXX use a rewrite rule such that if a list converted to stream
450− -- is passed to unionBy then this becomes an identity operation.
451332 xs <- Stream.fold Fold.toList s1
452333 -- XXX we can use postscanlMAfter' instead of IORef
453334 ref <- liftIO $ newIORef $! List.nubBy eq xs
@@ -460,21 +341,12 @@ unionBy eq s2 s1 =
460341 return $ Stream.fromList xs1
461342 return $ Stream.mapM f s2 `Stream.append` s3
462343
463−-- | A more efficient 'unionBy' for sorted streams.
464−--
465−-- Note that the behavior is different from 'unionBy'. In 'unionBy' we append
466−-- the unique elements from second stream only after exhausting the first one
467−-- whereas in sorted streams we can determine unique elements early even when
468−-- we are going through the first stream. Thus the result is an interleaving of
469−-- the two streams, merging those elements from the second stream that are not
470−-- present in the first.
344+-- | A more efficient 'unionWithStreamGenericBy' for sorted streams.
471345--
472346-- Space: O(1)
473347--
474−-- Both streams can be infinite.
475−--
476348-- /Unimplemented/
477−{-# INLINE sortedUnionBy #-}
478−sortedUnionBy :: -- (Monad m) =>
349+{-# INLINE unionWithStreamAscBy #-}
350+unionWithStreamAscBy :: -- (Monad m) =>
479351 (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
480−sortedUnionBy _eq _s1 _s2 = undefined
352+unionWithStreamAscBy _eq _s1 _s2 = undefined
core/src/Streamly/Internal/Data/Stream/Transform.hs+27−53
@@ -21,6 +21,8 @@ module Streamly.Internal.Data.Stream.Transform
2121
2222 -- * Mapping
2323 -- | Stateless one-to-one maps.
24+ , map
25+ , mapM
2426 , sequence
2527
2628 -- * Mapping Effects
@@ -73,7 +75,7 @@ module Streamly.Internal.Data.Stream.Transform
7375 , scanMaybe
7476 , filter
7577 , filterM
76− , deleteBy -- deleteOnceBy?
78+ , deleteBy
7779 , uniqBy
7880 , uniq
7981 , prune
@@ -81,8 +83,9 @@ module Streamly.Internal.Data.Stream.Transform
8183
8284 -- * Trimming
8385 -- | Produce a subset of the stream trimmed at ends.
84− , initNonEmpty
85− , tailNonEmpty
86+ , take
87+ , takeWhile
88+ , takeWhileM
8689 , takeWhileLast
8790 , takeWhileAround
8891 , drop
@@ -129,6 +132,7 @@ module Streamly.Internal.Data.Stream.Transform
129132 -- * Searching
130133 , findIndices
131134 , elemIndices
135+ , slicesBy
132136
133137 -- * Rolling map
134138 -- | Map using the previous element.
@@ -1070,55 +1074,6 @@ repeated = undefined
10701074-- Trimming
10711075------------------------------------------------------------------------------
10721076
1073−-- | init for non-empty streams, fails for empty stream case.
1074−--
1075−{-# INLINE initNonEmpty #-}
1076−initNonEmpty :: Monad m => Stream m a -> Stream m a
1077−initNonEmpty (Stream step1 state1) = Stream step (Nothing, state1)
1078−
1079− where
1080−
1081− step gst (Nothing, s1) = do
1082− r <- step1 (adaptState gst) s1
1083− return $
1084− case r of
1085− Yield x s -> Skip (Just x, s)
1086− Skip s -> Skip (Nothing, s)
1087− Stop -> error "initNonEmpty: empty Stream"
1088−
1089− step gst (Just a, s1) = do
1090− r <- step1 (adaptState gst) s1
1091− return $
1092− case r of
1093− Yield x s -> Yield a (Just x, s)
1094− Skip s -> Skip (Just a, s)
1095− Stop -> Stop
1096−
1097−-- | tail for non-empty streams, fails for empty stream case.
1098−--
1099−-- See also 'tail' for a non-partial version of this function..
1100−{-# INLINE tailNonEmpty #-}
1101−tailNonEmpty :: Monad m => Stream m a -> Stream m a
1102−tailNonEmpty (Stream step1 state1) = Stream step (Nothing, state1)
1103−
1104− where
1105−
1106− step gst (Nothing, s1) = do
1107− r <- step1 (adaptState gst) s1
1108− return $
1109− case r of
1110− Yield x s -> Skip (Just x, s)
1111− Skip s -> Skip (Nothing, s)
1112− Stop -> error "tailNonEmpty: empty Stream"
1113−
1114− step gst (Just a, s1) = do
1115− r <- step1 (adaptState gst) s1
1116− return $
1117− case r of
1118− Yield x s -> Yield x (Just x, s)
1119− Skip s -> Skip (Just a, s)
1120− Stop -> Stop
1121−
11221077-- | Take all consecutive elements at the end of the stream for which the
11231078-- predicate is true.
11241079--
@@ -1582,7 +1537,7 @@ reverse m = Stream step Nothing
15821537{-# INLINE reverseUnbox #-}
15831538reverseUnbox :: (MonadIO m, Unbox a) => Stream m a -> Stream m a
15841539reverseUnbox =
1585− A.concatRev -- unfoldMany A.readerRev
1540+ A.concatChunksRev -- unfoldMany A.readerRev
15861541 . fromStreamK
15871542 . K.reverse
15881543 . toStreamK
@@ -1754,6 +1709,25 @@ findIndices p (Stream step state) = Stream step' (state, 0)
17541709elemIndices :: (Monad m, Eq a) => a -> Stream m a -> Stream m Int
17551710elemIndices a = findIndices (== a)
17561711
1712+{-# INLINE_NORMAL slicesBy #-}
1713+slicesBy :: Monad m => (a -> Bool) -> Stream m a -> Stream m (Int, Int)
1714+slicesBy p (Stream step1 state1) = Stream step (Just (state1, 0, 0))
1715+
1716+ where
1717+
1718+ {-# INLINE_LATE step #-}
1719+ step gst (Just (st, i, len)) = i `seq` len `seq` do
1720+ r <- step1 (adaptState gst) st
1721+ return
1722+ $ case r of
1723+ Yield x s ->
1724+ if p x
1725+ then Yield (i, len + 1) (Just (s, i + len + 1, 0))
1726+ else Skip (Just (s, i, len + 1))
1727+ Skip s -> Skip (Just (s, i, len))
1728+ Stop -> if len == 0 then Stop else Yield (i, len) Nothing
1729+ step _ Nothing = return Stop
1730+
17571731------------------------------------------------------------------------------
17581732-- Rolling map
17591733------------------------------------------------------------------------------
core/src/Streamly/Internal/Data/Stream/Transformer.hs+1−2
@@ -11,11 +11,10 @@
1111
1212module Streamly.Internal.Data.Stream.Transformer
1313 (
14− -- * Fold to Transformer Monad
1514 foldlT
1615 , foldrT
1716
18− -- * Inner Monad Operations
17+ -- * Transform Inner Monad
1918 , liftInner
2019 , runReaderT
2120 , usingReaderT
core/src/Streamly/Internal/Data/Stream/Type.hs+3−129
@@ -1,11 +1,5 @@
11{-# LANGUAGE CPP #-}
2−{-# LANGUAGE PatternSynonyms #-}
3−{-# LANGUAGE TypeFamilies #-}
4−-- Must come after TypeFamilies, otherwise it is re-enabled.
5−-- MonoLocalBinds enabled by TypeFamilies causes perf regressions in general.
6−{-# LANGUAGE NoMonoLocalBinds #-}
72{-# LANGUAGE UndecidableInstances #-}
8−{-# LANGUAGE ViewPatterns #-}
93
104-- |
115-- Module : Streamly.Internal.Data.Stream.Type
@@ -22,18 +16,18 @@
2216
2317module Streamly.Internal.Data.Stream.Type
2418 (
25− -- * Type
19+ -- * The stream type
2620 Step (..)
2721 -- XXX UnStream is exported to avoid a performance issue in some
2822 -- combinators if we use the pattern synonym "Stream".
2923 , Stream (Stream, UnStream)
3024
31− -- * CrossStream
25+ -- * CrossStream type wrapper
3226 , CrossStream
3327 , unCross
3428 , mkCross
3529
36− -- * To StreamK
30+ -- * Conversion to StreamK
3731 , fromStreamK
3832 , toStreamK
3933
@@ -91,7 +85,6 @@ module Streamly.Internal.Data.Stream.Type
9185
9286 -- * Combining Two Streams
9387 -- ** Zipping
94− -- | Zip corresponding elements of two streams.
9588 , zipWithM
9689 , zipWith
9790
@@ -107,8 +100,6 @@ module Streamly.Internal.Data.Stream.Type
107100 , unfoldMany
108101
109102 -- * Concat
110− -- | Generate streams by mapping a stream generator on each element of an
111− -- input stream, append the resulting streams and flatten.
112103 , concatEffect
113104 , concatMap
114105 , concatMapM
@@ -132,22 +123,14 @@ module Streamly.Internal.Data.Stream.Type
132123 , foldManyPost
133124 , groupsOf
134125 , refoldMany
135− , refoldIterateM
136126
137127 -- * Fold Iterate
138128 , reduceIterateBfs
139129 , foldIterateBfs
140130
141− -- * Splitting
142− , indexOnSuffix
143−
144131 -- * Multi-stream folds
145− -- | These should probably be expressed using zipping operations.
146132 , eqBy
147133 , cmpBy
148−
149− -- * Deprecated
150− , sliceOnSuffix
151134 )
152135where
153136
@@ -179,7 +162,6 @@ import Streamly.Internal.Data.Maybe.Strict (Maybe'(..), toMaybe)
179162import Streamly.Internal.Data.Refold.Type (Refold(..))
180163import Streamly.Internal.Data.Stream.Step (Step (..))
181164import Streamly.Internal.Data.SVar.Type (State, adaptState, defState)
182−import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
183165import Streamly.Internal.Data.Unfold.Type (Unfold(..))
184166
185167import qualified Streamly.Internal.Data.Fold.Type as FL hiding (foldr)
@@ -572,12 +554,8 @@ foldAdd f =
572554-- >>> Stream.foldrM step (return False) s
573555-- True
574556--
575−-- >>> import Control.Monad (join)
576−-- >>> foldrM f z = join $ Stream.foldr f z
577−--
578557{-# INLINE_NORMAL foldrM #-}
579558foldrM :: Monad m => (a -> m b -> m b) -> m b -> Stream m a -> m b
580−-- foldrM f z = join . Streamly.Internal.Data.Stream.StreamD.Type.foldr f z
581559foldrM f z (Stream step state) = go SPEC state
582560 where
583561 {-# INLINE_LATE go #-}
@@ -1996,110 +1974,6 @@ refoldMany (Refold fstep inject extract) action (Stream step state) =
19961974 step' _ (FoldManyYield b next) = return $ Yield b next
19971975 step' _ FoldManyDone = return Stop
19981976
1999−{-# ANN type CIterState Fuse #-}
2000−data CIterState s f fs b
2001− = CIterInit s f
2002− | CIterConsume s fs
2003− | CIterYield b (CIterState s f fs b)
2004− | CIterStop
2005−
2006−-- | Like 'foldIterateM' but using the 'Refold' type instead. This could be
2007−-- much more efficient due to stream fusion.
2008−--
2009−-- /Internal/
2010−{-# INLINE_NORMAL refoldIterateM #-}
2011−refoldIterateM ::
2012− Monad m => Refold m b a b -> m b -> Stream m a -> Stream m b
2013−refoldIterateM (Refold fstep finject fextract) initial (Stream step state) =
2014− Stream stepOuter (CIterInit state initial)
2015−
2016− where
2017−
2018− {-# INLINE iterStep #-}
2019− iterStep st action = do
2020− res <- action
2021− return
2022− $ Skip
2023− $ case res of
2024− FL.Partial fs -> CIterConsume st fs
2025− FL.Done fb -> CIterYield fb $ CIterInit st (return fb)
2026−
2027− {-# INLINE_LATE stepOuter #-}
2028− stepOuter _ (CIterInit st action) = do
2029− iterStep st (action >>= finject)
2030− stepOuter gst (CIterConsume st fs) = do
2031− r <- step (adaptState gst) st
2032− case r of
2033− Yield x s -> iterStep s (fstep fs x)
2034− Skip s -> return $ Skip $ CIterConsume s fs
2035− Stop -> do
2036− b <- fextract fs
2037− return $ Skip $ CIterYield b CIterStop
2038− stepOuter _ (CIterYield a next) = return $ Yield a next
2039− stepOuter _ CIterStop = return Stop
2040−
2041−-- | The refold @indexerBy f n@ takes an (index, len) tuple as initial input,
2042−-- and returns @(index + len + n, b)@ as output where @b@ is the output of the
2043−-- fold.
2044−{-# INLINE indexerBy #-}
2045−indexerBy :: Monad m =>
2046− Fold m a Int -> Int -> Refold m (Int, Int) a (Int, Int)
2047−indexerBy (Fold step1 initial1 extract1 _final) n =
2048− Refold step inject extract
2049−
2050− where
2051−
2052− inject (i, len) = do
2053− r <- initial1
2054− return $ case r of
2055− FL.Partial s -> FL.Partial $ Tuple' (i + len + n) s
2056− FL.Done l -> FL.Done (i, l)
2057−
2058− step (Tuple' i s) x = do
2059− r <- step1 s x
2060− return $ case r of
2061− FL.Partial s1 -> FL.Partial $ Tuple' i s1
2062− FL.Done len -> FL.Done (i, len)
2063−
2064− extract (Tuple' i s) = (i,) <$> extract1 s
2065−
2066−-- | Like 'splitOnSuffix' but generates a stream of (index, len) tuples marking
2067−-- the places where the predicate matches in the stream.
2068−--
2069−-- /Pre-release/
2070−{-# INLINE indexOnSuffix #-}
2071−indexOnSuffix :: Monad m =>
2072− (a -> Bool) -> Stream m a -> Stream m (Int, Int)
2073−indexOnSuffix predicate =
2074− -- Scan the stream with the given refold
2075− refoldIterateM
2076− (indexerBy (FL.takeEndBy_ predicate FL.length) 1)
2077− (return (-1, 0))
2078−
2079−-- Alternate implementation
2080−{-# INLINE_NORMAL _indexOnSuffix #-}
2081−_indexOnSuffix :: Monad m => (a -> Bool) -> Stream m a -> Stream m (Int, Int)
2082−_indexOnSuffix p (Stream step1 state1) = Stream step (Just (state1, 0, 0))
2083−
2084− where
2085−
2086− {-# INLINE_LATE step #-}
2087− step gst (Just (st, i, len)) = i `seq` len `seq` do
2088− r <- step1 (adaptState gst) st
2089− return
2090− $ case r of
2091− Yield x s ->
2092− if p x
2093− then Yield (i, len + 1) (Just (s, i + len + 1, 0))
2094− else Skip (Just (s, i, len + 1))
2095− Skip s -> Skip (Just (s, i, len))
2096− Stop -> if len == 0 then Stop else Yield (i, len) Nothing
2097− step _ Nothing = return Stop
2098−
2099−{-# DEPRECATED sliceOnSuffix "Please use indexOnSuffix instead." #-}
2100−sliceOnSuffix :: Monad m => (a -> Bool) -> Stream m a -> Stream m (Int, Int)
2101−sliceOnSuffix = indexOnSuffix
2102−
21031977------------------------------------------------------------------------------
21041978-- Stream with a cross product style monad instance
21051979------------------------------------------------------------------------------
core/src/Streamly/Internal/Data/StreamK.hs+8−19
@@ -16,15 +16,16 @@ module Streamly.Internal.Data.StreamK
1616 --
1717 -- $setup
1818
19+ -- * The stream type
1920 module Streamly.Internal.Data.StreamK.Type
20− -- * Transformer
2121 , module Streamly.Internal.Data.StreamK.Transformer
2222
23− -- * From containers
23+ , StreamK(..)
2424 , fromList
2525 , fromStream
26+ , toStream
2627
27− -- * Specialized Generation
28+ -- ** Specialized Generation
2829 , repeatM
2930 , replicate
3031 , replicateM
@@ -66,13 +67,13 @@ module Streamly.Internal.Data.StreamK
6667 , find
6768 , (!!)
6869
69− -- ** To Containers
70− , toList
71− , toStream
72−
7370 -- ** Map and Fold
7471 , mapM_
7572
73+ -- ** Conversions
74+ , toList
75+ , hoist
76+
7677 -- * Transformation
7778 -- ** By folding (scans)
7879 , scanl'
@@ -99,7 +100,6 @@ module Streamly.Internal.Data.StreamK
99100
100101 -- ** Reordering
101102 , sortBy
102− , sortOn
103103
104104 -- ** Map and Filter
105105 , mapMaybe
@@ -115,9 +115,6 @@ module Streamly.Internal.Data.StreamK
115115 -- ** Transformation comprehensions
116116 , the
117117
118− -- ** Transforming Inner Monad
119− , hoist
120−
121118 -- * Exceptions
122119 , handle
123120
@@ -134,7 +131,6 @@ import Control.Exception (mask_, Exception)
134131import Control.Monad (void, join)
135132import Control.Monad.Catch (MonadCatch)
136133import Control.Monad.IO.Class (MonadIO(..))
137−import Data.Ord (comparing)
138134import Data.Proxy (Proxy(..))
139135import GHC.Types (SPEC(..))
140136import Streamly.Internal.Data.Array.Type (Array(..))
@@ -1721,10 +1717,3 @@ sortBy cmp =
17211717 . Stream.catRights -- its a non-failing backtracking parser
17221718 . Stream.parseMany (fmap (either id id) p)
17231719 . Stream.fromStreamK
1724−
1725−{-# INLINE sortOn #-}
1726−sortOn :: (Monad m, Ord b) => (a -> b) -> StreamK m a -> StreamK m a
1727−sortOn f =
1728− fmap snd
1729− . sortBy (comparing fst)
1730− . fmap (\x -> let y = f x in y `seq` (y, x))
core/src/Streamly/Internal/Data/StreamK/Type.hs+11−60
@@ -1,8 +1,4 @@
11{-# LANGUAGE CPP #-}
2−{-# LANGUAGE TypeFamilies #-}
3−-- Must come after TypeFamilies, otherwise it is re-enabled.
4−-- MonoLocalBinds enabled by TypeFamilies causes perf regressions in general.
5−{-# LANGUAGE NoMonoLocalBinds #-}
62{-# LANGUAGE UndecidableInstances #-}
73-- |
84-- Module : Streamly.Internal.Data.StreamK.Type
@@ -97,11 +93,8 @@ module Streamly.Internal.Data.StreamK.Type
9793 -- ** Specific Folds
9894 , drain
9995 , null
100− , headNonEmpty
10196 , tail
102− , tailNonEmpty
10397 , init
104− , initNonEmpty
10598
10699 -- * Mapping
107100 , map
@@ -1814,42 +1807,14 @@ iterateMWith cns step = go
18141807 !next <- s
18151808 foldStreamShared st stp sng yld (return next `cns` go (step next))
18161809
1817−-- | head for non-empty streams, fails for empty stream case.
1818−--
1819−{-# INLINE headNonEmpty #-}
1820−headNonEmpty :: Monad m => StreamK m a -> m a
1821−headNonEmpty = foldrM (\x _ -> return x) (error "headNonEmpty: empty stream")
1822−
1823−-- | init for non-empty streams, fails for empty stream case.
1824−--
1825−-- See also 'init' for a non-partial version of this function..
1826−{-# INLINE initNonEmpty #-}
1827−initNonEmpty :: Stream m a -> Stream m a
1828−initNonEmpty = go0
1829−
1830− where
1831−
1832− go0 m = mkStream $ \st yld sng stp ->
1833− let stop = error "initNonEmpty: Empty Stream."
1834− single _ = stp
1835− yieldk a r = foldStream st yld sng stp (go1 a r)
1836− in foldStream st yieldk single stop m
1837−
1838− go1 a r = mkStream $ \st yld sng stp ->
1839− let stop = stp
1840− single _ = sng a
1841− yieldk a1 r1 = yld a (go1 a1 r1)
1842− in foldStream st yieldk single stop r
1810+{-# INLINE headPartial #-}
1811+headPartial :: Monad m => StreamK m a -> m a
1812+headPartial = foldrM (\x _ -> return x) (error "head of nil")
18431813
1844−-- | tail for non-empty streams, fails for empty stream case.
1845−--
1846−-- See also 'tail' for a non-partial version of this function..
1847−--
1848−-- Note: this is same as "drop 1" with error on empty stream.
1849−{-# INLINE tailNonEmpty #-}
1850−tailNonEmpty :: StreamK m a -> StreamK m a
1851−tailNonEmpty m = mkStream $ \st yld sng stp ->
1852− let stop = error "tailNonEmpty: empty stream"
1814+{-# INLINE tailPartial #-}
1815+tailPartial :: StreamK m a -> StreamK m a
1816+tailPartial m = mkStream $ \st yld sng stp ->
1817+ let stop = error "tail of nil"
18531818 single _ = stp
18541819 yieldk _ r = foldStream st yld sng stp r
18551820 in foldStream st yieldk single stop m
@@ -1914,10 +1879,10 @@ mfix f = mkStream $ \st yld sng stp ->
19141879 where
19151880
19161881 -- fix the head element of the stream
1917− xs = fix (f . headNonEmpty)
1882+ xs = fix (f . headPartial)
19181883
19191884 -- now fix the tail recursively
1920− ys = mfix (tailNonEmpty . f)
1885+ ys = mfix (tailPartial . f)
19211886
19221887-------------------------------------------------------------------------------
19231888-- Conversions
@@ -1948,15 +1913,6 @@ uncons m =
19481913 yieldk a r = pure (Just (a, r))
19491914 in foldStream defState yieldk single stop m
19501915
1951−-- Note that this is not a StreamK -> StreamK because then we cannot handle the
1952−-- empty stream case without making this a partial function.
1953−--
1954−-- See tailNonEmpty as well above.
1955−
1956−-- | Same as:
1957−--
1958−-- >>> tail = fmap (fmap snd) StreamK.uncons
1959−--
19601916{-# INLINE tail #-}
19611917tail :: Applicative m => StreamK m a -> m (Maybe (StreamK m a))
19621918tail =
@@ -1965,14 +1921,9 @@ tail =
19651921 yieldk _ r = pure $ Just r
19661922 in foldStream defState yieldk single stop
19671923
1968−-- Note that this is not a StreamK -> StreamK because then we cannot handle the
1969−-- empty stream case without making this a partial function.
1924+-- | Extract all but the last element of the stream, if any.
19701925--
1971−-- XXX How do we implement unsnoc? Make StreamK a monad and return the
1972−-- remaining stream as a result value in the monad?
1973−
1974−-- | Extract all but the last element of the stream, if any. This will end up
1975−-- evaluating the last element as well to find out that it is last.
1926+-- Note: This will end up buffering the entire stream.
19761927--
19771928-- /Pre-release/
19781929{-# INLINE init #-}
core/src/Streamly/Internal/Data/Time/Units.hs+4
@@ -1,3 +1,7 @@
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE PolyKinds #-}
3+{-# LANGUAGE UnboxedTuples #-}
4+
15-- |
26-- Module : Streamly.Internal.Data.Time.Units
37-- Copyright : (c) 2019 Composewell Technologies
core/src/Streamly/Internal/Data/Unbox.hs+1−4
@@ -1,8 +1,5 @@
11{-# LANGUAGE DataKinds #-}
2−{-# LANGUAGE TypeFamilies #-}
3−-- Must come after TypeFamilies, otherwise it is re-enabled.
4−-- MonoLocalBinds enabled by TypeFamilies causes perf regressions in general.
5−{-# LANGUAGE NoMonoLocalBinds #-}
2+{-# LANGUAGE DefaultSignatures #-}
63{-# LANGUAGE UnboxedTuples #-}
74{-# LANGUAGE UndecidableInstances #-}
85
core/src/Streamly/Internal/Data/Unfold.hs+4−6
@@ -82,7 +82,7 @@ module Streamly.Internal.Data.Unfold
8282 , dropWhileM
8383
8484 -- ** Cross product
85− , innerJoin
85+ , joinInnerGeneric
8686
8787 -- ** Resource Management
8888 -- | 'bracket' is the most general resource management operation, all other
@@ -677,12 +677,10 @@ dropWhileM f (Unfold step inject) = Unfold step' inject'
677677dropWhile :: Monad m => (b -> Bool) -> Unfold m a b -> Unfold m a b
678678dropWhile f = dropWhileM (return . f)
679679
680−-- | Cross intersection of two unfolds. See
681−-- 'Streamly.Internal.Data.Stream.innerJoin' for more details.
682−{-# INLINE_NORMAL innerJoin #-}
683−innerJoin :: Monad m =>
680+{-# INLINE_NORMAL joinInnerGeneric #-}
681+joinInnerGeneric :: Monad m =>
684682 (b -> c -> Bool) -> Unfold m a b -> Unfold m a c -> Unfold m a (b, c)
685−innerJoin eq s1 s2 = filter (\(a, b) -> a `eq` b) $ cross s1 s2
683+joinInnerGeneric eq s1 s2 = filter (\(a, b) -> a `eq` b) $ cross s1 s2
686684
687685------------------------------------------------------------------------------
688686-- Exceptions
core/src/Streamly/Internal/FileSystem/File.hs+9−4
@@ -103,14 +103,15 @@ import qualified Control.Monad.Catch as MC
103103import qualified System.IO as SIO
104104
105105import Streamly.Data.Fold (groupsOf, drain)
106−import Streamly.Internal.Data.Array.Type (Array(..))
106+import Streamly.Internal.Data.Array.Type (Array(..), pinnedWriteNUnsafe)
107107import Streamly.Internal.Data.Fold.Type (Fold(..))
108108import Streamly.Data.Stream (Stream)
109+import Streamly.Internal.Data.Unbox (Unbox)
109110import Streamly.Internal.Data.Unfold.Type (Unfold(..))
110111-- import Streamly.String (encodeUtf8, decodeUtf8, foldLines)
111112import Streamly.Internal.System.IO (defaultChunkSize)
112113
113−import qualified Streamly.Internal.Data.Array as A
114+import qualified Streamly.Data.Array as A
114115import qualified Streamly.Data.Stream as S
115116import qualified Streamly.Data.Unfold as UF
116117import qualified Streamly.Internal.Data.Array.Type as IA (pinnedChunksOf)
@@ -338,6 +339,10 @@ readWithBufferOf = readerWith
338339reader :: (MonadIO m, MonadCatch m) => Unfold m FilePath Word8
339340reader = UF.many A.reader (usingFile FH.chunkReader)
340341
342+{-# INLINE concatChunks #-}
343+concatChunks :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
344+concatChunks = S.unfoldMany A.reader
345+
341346-- | Generate a stream of bytes from a file specified by path. The stream ends
342347-- when EOF is encountered. File is locked using multiple reader and single
343348-- writer locking mode.
@@ -346,7 +351,7 @@ reader = UF.many A.reader (usingFile FH.chunkReader)
346351--
347352{-# INLINE read #-}
348353read :: (MonadIO m, MonadCatch m) => FilePath -> Stream m Word8
349−read file = A.concat $ withFile file ReadMode FH.readChunks
354+read file = concatChunks $ withFile file ReadMode FH.readChunks
350355
351356{-# DEPRECATED toBytes "Please use 'read' instead" #-}
352357{-# INLINE toBytes #-}
@@ -462,7 +467,7 @@ writeChunks path = Fold step initial extract final
462467writeWith :: (MonadIO m, MonadCatch m)
463468 => Int -> FilePath -> Fold m Word8 ()
464469writeWith n path =
465− groupsOf n (A.unsafePinnedCreateOf n) (writeChunks path)
470+ groupsOf n (pinnedWriteNUnsafe n) (writeChunks path)
466471
467472{-# DEPRECATED writeWithBufferOf "Please use 'writeWith' instead" #-}
468473{-# INLINE writeWithBufferOf #-}
core/src/Streamly/Internal/FileSystem/Handle.hs+28−21
@@ -40,8 +40,8 @@ module Streamly.Internal.FileSystem.Handle
4040
4141 -- * Streams
4242 , read
43− , readWith -- readConcatChunksOf
44− , readChunksWith -- readChunksOf
43+ , readWith
44+ , readChunksWith
4545 , readChunks
4646
4747 -- * Unfolds
@@ -59,10 +59,10 @@ module Streamly.Internal.FileSystem.Handle
5959 -- , writeUtf8ByLines
6060 -- , writeByFrames
6161 -- , writeLines
62− , writeWith -- writeChunksOf
62+ , writeWith
6363 , writeChunks
64− , writeChunksWith -- writeCompactChunksOf
65− , writeMaybesWith -- writeCompactJustsOf
64+ , writeChunksWith
65+ , writeMaybesWith
6666
6767 -- * Refolds
6868 , writer
@@ -131,13 +131,16 @@ import Streamly.Internal.Data.Fold (Fold)
131131import Streamly.Internal.Data.Refold.Type (Refold(..))
132132import Streamly.Internal.Data.Unfold.Type (Unfold(..))
133133import Streamly.Internal.Data.Array.Type
134− (Array(..), unsafeFreezeWithShrink, byteLength)
134+ (Array(..), pinnedWriteNUnsafe, unsafeFreezeWithShrink, byteLength)
135135import Streamly.Internal.Data.Stream.Type (Stream)
136+import Streamly.Internal.Data.Array.Stream (lpackArraysChunksOf)
136137-- import Streamly.String (encodeUtf8, decodeUtf8, foldLines)
137138import Streamly.Internal.System.IO (defaultChunkSize)
138139
139140import qualified Streamly.Data.Fold as FL
140−import qualified Streamly.Internal.Data.Array as A
141+import qualified Streamly.Data.Array as A
142+import qualified Streamly.Internal.Data.Array.Type as A
143+import qualified Streamly.Internal.Data.Array.Stream as AS
141144import qualified Streamly.Internal.Data.MutArray.Type as MArray
142145import qualified Streamly.Internal.Data.Refold.Type as Refold
143146import qualified Streamly.Internal.Data.Fold.Type as FL(refoldMany)
@@ -166,8 +169,6 @@ import qualified Streamly.Internal.Data.StreamK.Type as K (mkStream)
166169-- Array IO (Input)
167170-------------------------------------------------------------------------------
168171
169−-- XXX add an API that compacts the arrays to an exact size.
170−
171172-- | Read a 'ByteArray' consisting of one or more bytes from a file handle. If
172173-- no data is available on the handle it blocks until at least one byte becomes
173174-- available. If any data is available then it immediately returns that data
@@ -177,9 +178,9 @@ import qualified Streamly.Internal.Data.StreamK.Type as K (mkStream)
177178{-# INLINABLE getChunk #-}
178179getChunk :: MonadIO m => Int -> Handle -> m (Array Word8)
179180getChunk size h = liftIO $ do
180− arr :: MArray.MutArray Word8 <- MArray.pinnedEmptyOf size
181+ arr <- MArray.pinnedNewBytes size
181182 -- ptr <- mallocPlainForeignPtrAlignedBytes size (alignment (undefined :: Word8))
182− MArray.unsafePinnedAsPtr arr $ \p -> do
183+ MArray.asPtrUnsafe arr $ \p -> do
183184 n <- hGetBufSome h p size
184185 -- XXX shrink only if the diff is significant
185186 return $
@@ -337,6 +338,10 @@ readerWith = UF.many A.reader chunkReaderWith
337338readWithBufferOf :: MonadIO m => Unfold m (Int, Handle) Word8
338339readWithBufferOf = readerWith
339340
341+{-# INLINE concatChunks #-}
342+concatChunks :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
343+concatChunks = S.unfoldMany A.reader
344+
340345-- | @readWith bufsize handle@ reads a byte stream from a file
341346-- handle, reads are performed in chunks of up to @bufsize@.
342347--
@@ -345,7 +350,7 @@ readWithBufferOf = readerWith
345350-- /Pre-release/
346351{-# INLINE readWith #-}
347352readWith :: MonadIO m => Int -> Handle -> Stream m Word8
348−readWith size h = A.concat $ readChunksWith size h
353+readWith size h = concatChunks $ readChunksWith size h
349354
350355-- | Unfolds a file handle into a byte stream. IO requests to the device are
351356-- performed in sizes of
@@ -364,7 +369,7 @@ reader = UF.many A.reader chunkReader
364369-- /Pre-release/
365370{-# INLINE read #-}
366371read :: MonadIO m => Handle -> Stream m Word8
367−read = A.concat . readChunks
372+read = concatChunks . readChunks
368373
369374-------------------------------------------------------------------------------
370375-- Writing
@@ -379,12 +384,12 @@ read = A.concat . readChunks
379384{-# INLINABLE putChunk #-}
380385putChunk :: MonadIO m => Handle -> Array a -> m ()
381386putChunk _ arr | byteLength arr == 0 = return ()
382−putChunk h arr = A.unsafePinnedAsPtr arr $ \ptr ->
387+putChunk h arr = A.asPtrUnsafe arr $ \ptr ->
383388 liftIO $ hPutBuf h ptr aLen
384389
385390 where
386391
387− -- XXX We should have the length passed by unsafePinnedAsPtr itself.
392+ -- XXX We should have the length passed by asPtrUnsafe itself.
388393 aLen = A.byteLength arr
389394
390395-------------------------------------------------------------------------------
@@ -416,7 +421,7 @@ putChunks h = S.fold (FL.drainMapM (putChunk h))
416421{-# INLINE putChunksWith #-}
417422putChunksWith :: (MonadIO m, Unbox a)
418423 => Int -> Handle -> Stream m (Array a) -> m ()
419−putChunksWith n h xs = putChunks h $ A.compactLE n xs
424+putChunksWith n h xs = putChunks h $ AS.compact n xs
420425
421426-- > putBytesWith n h m = Handle.putChunks h $ A.pinnedChunksOf n m
422427
@@ -456,6 +461,8 @@ writeChunks h = FL.drainMapM (putChunk h)
456461chunkWriter :: MonadIO m => Refold m Handle (Array a) ()
457462chunkWriter = Refold.drainBy putChunk
458463
464+-- XXX lpackArraysChunksOf should be written idiomatically
465+
459466-- | @writeChunksWith bufsize handle@ writes a stream of arrays
460467-- to @handle@ after coalescing the adjacent arrays in chunks of @bufsize@.
461468-- We never split an array, if a single array is bigger than the specified size
@@ -465,7 +472,7 @@ chunkWriter = Refold.drainBy putChunk
465472{-# INLINE writeChunksWith #-}
466473writeChunksWith :: (MonadIO m, Unbox a)
467474 => Int -> Handle -> Fold m (Array a) ()
468−writeChunksWith n h = A.lCompactGE n (writeChunks h)
475+writeChunksWith n h = lpackArraysChunksOf n (writeChunks h)
469476
470477-- | Same as 'writeChunksWith'
471478--
@@ -489,11 +496,11 @@ writeChunksWithBufferOf = writeChunksWith
489496-- Bytes in the input stream are collected into a buffer until we have a chunk
490497-- of @reqSize@ and then written to the IO device.
491498--
492−-- >>> writeWith n h = Fold.groupsOf n (Array.unsafeCreateOf n) (Handle.writeChunks h)
499+-- >>> writeWith n h = Fold.groupsOf n (Array.writeNUnsafe n) (Handle.writeChunks h)
493500--
494501{-# INLINE writeWith #-}
495502writeWith :: MonadIO m => Int -> Handle -> Fold m Word8 ()
496−writeWith n h = FL.groupsOf n (A.unsafePinnedCreateOf n) (writeChunks h)
503+writeWith n h = FL.groupsOf n (pinnedWriteNUnsafe n) (writeChunks h)
497504
498505-- | Same as 'writeWith'
499506--
@@ -511,7 +518,7 @@ writeWithBufferOf = writeWith
511518writeMaybesWith :: (MonadIO m )
512519 => Int -> Handle -> Fold m (Maybe Word8) ()
513520writeMaybesWith n h =
514− let writeNJusts = FL.lmap fromJust $ A.pinnedCreateOf n
521+ let writeNJusts = FL.lmap fromJust $ A.pinnedWriteN n
515522 writeOnNothing = FL.takeEndBy_ isNothing writeNJusts
516523 in FL.many writeOnNothing (writeChunks h)
517524
@@ -521,7 +528,7 @@ writeMaybesWith n h =
521528{-# INLINE writerWith #-}
522529writerWith :: MonadIO m => Int -> Refold m Handle Word8 ()
523530writerWith n =
524− FL.refoldMany (FL.take n $ A.unsafePinnedCreateOf n) chunkWriter
531+ FL.refoldMany (FL.take n $ pinnedWriteNUnsafe n) chunkWriter
525532
526533-- | Write a byte stream to a file handle. Accumulates the input in chunks of
527534-- up to 'Streamly.Internal.Data.Array.Type.defaultChunkSize' before writing
core/src/Streamly/Internal/FileSystem/Path.hs+4−36
@@ -36,7 +36,7 @@
3636module Streamly.Internal.FileSystem.Path
3737 (
3838 -- * Path Types
39− Path (..)
39+ Path
4040 , File
4141 , Dir
4242 , Abs
@@ -82,11 +82,6 @@ module Streamly.Internal.FileSystem.Path
8282 , toChars
8383
8484 -- * Operations
85− -- Do we need to export the separator functions? They are not essential if
86− -- operations to split and combine paths are provided. If someone wants to
87− -- work on paths at low level then they know what they are.
88− , primarySeparator
89− , isSeparator
9085 , extendPath
9186 , extendDir
9287 )
@@ -94,7 +89,6 @@ where
9489
9590import Control.Exception (Exception)
9691import Control.Monad.Catch (MonadThrow(..))
97−import Data.Char (chr)
9892import Data.Functor.Identity (Identity(..))
9993import Data.Word (Word8)
10094#if defined(mingw32_HOST_OS) || defined(__MINGW32__)
@@ -157,15 +151,6 @@ instance Exception PathException
157151-- | A type representing file system paths for directories or files.
158152newtype Path = Path (Array WORD_TYPE) -- deriving Eq
159153
160−-- Show instance prints raw bytes without any decoding for rountdtripping.
161−-- Should we print this as a string instead, may be useful for ascii chars but
162−-- utf8 encoded chars may be unprintable. Better use toString if you want to
163−-- pretty print the path.
164−{-
165−instance Show Path where
166− show (Path x) = show x
167−-}
168−
169154-- XXX Do we need a type for file or dir Name as names cannot have the
170155-- separator char and there may be other restrictions on names? For example,
171156-- length restriction. A file name cannot be "." or "..". We can use the types
@@ -453,25 +438,8 @@ mkRelFile = undefined
453438-- Operations
454439------------------------------------------------------------------------------
455440
456−separatorWord :: WORD_TYPE
457−separatorWord = SEPARATOR
458−
459−-- Portable definition for exporting.
460−
461−-- | Primary path separator character, @/@ on Posix and @\\@ on Windows.
462−-- Windows supports @/@ too as a separator. Please use 'isSeparator' for
463−-- testing if a char is a separator char.
464−primarySeparator :: Char
465−primarySeparator = chr (SEPARATOR)
466−
467−-- | On Posix only @/@ is a path separator but in windows it could be either
468−-- @/@ or @\\@.
469−isSeparator :: Char -> Bool
470−#if defined(mingw32_HOST_OS) || defined(__MINGW32__)
471−isSeparator c = (c == '/') || (c == '\\')
472−#else
473−isSeparator = (== '/')
474−#endif
441+separator :: WORD_TYPE
442+separator = SEPARATOR
475443
476444-- If we append an absolute path it may fail with an error if the 'Path'
477445-- implementation stores absolute path information (a leading separator char).
@@ -497,7 +465,7 @@ extendPath (Path a) (Path b) =
497465 newArr = unsafePerformIO $ do
498466 arr <- MutArray.new len
499467 arr1 <- MutArray.spliceUnsafe arr (Array.unsafeThaw a)
500− arr2 <- MutArray.snocUnsafe arr1 separatorWord
468+ arr2 <- MutArray.snocUnsafe arr1 separator
501469 arr3 <- MutArray.spliceUnsafe arr2 (Array.unsafeThaw b)
502470 return (Array.unsafeFreeze arr3)
503471 in Path newArr
core/src/Streamly/Internal/Unicode/Stream.hs+2−2
@@ -111,7 +111,7 @@ import GHC.IO.Encoding.Failure (isSurrogate)
111111import GHC.Ptr (Ptr (..), plusPtr)
112112import System.IO.Unsafe (unsafePerformIO)
113113import Streamly.Internal.Data.Array.Type (Array(..))
114−import Streamly.Internal.Data.MutByteArray.Type (MutByteArray)
114+import Streamly.Internal.Data.MutArray.Type (MutByteArray)
115115import Streamly.Internal.Data.Fold (Fold)
116116import Streamly.Internal.Data.Parser (Parser)
117117import Streamly.Internal.Data.Stream (Stream)
@@ -1057,7 +1057,7 @@ stripHead = Stream.dropWhile isSpace
10571057-- >>> Stream.fold Fold.toList $ Unicode.lines Fold.toList (Stream.fromList "lines\nthis\nstring\n\n\n")
10581058-- ["lines","this","string","",""]
10591059--
1060−-- >>> lines f = Stream.foldMany (Fold.takeEndBy_ (== '\n') f)
1060+-- > lines = Stream.splitOnSuffix (== '\n')
10611061--
10621062-- /Pre-release/
10631063{-# INLINE lines #-}
core/src/Streamly/Internal/Unicode/String.hs+7−7
@@ -39,14 +39,14 @@ module Streamly.Internal.Unicode.String
3939 --
4040 -- $setup
4141
42− str
42+ str
4343 ) where
4444
4545
4646import Control.Applicative (Alternative(..))
4747import Control.Exception (displayException)
4848import Data.Functor.Identity (runIdentity)
49−import Streamly.Internal.Data.Parser (Parser, ParseError)
49+import Streamly.Internal.Data.Parser (Parser)
5050
5151import Language.Haskell.TH
5252import Language.Haskell.TH.Quote
@@ -106,12 +106,9 @@ strSegmentExp (StrVar name) = do
106106strExp :: [StrSegment] -> Q Exp
107107strExp xs = appE [| concat |] $ listE $ map strSegmentExp xs
108108
109−parseStr :: String -> Either ParseError [StrSegment]
110−parseStr = runIdentity . Stream.parse strParser . Stream.fromList
111−
112109expandVars :: String -> Q Exp
113−expandVars input =
114− case parseStr input of
110+expandVars ln =
111+ case runIdentity $ Stream.parse strParser (Stream.fromList ln) of
115112 Left e ->
116113 fail $ "str QuasiQuoter parse error: " ++ displayException e
117114 Right x ->
@@ -144,6 +141,9 @@ expandVars input =
144141-- :}
145142-- "hello world!"
146143--
144+-- Bugs: because of a bug in parsers, a lone # at the end of input gets
145+-- removed.
146+--
147147str :: QuasiQuoter
148148str =
149149 QuasiQuoter
core/streamly-core.cabal+10−14
@@ -1,6 +1,6 @@
11cabal-version: 2.2
22name: streamly-core
3−version: 0.2.2
3+version: 0.2.1
44synopsis: Streaming, parsers, arrays, serialization and more
55description:
66 For upgrading to streamly-0.9.0+ please read the
@@ -116,7 +116,6 @@ extra-doc-files:
116116 docs/*.md
117117 docs/ApiChangelogs/0.1.0.txt
118118 docs/ApiChangelogs/0.1.0-0.2.0.txt
119− docs/ApiChangelogs/0.2.0-0.2.2.txt
120119
121120source-repository head
122121 type: git
@@ -218,6 +217,8 @@ common compile-options
218217common default-extensions
219218 default-extensions:
220219 BangPatterns
220+ CApiFFI
221+ CPP
221222 ConstraintKinds
222223 DeriveDataTypeable
223224 DeriveGeneric
@@ -228,29 +229,24 @@ common default-extensions
228229 GeneralizedNewtypeDeriving
229230 InstanceSigs
230231 KindSignatures
232+ LambdaCase
233+ MagicHash
231234 MultiParamTypeClasses
235+ PatternSynonyms
232236 RankNTypes
237+ RecordWildCards
233238 ScopedTypeVariables
234239 StandaloneDeriving
235240 TupleSections
236241 TypeApplications
242+ TypeFamilies
237243 TypeOperators
244+ ViewPatterns
238245
239− -- Not GHC2021
240− CApiFFI
241− CPP
242− DefaultSignatures
243− LambdaCase
244− MagicHash
245− RecordWildCards
246−
247− -- TypeFamilies is required by IsList, IsMap type classes and
248− -- Unbox generic deriving code.
249− -- TypeFamilies
250246 -- MonoLocalBinds, enabled by TypeFamilies, causes performance
251247 -- regressions. Disable it. This must come after TypeFamilies,
252248 -- otherwise TypeFamilies will enable it again.
253− -- NoMonoLocalBinds
249+ NoMonoLocalBinds
254250
255251 -- UndecidableInstances -- Does not show any perf impact
256252 -- UnboxedTuples -- interferes with (#.)
docs/Developer/optimization-guidelines.md−12
@@ -191,18 +191,6 @@ the stages of a loop, it is often not useful to inline the whole loop
191191itself, in fact we may have to occasionally use a `NOINLINE` so that the
192192compiler does not inline it.
193193
194−We need to be careful about NOINLINE on polymorphic functions. When
195−NOINLINE is used, the function cannot be specialized causing huge
196−performance degradation. To avoid that we can either make the
197−function monomorphic or sometimes using `NOINLINE [0]` can do the
198−trick. `NOINLINE [0]` blocks inlining in earlier phases but lets it
199−specialize in the last phase, inlining in the last phase is left to
200−the compiler. `INLINE [0]` may sound the same as `NOINLINE [0]`,
201−however, it behaves differently because we ask the compiler to INLINE
202−it compulsorily and it may not give us the desired results. The
203−Data.Fold.writeLastN benchmark is one such case where `NOINLINE [0]`
204−provides much better performance than `INLINE [0]`.
205−
206194### NoSpecConstr
207195
208196It is not always useful to specialize function calls for all constructors, some
docs/User/Project/Changelog.md+1−1
@@ -2,7 +2,7 @@
22
33<!-- See rendered changelog at https://streamly.composewell.com -->
44
5−## 0.10.1 (Jan 2024)
5+## Unreleased
66
77* Fix TH macros in `Streamly.Data.Stream.MkType` for GHC 9.6 and above.
88
docs/User/Project/README.md−1
@@ -1,7 +1,6 @@
11# [Streamly][]: Idiomatic Haskell with C-Like Performance
22
33[![Gitter chat](https://badges.gitter.im/composewell/gitter.svg)](https://gitter.im/composewell/streamly)
4−[![Hackage](https://img.shields.io/hackage/v/streamly-core.svg?style=flat)](https://hackage.haskell.org/package/streamly-core)
54[![Hackage](https://img.shields.io/hackage/v/streamly.svg?style=flat)](https://hackage.haskell.org/package/streamly)
65
76## Upgrading to 0.9.0+
src/Streamly/Internal/Data/IsMap/HashMap.hs−5
@@ -1,8 +1,3 @@
1−{-# LANGUAGE TypeFamilies #-}
2−-- Must come after TypeFamilies, otherwise it is re-enabled.
3−-- MonoLocalBinds enabled by TypeFamilies causes perf regressions in general.
4−{-# LANGUAGE NoMonoLocalBinds #-}
5−
61{-# OPTIONS_GHC -Wno-orphans #-}
72
83-- |
src/Streamly/Internal/Data/Stream/IsStream/Common.hs+1−1
@@ -529,7 +529,7 @@ reverse' :: (IsStream t, MonadIO m, Unbox a) => t m a -> t m a
529529-- reverse' s = fromStreamD $ D.reverse' $ toStreamD s
530530reverse' =
531531 fromStreamD
532− . A.concatRev -- unfoldMany A.readerRev
532+ . A.concatChunksRev -- unfoldMany A.readerRev
533533 . D.fromStreamK
534534 . K.reverse
535535 . D.toStreamK
src/Streamly/Internal/Data/Stream/IsStream/Expand.hs−5
@@ -1,8 +1,3 @@
1−{-# LANGUAGE TypeFamilies #-}
2−-- Must come after TypeFamilies, otherwise it is re-enabled.
3−-- MonoLocalBinds enabled by TypeFamilies causes perf regressions in general.
4−{-# LANGUAGE NoMonoLocalBinds #-}
5−
61{-# OPTIONS_GHC -Wno-deprecations #-}
72
83-- |
src/Streamly/Internal/Data/Stream/IsStream/Top.hs+1−1
@@ -649,7 +649,7 @@ intersectBySorted :: (IsStream t, Monad m) =>
649649 (a -> a -> Ordering) -> t m a -> t m a -> t m a
650650intersectBySorted eq s1 =
651651 IsStream.fromStreamD
652− . StreamD.sortedIntersectBy eq (IsStream.toStreamD s1)
652+ . StreamD.intersectBySorted eq (IsStream.toStreamD s1)
653653 . IsStream.toStreamD
654654
655655-- Roughly joinLeft s1 s2 = s1 `difference` s2 + s1 `intersection` s2
src/Streamly/Internal/Data/Stream/Serial.hs−5
@@ -1,9 +1,4 @@
1−{-# LANGUAGE TypeFamilies #-}
2−-- Must come after TypeFamilies, otherwise it is re-enabled.
3−-- MonoLocalBinds enabled by TypeFamilies causes perf regressions in general.
4−{-# LANGUAGE NoMonoLocalBinds #-}
51{-# LANGUAGE UndecidableInstances #-}
6−
72{-# OPTIONS_GHC -Wno-deprecations #-}
83{-# OPTIONS_GHC -Wno-redundant-constraints #-}
94
src/Streamly/Internal/Data/Stream/Zip.hs−5
@@ -1,9 +1,4 @@
1−{-# LANGUAGE TypeFamilies #-}
2−-- Must come after TypeFamilies, otherwise it is re-enabled.
3−-- MonoLocalBinds enabled by TypeFamilies causes perf regressions in general.
4−{-# LANGUAGE NoMonoLocalBinds #-}
51{-# LANGUAGE UndecidableInstances #-}
6−
72{-# OPTIONS_GHC -Wno-deprecations #-}
83
94-- |
src/Streamly/Internal/FileSystem/Event.hs−3
@@ -20,9 +20,6 @@
2020-- * "Streamly.Internal.FileSystem.Event.Linux"
2121-- * "Streamly.Internal.FileSystem.Event.Windows"
2222
23−-- XXX Need to ensure that the signatures of the exported APIs are same on all
24−-- platforms.
25−
2623module Streamly.Internal.FileSystem.Event
2724 (
2825 -- * Creating a Watch
src/Streamly/Internal/FileSystem/Event/Darwin.hs+1−1
@@ -451,7 +451,7 @@ openWatch Config{..} paths = do
451451
452452 withPathName :: Array Word8 -> (PathName -> IO a) -> IO a
453453 withPathName arr act = do
454− A.unsafePinnedAsPtr arr $ \ptr ->
454+ A.asPtrUnsafe arr $ \ptr ->
455455 let pname = PathName (castPtr ptr) (fromIntegral (A.length arr))
456456 in act pname
457457
src/Streamly/Internal/FileSystem/Event/Linux.hs+2−2
@@ -188,7 +188,7 @@ import qualified Streamly.FileSystem.Handle as FH
188188import qualified Streamly.Unicode.Stream as U
189189
190190import qualified Streamly.Internal.Data.Array as A
191− ( fromStream, asCStringUnsafe, unsafePinnedAsPtr
191+ ( fromStream, asCStringUnsafe, asPtrUnsafe
192192 , getSliceUnsafe, read
193193 )
194194import qualified Streamly.Internal.FileSystem.Dir as Dir (readDirs)
@@ -809,7 +809,7 @@ readOneEvent :: Config -> Watch -> Parser Word8 IO Event
809809readOneEvent cfg wt@(Watch _ wdMap) = do
810810 let headerLen = sizeOf (undefined :: CInt) + 12
811811 arr <- PR.takeEQ headerLen (A.writeN headerLen)
812− (ewd, eflags, cookie, pathLen) <- PR.fromEffect $ A.unsafePinnedAsPtr arr readHeader
812+ (ewd, eflags, cookie, pathLen) <- PR.fromEffect $ A.asPtrUnsafe arr readHeader
813813 -- XXX need the "initial" in parsers to return a step type so that "take 0"
814814 -- can return without an input. otherwise if pathLen is 0 we will keep
815815 -- waiting to read one more char before we return this event.
src/Streamly/Internal/FileSystem/FD.hs+5−5
@@ -130,7 +130,7 @@ import qualified GHC.IO.Device as RawIO
130130import Streamly.Data.Array (Array, Unbox)
131131import Streamly.Data.Stream (Stream)
132132
133−import Streamly.Internal.Data.Array (byteLength, unsafeFreeze, unsafePinnedAsPtr)
133+import Streamly.Internal.Data.Array (byteLength, unsafeFreeze, asPtrUnsafe)
134134import Streamly.Internal.System.IO (defaultChunkSize)
135135
136136#if !defined(mingw32_HOST_OS)
@@ -147,7 +147,7 @@ import qualified Streamly.Internal.System.IOVec.Type as RawIO
147147import qualified Streamly.Data.Array as A
148148import qualified Streamly.Data.Fold as FL
149149import qualified Streamly.Internal.Data.MutArray as MArray
150− (MutArray(..), unsafePinnedAsPtr, pinnedNewBytes)
150+ (MutArray(..), asPtrUnsafe, pinnedNewBytes)
151151import qualified Streamly.Internal.Data.Array.Stream as AS
152152import qualified Streamly.Internal.Data.Stream as S
153153import qualified Streamly.Internal.Data.Stream as D
@@ -220,7 +220,7 @@ readArrayUpto :: Int -> Handle -> IO (Array Word8)
220220readArrayUpto size (Handle fd) = do
221221 arr <- MArray.pinnedNewBytes size
222222 -- ptr <- mallocPlainForeignPtrAlignedBytes size (alignment (undefined :: Word8))
223− MArray.unsafePinnedAsPtr arr $ \p -> do
223+ MArray.asPtrUnsafe arr $ \p -> do
224224 -- n <- hGetBufSome h p size
225225#if MIN_VERSION_base(4,15,0)
226226 n <- RawIO.read fd p 0 size
@@ -244,7 +244,7 @@ readArrayUpto size (Handle fd) = do
244244writeArray :: Unbox a => Handle -> Array a -> IO ()
245245writeArray _ arr | A.length arr == 0 = return ()
246246writeArray (Handle fd) arr =
247− unsafePinnedAsPtr arr $ \p ->
247+ asPtrUnsafe arr $ \p ->
248248 -- RawIO.writeAll fd (castPtr p) aLen
249249#if MIN_VERSION_base(4,15,0)
250250 RawIO.write fd (castPtr p) 0 aLen
@@ -270,7 +270,7 @@ writeArray (Handle fd) arr =
270270writeIOVec :: Handle -> Array RawIO.IOVec -> IO ()
271271writeIOVec _ iov | A.length iov == 0 = return ()
272272writeIOVec (Handle fd) iov =
273− unsafePinnedAsPtr iov $ \p ->
273+ asPtrUnsafe iov $ \p ->
274274 RawIO.writevAll fd p (A.length iov)
275275-}
276276#endif
src/Streamly/Internal/Network/Inet/TCP.hs+3−3
@@ -116,6 +116,7 @@ import Prelude hiding (read)
116116import Streamly.Internal.Control.Concurrent (MonadAsync)
117117import Streamly.Internal.Control.ForkLifted (fork)
118118import Streamly.Data.Array (Array)
119+import Streamly.Internal.Data.Array (pinnedWriteNUnsafe)
119120import Streamly.Internal.Data.Fold ( Fold(..) )
120121import Streamly.Data.Stream (Stream)
121122import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
@@ -131,8 +132,7 @@ import qualified Streamly.Data.Array as A
131132import qualified Streamly.Data.Fold as FL
132133import qualified Streamly.Data.Stream as S
133134import qualified Streamly.Data.Unfold as UF
134−import qualified Streamly.Internal.Data.Array as A
135− (pinnedChunksOf, unsafePinnedCreateOf)
135+import qualified Streamly.Internal.Data.Array as A (pinnedChunksOf)
136136import qualified Streamly.Internal.Data.Unfold as UF (bracketIO)
137137import qualified Streamly.Internal.Data.Fold as FL (Step(..), reduce)
138138
@@ -435,7 +435,7 @@ writeWithBufferOf
435435 -> PortNumber
436436 -> Fold m Word8 ()
437437writeWithBufferOf n addr port =
438− FL.groupsOf n (A.unsafePinnedCreateOf n) (writeChunks addr port)
438+ FL.groupsOf n (pinnedWriteNUnsafe n) (writeChunks addr port)
439439
440440-- | Write a stream to the supplied IPv4 host address and port number.
441441--
src/Streamly/Internal/Network/Socket.hs+10−11
@@ -87,6 +87,7 @@ import Prelude hiding (read)
8787import qualified Network.Socket as Net
8888
8989import Streamly.Internal.Data.Array (Array(..))
90+import Streamly.Internal.Data.Array.Stream (lpackArraysChunksOf)
9091import Streamly.Data.Fold (Fold)
9192import Streamly.Data.Stream (Stream)
9293import Streamly.Internal.Data.Unfold (Unfold(..))
@@ -98,10 +99,10 @@ import qualified Streamly.Data.Fold as FL
9899import qualified Streamly.Data.Stream as S
99100import qualified Streamly.Data.Unfold as UF
100101import qualified Streamly.Internal.Data.Array as A
101− ( unsafeFreeze, unsafePinnedAsPtr, byteLength, pinnedChunksOf,
102− pinnedCreateOf, unsafePinnedCreateOf, lCompactGE )
102+ ( unsafeFreeze, asPtrUnsafe, byteLength, pinnedChunksOf,
103+ pinnedWriteN, pinnedWriteNUnsafe )
103104import qualified Streamly.Internal.Data.MutArray as MArray
104− (MutArray(..), unsafePinnedAsPtr, pinnedEmptyOf)
105+ (MutArray(..), asPtrUnsafe, pinnedNewBytes)
105106import qualified Streamly.Internal.Data.Stream as S (fromStreamK, Stream(..), Step(..))
106107import qualified Streamly.Internal.Data.StreamK as K (mkStream)
107108
@@ -252,8 +253,6 @@ accept tcpListenQ spec addr =
252253-- Array IO (Input)
253254-------------------------------------------------------------------------------
254255
255−-- XXX add an API that compacts the arrays to an exact size.
256−
257256{-# INLINABLE readArrayUptoWith #-}
258257readArrayUptoWith
259258 :: (h -> Ptr Word8 -> Int -> IO Int)
@@ -261,9 +260,9 @@ readArrayUptoWith
261260 -> h
262261 -> IO (Array Word8)
263262readArrayUptoWith f size h = do
264− arr <- MArray.pinnedEmptyOf size
263+ arr <- MArray.pinnedNewBytes size
265264 -- ptr <- mallocPlainForeignPtrAlignedBytes size (alignment (undefined :: Word8))
266− MArray.unsafePinnedAsPtr arr $ \p -> do
265+ MArray.asPtrUnsafe arr $ \p -> do
267266 n <- f h p size
268267 let v = A.unsafeFreeze
269268 $ arr { MArray.arrEnd = n, MArray.arrBound = size }
@@ -311,7 +310,7 @@ writeArrayWith :: Unbox a
311310 -> Array a
312311 -> IO ()
313312writeArrayWith _ _ arr | A.length arr == 0 = return ()
314−writeArrayWith f h arr = A.unsafePinnedAsPtr arr $ \ptr -> f h (castPtr ptr) aLen
313+writeArrayWith f h arr = A.asPtrUnsafe arr $ \ptr -> f h (castPtr ptr) aLen
315314
316315 where
317316
@@ -474,7 +473,7 @@ writeChunks h = FL.drainMapM (liftIO . putChunk h)
474473{-# INLINE writeChunksWith #-}
475474writeChunksWith :: (MonadIO m, Unbox a)
476475 => Int -> Socket -> Fold m (Array a) ()
477−writeChunksWith n h = A.lCompactGE n (writeChunks h)
476+writeChunksWith n h = lpackArraysChunksOf n (writeChunks h)
478477
479478-- | Same as 'writeChunksWith'
480479--
@@ -505,7 +504,7 @@ putBytesWith n h m = putChunks h $ A.pinnedChunksOf n m
505504--
506505{-# INLINE writeWith #-}
507506writeWith :: MonadIO m => Int -> Socket -> Fold m Word8 ()
508−writeWith n h = FL.groupsOf n (A.unsafePinnedCreateOf n) (writeChunks h)
507+writeWith n h = FL.groupsOf n (A.pinnedWriteNUnsafe n) (writeChunks h)
509508
510509-- | Same as 'writeWith'
511510--
@@ -523,7 +522,7 @@ writeWithBufferOf = writeWith
523522writeMaybesWith :: (MonadIO m )
524523 => Int -> Socket -> Fold m (Maybe Word8) ()
525524writeMaybesWith n h =
526− let writeNJusts = FL.lmap fromJust $ A.pinnedCreateOf n
525+ let writeNJusts = FL.lmap fromJust $ A.pinnedWriteN n
527526 writeOnNothing = FL.takeEndBy_ isNothing writeNJusts
528527 in FL.many writeOnNothing (writeChunks h)
529528
streamly.cabal+11−11
@@ -1,6 +1,6 @@
11cabal-version: 2.2
22name: streamly
3−version: 0.10.1
3+version: 0.10.0
44synopsis: Streaming, dataflow programming and declarative concurrency
55description:
66 For upgrading to streamly-0.9.0+ please read the
@@ -294,6 +294,8 @@ common compile-options
294294common default-extensions
295295 default-extensions:
296296 BangPatterns
297+ CApiFFI
298+ CPP
297299 ConstraintKinds
298300 DeriveDataTypeable
299301 DeriveGeneric
@@ -304,25 +306,23 @@ common default-extensions
304306 GeneralizedNewtypeDeriving
305307 InstanceSigs
306308 KindSignatures
309+ LambdaCase
310+ MagicHash
307311 MultiParamTypeClasses
312+ PatternSynonyms
308313 RankNTypes
314+ RecordWildCards
309315 ScopedTypeVariables
310316 TupleSections
311317 TypeApplications
318+ TypeFamilies
312319 TypeOperators
320+ ViewPatterns
313321
314− -- Not GHC2021
315− CApiFFI
316− CPP
317− LambdaCase
318− MagicHash
319− RecordWildCards
320−
321− -- TypeFamilies -- required by IsHashMap type class
322322 -- MonoLocalBinds, enabled by TypeFamilies, causes performance
323323 -- regressions. Disable it. This must come after TypeFamilies,
324324 -- otherwise TypeFamilies will enable it again.
325− -- NoMonoLocalBinds
325+ NoMonoLocalBinds
326326
327327 -- UndecidableInstances -- Does not show any perf impact
328328 -- UnboxedTuples -- interferes with (#.)
@@ -513,7 +513,7 @@ library
513513 , template-haskell >= 2.14 && < 2.22
514514
515515 -- The core streamly package
516− , streamly-core == 0.2.2
516+ , streamly-core >= 0.2.0 && < 0.2.2
517517
518518 , hashable >= 1.3 && < 1.5
519519 , unordered-containers >= 0.2 && < 0.3
test/Streamly/Test/Data/Array.hs+2−2
@@ -185,7 +185,7 @@ testUnsafeIndxedFromList inp =
185185testAsPtrUnsafeMA :: IO ()
186186testAsPtrUnsafeMA = do
187187 arr <- MA.fromList ([0 .. 99] :: [Int])
188− MA.unsafePinnedAsPtr arr (getList (0 :: Int)) `shouldReturn` [0 .. 99]
188+ MA.asPtrUnsafe arr (getList (0 :: Int)) `shouldReturn` [0 .. 99]
189189
190190 where
191191
@@ -229,7 +229,7 @@ main =
229229 prop "read . write === id" testFoldUnfold
230230 prop "fromList" testFromList
231231 prop "foldMany with writeNUnsafe concats to original"
232− (foldManyWith (\n -> Fold.take n (A.unsafeCreateOf n)))
232+ (foldManyWith (\n -> Fold.take n (A.writeNUnsafe n)))
233233 describe "unsafeSlice" $ do
234234 it "partial" $ unsafeSlice 2 4 [1..10]
235235 it "none" $ unsafeSlice 10 0 [1..10]