on 157c63f help sign in
60 files changed+1251−2617
since splitsnapshots
unifiedsplit
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−2 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+13−396 core/src/Streamly/Internal/Data/Array/Generic.hs+6−22 core/src/Streamly/Internal/Data/Array/Stream.hs+299−4 core/src/Streamly/Internal/Data/Array/Type.hs+46−144 core/src/Streamly/Internal/Data/IsMap.hs−4 core/src/Streamly/Internal/Data/MutArray.hs+3−24 core/src/Streamly/Internal/Data/MutArray/Generic.hs+30−65 core/src/Streamly/Internal/Data/MutArray/Type.hs+323−697 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+64−10 core/src/Streamly/Internal/Data/Stream/Top.hs+115−243 core/src/Streamly/Internal/Data/Stream/Transform.hs+26−52 core/src/Streamly/Internal/Data/Stream/Transformer.hs+1−2 core/src/Streamly/Internal/Data/Stream/Type.hs+3−37 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+1−1 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/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
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−2
@@ -11,9 +11,7 @@
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
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+13−396
@@ -74,16 +74,9 @@ module Streamly.Internal.Data.Array
7474 , interposeSuffix
7575 , intercalateSuffix
7676
77− , compactLE
78− , pinnedCompactLE
7977 , compactOnByte
8078 , compactOnByteSuffix
8179
82− , foldBreakChunks
83− , foldChunks
84− , foldBreakChunksK
85− , parseBreakChunksK
86−
8780 -- * Serialization
8881 , encodeAs
8982 , serialize
@@ -102,42 +95,32 @@ where
10295#include "ArrayMacros.h"
10396
10497import Control.Monad.IO.Class (MonadIO(..))
105−-- import Data.Bifunctor (first)
106−-- import Data.Either (fromRight)
10798import Data.Functor.Identity (Identity)
10899import Data.Proxy (Proxy(..))
109100import Data.Word (Word8)
110101import Foreign.C.String (CString)
111102import Foreign.Ptr (castPtr)
112103import Foreign.Storable (Storable)
113−import GHC.Types (SPEC(..))
114104import Streamly.Internal.Data.Unbox (Unbox(..))
115105import Prelude hiding (length, null, last, map, (!!), read, concat)
116106
117107import Streamly.Internal.Data.MutByteArray.Type (PinnedState(..), MutByteArray)
118108import Streamly.Internal.Data.Serialize.Type (Serialize)
119109import 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'(..))
110+import Streamly.Internal.Data.Stream (Stream)
111+import Streamly.Internal.Data.SVar.Type (adaptState)
112+import Streamly.Internal.Data.Tuple.Strict (Tuple3Fused'(..))
125113import Streamly.Internal.Data.Unfold.Type (Unfold(..))
126114import Streamly.Internal.System.IO (unsafeInlineIO)
127115
128−import qualified Streamly.Internal.Data.Fold.Type as Fold
129116import qualified Streamly.Internal.Data.Serialize.Type as Serialize
130117import qualified Streamly.Internal.Data.MutByteArray.Type as MBA
131118import qualified Streamly.Internal.Data.MutArray as MA
132119import qualified Streamly.Internal.Data.Fold as FL
133120import 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
136121import qualified Streamly.Internal.Data.Stream as D
137122import qualified Streamly.Internal.Data.Stream as Stream
138−import qualified Streamly.Internal.Data.StreamK as StreamK
139123import qualified Streamly.Internal.Data.Unfold as Unfold
140−import qualified Prelude
141124
142125import Streamly.Internal.Data.Array.Type
143126
@@ -205,8 +188,6 @@ last = getIndexRev 0
205188-- Folds with Array as the container
206189-------------------------------------------------------------------------------
207190
208−-- XXX We should generate this from Ring.
209−
210191-- | @writeLastN n@ folds a maximum of @n@ elements from the end of the input
211192-- stream to an 'Array'.
212193--
@@ -228,9 +209,11 @@ writeLastN n
228209 in fmap f $ liftIO $ RB.new n
229210
230211 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
212+ arr <- liftIO $ MA.new n
213+ foldFunc i rh snoc' arr rb
214+
215+ -- XXX We should write a read unfold for ring.
216+ snoc' b a = liftIO $ MA.snocUnsafe b a
234217
235218 foldFunc i
236219 | i < n = RB.unsafeFoldRingM
@@ -328,7 +311,6 @@ sliceIndexerFromLen from len =
328311 Unfold.lmap unsafeThaw (MA.sliceIndexerFromLen from len)
329312
330313{-# DEPRECATED genSlicesFromLen "Please use sliceIndexerFromLen instead." #-}
331−{-# INLINE genSlicesFromLen #-}
332314genSlicesFromLen :: forall m a. (Monad m, Unbox a)
333315 => Int -- ^ from index
334316 -> Int -- ^ length of the slice
@@ -350,7 +332,6 @@ slicerFromLen from len =
350332 $ Unfold.lmap unsafeThaw (MA.slicerFromLen from len)
351333
352334{-# DEPRECATED getSlicesFromLen "Please use slicerFromLen instead." #-}
353−{-# INLINE getSlicesFromLen #-}
354335getSlicesFromLen :: forall m a. (Monad m, Unbox a)
355336 => Int -- ^ from index
356337 -> Int -- ^ length of the slice
@@ -401,7 +382,6 @@ indexReader m =
401382
402383-- XXX DO NOT REMOVE, change the signature to use Stream instead of unfold
403384{-# DEPRECATED getIndices "Please use getIndices instead." #-}
404−{-# INLINE getIndices #-}
405385getIndices :: (Monad m, Unbox a) => Stream m Int -> Unfold m (Array a) a
406386getIndices = indexReader
407387
@@ -452,7 +432,7 @@ runPipe f arr = P.runPipe (toArrayMinChunk (length arr)) $ f (read arr)
452432streamTransform :: forall m a b. (MonadIO m, Unbox a, Unbox b)
453433 => (Stream m a -> Stream m b) -> Array a -> m (Array b)
454434streamTransform f arr =
455− Stream.fold (createWith (length arr)) $ f (read arr)
435+ Stream.fold (writeWith (length arr)) $ f (read arr)
456436
457437-------------------------------------------------------------------------------
458438-- Casts
@@ -505,8 +485,8 @@ cast arr =
505485asCStringUnsafe :: Array a -> (CString -> IO b) -> IO b
506486asCStringUnsafe arr act = do
507487 let arr1 = asBytes arr <> fromList [0]
508− -- unsafePinnedAsPtr makes sure the array is pinned
509− unsafePinnedAsPtr arr1 $ \ptr -> act (castPtr ptr)
488+ -- asPtrUnsafe makes sure the array is pinned
489+ asPtrUnsafe arr1 $ \ptr -> act (castPtr ptr)
510490
511491-------------------------------------------------------------------------------
512492-- Folds
@@ -598,7 +578,7 @@ data FlattenState s =
598578-- >>> interposeSuffix x = Stream.interposeSuffix x Array.reader
599579--
600580{-# INLINE_NORMAL interposeSuffix #-}
601−interposeSuffix :: forall m a. (Monad m, Unbox a)
581+interposeSuffix :: forall m a. (MonadIO m, Unbox a)
602582 => a -> Stream m (Array a) -> Stream m a
603583-- This does not require MonadIO constraint.
604584-- interposeSuffix x = D.interposeSuffix x reader
@@ -619,7 +599,7 @@ interposeSuffix sep (D.Stream step state) = D.Stream step' (OuterLoop state)
619599 return $ D.Yield sep $ OuterLoop st
620600
621601 step' _ (InnerLoop st contents p end) = do
622− x <- pure $ unsafeInlineIO $ peekAt p contents
602+ x <- liftIO $ peekAt p contents
623603 return $ D.Yield x (InnerLoop st contents (INDEX_NEXT(p,a)) end)
624604
625605-- | Insert the given array after each array and flatten.
@@ -631,24 +611,6 @@ intercalateSuffix :: (Monad m, Unbox a)
631611 => Array a -> Stream m (Array a) -> Stream m a
632612intercalateSuffix = D.intercalateSuffix reader
633613
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−
652614-- | Split a stream of arrays on a given separator byte, dropping the separator
653615-- and coalescing all the arrays between two separators into a single array.
654616--
@@ -671,348 +633,3 @@ compactOnByteSuffix
671633 -> Stream m (Array Word8)
672634compactOnByteSuffix byte =
673635 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+299−4
@@ -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
@@ -96,9 +95,11 @@ 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
100100import qualified Streamly.Internal.Data.Array as A
101101import qualified Streamly.Internal.Data.Array as Array
102+import qualified Streamly.Internal.Data.Fold.Type as FL (Fold(..), Step(..))
102103import qualified Streamly.Internal.Data.Parser as PR
103104import qualified Streamly.Internal.Data.Parser as PRD
104105 (Parser(..), Initial(..))
@@ -180,7 +181,71 @@ splitOnSuffix = Array.compactOnByteSuffix
180181{-# INLINE_NORMAL foldBreakD #-}
181182foldBreakD :: forall m a b. (MonadIO m, Unbox a) =>
182183 Fold m a b -> D.Stream m (Array a) -> m (b, D.Stream m (Array a))
183−foldBreakD = Array.foldBreakChunks
184+foldBreakD (FL.Fold fstep initial _ final) stream@(D.Stream step state) = do
185+ res <- initial
186+ case res of
187+ FL.Partial fs -> go SPEC state fs
188+ FL.Done fb -> return $! (fb, stream)
189+
190+ where
191+
192+ {-# INLINE go #-}
193+ go !_ st !fs = do
194+ r <- step defState st
195+ case r of
196+ D.Yield (Array contents start end) s ->
197+ let fp = Tuple' end contents
198+ in goArray SPEC s fp start fs
199+ D.Skip s -> go SPEC s fs
200+ D.Stop -> do
201+ b <- final fs
202+ return (b, D.nil)
203+
204+ goArray !_ s (Tuple' end _) !cur !fs
205+ | cur == end = do
206+ go SPEC s fs
207+ goArray !_ st fp@(Tuple' end contents) !cur !fs = do
208+ x <- liftIO $ peekByteIndex cur contents
209+ res <- fstep fs x
210+ let next = INDEX_NEXT(cur,a)
211+ case res of
212+ FL.Done b -> do
213+ let arr = Array contents next end
214+ return $! (b, D.cons arr (D.Stream step st))
215+ FL.Partial fs1 -> goArray SPEC st fp next fs1
216+
217+{-# INLINE_NORMAL foldBreakK #-}
218+foldBreakK :: forall m a b. (MonadIO m, Unbox a) =>
219+ Fold m a b -> K.StreamK m (Array a) -> m (b, K.StreamK m (Array a))
220+foldBreakK (FL.Fold fstep initial _ final) stream = do
221+ res <- initial
222+ case res of
223+ FL.Partial fs -> go fs stream
224+ FL.Done fb -> return (fb, stream)
225+
226+ where
227+
228+ {-# INLINE go #-}
229+ go !fs st = do
230+ let stop = (, K.nil) <$> final fs
231+ single a = yieldk a K.nil
232+ yieldk (Array contents start end) r =
233+ let fp = Tuple' end contents
234+ in goArray fs r fp start
235+ in K.foldStream defState yieldk single stop st
236+
237+ goArray !fs st (Tuple' end _) !cur
238+ | cur == end = do
239+ go fs st
240+ goArray !fs st fp@(Tuple' end contents) !cur = do
241+ x <- liftIO $ peekByteIndex cur contents
242+ res <- fstep fs x
243+ let next = INDEX_NEXT(cur,a)
244+ case res of
245+ FL.Done b -> do
246+ let arr = Array contents next end
247+ return $! (b, K.cons arr st)
248+ FL.Partial fs1 -> goArray fs1 st fp next
184249
185250-- | Fold an array stream using the supplied 'Fold'. Returns the fold result
186251-- and the unconsumed stream.
@@ -206,7 +271,7 @@ foldBreak ::
206271 => Fold m a b
207272 -> StreamK m (A.Array a)
208273 -> m (b, StreamK m (A.Array a))
209−foldBreak = Array.foldBreakChunksK
274+foldBreak = foldBreakK
210275--
211276-- foldBreak f s = fmap fromStreamD <$> foldBreakD f (toStreamD s)
212277--
@@ -270,6 +335,236 @@ splitAtArrayListRev n ls
270335{-# ANN type List NoSpecConstr #-}
271336newtype List a = List {getList :: [a]}
272337
338+{-
339+-- This can be generalized to any type provided it can be unfolded to a stream
340+-- and it can be combined using a semigroup operation.
341+--
342+-- XXX This should be written using CPS (as parseK) if we want it to scale wrt
343+-- to the number of times it can be called on the same stream.
344+{-# INLINE_NORMAL parseBreakD #-}
345+parseBreakD ::
346+ forall m a b. (MonadIO m, MonadThrow m, Unbox a)
347+ => PRD.Parser a m b
348+ -> D.Stream m (Array.Array a)
349+ -> m (b, D.Stream m (Array.Array a))
350+parseBreakD
351+ (PRD.Parser pstep initial extract) stream@(D.Stream step state) = do
352+
353+ res <- initial
354+ case res of
355+ PRD.IPartial s -> go SPEC state (List []) s
356+ PRD.IDone b -> return (b, stream)
357+ PRD.IError err -> throwM $ ParseError err
358+
359+ where
360+
361+ -- "backBuf" contains last few items in the stream that we may have to
362+ -- backtrack to.
363+ --
364+ -- XXX currently we are using a dumb list based approach for backtracking
365+ -- buffer. This can be replaced by a sliding/ring buffer using Data.Array.
366+ -- That will allow us more efficient random back and forth movement.
367+ go !_ st backBuf !pst = do
368+ r <- step defState st
369+ case r of
370+ D.Yield (Array contents start end) s ->
371+ gobuf SPEC s backBuf
372+ (Tuple' end contents) start pst
373+ D.Skip s -> go SPEC s backBuf pst
374+ D.Stop -> do
375+ b <- extract pst
376+ return (b, D.nil)
377+
378+ -- Use strictness on "cur" to keep it unboxed
379+ gobuf !_ s backBuf (Tuple' end _) !cur !pst
380+ | cur == end = do
381+ go SPEC s backBuf pst
382+ gobuf !_ s backBuf fp@(Tuple' end contents) !cur !pst = do
383+ x <- liftIO $ peekByteIndex contents cur
384+ pRes <- pstep pst x
385+ let next = INDEX_NEXT(cur,a)
386+ case pRes of
387+ PR.Partial 0 pst1 ->
388+ gobuf SPEC s (List []) fp next pst1
389+ PR.Partial n pst1 -> do
390+ assert (n <= Prelude.length (x:getList backBuf)) (return ())
391+ let src0 = Prelude.take n (x:getList backBuf)
392+ arr0 = A.fromListN n (Prelude.reverse src0)
393+ arr1 = Array contents next end
394+ src = arr0 <> arr1
395+ let !(Array cont1 start end1) = src
396+ fp1 = Tuple' end1 cont1
397+ gobuf SPEC s (List []) fp1 start pst1
398+ PR.Continue 0 pst1 ->
399+ gobuf SPEC s (List (x:getList backBuf)) fp next pst1
400+ PR.Continue n pst1 -> do
401+ assert (n <= Prelude.length (x:getList backBuf)) (return ())
402+ let (src0, buf1) = splitAt n (x:getList backBuf)
403+ arr0 = A.fromListN n (Prelude.reverse src0)
404+ arr1 = Array contents next end
405+ src = arr0 <> arr1
406+ let !(Array cont1 start end1) = src
407+ fp1 = Tuple' end1 cont1
408+ gobuf SPEC s (List buf1) fp1 start pst1
409+ PR.Done 0 b -> do
410+ let arr = Array contents next end
411+ return (b, D.cons arr (D.Stream step s))
412+ PR.Done n b -> do
413+ assert (n <= Prelude.length (x:getList backBuf)) (return ())
414+ let src0 = Prelude.take n (x:getList backBuf)
415+ -- XXX create the array in reverse instead
416+ arr0 = A.fromListN n (Prelude.reverse src0)
417+ arr1 = Array contents next end
418+ -- XXX Use StreamK to avoid adding arbitrary layers of
419+ -- constructors every time.
420+ str = D.cons arr0 (D.cons arr1 (D.Stream step s))
421+ return (b, str)
422+ PR.Error err -> throwM $ ParseError err
423+-}
424+
425+{-# INLINE_NORMAL parseBreakK #-}
426+parseBreakK ::
427+ forall m a b. (MonadIO m, Unbox a)
428+ => PRD.Parser a m b
429+ -> K.StreamK m (Array.Array a)
430+ -> m (Either ParseError b, K.StreamK m (Array.Array a))
431+parseBreakK (PRD.Parser pstep initial extract) stream = do
432+ res <- initial
433+ case res of
434+ PRD.IPartial s -> go s stream []
435+ PRD.IDone b -> return (Right b, stream)
436+ PRD.IError err -> return (Left (ParseError err), stream)
437+
438+ where
439+
440+ -- "backBuf" contains last few items in the stream that we may have to
441+ -- backtrack to.
442+ --
443+ -- XXX currently we are using a dumb list based approach for backtracking
444+ -- buffer. This can be replaced by a sliding/ring buffer using Data.Array.
445+ -- That will allow us more efficient random back and forth movement.
446+ go !pst st backBuf = do
447+ let stop = goStop pst backBuf -- (, K.nil) <$> extract pst
448+ single a = yieldk a K.nil
449+ yieldk arr r = goArray pst backBuf r arr
450+ in K.foldStream defState yieldk single stop st
451+
452+ -- Use strictness on "cur" to keep it unboxed
453+ goArray !pst backBuf st (Array _ cur end) | cur == end = go pst st backBuf
454+ goArray !pst backBuf st (Array contents cur end) = do
455+ x <- liftIO $ peekByteIndex cur contents
456+ pRes <- pstep pst x
457+ let next = INDEX_NEXT(cur,a)
458+ case pRes of
459+ PR.Partial 0 s ->
460+ goArray s [] st (Array contents next end)
461+ PR.Partial n s -> do
462+ assert (n <= Prelude.length (x:backBuf)) (return ())
463+ let src0 = Prelude.take n (x:backBuf)
464+ arr0 = A.fromListN n (Prelude.reverse src0)
465+ arr1 = Array contents next end
466+ src = arr0 <> arr1
467+ goArray s [] st src
468+ PR.Continue 0 s ->
469+ goArray s (x:backBuf) st (Array contents next end)
470+ PR.Continue n s -> do
471+ assert (n <= Prelude.length (x:backBuf)) (return ())
472+ let (src0, buf1) = splitAt n (x:backBuf)
473+ arr0 = A.fromListN n (Prelude.reverse src0)
474+ arr1 = Array contents next end
475+ src = arr0 <> arr1
476+ goArray s buf1 st src
477+ PR.Done 0 b -> do
478+ let arr = Array contents next end
479+ return (Right b, K.cons arr st)
480+ PR.Done n b -> do
481+ assert (n <= Prelude.length (x:backBuf)) (return ())
482+ let src0 = Prelude.take n (x:backBuf)
483+ -- XXX Use fromListRevN once implemented
484+ -- arr0 = A.fromListRevN n src0
485+ arr0 = A.fromListN n (Prelude.reverse src0)
486+ arr1 = Array contents next end
487+ str = K.cons arr0 (K.cons arr1 st)
488+ return (Right b, str)
489+ PR.Error err -> do
490+ let n = Prelude.length backBuf
491+ arr0 = A.fromListN n (Prelude.reverse backBuf)
492+ arr1 = Array contents cur end
493+ str = K.cons arr0 (K.cons arr1 stream)
494+ return (Left (ParseError err), str)
495+
496+ -- This is a simplified goArray
497+ goExtract !pst backBuf (Array _ cur end)
498+ | cur == end = goStop pst backBuf
499+ goExtract !pst backBuf (Array contents cur end) = do
500+ x <- liftIO $ peekByteIndex cur contents
501+ pRes <- pstep pst x
502+ let next = INDEX_NEXT(cur,a)
503+ case pRes of
504+ PR.Partial 0 s ->
505+ goExtract s [] (Array contents next end)
506+ PR.Partial n s -> do
507+ assert (n <= Prelude.length (x:backBuf)) (return ())
508+ let src0 = Prelude.take n (x:backBuf)
509+ arr0 = A.fromListN n (Prelude.reverse src0)
510+ arr1 = Array contents next end
511+ src = arr0 <> arr1
512+ goExtract s [] src
513+ PR.Continue 0 s ->
514+ goExtract s backBuf (Array contents next end)
515+ PR.Continue n s -> do
516+ assert (n <= Prelude.length (x:backBuf)) (return ())
517+ let (src0, buf1) = splitAt n (x:backBuf)
518+ arr0 = A.fromListN n (Prelude.reverse src0)
519+ arr1 = Array contents next end
520+ src = arr0 <> arr1
521+ goExtract s buf1 src
522+ PR.Done 0 b -> do
523+ let arr = Array contents next end
524+ return (Right b, K.fromPure arr)
525+ PR.Done n b -> do
526+ assert (n <= Prelude.length backBuf) (return ())
527+ let src0 = Prelude.take n backBuf
528+ -- XXX Use fromListRevN once implemented
529+ -- arr0 = A.fromListRevN n src0
530+ arr0 = A.fromListN n (Prelude.reverse src0)
531+ arr1 = Array contents next end
532+ str = K.cons arr0 (K.fromPure arr1)
533+ return (Right b, str)
534+ PR.Error err -> do
535+ let n = Prelude.length backBuf
536+ arr0 = A.fromListN n (Prelude.reverse backBuf)
537+ arr1 = Array contents cur end
538+ str = K.cons arr0 (K.cons arr1 stream)
539+ return (Left (ParseError err), str)
540+
541+ -- This is a simplified goExtract
542+ {-# INLINE goStop #-}
543+ goStop !pst backBuf = do
544+ pRes <- extract pst
545+ case pRes of
546+ PR.Partial _ _ -> error "Bug: parseBreak: Partial in extract"
547+ PR.Continue 0 s ->
548+ goStop s backBuf
549+ PR.Continue n s -> do
550+ assert (n <= Prelude.length backBuf) (return ())
551+ let (src0, buf1) = splitAt n backBuf
552+ arr = A.fromListN n (Prelude.reverse src0)
553+ goExtract s buf1 arr
554+ PR.Done 0 b ->
555+ return (Right b, K.nil)
556+ PR.Done n b -> do
557+ assert (n <= Prelude.length backBuf) (return ())
558+ let src0 = Prelude.take n backBuf
559+ -- XXX Use fromListRevN once implemented
560+ -- arr0 = A.fromListRevN n src0
561+ arr0 = A.fromListN n (Prelude.reverse src0)
562+ return (Right b, K.fromPure arr0)
563+ PR.Error err -> do
564+ let n = Prelude.length backBuf
565+ arr0 = A.fromListN n (Prelude.reverse backBuf)
566+ return (Left (ParseError err), K.fromPure arr0)
567+
273568-- | Parse an array stream using the supplied 'Parser'. Returns the parse
274569-- result and the unconsumed stream. Throws 'ParseError' if the parse fails.
275570--
@@ -293,7 +588,7 @@ parseBreak ::
293588parseBreak p s =
294589 fmap fromStreamD <$> parseBreakD (PRD.fromParserK p) (toStreamD s)
295590-}
296−parseBreak = Array.parseBreakChunksK
591+parseBreak = parseBreakK
297592-- parseBreak p = K.parseBreakChunks (ParserK.adaptC p)
298593
299594-------------------------------------------------------------------------------
core/src/Streamly/Internal/Data/Array/Type.hs+46−144
@@ -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-- |
73-- Module : Streamly.Internal.Data.Array.Type
84-- Copyright : (c) 2020 Composewell Technologies
@@ -32,10 +28,10 @@ module Streamly.Internal.Data.Array.Type
3228 , isPinned
3329
3430 -- *** Casting
35− , unsafePinnedAsPtr
31+ , asPtrUnsafe
3632
3733 -- ** Construction
38− , empty
34+ , nil
3935
4036 -- *** Cloning
4137 -- XXX Why would we clone an immutable array?
@@ -49,13 +45,15 @@ module Streamly.Internal.Data.Array.Type
4945
5046 -- *** Stream Folds
5147 , unsafeMakePure
52− , createOf
53− , pinnedCreateOf
54− , unsafeCreateOf
55− , unsafePinnedCreateOf
56− , create
57− , pinnedCreate
58− , createWith
48+ , writeWith
49+ , writeN
50+ , pinnedWriteN
51+ , writeNUnsafe
52+ , pinnedWriteNUnsafe
53+ -- , MA.ArrayUnsafe (..)
54+ , pinnedWriteNAligned
55+ , write
56+ , pinnedWrite
5957
6058 -- *** From containers
6159 , fromListN
@@ -77,8 +75,8 @@ module Streamly.Internal.Data.Array.Type
7775 -- ** Reading
7876
7977 -- *** Indexing
80− , unsafeIndexIO -- XXX unsafeGetIndexIO
81− , getIndexUnsafe -- XXX unsafeGetIndex
78+ , unsafeIndexIO -- XXX rename to getIndexUnsafeIO
79+ , getIndexUnsafe
8280
8381 -- *** To Streams
8482 , read
@@ -125,14 +123,12 @@ module Streamly.Internal.Data.Array.Type
125123
126124 -- *** Compact
127125 -- | Append the arrays in a stream to form a stream of larger arrays.
126+ , compactLE
128127 , fCompactGE
129− , fPinnedCompactGE
130128 , lCompactGE
131− , lPinnedCompactGE
132129 , compactGE
133130
134131 -- ** Deprecated
135− , asPtrUnsafe
136132 , unsafeIndex
137133 , bufferChunks
138134 , flattenArrays
@@ -144,15 +140,6 @@ module Streamly.Internal.Data.Array.Type
144140 , toStreamDRev
145141 , toStream
146142 , toStreamRev
147− , nil
148− , writeWith
149− , writeN
150− , pinnedWriteN
151− , writeNUnsafe
152− , pinnedWriteNUnsafe
153− , pinnedWriteNAligned
154− , write
155− , pinnedWrite
156143 )
157144where
158145
@@ -243,20 +230,15 @@ data Array a =
243230
244231-- | Use an @Array a@ as @Ptr a@.
245232--
246−-- See 'MA.unsafePinnedAsPtr' in the Mutable array module for more details.
233+-- See 'MA.asPtrUnsafe' in the Mutable array module for more details.
247234--
248235-- /Unsafe/
249236--
250237-- /Pre-release/
251238--
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." #-}
257239{-# INLINE asPtrUnsafe #-}
258240asPtrUnsafe :: MonadIO m => Array a -> (Ptr a -> m b) -> m b
259−asPtrUnsafe = unsafePinnedAsPtr
241+asPtrUnsafe arr = MA.asPtrUnsafe (unsafeThaw arr)
260242
261243-------------------------------------------------------------------------------
262244-- Freezing and Thawing
@@ -477,13 +459,12 @@ pinnedChunksOf n str = D.map unsafeFreeze $ MA.pinnedChunksOf n str
477459-- >>> concat = Stream.unfoldMany Array.reader
478460--
479461{-# INLINE_NORMAL concat #-}
480−concat :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
462+concat :: (MonadIO m, Unbox a) => Stream m (Array a) -> Stream m a
481463-- XXX this requires MonadIO whereas the unfoldMany version does not
482−concat = MA.concatWith (pure . unsafeInlineIO) . D.map unsafeThaw
464+concat = MA.concat . D.map unsafeThaw
483465-- concat = D.unfoldMany reader
484466
485467{-# DEPRECATED flattenArrays "Please use \"unfoldMany reader\" instead." #-}
486−{-# INLINE flattenArrays #-}
487468flattenArrays :: forall m a. (MonadIO m, Unbox a)
488469 => D.Stream m (Array a) -> D.Stream m a
489470flattenArrays = concat
@@ -494,14 +475,13 @@ flattenArrays = concat
494475-- >>> concatRev = Stream.unfoldMany Array.readerRev
495476--
496477{-# INLINE_NORMAL concatRev #-}
497−concatRev :: forall m a. (Monad m, Unbox a)
478+concatRev :: forall m a. (MonadIO m, Unbox a)
498479 => D.Stream m (Array a) -> D.Stream m a
499480-- XXX this requires MonadIO whereas the unfoldMany version does not
500−concatRev = MA.concatRevWith (pure . unsafeInlineIO) . D.map unsafeThaw
481+concatRev = MA.concatRev . D.map unsafeThaw
501482-- concatRev = D.unfoldMany readerRev
502483
503484{-# DEPRECATED flattenArraysRev "Please use \"unfoldMany readerRev\" instead." #-}
504−{-# INLINE flattenArraysRev #-}
505485flattenArraysRev :: forall m a. (MonadIO m, Unbox a)
506486 => D.Stream m (Array a) -> D.Stream m a
507487flattenArraysRev = concatRev
@@ -515,28 +495,26 @@ flattenArraysRev = concatRev
515495-- arrays would have no capacity to append, therefore, a copy will be forced
516496-- anyway.
517497
498+-- | Scan @compactLE n@ coalesces adjacent arrays in the input stream
499+-- only if the combined size would be less than or equal to n.
500+{-# INLINE_NORMAL compactLE #-}
501+compactLE :: (MonadIO m, Unbox a)
502+ => Int -> Stream m (Array a) -> Stream m (Array a)
503+compactLE n stream =
504+ D.map unsafeFreeze $ MA.rCompactLE n $ D.map unsafeThaw stream
505+
518506-- | Fold @fCompactGE n@ coalesces adjacent arrays in the input stream
519507-- until the size becomes greater than or equal to n.
520508--
521−-- Generates unpinned arrays irrespective of the pinning status of input
522−-- arrays.
523509{-# INLINE_NORMAL fCompactGE #-}
524510fCompactGE :: (MonadIO m, Unbox a) => Int -> Fold m (Array a) (Array a)
525511fCompactGE n = fmap unsafeFreeze $ Fold.lmap unsafeThaw $ MA.fCompactGE n
526512
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−
533513-- | @compactGE n stream@ coalesces adjacent arrays in the @stream@ until
534514-- the size becomes greater than or equal to @n@.
535515--
536516-- >>> compactGE n = Stream.foldMany (Array.fCompactGE n)
537517--
538−-- Generates unpinned arrays irrespective of the pinning status of input
539−-- arrays.
540518{-# INLINE compactGE #-}
541519compactGE ::
542520 (MonadIO m, Unbox a)
@@ -548,21 +526,12 @@ compactGE n stream =
548526--
549527-- >>> lCompactGE n = Fold.many (Array.fCompactGE n)
550528--
551−-- Generates unpinned arrays irrespective of the pinning status of input
552−-- arrays.
553529{-# INLINE_NORMAL lCompactGE #-}
554530lCompactGE :: (MonadIO m, Unbox a)
555531 => Int -> Fold m (Array a) () -> Fold m (Array a) ()
556532lCompactGE n fld =
557533 Fold.lmap unsafeThaw $ MA.lCompactGE n (Fold.lmap unsafeFreeze fld)
558534
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−
566535-------------------------------------------------------------------------------
567536-- Splitting
568537-------------------------------------------------------------------------------
@@ -757,28 +726,17 @@ toList s = build (\c n -> toListFB c n s)
757726-- Folds
758727-------------------------------------------------------------------------------
759728
760−-- | @createOf n@ folds a maximum of @n@ elements from the input stream to an
729+-- | @writeN n@ folds a maximum of @n@ elements from the input stream to an
761730-- 'Array'.
762731--
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 #-}
732+{-# INLINE_NORMAL writeN #-}
770733writeN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
771−writeN = createOf
734+writeN = fmap unsafeFreeze . MA.writeN
772735
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
777−
778−{-# DEPRECATED pinnedWriteN "Please use pinnedCreateOf instead." #-}
779−{-# INLINE pinnedWriteN #-}
736+-- | Like 'fromListN' but creates a pinned array.
737+{-# INLINE_NORMAL pinnedWriteN #-}
780738pinnedWriteN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
781−pinnedWriteN = pinnedCreateOf
739+pinnedWriteN = fmap unsafeFreeze . MA.pinnedWriteN
782740
783741-- | @pinnedWriteNAligned alignment n@ folds a maximum of @n@ elements from the input
784742-- stream to an 'Array' aligned to the given size.
@@ -786,74 +744,44 @@ pinnedWriteN = pinnedCreateOf
786744-- /Pre-release/
787745--
788746{-# INLINE_NORMAL pinnedWriteNAligned #-}
789−{-# DEPRECATED pinnedWriteNAligned "To be removed." #-}
790747pinnedWriteNAligned :: forall m a. (MonadIO m, Unbox a)
791748 => Int -> Int -> Fold m a (Array a)
792749pinnedWriteNAligned alignSize = fmap unsafeFreeze . MA.pinnedWriteNAligned alignSize
793750
794−-- | Like 'createOf' but does not check the array bounds when writing. The fold
751+-- | Like 'writeN' but does not check the array bounds when writing. The fold
795752-- driver must not call the step function more than 'n' times otherwise it will
796753-- corrupt the memory and crash. This function exists mainly because any
797754-- conditional in the step function blocks fusion causing 10x performance
798755-- slowdown.
799756--
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 #-}
757+{-# INLINE_NORMAL writeNUnsafe #-}
807758writeNUnsafe :: forall m a. (MonadIO m, Unbox a)
808759 => 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
760+writeNUnsafe n = unsafeFreeze <$> MA.writeNUnsafe n
815761
816−{-# DEPRECATED pinnedWriteNUnsafe "Please use unsafePinnedCreateOf instead." #-}
817−{-# INLINE pinnedWriteNUnsafe #-}
762+{-# INLINE_NORMAL pinnedWriteNUnsafe #-}
818763pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a)
819764 => Int -> Fold m a (Array a)
820−pinnedWriteNUnsafe = unsafePinnedCreateOf
765+pinnedWriteNUnsafe n = unsafeFreeze <$> MA.pinnedWriteNUnsafe n
821766
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 #-}
767+{-# INLINE_NORMAL writeWith #-}
830768writeWith :: forall m a. (MonadIO m, Unbox a)
831769 => Int -> Fold m a (Array a)
832−writeWith = createWith
770+-- writeWith n = FL.rmapM spliceArrays $ toArraysOf n
771+writeWith elemCount = unsafeFreeze <$> MA.writeWith elemCount
833772
834773-- | Fold the whole input to a single array.
835774--
836775-- /Caution! Do not use this on infinite streams./
837776--
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." #-}
844777{-# INLINE write #-}
845778write :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
846−write = create
779+write = fmap unsafeFreeze MA.write
847780
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
852−
853−{-# DEPRECATED pinnedWrite "Please use pinnedCreate instead." #-}
781+-- | Like 'write' but creates a pinned array.
854782{-# INLINE pinnedWrite #-}
855783pinnedWrite :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
856−pinnedWrite = pinnedCreate
784+pinnedWrite = fmap unsafeFreeze MA.pinnedWrite
857785
858786-- | Fold "step" has a dependency on "initial", and each step is dependent on
859787-- the previous invocation of step due to state passing, finally extract
@@ -901,19 +829,13 @@ fromPureStream x = unsafePerformIO $ fmap (unsafeFreeze) (MA.fromPureStream x)
901829-- fromPureStream = runIdentity . D.fold (unsafeMakePure write)
902830-- fromPureStream = fromList . runIdentity . D.toList
903831
904−-- XXX This should be monadic.
905−
906832-- | Copy an immutable 'Ptr Word8' sequence into an array.
907833--
908834-- /Unsafe:/ The caller is responsible for safe addressing.
909835--
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.
912836fromPtrN :: Int -> Ptr Word8 -> Array Word8
913837fromPtrN n addr = unsafePerformIO $ fmap unsafeFreeze (MA.fromPtrN n addr)
914838
915−-- XXX This should be monadic.
916−
917839-- | Copy a null terminated immutable 'Addr#' Word8 sequence into an array.
918840--
919841-- /Unsafe:/ The caller is responsible for safe addressing.
@@ -924,15 +846,9 @@ fromPtrN n addr = unsafePerformIO $ fmap unsafeFreeze (MA.fromPtrN n addr)
924846-- >>> Array.toList $ Array.fromByteStr# "\1\2\3\0"#
925847-- [1,2,3]
926848--
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.
929849fromByteStr# :: Addr# -> Array Word8
930850fromByteStr# addr = unsafePerformIO $ fmap unsafeFreeze (MA.fromByteStr# addr)
931851
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.
936852fromByteStr :: Ptr Word8 -> Array Word8
937853fromByteStr (Ptr addr#) = fromByteStr# addr#
938854
@@ -1007,7 +923,6 @@ instance Unbox a => IsList (Array a) where
1007923{-# INLINE byteCmp #-}
1008924byteCmp :: Array a -> Array a -> Ordering
1009925byteCmp arr1 arr2 =
1010− -- unsafePerformIO?
1011926 unsafeInlineIO $! unsafeThaw arr1 `MA.byteCmp` unsafeThaw arr2
1012927
1013928-- | Byte equality of two arrays.
@@ -1029,16 +944,11 @@ MK_EQ_INSTANCE(Char)
1029944MK_EQ_INSTANCE(Word8)
1030945MK_EQ_INSTANCE(Word16)
1031946MK_EQ_INSTANCE(Word32)
1032−
1033−-- XXX The Word64 default instance should be as fast because we are comparing
1034−-- 64-bit at a time.
1035947MK_EQ_INSTANCE(Word64)
1036948MK_EQ_INSTANCE(Int)
1037949MK_EQ_INSTANCE(Int8)
1038950MK_EQ_INSTANCE(Int16)
1039951MK_EQ_INSTANCE(Int32)
1040−
1041−-- XXX The Int64 default instance should be as fast.
1042952MK_EQ_INSTANCE(Int64)
1043953
1044954-- | If the type allows a byte-by-byte comparison this instance can be
@@ -1128,20 +1038,12 @@ instance Foldable Array where
11281038instance Unbox a => Semigroup (Array a) where
11291039 arr1 <> arr2 = unsafePerformIO $ splice arr1 arr2
11301040
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." #-}
11391041nil ::
11401042#ifdef DEVBUILD
11411043 Unbox a =>
11421044#endif
11431045 Array a
1144−nil = empty
1046+nil = Array Unboxed.nil 0 0
11451047
11461048instance Unbox a => Monoid (Array a) where
11471049 mempty = nil
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+3−24
@@ -14,7 +14,6 @@ module Streamly.Internal.Data.MutArray
1414 , sliceIndexerFromLen
1515 , slicerFromLen
1616 , compactLE
17− , pinnedCompactLE
1817 , compactOnByte
1918 , compactOnByteSuffix
2019 -- * Unboxed IORef
@@ -30,7 +29,6 @@ where
3029
3130import Control.Monad.IO.Class (MonadIO(..))
3231import Data.Word (Word8)
33−import Streamly.Internal.Data.MutByteArray.Type (PinnedState(..))
3432import Streamly.Internal.Data.Stream.Type (Stream)
3533import Streamly.Internal.Data.Unbox (Unbox)
3634import Streamly.Internal.Data.Unfold.Type (Unfold(..))
@@ -89,34 +87,15 @@ getSlicesFromLen :: forall m a. (Monad m, Unbox a)
8987 -> Unfold m (MutArray a) (MutArray a)
9088getSlicesFromLen = slicerFromLen
9189
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.
90+-- | Scan @compactLE n@ coalesces adjacent arrays in the input stream
91+-- only if the combined size would be less than or equal to n.
10592{-# INLINE compactLE #-}
10693compactLE :: (MonadIO m, Unbox a) =>
10794 Int -> Stream m (MutArray a) -> Stream m (MutArray a)
10895-- XXX compactLE can be moved to MutArray/Type if we are not using the parser
10996-- to implement it.
110−compactLE = compactLeAs Unpinned
111−-- The parser version turns out to be a little bit slower.
11297-- 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)
98+compactLE = rCompactLE
12099
121100data SplitState s arr
122101 = Initial s
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/Type.hs+323−697
@@ -40,22 +40,22 @@ module Streamly.Internal.Data.MutArray.Type
4040
4141 -- ** Casting
4242 , cast
43− , castUnsafe -- XXX unsafeCast
43+ , castUnsafe
4444 , asBytes
45− , unsafePinnedAsPtr
46− , unsafeAsPtr
45+ , asPtrUnsafe
46+ , asUnpinnedPtrUnsafe
4747
4848 -- ** Construction
49− , empty
49+ , nil
5050
5151 -- *** New
5252 -- | New arrays are always empty arrays with some reserve capacity to
5353 -- extend the length without reallocating.
54− , emptyOf
55− , newArrayWith -- emptyAlignedWith
56− , pinnedEmptyOf
57− , pinnedNewAligned -- XXX not required
58− -- , new -- uninitialized array of specified length
54+ , new
55+ , newArrayWith
56+ , pinnedNew
57+ , pinnedNewBytes
58+ , pinnedNewAligned
5959
6060 -- *** Cloning
6161 , clone
@@ -63,25 +63,27 @@ module Streamly.Internal.Data.MutArray.Type
6363
6464 -- *** Slicing
6565 -- | Get a subarray without copying
66− , getSliceUnsafe -- XXX unsafeGetSlice
66+ , getSliceUnsafe
6767 , getSlice
6868 , splitAt -- XXX should be able to express using getSlice
6969 , breakOn
7070
7171 -- *** Stream Folds
7272 , ArrayUnsafe (..)
73− , unsafeCreateOfWith
74− , unsafeCreateOf
75− , unsafePinnedCreateOf
76− , pinnedCreateOf
77− , createOfWith
78− , createOf
79− , revCreateOf
80−
81− , pinnedCreate
82− , createWith
83− , create
84− -- , revCreate
73+ , writeNWithUnsafe
74+ , writeNWith
75+ , writeNUnsafe
76+ , pinnedWriteNUnsafe
77+ , writeN
78+ , pinnedWriteN
79+ , pinnedWriteNAligned
80+
81+ , writeWith
82+ , write
83+ , pinnedWrite
84+
85+ , writeRevN
86+ -- , writeRev
8587
8688 -- *** From containers
8789 , fromListN
@@ -97,11 +99,11 @@ module Streamly.Internal.Data.MutArray.Type
9799 , fromByteStr#
98100 , fromPtrN
99101 , fromChunksK
100− , fromChunksRealloced -- fromSmallChunks
102+ , fromChunksRealloced
101103
102104 -- ** Random writes
103105 , putIndex
104− , putIndexUnsafe -- XXX unsafePutIndex
106+ , putIndexUnsafe
105107 , putIndices
106108 -- , putFromThenTo
107109 -- , putFrom -- start writing at the given position
@@ -109,7 +111,7 @@ module Streamly.Internal.Data.MutArray.Type
109111 -- , putFromTo
110112 -- , putFromRev
111113 -- , putUptoRev
112− , modifyIndexUnsafe -- XXX unsafeModifyIndex
114+ , modifyIndexUnsafe
113115 , modifyIndex
114116 , modifyIndices
115117 , modify
@@ -120,9 +122,9 @@ module Streamly.Internal.Data.MutArray.Type
120122
121123 -- *** Indexing
122124 , getIndex
123− , getIndexUnsafe -- XXX unsafeGetIndex
125+ , getIndexUnsafe
124126 -- , getFromThenTo
125− , getIndexRev -- getRevIndex?
127+ , getIndexRev
126128 , indexReader
127129 , indexReaderWith
128130
@@ -162,9 +164,9 @@ module Streamly.Internal.Data.MutArray.Type
162164 , blockSize
163165 , arrayChunkBytes
164166 , allocBytesToElemCount
165− , realloc -- this is "resize"
166− , grow
167− , growExp
167+ , realloc
168+ , resize
169+ , resizeExp
168170 , rightSize
169171
170172 -- ** Folding
@@ -193,34 +195,24 @@ module Streamly.Internal.Data.MutArray.Type
193195 , snoc
194196 , snocLinear
195197 , snocMay
196− , snocUnsafe -- XXX unsafeSnoc
198+ , snocUnsafe
197199
198200 -- *** Appending streams
199− , unsafeAppendN
200− , appendN
201− , appendWith
202− , append
201+ , writeAppendNUnsafe
202+ , writeAppendN
203+ , writeAppendWith
204+ , writeAppend
203205
204206 -- *** Appending arrays
205207 , spliceCopy
206208 , spliceWith
207209 , splice
208210 , spliceExp
209− , spliceUnsafe -- XXX unsafeSplice
211+ , spliceUnsafe
210212 -- , putSlice
211213 -- , appendSlice
212214 -- , appendSliceFrom
213215
214− -- ** Serialization using Unbox
215− , pokeAppend
216− , pokeAppendMay
217− , pokeSkipUnsafe -- unsafePokeSkip
218−
219− -- ** Deserialization using Unbox
220− , peekUncons
221− , peekUnconsUnsafe -- unsafePeekUncons
222− , peekSkipUnsafe -- unsafePeekSkip
223−
224216 -- Arrays of arrays
225217 -- We can add dimensionality parameter to the array type to get
226218 -- multidimensional arrays. Multidimensional arrays would just be a
@@ -242,8 +234,6 @@ module Streamly.Internal.Data.MutArray.Type
242234
243235 -- *** Concat
244236 -- | Append the arrays in a stream to form a stream of elements.
245− , concatWith
246− , concatRevWith
247237 , concat
248238 , concatRev
249239
@@ -251,12 +241,9 @@ module Streamly.Internal.Data.MutArray.Type
251241 -- | Append the arrays in a stream to form a stream of larger arrays.
252242 , SpliceState (..)
253243 , pCompactLE
254− , pPinnedCompactLE
255− , compactLeAs
244+ , rCompactLE
256245 , fCompactGE
257− , fPinnedCompactGE
258246 , lCompactGE
259− , lPinnedCompactGE
260247 , compactGE
261248 , compactEQ
262249
@@ -267,7 +254,6 @@ module Streamly.Internal.Data.MutArray.Type
267254 , c_memchr
268255
269256 -- * Deprecated
270− , asPtrUnsafe
271257 , writeChunks
272258 , flattenArrays
273259 , flattenArraysRev
@@ -277,27 +263,6 @@ module Streamly.Internal.Data.MutArray.Type
277263 , cmp
278264 , getIndices
279265 , 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
301266 )
302267where
303268
@@ -479,8 +444,6 @@ isPinned MutArray{..} = Unboxed.isPinned arrContents
479444-- we need more than that. See stg_pinnedNewAlignedByteArrayzh and
480445-- allocatePinned in GHC source.
481446
482−-- XXX Rename to emptyAlignedWith, alignSize should be first arg.
483−
484447-- | @newArrayWith allocator alignment count@ allocates a new array of zero
485448-- length and with a capacity to hold @count@ elements, using @allocator
486449-- size alignment@ as the memory allocator function.
@@ -504,25 +467,12 @@ newArrayWith alloc alignSize count = do
504467 , arrBound = size
505468 }
506469
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." #-}
520470nil ::
521471#ifdef DEVBUILD
522472 Unbox a =>
523473#endif
524474 MutArray a
525−nil = empty
475+nil = MutArray Unboxed.nil 0 0 0
526476
527477{-# INLINE newBytesAs #-}
528478newBytesAs :: MonadIO m =>
@@ -539,13 +489,12 @@ newBytesAs ps bytes = do
539489 , arrBound = bytes
540490 }
541491
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.
492+-- | Allocates a pinned empty array that can hold 'count' items. The memory of
493+-- the array is uninitialized and the allocation is aligned as per the
494+-- 'Unboxed' instance of the type.
545495--
546496-- /Pre-release/
547497{-# INLINE pinnedNewBytes #-}
548−{-# DEPRECATED pinnedNewBytes "Please use pinnedEmptyOf with appropriate calculation" #-}
549498pinnedNewBytes :: MonadIO m =>
550499#ifdef DEVBUILD
551500 Unbox a =>
@@ -570,31 +519,21 @@ newAs ps =
570519 (error "new: alignment is not used in unpinned arrays.")
571520
572521-- 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." #-}
522+--
523+-- | Allocates an empty pinned array that can hold 'count' items. The memory of
524+-- the array is uninitialized and the allocation is aligned as per the 'Unboxed'
525+-- instance of the type.
526+--
582527{-# INLINE pinnedNew #-}
583528pinnedNew :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a)
584−pinnedNew = pinnedEmptyOf
529+pinnedNew = newAs Pinned
585530
586−-- | Allocates an unpinned array of zero length but growable to the specified
587−-- capacity without reallocation.
531+-- | Allocates an empty unpinned array that can hold 'count' items. The memory
532+-- of the array is uninitialized.
588533--
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." #-}
595534{-# INLINE new #-}
596535new :: (MonadIO m, Unbox a) => Int -> m (MutArray a)
597−new = emptyOf
536+new = newAs Unpinned
598537
599538-------------------------------------------------------------------------------
600539-- Random writes
@@ -642,7 +581,7 @@ putIndices arr = FL.foldlM' step (return ())
642581
643582 where
644583
645− step () (i, x) = putIndex i arr x
584+ step () (i, x) = liftIO (putIndex i arr x)
646585
647586-- | Modify a given index of an array using a modifier function.
648587--
@@ -838,19 +777,22 @@ arrayChunkBytes = 1024
838777roundDownTo :: Int -> Int -> Int
839778roundDownTo elemSize size = size - (size `mod` elemSize)
840779
780+-- XXX See if resizing can be implemented by reading the old array as a stream
781+-- and then using writeN to the new array.
782+--
841783-- NOTE: we are passing elemSize explicitly to avoid an Unboxed constraint.
842784-- Since this is not inlined Unboxed consrraint leads to dictionary passing
843785-- which complicates some inspection tests.
844786--
845−{-# NOINLINE reallocExplicitAs #-}
846−reallocExplicitAs :: PinnedState -> Int -> Int -> MutArray a -> IO (MutArray a)
847−reallocExplicitAs ps elemSize newCapacityInBytes MutArray{..} = do
787+{-# NOINLINE reallocExplicit #-}
788+reallocExplicit :: Int -> Int -> MutArray a -> IO (MutArray a)
789+reallocExplicit elemSize newCapacityInBytes MutArray{..} = do
848790 assertM(arrEnd <= arrBound)
849791
850792 -- Allocate new array
851793 let newCapMaxInBytes = roundUpLargeArray newCapacityInBytes
852794 contents <-
853− if ps == Pinned
795+ if Unboxed.isPinned arrContents
854796 then Unboxed.pinnedNew newCapMaxInBytes
855797 else Unboxed.new newCapMaxInBytes
856798 let !(MutByteArray mbarrFrom#) = arrContents
@@ -875,10 +817,6 @@ reallocExplicitAs ps elemSize newCapacityInBytes MutArray{..} = do
875817 , arrBound = newCapInBytes
876818 }
877819
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−
882820-- | @realloc newCapacity array@ reallocates the array to the specified
883821-- capacity in bytes.
884822--
@@ -890,12 +828,7 @@ reallocExplicitAs ps elemSize newCapacityInBytes MutArray{..} = do
890828-- If the original array is pinned, the newly allocated array is also pinned.
891829{-# INLINABLE realloc #-}
892830realloc :: 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
831+realloc bytes arr = liftIO $ reallocExplicit (SIZE_OF(a)) bytes arr
899832
900833-- | @reallocWith label capSizer minIncrBytes array@. The label is used
901834-- in error messages and the capSizer is used to determine the capacity of the
@@ -925,7 +858,7 @@ reallocWith label capSizer minIncrBytes arr = do
925858 , ". Please check the sizing function passed."
926859 ]
927860
928−-- | @grow newCapacity array@ changes the total capacity of the array so that
861+-- | @resize newCapacity array@ changes the total capacity of the array so that
929862-- it is enough to hold the specified number of elements. Nothing is done if
930863-- the specified capacity is less than the length of the array.
931864--
@@ -933,46 +866,34 @@ reallocWith label capSizer minIncrBytes arr = do
933866-- the block size (4K).
934867--
935868-- /Pre-release/
936−{-# INLINE grow #-}
937−grow :: forall m a. (MonadIO m, Unbox a) =>
869+{-# INLINE resize #-}
870+resize :: forall m a. (MonadIO m, Unbox a) =>
938871 Int -> MutArray a -> m (MutArray a)
939−grow nElems arr@MutArray{..} = do
872+resize nElems arr@MutArray{..} = do
940873 let req = SIZE_OF(a) * nElems
941− cap = arrBound - arrStart
942− if req < cap
874+ len = arrEnd - arrStart
875+ if req < len
943876 then return arr
944877 else realloc req arr
945878
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.
879+-- | Like 'resize' but if the byte capacity is more than 'largeObjectThreshold'
880+-- then it is rounded up to the closest power of 2.
954881--
955882-- /Pre-release/
956−{-# INLINE growExp #-}
957−growExp :: forall m a. (MonadIO m, Unbox a) =>
883+{-# INLINE resizeExp #-}
884+resizeExp :: forall m a. (MonadIO m, Unbox a) =>
958885 Int -> MutArray a -> m (MutArray a)
959−growExp nElems arr@MutArray{..} = do
886+resizeExp nElems arr@MutArray{..} = do
960887 let req = roundUpLargeArray (SIZE_OF(a) * nElems)
961888 req1 =
962889 if req > largeObjectThreshold
963890 then roundUpToPower2 req
964891 else req
965− cap = arrBound - arrStart
966− if req1 < cap
892+ len = arrEnd - arrStart
893+ if req1 < len
967894 then return arr
968895 else realloc req1 arr
969896
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−
976897-- | Resize the allocated memory to drop any reserved free space at the end of
977898-- the array and reallocate it to reduce wastage.
978899--
@@ -1037,7 +958,7 @@ snocUnsafe arr@MutArray{..} = snocNewEnd (INDEX_NEXT(arrEnd,a)) arr
1037958{-# INLINE snocMay #-}
1038959snocMay :: forall m a. (MonadIO m, Unbox a) =>
1039960 MutArray a -> a -> m (Maybe (MutArray a))
1040−snocMay arr@MutArray{..} x = do
961+snocMay arr@MutArray{..} x = liftIO $ do
1041962 let newEnd = INDEX_NEXT(arrEnd,a)
1042963 if newEnd <= arrBound
1043964 then Just <$> snocNewEnd newEnd arr x
@@ -1051,7 +972,7 @@ snocWithRealloc :: forall m a. (MonadIO m, Unbox a) =>
1051972 -> a
1052973 -> m (MutArray a)
1053974snocWithRealloc sizer arr x = do
1054− arr1 <- reallocWith "snocWith" sizer (SIZE_OF(a)) arr
975+ arr1 <- liftIO $ reallocWith "snocWith" sizer (SIZE_OF(a)) arr
1055976 snocUnsafe arr1 x
1056977
1057978-- | @snocWith sizer arr elem@ mutates @arr@ to append @elem@. The length of
@@ -1073,7 +994,7 @@ snocWith :: forall m a. (MonadIO m, Unbox a) =>
1073994 -> MutArray a
1074995 -> a
1075996 -> m (MutArray a)
1076−snocWith allocSize arr x = do
997+snocWith allocSize arr x = liftIO $ do
1077998 let newEnd = INDEX_NEXT(arrEnd arr,a)
1078999 if newEnd <= arrBound arr
10791000 then snocNewEnd newEnd arr x
@@ -1117,126 +1038,6 @@ snoc = snocWith f
11171038 then oldSize * 2
11181039 else roundUpToPower2 oldSize * 2
11191040
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−
12401041-------------------------------------------------------------------------------
12411042-- Random reads
12421043-------------------------------------------------------------------------------
@@ -1302,7 +1103,6 @@ indexReaderWith liftio (D.Stream stepi sti) = Unfold step inject
13021103 D.Stop -> return D.Stop
13031104
13041105{-# DEPRECATED getIndicesWith "Please use indexReaderWith instead." #-}
1305−{-# INLINE getIndicesWith #-}
13061106getIndicesWith :: (Monad m, Unbox a) =>
13071107 (forall b. IO b -> m b) -> D.Stream m Int -> Unfold m (MutArray a) a
13081108getIndicesWith = indexReaderWith
@@ -1314,11 +1114,10 @@ getIndicesWith = indexReaderWith
13141114-- /Pre-release/
13151115{-# INLINE indexReader #-}
13161116indexReader :: (MonadIO m, Unbox a) => Stream m Int -> Unfold m (MutArray a) a
1317−indexReader = indexReaderWith liftIO
1117+indexReader = getIndicesWith liftIO
13181118
13191119-- XXX DO NOT REMOVE, change the signature to use Stream instead of unfold
13201120{-# DEPRECATED getIndices "Please use indexReader instead." #-}
1321−{-# INLINE getIndices #-}
13221121getIndices :: (MonadIO m, Unbox a) => Stream m Int -> Unfold m (MutArray a) a
13231122getIndices = indexReader
13241123
@@ -1615,7 +1414,7 @@ chunksOfAs ps n (D.Stream step state) =
16151414--
16161415-- Same as the following but may be more efficient:
16171416--
1618−-- >>> chunksOf n = Stream.foldMany (MutArray.createOf n)
1417+-- >>> chunksOf n = Stream.foldMany (MutArray.writeN n)
16191418--
16201419-- /Pre-release/
16211420{-# INLINE_NORMAL chunksOf #-}
@@ -1624,14 +1423,14 @@ chunksOf :: forall m a. (MonadIO m, Unbox a)
16241423-- XXX the idiomatic implementation leads to large regression in the D.reverse'
16251424-- benchmark. It seems it has difficulty producing optimized code when
16261425-- converting to StreamK. Investigate GHC optimizations.
1627−-- chunksOf n = D.foldMany (createOf n)
1426+-- chunksOf n = D.foldMany (writeN n)
16281427chunksOf = chunksOfAs Unpinned
16291428
16301429-- | Like 'chunksOf' but creates pinned arrays.
16311430{-# INLINE_NORMAL pinnedChunksOf #-}
16321431pinnedChunksOf :: forall m a. (MonadIO m, Unbox a)
16331432 => Int -> D.Stream m a -> D.Stream m (MutArray a)
1634−-- pinnedChunksOf n = D.foldMany (pinnedCreateOf n)
1433+-- pinnedChunksOf n = D.foldMany (pinnedWriteN n)
16351434pinnedChunksOf = chunksOfAs Pinned
16361435
16371436-- | When we are buffering a stream of unknown size into an array we do not
@@ -1664,10 +1463,16 @@ data FlattenState s contents a =
16641463 OuterLoop s
16651464 | InnerLoop s contents !Int !Int
16661465
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)
1466+-- | Use the "reader" unfold instead.
1467+--
1468+-- @concat = unfoldMany reader@
1469+--
1470+-- We can try this if there are any fusion issues in the unfold.
1471+--
1472+{-# INLINE_NORMAL concat #-}
1473+concat :: forall m a. (MonadIO m, Unbox a)
1474+ => D.Stream m (MutArray a) -> D.Stream m a
1475+concat (D.Stream step state) = D.Stream step' (OuterLoop state)
16711476
16721477 where
16731478
@@ -1684,30 +1489,24 @@ concatWith liftio (D.Stream step state) = D.Stream step' (OuterLoop state)
16841489 return $ D.Skip $ OuterLoop st
16851490
16861491 step' _ (InnerLoop st contents p end) = do
1687− x <- liftio $ peekAt p contents
1492+ x <- liftIO $ peekAt p contents
16881493 return $ D.Yield x (InnerLoop st contents (INDEX_NEXT(p,a)) end)
16891494
1690−-- | Use the "reader" unfold instead.
1691−--
1692−-- @concat = unfoldMany reader@
1693−--
1694−-- We can try this if there are any fusion issues in the unfold.
1695−--
1696−{-# INLINE_NORMAL concat #-}
1697−concat :: forall m a. (MonadIO m, Unbox a)
1698− => D.Stream m (MutArray a) -> D.Stream m a
1699−concat = concatWith liftIO
1700−
17011495{-# DEPRECATED flattenArrays "Please use \"unfoldMany reader\" instead." #-}
1702−{-# INLINE flattenArrays #-}
17031496flattenArrays :: forall m a. (MonadIO m, Unbox a)
17041497 => D.Stream m (MutArray a) -> D.Stream m a
17051498flattenArrays = concat
17061499
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)
1500+-- | Use the "readerRev" unfold instead.
1501+--
1502+-- @concat = unfoldMany readerRev@
1503+--
1504+-- We can try this if there are any fusion issues in the unfold.
1505+--
1506+{-# INLINE_NORMAL concatRev #-}
1507+concatRev :: forall m a. (MonadIO m, Unbox a)
1508+ => D.Stream m (MutArray a) -> D.Stream m a
1509+concatRev (D.Stream step state) = D.Stream step' (OuterLoop state)
17111510
17121511 where
17131512
@@ -1725,23 +1524,11 @@ concatRevWith liftio (D.Stream step state) = D.Stream step' (OuterLoop state)
17251524 return $ D.Skip $ OuterLoop st
17261525
17271526 step' _ (InnerLoop st contents p start) = do
1728− x <- liftio $ peekAt p contents
1527+ x <- liftIO $ peekAt p contents
17291528 let cur = INDEX_PREV(p,a)
17301529 return $ D.Yield x (InnerLoop st contents cur start)
17311530
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−
17431531{-# DEPRECATED flattenArraysRev "Please use \"unfoldMany readerRev\" instead." #-}
1744−{-# INLINE flattenArraysRev #-}
17451532flattenArraysRev :: forall m a. (MonadIO m, Unbox a)
17461533 => D.Stream m (MutArray a) -> D.Stream m a
17471534flattenArraysRev = concatRev
@@ -1973,7 +1760,7 @@ foldr f z arr = D.foldr f z $ read arr
19731760
19741761-- XXX Keep the bound intact to not lose any free space? Perf impact?
19751762
1976−-- | @unsafeAppendN n arr@ appends up to @n@ input items to the supplied
1763+-- | @writeAppendNUnsafe n arr@ appends up to @n@ input items to the supplied
19771764-- array.
19781765--
19791766-- Unsafe: Do not drive the fold beyond @n@ elements, it will lead to memory
@@ -1982,12 +1769,13 @@ foldr f z arr = D.foldr f z $ read arr
19821769-- Any free space left in the array after appending @n@ elements is lost.
19831770--
19841771-- /Internal/
1985−{-# INLINE_NORMAL unsafeAppendN #-}
1986−unsafeAppendN :: forall m a. (MonadIO m, Unbox a) =>
1772+{-# INLINE_NORMAL writeAppendNUnsafe #-}
1773+writeAppendNUnsafe :: forall m a. (MonadIO m, Unbox a) =>
19871774 Int
19881775 -> m (MutArray a)
19891776 -> Fold m a (MutArray a)
1990−unsafeAppendN n action = fmap fromArrayUnsafe $ FL.foldlM' step initial
1777+writeAppendNUnsafe n action =
1778+ fmap fromArrayUnsafe $ FL.foldlM' step initial
19911779
19921780 where
19931781
@@ -2000,7 +1788,7 @@ unsafeAppendN n action = fmap fromArrayUnsafe $ FL.foldlM' step initial
20001788 -- otherwise we lose that space.
20011789 arr1 <-
20021790 if free < needed
2003− then noinline reallocWith "unsafeAppendN" (+ needed) needed arr
1791+ then noinline reallocWith "writeAppendNUnsafeWith" (+ needed) needed arr
20041792 else return arr
20051793 return $ toArrayUnsafe arr1
20061794
@@ -2008,51 +1796,30 @@ unsafeAppendN n action = fmap fromArrayUnsafe $ FL.foldlM' step initial
20081796 liftIO $ pokeAt end contents x
20091797 return $ ArrayUnsafe contents start (INDEX_NEXT(end,a))
20101798
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−
20191799-- | Append @n@ elements to an existing array. Any free space left in the array
20201800-- after appending @n@ elements is lost.
20211801--
2022−-- >>> appendN n initial = Fold.take n (MutArray.unsafeAppendN n initial)
1802+-- >>> writeAppendN n initial = Fold.take n (MutArray.writeAppendNUnsafe n initial)
20231803--
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 #-}
1804+{-# INLINE_NORMAL writeAppendN #-}
20321805writeAppendN :: forall m a. (MonadIO m, Unbox a) =>
20331806 Int -> m (MutArray a) -> Fold m a (MutArray a)
2034−writeAppendN = appendN
1807+writeAppendN n initial = FL.take n (writeAppendNUnsafe n initial)
20351808
2036−-- | @appendWith realloc action@ mutates the array generated by @action@ to
1809+-- | @writeAppendWith realloc action@ mutates the array generated by @action@ to
20371810-- append the input stream. If there is no reserved space available in the
20381811-- array it is reallocated to a size in bytes determined by @realloc oldSize@,
20391812-- where @oldSize@ is the current size of the array in bytes.
20401813--
20411814-- Note that the returned array may be a mutated version of original array.
20421815--
2043−-- >>> appendWith sizer = Fold.foldlM' (MutArray.snocWith sizer)
1816+-- >>> writeAppendWith sizer = Fold.foldlM' (MutArray.snocWith sizer)
20441817--
20451818-- /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." #-}
20521819{-# INLINE writeAppendWith #-}
20531820writeAppendWith :: forall m a. (MonadIO m, Unbox a) =>
20541821 (Int -> Int) -> m (MutArray a) -> Fold m a (MutArray a)
2055−writeAppendWith = appendWith
1822+writeAppendWith sizer = FL.foldlM' (snocWith sizer)
20561823
20571824-- | @append action@ mutates the array generated by @action@ to append the
20581825-- input stream. If there is no reserved space available in the array it is
@@ -2060,33 +1827,26 @@ writeAppendWith = appendWith
20601827--
20611828-- Note that the returned array may be a mutated version of original array.
20621829--
2063−-- >>> append = MutArray.appendWith (* 2)
1830+-- >>> writeAppend = MutArray.writeAppendWith (* 2)
20641831--
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." #-}
20721832{-# INLINE writeAppend #-}
20731833writeAppend :: forall m a. (MonadIO m, Unbox a) =>
20741834 m (MutArray a) -> Fold m a (MutArray a)
2075−writeAppend = append
1835+writeAppend = writeAppendWith (* 2)
20761836
20771837-- XXX We can carry bound as well in the state to make sure we do not lose the
20781838-- remaining capacity. Need to check perf impact.
20791839--
2080−-- | Like 'unsafeCreateOf' but takes a new array allocator @alloc size@
2081−-- function as argument.
1840+-- | Like 'writeNUnsafe' but takes a new array allocator @alloc size@ function
1841+-- as argument.
20821842--
2083−-- >>> unsafeCreateOfWith alloc n = MutArray.unsafeAppendN (alloc n) n
1843+-- >>> writeNWithUnsafe alloc n = MutArray.writeAppendNUnsafe (alloc n) n
20841844--
20851845-- /Pre-release/
2086−{-# INLINE_NORMAL unsafeCreateOfWith #-}
2087−unsafeCreateOfWith :: forall m a. (MonadIO m, Unbox a)
1846+{-# INLINE_NORMAL writeNWithUnsafe #-}
1847+writeNWithUnsafe :: forall m a. (MonadIO m, Unbox a)
20881848 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
2089−unsafeCreateOfWith alloc n = fromArrayUnsafe <$> FL.foldlM' step initial
1849+writeNWithUnsafe alloc n = fromArrayUnsafe <$> FL.foldlM' step initial
20901850
20911851 where
20921852
@@ -2097,64 +1857,40 @@ unsafeCreateOfWith alloc n = fromArrayUnsafe <$> FL.foldlM' step initial
20971857 return
20981858 $ ArrayUnsafe contents start (INDEX_NEXT(end,a))
20991859
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−
21061860{-# INLINE_NORMAL writeNUnsafeAs #-}
21071861writeNUnsafeAs :: forall m a. (MonadIO m, Unbox a)
21081862 => PinnedState -> Int -> Fold m a (MutArray a)
2109−writeNUnsafeAs ps = unsafeCreateOfWith (newAs ps)
1863+writeNUnsafeAs ps = writeNWithUnsafe (newAs ps)
21101864
2111−-- | Like 'createOf' but does not check the array bounds when writing. The fold
1865+-- | Like 'writeN' but does not check the array bounds when writing. The fold
21121866-- driver must not call the step function more than 'n' times otherwise it will
21131867-- corrupt the memory and crash. This function exists mainly because any
21141868-- conditional in the step function blocks fusion causing 10x performance
21151869-- slowdown.
21161870--
2117−-- >>> unsafeCreateOf = MutArray.unsafeCreateOfWith MutArray.emptyOf
1871+-- >>> writeNUnsafe = MutArray.writeNWithUnsafe MutArray.new
21181872--
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 #-}
1873+{-# INLINE_NORMAL writeNUnsafe #-}
21261874writeNUnsafe :: forall m a. (MonadIO m, Unbox a)
21271875 => Int -> Fold m a (MutArray a)
2128−writeNUnsafe = unsafeCreateOf
1876+writeNUnsafe = writeNUnsafeAs Unpinned
21291877
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
2135−
2136−{-# DEPRECATED pinnedWriteNUnsafe "Please use unsafePinnedCreateOf instead." #-}
2137−{-# INLINE pinnedWriteNUnsafe #-}
1878+-- | Like 'writeNUnsafe' but creates a pinned array.
1879+{-# INLINE_NORMAL pinnedWriteNUnsafe #-}
21381880pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a)
21391881 => Int -> Fold m a (MutArray a)
2140−pinnedWriteNUnsafe = unsafePinnedCreateOf
1882+pinnedWriteNUnsafe = writeNUnsafeAs Pinned
21411883
2142−-- | @createOfWith alloc n@ folds a maximum of @n@ elements into an array
1884+-- | @writeNWith alloc n@ folds a maximum of @n@ elements into an array
21431885-- allocated using the @alloc@ function.
21441886--
2145−-- >>> createOfWith alloc n = Fold.take n (MutArray.unsafeCreateOfWith alloc n)
2146−-- >>> createOfWith alloc n = MutArray.appendN (alloc n) n
1887+-- >>> writeNWith alloc n = Fold.take n (MutArray.writeNWithUnsafe alloc n)
1888+-- >>> writeNWith alloc n = MutArray.writeAppendN (alloc n) n
21471889--
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 #-}
1890+{-# INLINE_NORMAL writeNWith #-}
21551891writeNWith :: forall m a. (MonadIO m, Unbox a)
21561892 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
2157−writeNWith = createOfWith
1893+writeNWith alloc n = FL.take n (writeNWithUnsafe alloc n)
21581894
21591895{-# INLINE_NORMAL writeNAs #-}
21601896writeNAs ::
@@ -2162,42 +1898,28 @@ writeNAs ::
21621898 => PinnedState
21631899 -> Int
21641900 -> Fold m a (MutArray a)
2165−writeNAs ps = createOfWith (newAs ps)
1901+writeNAs ps = writeNWith (newAs ps)
21661902
2167−-- | @createOf n@ folds a maximum of @n@ elements from the input stream to an
1903+-- | @writeN n@ folds a maximum of @n@ elements from the input stream to an
21681904-- 'MutArray'.
21691905--
2170−-- >>> createOf = MutArray.createOfWith MutArray.new
2171−-- >>> createOf n = Fold.take n (MutArray.unsafeCreateOf n)
2172−-- >>> createOf n = MutArray.appendN n (MutArray.emptyOf n)
1906+-- >>> writeN = MutArray.writeNWith MutArray.new
1907+-- >>> writeN n = Fold.take n (MutArray.writeNUnsafe n)
1908+-- >>> writeN n = MutArray.writeAppendN n (MutArray.new n)
21731909--
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 #-}
1910+{-# INLINE_NORMAL writeN #-}
21811911writeN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
2182−writeN = createOf
1912+writeN = writeNAs Unpinned
21831913
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 #-}
1914+-- | Like 'writeN' but creates a pinned array.
1915+{-# INLINE_NORMAL pinnedWriteN #-}
21941916pinnedWriteN ::
21951917 forall m a. (MonadIO m, Unbox a)
21961918 => Int
21971919 -> Fold m a (MutArray a)
2198−pinnedWriteN = pinnedCreateOf
1920+pinnedWriteN = writeNAs Pinned
21991921
2200−-- | Like unsafeCreateOfWith but writes the array in reverse order.
1922+-- | Like writeNWithUnsafe but writes the array in reverse order.
22011923--
22021924-- /Internal/
22031925{-# INLINE_NORMAL writeRevNWithUnsafe #-}
@@ -2218,7 +1940,7 @@ writeRevNWithUnsafe alloc n = fromArrayUnsafe <$> FL.foldlM' step initial
22181940 return
22191941 $ ArrayUnsafe contents ptr end
22201942
2221−-- | Like createOfWith but writes the array in reverse order.
1943+-- | Like writeNWith but writes the array in reverse order.
22221944--
22231945-- /Internal/
22241946{-# INLINE_NORMAL writeRevNWith #-}
@@ -2226,36 +1948,31 @@ writeRevNWith :: forall m a. (MonadIO m, Unbox a)
22261948 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
22271949writeRevNWith alloc n = FL.take n (writeRevNWithUnsafe alloc n)
22281950
2229−-- | Like 'createOf' but writes the array in reverse order.
1951+-- | Like writeN but writes the array in reverse order.
22301952--
22311953-- /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 #-}
1954+{-# INLINE_NORMAL writeRevN #-}
22381955writeRevN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
2239−writeRevN = revCreateOf
1956+writeRevN = writeRevNWith new
22401957
22411958-- | @pinnedWriteNAligned align n@ folds a maximum of @n@ elements from the
22421959-- input stream to a 'MutArray' aligned to the given size.
22431960--
2244−-- >>> pinnedWriteNAligned align = MutArray.createOfWith (MutArray.pinnedNewAligned align)
2245−-- >>> pinnedWriteNAligned align n = MutArray.appendN n (MutArray.pinnedNewAligned align n)
1961+-- >>> pinnedWriteNAligned align = MutArray.writeNWith (MutArray.pinnedNewAligned align)
1962+-- >>> pinnedWriteNAligned align n = MutArray.writeAppendN n (MutArray.pinnedNewAligned align n)
22461963--
22471964-- /Pre-release/
22481965--
22491966{-# INLINE_NORMAL pinnedWriteNAligned #-}
22501967pinnedWriteNAligned :: forall m a. (MonadIO m, Unbox a)
22511968 => Int -> Int -> Fold m a (MutArray a)
2252−pinnedWriteNAligned align = createOfWith (pinnedNewAligned align)
1969+pinnedWriteNAligned align = writeNWith (pinnedNewAligned align)
22531970
22541971-- XXX Buffer to a list instead?
22551972
22561973-- | Buffer a stream into a stream of arrays.
22571974--
2258−-- >>> buildChunks n = Fold.many (MutArray.createOf n) Fold.toStreamK
1975+-- >>> buildChunks n = Fold.many (MutArray.writeN n) Fold.toStreamK
22591976--
22601977-- Breaking an array into an array stream can be useful to consume a large
22611978-- array sequentially such that memory of the array is released incrementatlly.
@@ -2267,10 +1984,9 @@ pinnedWriteNAligned align = createOfWith (pinnedNewAligned align)
22671984{-# INLINE_NORMAL buildChunks #-}
22681985buildChunks :: (MonadIO m, Unbox a) =>
22691986 Int -> Fold m a (StreamK n (MutArray a))
2270−buildChunks n = FL.many (createOf n) FL.toStreamK
1987+buildChunks n = FL.many (writeN n) FL.toStreamK
22711988
22721989{-# DEPRECATED writeChunks "Please use buildChunks instead." #-}
2273−{-# INLINE writeChunks #-}
22741990writeChunks :: (MonadIO m, Unbox a) =>
22751991 Int -> Fold m a (StreamK n (MutArray a))
22761992writeChunks = buildChunks
@@ -2278,29 +1994,29 @@ writeChunks = buildChunks
22781994{-# INLINE_NORMAL writeWithAs #-}
22791995writeWithAs :: forall m a. (MonadIO m, Unbox a)
22801996 => PinnedState -> Int -> Fold m a (MutArray a)
2281−-- writeWithAs ps n = FL.rmapM rightSize $ appendWith (* 2) (newAs ps n)
1997+-- writeWithAs ps n = FL.rmapM rightSize $ writeAppendWith (* 2) (newAs ps n)
22821998writeWithAs ps elemCount =
22831999 FL.rmapM extract $ FL.foldlM' step initial
22842000
22852001 where
22862002
22872003 initial = do
2288− when (elemCount < 0) $ error "createWith: elemCount is negative"
2289− newAs ps elemCount
2004+ when (elemCount < 0) $ error "writeWith: elemCount is negative"
2005+ liftIO $ newAs ps elemCount
22902006
22912007 step arr@(MutArray _ start end bound) x
22922008 | INDEX_NEXT(end,a) > bound = do
22932009 let oldSize = end - start
22942010 newSize = max (oldSize * 2) 1
2295− arr1 <- liftIO $ reallocExplicitAs ps (SIZE_OF(a)) newSize arr
2011+ arr1 <- liftIO $ reallocExplicit (SIZE_OF(a)) newSize arr
22962012 snocUnsafe arr1 x
22972013 step arr x = snocUnsafe arr x
22982014
22992015 extract = liftIO . rightSize
23002016
2301−-- XXX Compare createWith with fromStreamD which uses an array of streams
2017+-- XXX Compare writeWith with fromStreamD which uses an array of streams
23022018-- implementation. We can write this using buildChunks above if that is faster.
2303−-- If createWith is faster then we should use that to implement
2019+-- If writeWith is faster then we should use that to implement
23042020-- fromStreamD.
23052021--
23062022-- XXX The realloc based implementation needs to make one extra copy if we use
@@ -2315,56 +2031,39 @@ writeWithAs ps elemCount =
23152031-- XXX check if GHC's memory allocator is efficient enough. We can try the C
23162032-- malloc to compare against.
23172033
2318−-- | @createWith minCount@ folds the whole input to a single array. The array
2034+-- | @writeWith minCount@ folds the whole input to a single array. The array
23192035-- starts at a size big enough to hold minCount elements, the size is doubled
23202036-- every time the array needs to be grown.
23212037--
23222038-- /Caution! Do not use this on infinite streams./
23232039--
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)
2040+-- >>> f n = MutArray.writeAppendWith (* 2) (MutArray.new n)
2041+-- >>> writeWith n = Fold.rmapM MutArray.rightSize (f n)
2042+-- >>> writeWith n = Fold.rmapM MutArray.fromChunksK (MutArray.buildChunks n)
23272043--
23282044-- /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 #-}
2045+{-# INLINE_NORMAL writeWith #-}
23372046writeWith :: forall m a. (MonadIO m, Unbox a)
23382047 => Int -> Fold m a (MutArray a)
2339−writeWith = createWith
2048+-- writeWith n = FL.rmapM rightSize $ writeAppendWith (* 2) (new n)
2049+writeWith = writeWithAs Unpinned
23402050
23412051-- | Fold the whole input to a single array.
23422052--
2343−-- Same as 'createWith' using an initial array size of 'arrayChunkBytes' bytes
2053+-- Same as 'writeWith' using an initial array size of 'arrayChunkBytes' bytes
23442054-- rounded up to the element size.
23452055--
23462056-- /Caution! Do not use this on infinite streams./
23472057--
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." #-}
23542058{-# INLINE write #-}
23552059write :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
2356−write = create
2357−
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)
2060+write = writeWith (allocBytesToElemCount (undefined :: a) arrayChunkBytes)
23632061
2364−{-# DEPRECATED pinnedWrite "Please use pinnedCreate instead." #-}
2062+-- | Like 'write' but creates a pinned array.
23652063{-# INLINE pinnedWrite #-}
23662064pinnedWrite :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
2367−pinnedWrite = pinnedCreate
2065+pinnedWrite =
2066+ writeWithAs Pinned (allocBytesToElemCount (undefined :: a) arrayChunkBytes)
23682067
23692068-------------------------------------------------------------------------------
23702069-- construct from streams, known size
@@ -2374,7 +2073,7 @@ pinnedWrite = pinnedCreate
23742073fromStreamDNAs :: forall m a. (MonadIO m, Unbox a)
23752074 => PinnedState -> Int -> D.Stream m a -> m (MutArray a)
23762075fromStreamDNAs ps limit str = do
2377− (arr :: MutArray a) <- newAs ps limit
2076+ (arr :: MutArray a) <- liftIO $ newAs ps limit
23782077 end <- D.foldlM' (fwrite (arrContents arr)) (return $ arrEnd arr) $ D.take limit str
23792078 return $ arr {arrEnd = end}
23802079
@@ -2384,18 +2083,17 @@ fromStreamDNAs ps limit str = do
23842083 liftIO $ pokeAt ptr arrContents x
23852084 return $ INDEX_NEXT(ptr,a)
23862085
2387−-- | Use the 'createOf' fold instead.
2086+-- | Use the 'writeN' fold instead.
23882087--
2389−-- >>> fromStreamN n = Stream.fold (MutArray.createOf n)
2088+-- >>> fromStreamN n = Stream.fold (MutArray.writeN n)
23902089--
23912090{-# INLINE_NORMAL fromStreamN #-}
23922091fromStreamN :: forall m a. (MonadIO m, Unbox a)
23932092 => Int -> D.Stream m a -> m (MutArray a)
2394−-- fromStreamDN n = D.fold (createOf n)
2093+-- fromStreamDN n = D.fold (writeN n)
23952094fromStreamN = fromStreamDNAs Unpinned
23962095
23972096{-# DEPRECATED fromStreamDN "Please use fromStreamN instead." #-}
2398−{-# INLINE fromStreamDN #-}
23992097fromStreamDN :: forall m a. (MonadIO m, Unbox a)
24002098 => Int -> D.Stream m a -> m (MutArray a)
24012099fromStreamDN = fromStreamN
@@ -2418,20 +2116,20 @@ pinnedFromListN n xs = fromStreamDNAs Pinned n $ D.fromList xs
24182116-- /Pre-release/
24192117{-# INLINE fromListRevN #-}
24202118fromListRevN :: (MonadIO m, Unbox a) => Int -> [a] -> m (MutArray a)
2421−fromListRevN n xs = D.fold (revCreateOf n) $ D.fromList xs
2119+fromListRevN n xs = D.fold (writeRevN n) $ D.fromList xs
24222120
24232121-- | Convert a pure stream in Identity monad to a mutable array.
24242122{-# INLINABLE fromPureStreamN #-}
24252123fromPureStreamN :: (MonadIO m, Unbox a) =>
24262124 Int -> Stream Identity a -> m (MutArray a)
24272125fromPureStreamN n xs =
2428− D.fold (createOf n) $ D.morphInner (return . runIdentity) xs
2126+ liftIO $ D.fold (writeN n) $ D.morphInner (return . runIdentity) xs
24292127
24302128-- | Convert a pure stream in Identity monad to a mutable array.
24312129{-# INLINABLE fromPureStream #-}
24322130fromPureStream :: (MonadIO m, Unbox a) => Stream Identity a -> m (MutArray a)
24332131fromPureStream xs =
2434− D.fold create $ D.morphInner (return . runIdentity) xs
2132+ liftIO $ D.fold write $ D.morphInner (return . runIdentity) xs
24352133
24362134{-# INLINABLE fromPtrN #-}
24372135fromPtrN :: MonadIO m => Int -> Ptr Word8 -> m (MutArray Word8)
@@ -2440,7 +2138,7 @@ fromPtrN len addr = do
24402138 -- XXX We can implement a stream copy in a similar way by streaming Word64
24412139 -- first and then remaining Word8.
24422140 arr <- new len
2443− _ <- unsafeAsPtr arr
2141+ _ <- asUnpinnedPtrUnsafe arr
24442142 (\ptr -> liftIO $ c_memcpy ptr addr (fromIntegral len))
24452143 return (arr {arrEnd = len})
24462144
@@ -2456,7 +2154,7 @@ fromByteStr# addr = do
24562154 len <- liftIO $ c_strlen (Ptr addr)
24572155 let lenInt = fromIntegral len
24582156 arr <- new lenInt
2459− _ <- unsafeAsPtr arr (\ptr -> liftIO $ c_memcpy ptr (Ptr addr) len)
2157+ _ <- asUnpinnedPtrUnsafe arr (\ptr -> liftIO $ c_memcpy ptr (Ptr addr) len)
24602158 return (arr {arrEnd = lenInt})
24612159
24622160-------------------------------------------------------------------------------
@@ -2477,7 +2175,7 @@ fromChunksRealloced s = do
24772175 arr <- D.foldlM' spliceExp (pure a) strm
24782176 -- Reallocation is exponential so there may be 50% empty space in
24792177 -- worst case. One more reallocation to reclaim the space.
2480− rightSize arr
2178+ liftIO $ rightSize arr
24812179 Nothing -> pure nil
24822180
24832181-------------------------------------------------------------------------------
@@ -2515,7 +2213,6 @@ fromChunksK :: (Unbox a, MonadIO m) =>
25152213fromChunksK = fromChunkskAs Unpinned
25162214
25172215{-# DEPRECATED fromArrayStreamK "Please use fromChunksK instead." #-}
2518−{-# INLINE fromArrayStreamK #-}
25192216fromArrayStreamK :: (Unbox a, MonadIO m) =>
25202217 StreamK m (MutArray a) -> m (MutArray a)
25212218fromArrayStreamK = fromChunksK
@@ -2527,7 +2224,7 @@ fromStreamDAs ps m =
25272224 arrayStreamKFromStreamDAs Unpinned m >>= fromChunkskAs ps
25282225
25292226-- | 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
2227+-- single array from a stream of unknown size. 'writeN' is at least twice
25312228-- as efficient when the size is already known.
25322229--
25332230-- Note that if the input stream is too large memory allocation for the array
@@ -2539,19 +2236,19 @@ fromStreamDAs ps m =
25392236fromStream :: (MonadIO m, Unbox a) => Stream m a -> m (MutArray a)
25402237fromStream = fromStreamDAs Unpinned
25412238
2542−-- fromStream (Stream m) = P.fold create m
2239+-- fromStream (Stream m) = P.fold write m
25432240-- CAUTION: a very large number (millions) of arrays can degrade performance
25442241-- due to GC overhead because we need to buffer the arrays before we flatten
25452242-- all the arrays.
25462243--
2547−-- XXX Compare if this is faster or "fold create".
2244+-- XXX Compare if this is faster or "fold write".
25482245--
25492246-- | We could take the approach of doubling the memory allocation on each
25502247-- overflow. This would result in more or less the same amount of copying as in
25512248-- the chunking approach. However, if we have to shrink in the end then it may
25522249-- result in an extra copy of the entire data.
25532250--
2554−-- >>> fromStreamD = StreamD.fold MutArray.create
2251+-- >>> fromStreamD = StreamD.fold MutArray.write
25552252--
25562253{-# INLINE fromStreamD #-}
25572254{-# DEPRECATED fromStreamD "Please use fromStream instead." #-}
@@ -2581,10 +2278,6 @@ fromListRev xs = fromListRevN (Prelude.length xs) xs
25812278-- Cloning
25822279-------------------------------------------------------------------------------
25832280
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−
25882281{-# INLINE cloneAs #-}
25892282cloneAs ::
25902283 ( MonadIO m
@@ -2594,7 +2287,7 @@ cloneAs ::
25942287 )
25952288 => PinnedState -> MutArray a -> m (MutArray a)
25962289cloneAs ps src =
2597− do
2290+ liftIO $ do
25982291 let startSrc = arrStart src
25992292 srcLen = arrEnd src - startSrc
26002293 newArrContents <-
@@ -2633,16 +2326,17 @@ spliceCopy :: forall m a. MonadIO m =>
26332326 Unbox a =>
26342327#endif
26352328 MutArray a -> MutArray a -> m (MutArray a)
2636−spliceCopy arr1 arr2 = do
2329+spliceCopy arr1 arr2 = liftIO $ do
26372330 let start1 = arrStart arr1
26382331 start2 = arrStart arr2
26392332 len1 = arrEnd arr1 - start1
26402333 len2 = arrEnd arr2 - start2
2641− let len = len1 + len2
2334+ let newLen = len1 + len2
26422335 newArrContents <-
26432336 if Unboxed.isPinned (arrContents arr1)
2644− then liftIO $ Unboxed.pinnedNew len
2645− else liftIO $ Unboxed.new len
2337+ then Unboxed.pinnedNew newLen
2338+ else Unboxed.new newLen
2339+ let len = len1 + len2
26462340 putSliceUnsafe (arrContents arr1) start1 newArrContents 0 len1
26472341 putSliceUnsafe (arrContents arr2) start2 newArrContents len1 len2
26482342 return $ MutArray newArrContents 0 len len
@@ -2654,7 +2348,7 @@ spliceCopy arr1 arr2 = do
26542348spliceUnsafe :: MonadIO m =>
26552349 MutArray a -> MutArray a -> m (MutArray a)
26562350spliceUnsafe dst src =
2657− do
2351+ liftIO $ do
26582352 let startSrc = arrStart src
26592353 srcLen = arrEnd src - startSrc
26602354 endDst = arrEnd dst
@@ -2676,7 +2370,7 @@ spliceWith :: forall m a. (MonadIO m, Unbox a) =>
26762370 (Int -> Int -> Int) -> MutArray a -> MutArray a -> m (MutArray a)
26772371spliceWith sizer dst@(MutArray _ start end bound) src = do
26782372{-
2679− let f = appendWith (`sizer` byteLength src) (return dst)
2373+ let f = writeAppendWith (`sizer` byteLength src) (return dst)
26802374 in D.fold f (toStreamD src)
26812375-}
26822376 assert (end <= bound) (return ())
@@ -2692,7 +2386,7 @@ spliceWith sizer dst@(MutArray _ start end bound) src = do
26922386 $ "splice: newSize is less than the total size "
26932387 ++ "of arrays being appended. Please check the "
26942388 ++ "sizer function passed."
2695− realloc newSizeInBytes dst
2389+ liftIO $ realloc newSizeInBytes dst
26962390 else return dst
26972391 spliceUnsafe dst1 src
26982392
@@ -2744,7 +2438,7 @@ splitOn predicate arr =
27442438{-# INLINE breakOn #-}
27452439breakOn :: MonadIO m
27462440 => Word8 -> MutArray Word8 -> m (MutArray Word8, Maybe (MutArray Word8))
2747−breakOn sep arr@MutArray{..} = unsafeAsPtr arr $ \p -> liftIO $ do
2441+breakOn sep arr@MutArray{..} = asUnpinnedPtrUnsafe arr $ \p -> liftIO $ do
27482442 -- XXX We do not need memchr here, we can use a Haskell equivalent.
27492443 -- Need efficient stream based primitives that work on Word64.
27502444 loc <- c_memchr p sep (fromIntegral $ byteLength arr)
@@ -2767,41 +2461,33 @@ breakOn sep arr@MutArray{..} = unsafeAsPtr arr $ \p -> liftIO $ do
27672461 }
27682462 )
27692463
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−
27922464-- | Create two slices of an array without copying the original array. The
27932465-- specified index @i@ is the first index of the second slice.
27942466--
27952467{-# INLINE splitAt #-}
27962468splitAt :: forall a. Unbox a => Int -> MutArray a -> (MutArray a, MutArray a)
2797−splitAt i arr =
2469+splitAt i arr@MutArray{..} =
27982470 let maxIndex = length arr - 1
27992471 in if i < 0
28002472 then error "sliceAt: negative array index"
28012473 else if i > maxIndex
28022474 then error $ "sliceAt: specified array index " ++ show i
28032475 ++ " is beyond the maximum index " ++ show maxIndex
2804− else unsafeSplitAt i arr
2476+ else let off = i * SIZE_OF(a)
2477+ p = arrStart + off
2478+ in ( MutArray
2479+ { arrContents = arrContents
2480+ , arrStart = arrStart
2481+ , arrEnd = p
2482+ , arrBound = p
2483+ }
2484+ , MutArray
2485+ { arrContents = arrContents
2486+ , arrStart = p
2487+ , arrEnd = arrEnd
2488+ , arrBound = arrBound
2489+ }
2490+ )
28052491
28062492-------------------------------------------------------------------------------
28072493-- Casting
@@ -2851,13 +2537,9 @@ cast arr =
28512537-- guarantees that unsafe calls will be performed in the calling thread. Making
28522538-- it safe to pass heap-allocated objects to unsafe functions.
28532539
2854−-- XXX Should we just name it asPtr, the unsafety is implicit for any pointer
2540+-- Should we just name it asPtr, the unsafety is implicit for any pointer
28552541-- operations. And we are safe from Haskell perspective because we will be
28562542-- 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.
28612543
28622544-- | Use a @MutArray a@ as @Ptr a@. This is useful when we want to pass an
28632545-- array as a pointer to some operating system call or to a "safe" FFI call.
@@ -2875,21 +2557,16 @@ cast arr =
28752557--
28762558-- /Pre-release/
28772559--
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." #-}
28852560{-# INLINE asPtrUnsafe #-}
28862561asPtrUnsafe :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
2887−asPtrUnsafe = unsafePinnedAsPtr
2562+asPtrUnsafe arr f =
2563+ Unboxed.asPtrUnsafe
2564+ (arrContents arr) (\ptr -> f (ptr `plusPtr` arrStart arr))
28882565
2889−{-# INLINE unsafeAsPtr #-}
2890−unsafeAsPtr :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
2891−unsafeAsPtr arr f =
2892− Unboxed.unsafeAsPtr
2566+{-# INLINE asUnpinnedPtrUnsafe #-}
2567+asUnpinnedPtrUnsafe :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
2568+asUnpinnedPtrUnsafe arr f =
2569+ Unboxed.asUnpinnedPtrUnsafe
28932570 (arrContents arr) (\ptr -> f (ptr `plusPtr` arrStart arr))
28942571
28952572-------------------------------------------------------------------------------
@@ -2907,26 +2584,28 @@ unsafeAsPtr arr f =
29072584-- /Pre-release/
29082585{-# INLINE byteCmp #-}
29092586byteCmp :: 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
2587+byteCmp arr1 arr2 =
2588+ liftIO
2589+ $ do
2590+ let marr1 = getMutableByteArray# (arrContents arr1)
2591+ marr2 = getMutableByteArray# (arrContents arr2)
2592+ !(I# st1#) = arrStart arr1
2593+ !(I# st2#) = arrStart arr2
2594+ !(I# len#) = byteLength arr1
2595+ case compare (byteLength arr1) (byteLength arr2) of
2596+ EQ -> do
2597+ r <- liftIO $ IO $ \s# ->
2598+ let res =
2599+ I#
2600+ (compareByteArrays#
2601+ (unsafeCoerce# marr1)
2602+ st1#
2603+ (unsafeCoerce# marr2)
2604+ st2#
2605+ len#)
2606+ in (# s#, res #)
2607+ return $ compare r 0
2608+ x -> return x
29302609
29312610{-# INLINE cmp #-}
29322611{-# DEPRECATED cmp "Please use byteCmp instead." #-}
@@ -2946,48 +2625,46 @@ byteEq arr1 arr2 = fmap (EQ ==) $ byteCmp arr1 arr2
29462625-- Compact
29472626-------------------------------------------------------------------------------
29482627
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 ::
2628+-- | Parser @pCompactLE n@ coalesces adjacent arrays in the input stream
2629+-- only if the combined size would be less than or equal to n.
2630+--
2631+-- /Internal/
2632+{-# INLINE_NORMAL pCompactLE #-}
2633+pCompactLE ::
29562634 forall m a. (MonadIO m, Unbox a)
2957− => PinnedState -> Int -> Parser (MutArray a) m (MutArray a)
2958−pCompactLeAs ps maxElems = Parser step initial extract
2635+ => Int -> Parser (MutArray a) m (MutArray a)
2636+pCompactLE n = Parser step initial extract
29592637
29602638 where
29612639
2962− maxBytes = maxElems * SIZE_OF(a)
2640+ nBytes = n * SIZE_OF(a)
29632641
29642642 functionName = "Streamly.Internal.Data.MutArray.pCompactLE"
29652643
29662644 initial =
29672645 return
2968− $ if maxElems <= 0
2646+ $ if n <= 0
29692647 then error
29702648 $ functionName
29712649 ++ ": the size of arrays ["
2972− ++ show maxElems ++ "] must be a natural number"
2650+ ++ show n ++ "] must be a natural number"
29732651 else Parser.IPartial Nothing
29742652
29752653 step Nothing arr =
29762654 return
29772655 $ let len = byteLength arr
2978− in if len >= maxBytes
2656+ in if len >= nBytes
29792657 then Parser.Done 0 arr
29802658 else Parser.Partial 0 (Just arr)
2981− -- XXX Split the last array to use the space more compactly.
29822659 step (Just buf) arr =
29832660 let len = byteLength buf + byteLength arr
2984− in if len > maxBytes
2661+ in if len > nBytes
29852662 then return $ Parser.Done 1 buf
29862663 else do
2664+ -- XXX check this in the Nothing case
29872665 buf1 <-
2988− if byteCapacity buf < maxBytes
2989− then liftIO $ reallocExplicitAs
2990− ps (SIZE_OF(a)) maxBytes buf
2666+ if byteCapacity buf < nBytes
2667+ then liftIO $ realloc nBytes buf
29912668 else return buf
29922669 buf2 <- spliceUnsafe buf1 arr
29932670 return $ Parser.Partial 0 (Just buf2)
@@ -2995,30 +2672,6 @@ pCompactLeAs ps maxElems = Parser step initial extract
29952672 extract Nothing = return $ Parser.Done 0 nil
29962673 extract (Just buf) = return $ Parser.Done 0 buf
29972674
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−
30222675data SpliceState s arr
30232676 = SpliceInitial s
30242677 | SpliceBuffering s arr
@@ -3030,47 +2683,48 @@ data SpliceState s arr
30302683-- immutable array never has additional space so a new array is allocated
30312684-- instead of mutating it.
30322685
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) =
2686+-- | Scan @rCompactLE n@ coalesces adjacent arrays in the input stream
2687+-- only if the combined size would be less than or equal to n.
2688+--
2689+-- /Internal/
2690+{-# INLINE_NORMAL rCompactLE #-}
2691+rCompactLE :: (MonadIO m, Unbox a)
2692+ => Int -> D.Stream m (MutArray a) -> D.Stream m (MutArray a)
2693+rCompactLE n (D.Stream step state) =
30372694 D.Stream step' (SpliceInitial state)
30382695
30392696 where
30402697
3041− maxBytes = maxElems * SIZE_OF(a)
3042−
30432698 functionName = "Streamly.Internal.Data.MutArray.rCompactLE"
30442699
30452700 {-# INLINE_LATE step' #-}
30462701 step' gst (SpliceInitial st) = do
3047− when (maxElems <= 0) $
2702+ when (n <= 0) $
30482703 -- XXX we can pass the module string from the higher level API
3049− error $ functionName ++ ": the size of arrays [" ++ show maxElems
2704+ error $ functionName ++ ": the size of arrays [" ++ show n
30502705 ++ "] must be a natural number"
30512706 r <- step gst st
30522707 case r of
30532708 D.Yield arr s -> return $
30542709 let len = byteLength arr
3055− in if len >= maxBytes
2710+ in if len >= n
30562711 then D.Skip (SpliceYielding arr (SpliceInitial s))
30572712 else D.Skip (SpliceBuffering s arr)
30582713 D.Skip s -> return $ D.Skip (SpliceInitial s)
30592714 D.Stop -> return D.Stop
30602715
3061− -- XXX Split the last array to use the space more compactly.
30622716 step' gst (SpliceBuffering st buf) = do
30632717 r <- step gst st
30642718 case r of
30652719 D.Yield arr s -> do
30662720 let len = byteLength buf + byteLength arr
3067− if len > maxBytes
2721+ if len > n
30682722 then return $
30692723 D.Skip (SpliceYielding buf (SpliceBuffering s arr))
30702724 else do
3071− buf1 <- if byteCapacity buf < maxBytes
3072− then liftIO $ reallocExplicitAs
3073− ps (SIZE_OF(a)) maxBytes buf
2725+ -- XXX check this in the SpliceInitial case
2726+ buf1 <- if byteCapacity buf < n
2727+ then liftIO $ realloc n buf
30742728 else return buf
30752729 buf2 <- spliceUnsafe buf1 arr
30762730 return $ D.Skip (SpliceBuffering s buf2)
@@ -3081,119 +2735,108 @@ compactLeAs ps maxElems (D.Stream step state) =
30812735
30822736 step' _ (SpliceYielding arr next) = return $ D.Yield arr next
30832737
3084−
3085−{-# INLINE_NORMAL fCompactGeAs #-}
3086−fCompactGeAs ::
2738+-- | Fold @fCompactGE n@ coalesces adjacent arrays in the input stream
2739+-- until the size becomes greater than or equal to n.
2740+--
2741+{-# INLINE_NORMAL fCompactGE #-}
2742+fCompactGE ::
30872743 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
2744+ => Int -> FL.Fold m (MutArray a) (MutArray a)
2745+fCompactGE n = Fold step initial extract extract
30902746
30912747 where
30922748
3093− minBytes = minElems * SIZE_OF(a)
2749+ nBytes = n * SIZE_OF(a)
30942750
30952751 functionName = "Streamly.Internal.Data.MutArray.fCompactGE"
30962752
30972753 initial =
30982754 return
3099− $ if minElems < 0
2755+ $ if n < 0
31002756 then error
31012757 $ functionName
31022758 ++ ": the size of arrays ["
3103− ++ show minElems ++ "] must be a natural number"
2759+ ++ show n ++ "] must be a natural number"
31042760 else FL.Partial Nothing
31052761
31062762 step Nothing arr =
31072763 return
31082764 $ let len = byteLength arr
3109− in if len >= minBytes
2765+ in if len >= nBytes
31102766 then FL.Done arr
31112767 else FL.Partial (Just arr)
3112− -- XXX Buffer arrays as a list to avoid copy and reallocations
31132768 step (Just buf) arr = do
31142769 let len = byteLength buf + byteLength arr
31152770 buf1 <-
31162771 if byteCapacity buf < len
3117− then liftIO $ reallocExplicitAs
3118− ps (SIZE_OF(a)) (max minBytes len) buf
2772+ then liftIO $ realloc (max len nBytes) buf
31192773 else return buf
31202774 buf2 <- spliceUnsafe buf1 arr
3121− if len >= minBytes
2775+ if len >= n
31222776 then return $ FL.Done buf2
31232777 else return $ FL.Partial (Just buf2)
31242778
31252779 extract Nothing = return nil
31262780 extract (Just buf) = return buf
31272781
3128−-- | Fold @fCompactGE minElems@ coalesces adjacent arrays in the input stream
3129−-- until the size becomes greater than or equal to @minElems@.
2782+-- | Like 'compactGE' but for transforming folds instead of stream.
31302783--
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) =
2784+-- >>> lCompactGE n = Fold.many (MutArray.fCompactGE n)
2785+--
2786+{-# INLINE_NORMAL lCompactGE #-}
2787+lCompactGE :: (MonadIO m, Unbox a)
2788+ => Int -> Fold m (MutArray a) () -> Fold m (MutArray a) ()
2789+-- lCompactGE n = Fold.many (fCompactGE n)
2790+lCompactGE n (Fold step1 initial1 _ final1) =
31522791 Fold step initial extract final
31532792
31542793 where
31552794
3156− minBytes = minElems * SIZE_OF(a)
3157−
31582795 functionName = "Streamly.Internal.Data.MutArray.lCompactGE"
31592796
31602797 initial = do
3161− when (minElems <= 0) $
2798+ when (n <= 0) $
31622799 -- XXX we can pass the module string from the higher level API
31632800 error $ functionName ++ ": the size of arrays ["
3164− ++ show minElems ++ "] must be a natural number"
2801+ ++ show n ++ "] must be a natural number"
31652802
31662803 r <- initial1
31672804 return $ first (Tuple' Nothing) r
31682805
3169− {-# INLINE runInner #-}
3170− runInner len acc buf =
3171− if len >= minBytes
2806+ step (Tuple' Nothing r1) arr =
2807+ let len = byteLength arr
2808+ in if len >= n
2809+ then do
2810+ r <- step1 r1 arr
2811+ case r of
2812+ FL.Done _ -> return $ FL.Done ()
2813+ FL.Partial s -> do
2814+ _ <- final1 s
2815+ res <- initial1
2816+ return $ first (Tuple' Nothing) res
2817+ else return $ FL.Partial $ Tuple' (Just arr) r1
2818+
2819+ step (Tuple' (Just buf) r1) arr = do
2820+ let len = byteLength buf + byteLength arr
2821+ buf1 <- if byteCapacity buf < len
2822+ then liftIO $ realloc (max n len) buf
2823+ else return buf
2824+ buf2 <- spliceUnsafe buf1 arr
2825+
2826+ -- XXX this is common in both the equations of step
2827+ if len >= n
31722828 then do
3173− r <- step1 acc buf
2829+ r <- step1 r1 buf2
31742830 case r of
31752831 FL.Done _ -> return $ FL.Done ()
31762832 FL.Partial s -> do
31772833 _ <- final1 s
31782834 res <- initial1
31792835 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
2836+ else return $ FL.Partial $ Tuple' (Just buf2) r1
31942837
31952838 -- 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
2839+ -- return "m b" rather than using extract post it if we want extract to be
31972840 -- partial.
31982841 --
31992842 -- extract forces the pending buffer to be sent to the fold which is not
@@ -3207,23 +2850,6 @@ lCompactGeAs ps minElems (Fold step1 initial1 _ final1) =
32072850 FL.Partial rr -> final1 rr
32082851 FL.Done _ -> return ()
32092852
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−
32272853-- | @compactGE n stream@ coalesces adjacent arrays in the @stream@ until
32282854-- the size becomes greater than or equal to @n@.
32292855--
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+64−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,8 @@ 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
136152
137153 -- XXX Implement these as folds or parsers instead.
138154 , splitOnSuffixSeqAny
@@ -141,8 +157,9 @@ module Streamly.Internal.Data.Stream.Nesting
141157
142158 -- * Transform (Nested Containers)
143159 -- | Opposite to compact in ArrayStream
144− , splitInnerBy -- XXX innerSplitOn
145− , splitInnerBySuffix -- XXX innerSplitOnSuffix
160+ , splitInnerBy
161+ , splitInnerBySuffix
162+ , intersectBySorted
146163
147164 -- * Reduce By Streams
148165 , dropPrefix
@@ -592,6 +609,49 @@ mergeFstBy :: -- Monad m =>
592609mergeFstBy _f _m1 _m2 = undefined
593610 -- fromStreamK $ D.mergeFstBy f (toStreamD m1) (toStreamD m2)
594611
612+-------------------------------------------------------------------------------
613+-- Intersection of sorted streams
614+-------------------------------------------------------------------------------
615+
616+-- Assuming the streams are sorted in ascending order
617+{-# INLINE_NORMAL intersectBySorted #-}
618+intersectBySorted :: Monad m
619+ => (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
620+intersectBySorted cmp (Stream stepa ta) (Stream stepb tb) =
621+ Stream step
622+ ( ta -- left stream state
623+ , tb -- right stream state
624+ , Nothing -- left value
625+ , Nothing -- right value
626+ )
627+
628+ where
629+
630+ {-# INLINE_LATE step #-}
631+ -- step 1, fetch the first value
632+ step gst (sa, sb, Nothing, b) = do
633+ r <- stepa gst sa
634+ return $ case r of
635+ Yield a sa' -> Skip (sa', sb, Just a, b) -- step 2/3
636+ Skip sa' -> Skip (sa', sb, Nothing, b)
637+ Stop -> Stop
638+
639+ -- step 2, fetch the second value
640+ step gst (sa, sb, a@(Just _), Nothing) = do
641+ r <- stepb gst sb
642+ return $ case r of
643+ Yield b sb' -> Skip (sa, sb', a, Just b) -- step 3
644+ Skip sb' -> Skip (sa, sb', a, Nothing)
645+ Stop -> Stop
646+
647+ -- step 3, compare the two values
648+ step _ (sa, sb, Just a, Just b) = do
649+ let res = cmp a b
650+ return $ case res of
651+ GT -> Skip (sa, sb, Just a, Nothing) -- step 2
652+ LT -> Skip (sa, sb, Nothing, Just b) -- step 1
653+ EQ -> Yield a (sa, sb, Nothing, Just b) -- step 1
654+
595655------------------------------------------------------------------------------
596656-- Combine N Streams - unfoldMany
597657------------------------------------------------------------------------------
@@ -2986,8 +3046,6 @@ splitInnerBySuffix isEmpty splitter joiner (Stream step1 state1) =
29863046--
29873047-- Space: @O(1)@
29883048--
2989−-- See also stripPrefix.
2990−--
29913049-- /Unimplemented/
29923050{-# INLINE dropPrefix #-}
29933051dropPrefix ::
@@ -3000,8 +3058,6 @@ dropPrefix = error "Not implemented yet!"
30003058--
30013059-- Space: @O(n)@ where n is the length of the infix.
30023060--
3003−-- See also stripInfix.
3004−--
30053061-- /Unimplemented/
30063062{-# INLINE dropInfix #-}
30073063dropInfix ::
@@ -3014,8 +3070,6 @@ dropInfix = error "Not implemented yet!"
30143070--
30153071-- Space: @O(n)@ where n is the length of the suffix.
30163072--
3017−-- See also stripSuffix.
3018−--
30193073-- /Unimplemented/
30203074{-# INLINE dropSuffix #-}
30213075dropSuffix ::
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+26−52
@@ -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--
@@ -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−37
@@ -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
@@ -142,7 +133,6 @@ module Streamly.Internal.Data.Stream.Type
142133 , indexOnSuffix
143134
144135 -- * Multi-stream folds
145− -- | These should probably be expressed using zipping operations.
146136 , eqBy
147137 , cmpBy
148138
@@ -572,12 +562,8 @@ foldAdd f =
572562-- >>> Stream.foldrM step (return False) s
573563-- True
574564--
575−-- >>> import Control.Monad (join)
576−-- >>> foldrM f z = join $ Stream.foldr f z
577−--
578565{-# INLINE_NORMAL foldrM #-}
579566foldrM :: 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
581567foldrM f z (Stream step state) = go SPEC state
582568 where
583569 {-# INLINE_LATE go #-}
@@ -2076,26 +2062,6 @@ indexOnSuffix predicate =
20762062 (indexerBy (FL.takeEndBy_ predicate FL.length) 1)
20772063 (return (-1, 0))
20782064
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−
20992065{-# DEPRECATED sliceOnSuffix "Please use indexOnSuffix instead." #-}
21002066sliceOnSuffix :: Monad m => (a -> Bool) -> Stream m a -> Stream m (Int, Int)
21012067sliceOnSuffix = indexOnSuffix
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+1−1
@@ -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/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]