on master help sign in
configure+9−9
since splitsnapshots
unifiedsplit
@@ -1,6 +1,6 @@
1#! /bin/sh
1#! /bin/sh
2# Guess values for system-dependent variables and create Makefiles.
2# Guess values for system-dependent variables and create Makefiles.
3−# Generated by GNU Autoconf 2.71 for streamly 0.10.0.
3+# Generated by GNU Autoconf 2.71 for streamly 0.10.1.
4#
4#
5# Report bugs to <streamly@composewell.com>.
5# Report bugs to <streamly@composewell.com>.
6#
6#
@@ -610,8 +610,8 @@ MAKEFLAGS=
610# Identity of this package.
610# Identity of this package.
611PACKAGE_NAME='streamly'
611PACKAGE_NAME='streamly'
612PACKAGE_TARNAME='streamly'
612PACKAGE_TARNAME='streamly'
613−PACKAGE_VERSION='0.10.0'
613+PACKAGE_VERSION='0.10.1'
614−PACKAGE_STRING='streamly 0.10.0'
614+PACKAGE_STRING='streamly 0.10.1'
615PACKAGE_BUGREPORT='streamly@composewell.com'
615PACKAGE_BUGREPORT='streamly@composewell.com'
616PACKAGE_URL='https://streamly.composewell.com'
616PACKAGE_URL='https://streamly.composewell.com'
617
617
@@ -1224,7 +1224,7 @@ if test "$ac_init_help" = "long"; then
1224 # Omit some internal or obsolete options to make the list less imposing.
1224 # Omit some internal or obsolete options to make the list less imposing.
1225 # This message is too long to be a string in the A/UX 3.1 sh.
1225 # This message is too long to be a string in the A/UX 3.1 sh.
1226 cat <<_ACEOF
1226 cat <<_ACEOF
1227−\`configure' configures streamly 0.10.0 to adapt to many kinds of systems.
1227+\`configure' configures streamly 0.10.1 to adapt to many kinds of systems.
1228
1228
1229Usage: $0 [OPTION]... [VAR=VALUE]...
1229Usage: $0 [OPTION]... [VAR=VALUE]...
1230
1230
@@ -1286,7 +1286,7 @@ fi
1286
1286
1287if test -n "$ac_init_help"; then
1287if test -n "$ac_init_help"; then
1288 case $ac_init_help in
1288 case $ac_init_help in
1289− short | recursive ) echo "Configuration of streamly 0.10.0:";;
1289+ short | recursive ) echo "Configuration of streamly 0.10.1:";;
1290 esac
1290 esac
1291 cat <<\_ACEOF
1291 cat <<\_ACEOF
1292
1292
@@ -1372,7 +1372,7 @@ fi
1372test -n "$ac_init_help" && exit $ac_status
1372test -n "$ac_init_help" && exit $ac_status
1373if $ac_init_version; then
1373if $ac_init_version; then
1374 cat <<\_ACEOF
1374 cat <<\_ACEOF
1375−streamly configure 0.10.0
1375+streamly configure 0.10.1
1376generated by GNU Autoconf 2.71
1376generated by GNU Autoconf 2.71
1377
1377
1378Copyright (C) 2021 Free Software Foundation, Inc.
1378Copyright (C) 2021 Free Software Foundation, Inc.
@@ -1500,7 +1500,7 @@ cat >config.log <<_ACEOF
1500This file contains any messages produced by compilers while
1500This file contains any messages produced by compilers while
1501running configure, to aid debugging if configure makes a mistake.
1501running configure, to aid debugging if configure makes a mistake.
1502
1502
1503−It was created by streamly $as_me 0.10.0, which was
1503+It was created by streamly $as_me 0.10.1, which was
1504generated by GNU Autoconf 2.71. Invocation command line was
1504generated by GNU Autoconf 2.71. Invocation command line was
1505
1505
1506 $ $0$ac_configure_args_raw
1506 $ $0$ac_configure_args_raw
@@ -3800,7 +3800,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
3800# report actual input values of CONFIG_FILES etc. instead of their
3800# report actual input values of CONFIG_FILES etc. instead of their
3801# values after options handling.
3801# values after options handling.
3802ac_log="
3802ac_log="
3803−This file was extended by streamly $as_me 0.10.0, which was
3803+This file was extended by streamly $as_me 0.10.1, which was
3804generated by GNU Autoconf 2.71. Invocation command line was
3804generated by GNU Autoconf 2.71. Invocation command line was
3805
3805
3806 CONFIG_FILES = $CONFIG_FILES
3806 CONFIG_FILES = $CONFIG_FILES
@@ -3856,7 +3856,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
3856cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
3856cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
3857ac_cs_config='$ac_cs_config_escaped'
3857ac_cs_config='$ac_cs_config_escaped'
3858ac_cs_version="\\
3858ac_cs_version="\\
3859−streamly config.status 0.10.0
3859+streamly config.status 0.10.1
3860configured by $0, generated by GNU Autoconf 2.71,
3860configured by $0, generated by GNU Autoconf 2.71,
3861 with options \\"\$ac_cs_config\\"
3861 with options \\"\$ac_cs_config\\"
3862
3862
configure.ac+1−1
@@ -3,7 +3,7 @@
3# See https://www.gnu.org/software/autoconf/manual/autoconf.html for help on
3# See https://www.gnu.org/software/autoconf/manual/autoconf.html for help on
4# the macros used in this file.
4# the macros used in this file.
5
5
6−AC_INIT([streamly], [0.10.0], [streamly@composewell.com], [streamly], [https://streamly.composewell.com])
6+AC_INIT([streamly], [0.10.1], [streamly@composewell.com], [streamly], [https://streamly.composewell.com])
7
7
8# To suppress "WARNING: unrecognized options: --with-compiler"
8# To suppress "WARNING: unrecognized options: --with-compiler"
9AC_ARG_WITH([compiler], [GHC])
9AC_ARG_WITH([compiler], [GHC])
core/configure+9−9
@@ -1,6 +1,6 @@
1#! /bin/sh
1#! /bin/sh
2# Guess values for system-dependent variables and create Makefiles.
2# Guess values for system-dependent variables and create Makefiles.
3−# Generated by GNU Autoconf 2.71 for streamly-core 0.2.1.
3+# Generated by GNU Autoconf 2.71 for streamly-core 0.2.2.
4#
4#
5# Report bugs to <streamly@composewell.com>.
5# Report bugs to <streamly@composewell.com>.
6#
6#
@@ -610,8 +610,8 @@ MAKEFLAGS=
610# Identity of this package.
610# Identity of this package.
611PACKAGE_NAME='streamly-core'
611PACKAGE_NAME='streamly-core'
612PACKAGE_TARNAME='streamly-core'
612PACKAGE_TARNAME='streamly-core'
613−PACKAGE_VERSION='0.2.1'
613+PACKAGE_VERSION='0.2.2'
614−PACKAGE_STRING='streamly-core 0.2.1'
614+PACKAGE_STRING='streamly-core 0.2.2'
615PACKAGE_BUGREPORT='streamly@composewell.com'
615PACKAGE_BUGREPORT='streamly@composewell.com'
616PACKAGE_URL='https://streamly.composewell.com'
616PACKAGE_URL='https://streamly.composewell.com'
617
617
@@ -1256,7 +1256,7 @@ if test "$ac_init_help" = "long"; then
1256 # Omit some internal or obsolete options to make the list less imposing.
1256 # Omit some internal or obsolete options to make the list less imposing.
1257 # This message is too long to be a string in the A/UX 3.1 sh.
1257 # This message is too long to be a string in the A/UX 3.1 sh.
1258 cat <<_ACEOF
1258 cat <<_ACEOF
1259−\`configure' configures streamly-core 0.2.1 to adapt to many kinds of systems.
1259+\`configure' configures streamly-core 0.2.2 to adapt to many kinds of systems.
1260
1260
1261Usage: $0 [OPTION]... [VAR=VALUE]...
1261Usage: $0 [OPTION]... [VAR=VALUE]...
1262
1262
@@ -1318,7 +1318,7 @@ fi
1318
1318
1319if test -n "$ac_init_help"; then
1319if test -n "$ac_init_help"; then
1320 case $ac_init_help in
1320 case $ac_init_help in
1321− short | recursive ) echo "Configuration of streamly-core 0.2.1:";;
1321+ short | recursive ) echo "Configuration of streamly-core 0.2.2:";;
1322 esac
1322 esac
1323 cat <<\_ACEOF
1323 cat <<\_ACEOF
1324
1324
@@ -1404,7 +1404,7 @@ fi
1404test -n "$ac_init_help" && exit $ac_status
1404test -n "$ac_init_help" && exit $ac_status
1405if $ac_init_version; then
1405if $ac_init_version; then
1406 cat <<\_ACEOF
1406 cat <<\_ACEOF
1407−streamly-core configure 0.2.1
1407+streamly-core configure 0.2.2
1408generated by GNU Autoconf 2.71
1408generated by GNU Autoconf 2.71
1409
1409
1410Copyright (C) 2021 Free Software Foundation, Inc.
1410Copyright (C) 2021 Free Software Foundation, Inc.
@@ -1622,7 +1622,7 @@ cat >config.log <<_ACEOF
1622This file contains any messages produced by compilers while
1622This file contains any messages produced by compilers while
1623running configure, to aid debugging if configure makes a mistake.
1623running configure, to aid debugging if configure makes a mistake.
1624
1624
1625−It was created by streamly-core $as_me 0.2.1, which was
1625+It was created by streamly-core $as_me 0.2.2, which was
1626generated by GNU Autoconf 2.71. Invocation command line was
1626generated by GNU Autoconf 2.71. Invocation command line was
1627
1627
1628 $ $0$ac_configure_args_raw
1628 $ $0$ac_configure_args_raw
@@ -3832,7 +3832,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
3832# report actual input values of CONFIG_FILES etc. instead of their
3832# report actual input values of CONFIG_FILES etc. instead of their
3833# values after options handling.
3833# values after options handling.
3834ac_log="
3834ac_log="
3835−This file was extended by streamly-core $as_me 0.2.1, which was
3835+This file was extended by streamly-core $as_me 0.2.2, which was
3836generated by GNU Autoconf 2.71. Invocation command line was
3836generated by GNU Autoconf 2.71. Invocation command line was
3837
3837
3838 CONFIG_FILES = $CONFIG_FILES
3838 CONFIG_FILES = $CONFIG_FILES
@@ -3888,7 +3888,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
3888cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
3888cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
3889ac_cs_config='$ac_cs_config_escaped'
3889ac_cs_config='$ac_cs_config_escaped'
3890ac_cs_version="\\
3890ac_cs_version="\\
3891−streamly-core config.status 0.2.1
3891+streamly-core config.status 0.2.2
3892configured by $0, generated by GNU Autoconf 2.71,
3892configured by $0, generated by GNU Autoconf 2.71,
3893 with options \\"\$ac_cs_config\\"
3893 with options \\"\$ac_cs_config\\"
3894
3894
core/configure.ac+1−1
@@ -3,7 +3,7 @@
3# See https://www.gnu.org/software/autoconf/manual/autoconf.html for help on
3# See https://www.gnu.org/software/autoconf/manual/autoconf.html for help on
4# the macros used in this file.
4# the macros used in this file.
5
5
6−AC_INIT([streamly-core], [0.2.1], [streamly@composewell.com], [streamly-core], [https://streamly.composewell.com])
6+AC_INIT([streamly-core], [0.2.2], [streamly@composewell.com], [streamly-core], [https://streamly.composewell.com])
7
7
8# To suppress "WARNING: unrecognized options: --with-compiler"
8# To suppress "WARNING: unrecognized options: --with-compiler"
9AC_ARG_WITH([compiler], [GHC])
9AC_ARG_WITH([compiler], [GHC])
core/docs/ApiChangelogs/0.2.0-0.2.2.txtnew file+306
@@ -0,0 +1,306 @@
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−1
@@ -1,6 +1,6 @@
1# Changelog
1# Changelog
2
2
3−## Unreleased
3+## 0.2.2 (Jan 2024)
4
4
5* Add fixities `infixr 5` for `cons` and `consM` functions.
5* Add fixities `infixr 5` for `cons` and `consM` functions.
6* Fix a bug in Array `Eq` instance when the type is a sum type with
6* Fix a bug in Array `Eq` instance when the type is a sum type with
core/src/DocTestDataStream.hs+2
@@ -6,6 +6,7 @@
6>>> import Control.Monad.IO.Class (MonadIO (liftIO))
6>>> import Control.Monad.IO.Class (MonadIO (liftIO))
7>>> import Control.Monad.Trans.Class (lift)
7>>> import Control.Monad.Trans.Class (lift)
8>>> import Control.Monad.Trans.Identity (runIdentityT)
8>>> import Control.Monad.Trans.Identity (runIdentityT)
9+>>> import Data.Char (isSpace)
9>>> import Data.Either (fromLeft, fromRight, isLeft, isRight, either)
10>>> import Data.Either (fromLeft, fromRight, isLeft, isRight, either)
10>>> import Data.Maybe (fromJust, isJust)
11>>> import Data.Maybe (fromJust, isJust)
11>>> import Data.Function (fix, (&))
12>>> import Data.Function (fix, (&))
@@ -32,6 +33,7 @@ For APIs that have not been released yet.
32>>> import qualified Streamly.Internal.Data.Fold as Fold
33>>> import qualified Streamly.Internal.Data.Fold as Fold
33>>> import qualified Streamly.Internal.Data.Parser as Parser
34>>> import qualified Streamly.Internal.Data.Parser as Parser
34>>> import qualified Streamly.Internal.Data.Stream as Stream
35>>> import qualified Streamly.Internal.Data.Stream as Stream
36+>>> import qualified Streamly.Internal.Data.StreamK as StreamK
35>>> import qualified Streamly.Internal.Data.Unfold as Unfold
37>>> import qualified Streamly.Internal.Data.Unfold as Unfold
36>>> import qualified Streamly.Internal.FileSystem.Dir as Dir
38>>> import qualified Streamly.Internal.FileSystem.Dir as Dir
37-}
39-}
core/src/DocTestFileSystemHandle.hs+1−1
@@ -8,7 +8,7 @@
8
8
9For APIs that have not been released yet.
9For APIs that have not been released yet.
10
10
11−>>> import qualified Streamly.Internal.Data.Array as Array (writeNUnsafe)
11+>>> import qualified Streamly.Internal.Data.Array as Array (unsafeCreateOf)
12>>> import qualified Streamly.Internal.Data.Unfold as Unfold (first)
12>>> import qualified Streamly.Internal.Data.Unfold as Unfold (first)
13>>> import qualified Streamly.Internal.FileSystem.Handle as Handle
13>>> import qualified Streamly.Internal.FileSystem.Handle as Handle
14>>> import qualified Streamly.Internal.System.IO as IO (defaultChunkSize)
14>>> import qualified Streamly.Internal.System.IO as IO (defaultChunkSize)
core/src/Streamly/Data/Array.hs+30−27
@@ -31,42 +31,42 @@ module Streamly.Data.Array
31 -- * The Array Type
31 -- * The Array Type
32 Array
32 Array
33
33
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+
34 -- * Construction
47 -- * Construction
35 -- | When performance matters, the fastest way to generate an array is
48 -- | When performance matters, the fastest way to generate an array is
36− -- 'writeN'. 'IsList' and 'IsString' instances can be
49+ -- 'createOf'. 'IsList' and 'IsString' instances can be
37 -- used to conveniently construct arrays from literal values.
50 -- used to conveniently construct arrays from literal values.
38 -- 'OverloadedLists' extension or 'fromList' can be used to construct an
51 -- 'OverloadedLists' extension or 'fromList' can be used to construct an
39 -- array from a list literal. Similarly, 'OverloadedStrings' extension or
52 -- array from a list literal. Similarly, 'OverloadedStrings' extension or
40 -- 'fromList' can be used to construct an array from a string literal.
53 -- 'fromList' can be used to construct an array from a string literal.
41
54
55+ -- ** From Stream
56+ , createOf
57+ , create
58+ , writeLastN -- drop old (ring buffer)
59+
42− -- Pure List APIs
60+ -- ** From List
43 , fromListN
61 , fromListN
44 , fromList
62 , fromList
45
63
46− -- Monadic APIs
64+ -- * To List
47− , writeN -- drop new
48− , write -- full buffer
49− , writeLastN -- drop old (ring buffer)
50−
51− -- * Conversion
52 -- 'GHC.Exts.toList' from "GHC.Exts" can be used to convert an array to a
65 -- 'GHC.Exts.toList' from "GHC.Exts" can be used to convert an array to a
53 -- list.
66 -- list.
54 , toList
67 , toList
55
68
56− -- * Pinning & Unpinning
69+ -- * To Stream
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
70 , read
70 , read
71 , readRev
71 , readRev
72
72
@@ -90,6 +90,10 @@ module Streamly.Data.Array
90 -- * Re-exports
90 -- * Re-exports
91 , Unbox (..)
91 , Unbox (..)
92 , Serialize(..)
92 , Serialize(..)
93+
94+ -- * Deprecated
95+ , writeN -- drop new
96+ , write -- full buffer
93 )
97 )
94where
98where
95
99
@@ -122,7 +126,7 @@ import Prelude hiding (read, length)
122--
126--
123-- Convert array to stream, transform, and fold back to array:
127-- Convert array to stream, transform, and fold back to array:
124--
128--
125−-- >>> amap f arr = Array.read arr & fmap f & Stream.fold Array.write
129+-- >>> amap f arr = Array.read arr & fmap f & Stream.fold (Array.createOf (Array.length arr))
126-- >>> amap (+1) (Array.fromList [1,2,3::Int])
130-- >>> amap (+1) (Array.fromList [1,2,3::Int])
127-- fromList [2,3,4]
131-- fromList [2,3,4]
128--
132--
@@ -149,12 +153,11 @@ import Prelude hiding (read, length)
149-- See the 'fromPureStream' unreleased API to generate an array from an
153-- See the 'fromPureStream' unreleased API to generate an array from an
150-- Identity stream safely without using MonadIO constraint.
154-- Identity stream safely without using MonadIO constraint.
151--
155--
152−--
153-- Note that 'Identity' streams can be generalized to IO streams:
156-- Note that 'Identity' streams can be generalized to IO streams:
154--
157--
155−-- >>> pure = Stream.fromList [1,2,3] :: Stream Identity Int
158+-- >>> stream = Stream.fromList [1,2,3] :: Stream Identity Int
156−-- >>> generally = Stream.morphInner (return . runIdentity)
159+-- >>> pure2IO s = Stream.morphInner (return . runIdentity) s :: Stream IO Int
157−-- >>> Stream.fold Array.write (generally pure :: Stream IO Int)
160+-- >>> Stream.fold Array.create (pure2IO stream)
158-- fromList [1,2,3]
161-- fromList [1,2,3]
159--
162--
160-- == Programming Tips
163-- == Programming Tips
core/src/Streamly/Data/Array/Generic.hs+16−13
@@ -15,34 +15,37 @@ module Streamly.Data.Array.Generic
15 ( Array
15 ( Array
16
16
17 -- * Construction
17 -- * Construction
18− , A.fromListN
18+ , fromListN
19− , A.fromList
19+ , fromList
20
20
21 -- MonadicAPIs
21 -- MonadicAPIs
22− , A.writeN
22+ , createOf
23− , A.write
23+ , create
24
24
25 -- * Conversion
25 -- * Conversion
26− , A.toList
26+ , toList
27
27
28 -- * Streams
28 -- * Streams
29− , A.read
29+ , read
30− , A.readRev
30+ , readRev
31
31
32 -- * Unfolds
32 -- * Unfolds
33− , A.reader
33+ , reader
34 -- , A.readerRev
34 -- , A.readerRev
35
35
36 -- * Random Access
36 -- * Random Access
37− , A.length
37+ , length
38− , A.getIndex
38+ , getIndex
39
39
40 -- -- * Folding Arrays
40 -- -- * Folding Arrays
41 -- , A.streamFold
41 -- , A.streamFold
42 -- , A.fold
42 -- , A.fold
43+
44+ -- * Deprecated
45+ , writeN
46+ , write
43 )
47 )
44where
48where
45
49
46−import Streamly.Internal.Data.Array.Generic (Array)
50+import Streamly.Internal.Data.Array.Generic
47−
51+import Prelude hiding (length, read)
48−import qualified Streamly.Internal.Data.Array.Generic as A
core/src/Streamly/Data/MutArray.hs+12−6
@@ -32,14 +32,14 @@ module Streamly.Data.MutArray
32 -- * Construction
32 -- * Construction
33
33
34 -- Uninitialized Arrays
34 -- Uninitialized Arrays
35− , new
35+ , emptyOf
36− , pinnedNew
36+ , pinnedEmptyOf
37
37
38 -- From containers
38 -- From containers
39 , fromListN
39 , fromListN
40 , fromList
40 , fromList
41− , writeN -- drop new
41+ , createOf
42− , write -- full buffer
42+ , create
43 -- writeLastN
43 -- writeLastN
44
44
45 -- * Pinning & Unpinning
45 -- * Pinning & Unpinning
@@ -51,8 +51,8 @@ module Streamly.Data.MutArray
51 , snoc
51 , snoc
52
52
53 -- * Appending streams
53 -- * Appending streams
54− , writeAppendN -- XXX Rename to writeSnocN?
54+ , appendN
55− , writeAppend -- XXX Rename to writeSnoc?
55+ , append
56
56
57 -- * Inplace mutation
57 -- * Inplace mutation
58 , putIndex
58 , putIndex
@@ -88,6 +88,12 @@ module Streamly.Data.MutArray
88
88
89 -- * Deprecated
89 -- * Deprecated
90 , newPinned
90 , newPinned
91+ , new
92+ , pinnedNew
93+ , writeN
94+ , write
95+ , writeAppendN
96+ , writeAppend
91 )
97 )
92where
98where
93
99
core/src/Streamly/Data/MutArray/Generic.hs+8−3
@@ -23,11 +23,11 @@ module Streamly.Data.MutArray.Generic
23 MutArray
23 MutArray
24
24
25 -- * Construction
25 -- * Construction
26− , new
26+ , emptyOf
27 , fromListN
27 , fromListN
28 , fromList
28 , fromList
29− , writeN
29+ , createOf
30− , write
30+ , create
31
31
32 -- * Appending elements
32 -- * Appending elements
33 , snoc
33 , snoc
@@ -56,6 +56,11 @@ module Streamly.Data.MutArray.Generic
56
56
57 -- * Size
57 -- * Size
58 , length
58 , length
59+
60+ -- * Deprecated
61+ , new
62+ , writeN
63+ , write
59 )
64 )
60where
65where
61
66
core/src/Streamly/Data/Stream.hs+129−20
@@ -70,6 +70,15 @@ module Streamly.Data.Stream
70
70
71 -- ** From Values
71 -- ** From Values
72 -- | Generate a monadic stream from a seed value or values.
72 -- | 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+ --
73 , fromPure
82 , fromPure
74 , fromEffect
83 , fromEffect
75 , repeat
84 , repeat
@@ -212,21 +221,57 @@ module Streamly.Data.Stream
212 -- operations like mapping a function over the stream.
221 -- operations like mapping a function over the stream.
213 , foldrM
222 , foldrM
214 , foldr
223 , foldr
224+ -- foldr1
215
225
216 -- ** Specific Folds
226 -- ** Specific Folds
217− -- | Usually you can use the folds in "Streamly.Data.Fold". However, some
227+ -- | Streams are folded using folds in "Streamly.Data.Fold". Here are some
218− -- folds that may be commonly used or may have an edge in performance in
228+ -- idioms and equivalents of Data.List APIs using folds:
219− -- some cases are provided here.
220− --
221− -- Useful idioms:
222 --
229 --
223 -- >>> foldlM' f a = Stream.fold (Fold.foldlM' f a)
230 -- >>> foldlM' f a = Stream.fold (Fold.foldlM' f a)
224− -- >>> foldl1 f = Stream.fold (Fold.foldl1' f)
231+ -- >>> foldl1' f = Stream.fold (Fold.foldl1' f)
225 -- >>> foldl' f a = Stream.fold (Fold.foldl' f a)
232 -- >>> foldl' f a = Stream.fold (Fold.foldl' f a)
226 -- >>> drain = Stream.fold Fold.drain
233 -- >>> drain = Stream.fold Fold.drain
227 -- >>> mapM_ f = Stream.fold (Fold.drainMapM f)
234 -- >>> mapM_ f = Stream.fold (Fold.drainMapM f)
228 -- >>> length = Stream.fold Fold.length
235 -- >>> length = Stream.fold Fold.length
236+ -- >>> genericLength = Stream.fold Fold.lengthGeneric
229 -- >>> head = Stream.fold Fold.one
237 -- >>> 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
230 , toList
275 , toList
231
276
232 -- * Mapping
277 -- * Mapping
@@ -280,6 +325,15 @@ module Streamly.Data.Stream
280 , scan
325 , scan
281 , postscan
326 , postscan
282 -- XXX postscan1 can be implemented using Monoids or Refolds.
327 -- 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
283
337
284 -- ** Specific scans
338 -- ** Specific scans
285 -- Indexing can be considered as a special type of zipping where we zip a
339 -- Indexing can be considered as a special type of zipping where we zip a
@@ -288,6 +342,8 @@ module Streamly.Data.Stream
288
342
289 -- * Insertion
343 -- * Insertion
290 -- | Add elements to the stream.
344 -- | Add elements to the stream.
345+ --
346+ -- >>> insert = Stream.insertBy compare
291
347
292 -- Inserting elements is a special case of interleaving/merging streams.
348 -- Inserting elements is a special case of interleaving/merging streams.
293 , insertBy
349 , insertBy
@@ -323,12 +379,15 @@ module Streamly.Data.Stream
323 -- "Streamly.Internal.Data.Fold" can be used along with 'scanMaybe' to
379 -- "Streamly.Internal.Data.Fold" can be used along with 'scanMaybe' to
324 -- perform stateful filtering operations in general.
380 -- perform stateful filtering operations in general.
325 --
381 --
326− -- Useful idioms:
382+ -- Idioms and equivalents of Data.List APIs:
327 --
383 --
328 -- >>> deleteBy cmp x = Stream.scanMaybe (Fold.deleteBy cmp x)
384 -- >>> deleteBy cmp x = Stream.scanMaybe (Fold.deleteBy cmp x)
385+ -- >>> deleteBy = Stream.deleteBy -- unreleased API
386+ -- >>> delete = deleteBy (==)
329 -- >>> findIndices p = Stream.scanMaybe (Fold.findIndices p)
387 -- >>> findIndices p = Stream.scanMaybe (Fold.findIndices p)
330 -- >>> elemIndices a = findIndices (== a)
388 -- >>> elemIndices a = findIndices (== a)
331 -- >>> uniq = Stream.scanMaybe (Fold.uniqBy (==))
389 -- >>> uniq = Stream.scanMaybe (Fold.uniqBy (==))
390+ -- >>> partition p = Stream.fold (Fold.partition Fold.toList Fold.toList) . fmap (if p then Left else Right)
332 , scanMaybe
391 , scanMaybe
333 , take
392 , take
334 , takeWhile
393 , takeWhile
@@ -336,6 +395,8 @@ module Streamly.Data.Stream
336 , drop
395 , drop
337 , dropWhile
396 , dropWhile
338 , dropWhileM
397 , dropWhileM
398+ -- XXX write to an array in reverse and then read in reverse
399+ -- > dropWhileEnd = reverse . dropWhile p . reverse
339
400
340 -- XXX These are available as scans in folds. We need to check the
401 -- XXX These are available as scans in folds. We need to check the
341 -- performance though. If these are common and we need convenient stream
402 -- performance though. If these are common and we need convenient stream
@@ -372,6 +433,9 @@ module Streamly.Data.Stream
372 -- >>> s = s1 `Stream.append` s2
433 -- >>> s = s1 `Stream.append` s2
373
434
374 -- ** Appending
435 -- ** Appending
436+ -- | Equivalent of Data.List append:
437+ --
438+ -- >>> (++) = Stream.append
375 , append
439 , append
376
440
377 -- ** Interleaving
441 -- ** Interleaving
@@ -382,8 +446,14 @@ module Streamly.Data.Stream
382 , mergeByM
446 , mergeByM
383
447
384 -- ** Zipping
448 -- ** Zipping
449+ -- | Idioms and equivalents of Data.List APIs:
450+ --
451+ -- >>> zip = Stream.zipWith (,)
452+ -- >>> unzip = Stream.fold (Fold.unzip Fold.toList Fold.toList)
385 , zipWith
453 , zipWith
386 , zipWithM
454 , zipWithM
455+ -- XXX zipWith3,4,5,6,7
456+ -- XXX unzip3,4,5,6,7
387 -- , ZipStream (..)
457 -- , ZipStream (..)
388
458
389 -- ** Cross Product
459 -- ** Cross Product
@@ -416,48 +486,89 @@ module Streamly.Data.Stream
416 -- One dimension loops are just a special case of nested loops. For
486 -- One dimension loops are just a special case of nested loops. For
417 -- example, 'concatMap' can degenerate to a simple map operation:
487 -- example, 'concatMap' can degenerate to a simple map operation:
418 --
488 --
419− -- > map f m = S.concatMap (\x -> S.fromPure (f x)) m
489+ -- >>> map f m = Stream.concatMap (\x -> Stream.fromPure (f x)) m
420 --
490 --
421 -- Similarly, 'concatMap' can perform filtering by mapping an element to a
491 -- Similarly, 'concatMap' can perform filtering by mapping an element to a
422 -- 'nil' stream:
492 -- 'nil' stream:
423 --
493 --
424− -- > filter p m = S.concatMap (\x -> if p x then S.fromPure x else S.nil) m
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:
425 --
497 --
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 " "
426
503
427 , concatEffect
504 , concatEffect
428 , concatMap
505 , concatMap
429 , concatMapM
506 , concatMapM
430
507
431 -- * Repeated Fold
508 -- * Repeated Fold
432− -- | Useful idioms:
509+ -- | Idioms and equivalents of Data.List APIs:
433 --
510 --
434− -- >>> splitWithSuffix p f = Stream.foldMany (Fold.takeEndBy p f)
511+ -- >>> groupsOf n = Stream.foldMany (Fold.take n Fold.toList)
435− -- >>> splitOnSuffix p f = Stream.foldMany (Fold.takeEndBy_ p f)
512+ -- >>> groupBy eq = Stream.groupsWhile eq Fold.toList
436− -- >>> groupsBy eq f = Stream.parseMany (Parser.groupBy eq f)
513+ -- >>> groupBy eq = Stream.parseMany (Parser.groupBy eq Fold.toList)
437− -- >>> groupsByRolling eq f = Stream.parseMany (Parser.groupByRolling eq f)
514+ -- >>> groupsByRolling eq = Stream.parseMany (Parser.groupByRolling eq Fold.toList)
438− -- >>> groupsOf n f = Stream.foldMany (Fold.take n f)
515+ -- >>> groups = groupBy (==)
439 , foldMany -- XXX Rename to foldRepeat
516 , foldMany -- XXX Rename to foldRepeat
440 , groupsOf
517 , groupsOf
441 , parseMany
518 , parseMany
442
519
443 -- * Splitting
520 -- * 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)
444 , splitOn
530 , splitOn
445 , wordsBy
531 , wordsBy
446
532
447 -- * Buffered Operations
533 -- * Buffered Operations
448 -- | Operations that require buffering of the stream.
534 -- | Operations that require buffering of the stream.
449 -- Reverse is essentially a left fold followed by an unfold.
535 -- 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+ --
450 , reverse
550 , 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
451
557
452 -- * Multi-Stream folds
558 -- * Multi-Stream folds
453 -- | Operations that consume multiple streams at the same time.
559 -- | Operations that consume multiple streams at the same time.
454 , eqBy
560 , eqBy
455 , cmpBy
561 , cmpBy
456 , isPrefixOf
562 , isPrefixOf
563+ , isInfixOf
564+ -- , isSuffixOf
565+ -- , isSuffixOfUnbox
457 , isSubsequenceOf
566 , isSubsequenceOf
458
567
459 -- trimming sequences
568 -- trimming sequences
460− , stripPrefix
569+ -- , stripPrefix
570+ -- , stripSuffix
571+ -- , stripSuffixUnbox
461
572
462 -- Exceptions and resource management depend on the "exceptions" package
573 -- Exceptions and resource management depend on the "exceptions" package
463 -- XXX We can have IO Stream operations not depending on "exceptions"
574 -- XXX We can have IO Stream operations not depending on "exceptions"
@@ -521,10 +632,8 @@ where
521import Streamly.Internal.Data.Stream
632import Streamly.Internal.Data.Stream
522import Prelude
633import Prelude
523 hiding (filter, drop, dropWhile, take, takeWhile, zipWith, foldr,
634 hiding (filter, drop, dropWhile, take, takeWhile, zipWith, foldr,
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, (!!),
635+ mapM, sequence, reverse, iterate, foldr1, repeat, replicate,
527− scanl, scanl1, repeat, replicate, concatMap, span)
636+ concatMap)
528
637
529import qualified Streamly.Internal.Data.Array.Type as Array
638import qualified Streamly.Internal.Data.Array.Type as Array
530
639
core/src/Streamly/Internal/Data/Array.hs+30−5
@@ -74,6 +74,8 @@ module Streamly.Internal.Data.Array
74 , interposeSuffix
74 , interposeSuffix
75 , intercalateSuffix
75 , intercalateSuffix
76
76
77+ , compactLE
78+ , pinnedCompactLE
77 , compactOnByte
79 , compactOnByte
78 , compactOnByteSuffix
80 , compactOnByteSuffix
79
81
@@ -203,6 +205,8 @@ last = getIndexRev 0
203-- Folds with Array as the container
205-- Folds with Array as the container
204-------------------------------------------------------------------------------
206-------------------------------------------------------------------------------
205
207
208+-- XXX We should generate this from Ring.
209+
206-- | @writeLastN n@ folds a maximum of @n@ elements from the end of the input
210-- | @writeLastN n@ folds a maximum of @n@ elements from the end of the input
207-- stream to an 'Array'.
211-- stream to an 'Array'.
208--
212--
@@ -324,6 +328,7 @@ sliceIndexerFromLen from len =
324 Unfold.lmap unsafeThaw (MA.sliceIndexerFromLen from len)
328 Unfold.lmap unsafeThaw (MA.sliceIndexerFromLen from len)
325
329
326{-# DEPRECATED genSlicesFromLen "Please use sliceIndexerFromLen instead." #-}
330{-# DEPRECATED genSlicesFromLen "Please use sliceIndexerFromLen instead." #-}
331+{-# INLINE genSlicesFromLen #-}
327genSlicesFromLen :: forall m a. (Monad m, Unbox a)
332genSlicesFromLen :: forall m a. (Monad m, Unbox a)
328 => Int -- ^ from index
333 => Int -- ^ from index
329 -> Int -- ^ length of the slice
334 -> Int -- ^ length of the slice
@@ -345,6 +350,7 @@ slicerFromLen from len =
345 $ Unfold.lmap unsafeThaw (MA.slicerFromLen from len)
350 $ Unfold.lmap unsafeThaw (MA.slicerFromLen from len)
346
351
347{-# DEPRECATED getSlicesFromLen "Please use slicerFromLen instead." #-}
352{-# DEPRECATED getSlicesFromLen "Please use slicerFromLen instead." #-}
353+{-# INLINE getSlicesFromLen #-}
348getSlicesFromLen :: forall m a. (Monad m, Unbox a)
354getSlicesFromLen :: forall m a. (Monad m, Unbox a)
349 => Int -- ^ from index
355 => Int -- ^ from index
350 -> Int -- ^ length of the slice
356 -> Int -- ^ length of the slice
@@ -395,6 +401,7 @@ indexReader m =
395
401
396-- XXX DO NOT REMOVE, change the signature to use Stream instead of unfold
402-- XXX DO NOT REMOVE, change the signature to use Stream instead of unfold
397{-# DEPRECATED getIndices "Please use getIndices instead." #-}
403{-# DEPRECATED getIndices "Please use getIndices instead." #-}
404+{-# INLINE getIndices #-}
398getIndices :: (Monad m, Unbox a) => Stream m Int -> Unfold m (Array a) a
405getIndices :: (Monad m, Unbox a) => Stream m Int -> Unfold m (Array a) a
399getIndices = indexReader
406getIndices = indexReader
400
407
@@ -445,7 +452,7 @@ runPipe f arr = P.runPipe (toArrayMinChunk (length arr)) $ f (read arr)
445streamTransform :: forall m a b. (MonadIO m, Unbox a, Unbox b)
452streamTransform :: forall m a b. (MonadIO m, Unbox a, Unbox b)
446 => (Stream m a -> Stream m b) -> Array a -> m (Array b)
453 => (Stream m a -> Stream m b) -> Array a -> m (Array b)
447streamTransform f arr =
454streamTransform f arr =
448− Stream.fold (writeWith (length arr)) $ f (read arr)
455+ Stream.fold (createWith (length arr)) $ f (read arr)
449
456
450-------------------------------------------------------------------------------
457-------------------------------------------------------------------------------
451-- Casts
458-- Casts
@@ -498,8 +505,8 @@ cast arr =
498asCStringUnsafe :: Array a -> (CString -> IO b) -> IO b
505asCStringUnsafe :: Array a -> (CString -> IO b) -> IO b
499asCStringUnsafe arr act = do
506asCStringUnsafe arr act = do
500 let arr1 = asBytes arr <> fromList [0]
507 let arr1 = asBytes arr <> fromList [0]
501− -- asPtrUnsafe makes sure the array is pinned
508+ -- unsafePinnedAsPtr makes sure the array is pinned
502− asPtrUnsafe arr1 $ \ptr -> act (castPtr ptr)
509+ unsafePinnedAsPtr arr1 $ \ptr -> act (castPtr ptr)
503
510
504-------------------------------------------------------------------------------
511-------------------------------------------------------------------------------
505-- Folds
512-- Folds
@@ -591,7 +598,7 @@ data FlattenState s =
591-- >>> interposeSuffix x = Stream.interposeSuffix x Array.reader
598-- >>> interposeSuffix x = Stream.interposeSuffix x Array.reader
592--
599--
593{-# INLINE_NORMAL interposeSuffix #-}
600{-# INLINE_NORMAL interposeSuffix #-}
594−interposeSuffix :: forall m a. (MonadIO m, Unbox a)
601+interposeSuffix :: forall m a. (Monad m, Unbox a)
595 => a -> Stream m (Array a) -> Stream m a
602 => a -> Stream m (Array a) -> Stream m a
596-- This does not require MonadIO constraint.
603-- This does not require MonadIO constraint.
597-- interposeSuffix x = D.interposeSuffix x reader
604-- interposeSuffix x = D.interposeSuffix x reader
@@ -612,7 +619,7 @@ interposeSuffix sep (D.Stream step state) = D.Stream step' (OuterLoop state)
612 return $ D.Yield sep $ OuterLoop st
619 return $ D.Yield sep $ OuterLoop st
613
620
614 step' _ (InnerLoop st contents p end) = do
621 step' _ (InnerLoop st contents p end) = do
615− x <- liftIO $ peekAt p contents
622+ x <- pure $ unsafeInlineIO $ peekAt p contents
616 return $ D.Yield x (InnerLoop st contents (INDEX_NEXT(p,a)) end)
623 return $ D.Yield x (InnerLoop st contents (INDEX_NEXT(p,a)) end)
617
624
618-- | Insert the given array after each array and flatten.
625-- | Insert the given array after each array and flatten.
@@ -624,6 +631,24 @@ intercalateSuffix :: (Monad m, Unbox a)
624 => Array a -> Stream m (Array a) -> Stream m a
631 => Array a -> Stream m (Array a) -> Stream m a
625intercalateSuffix = D.intercalateSuffix reader
632intercalateSuffix = D.intercalateSuffix reader
626
633
634+-- | @compactLE n@ coalesces adjacent arrays in the input stream
635+-- only if the combined size would be less than or equal to n.
636+--
637+-- Generates unpinned arrays irrespective of the pinning status of input
638+-- arrays.
639+{-# INLINE_NORMAL compactLE #-}
640+compactLE :: (MonadIO m, Unbox a)
641+ => Int -> Stream m (Array a) -> Stream m (Array a)
642+compactLE n stream =
643+ D.map unsafeFreeze $ MA.compactLE n $ D.map unsafeThaw stream
644+
645+-- | Pinned version of 'compactLE'.
646+{-# INLINE_NORMAL pinnedCompactLE #-}
647+pinnedCompactLE :: (MonadIO m, Unbox a)
648+ => Int -> Stream m (Array a) -> Stream m (Array a)
649+pinnedCompactLE n stream =
650+ D.map unsafeFreeze $ MA.pinnedCompactLE n $ D.map unsafeThaw stream
651+
627-- | Split a stream of arrays on a given separator byte, dropping the separator
652-- | Split a stream of arrays on a given separator byte, dropping the separator
628-- and coalescing all the arrays between two separators into a single array.
653-- and coalescing all the arrays between two separators into a single array.
629--
654--
core/src/Streamly/Internal/Data/Array/Generic.hs+22−6
@@ -11,8 +11,8 @@ module Streamly.Internal.Data.Array.Generic
11
11
12 -- * Construction
12 -- * Construction
13 , nil
13 , nil
14− , writeN
14+ , createOf
15− , write
15+ , create
16 , writeWith
16 , writeWith
17 , writeLastN
17 , writeLastN
18
18
@@ -44,6 +44,10 @@ module Streamly.Internal.Data.Array.Generic
44 , getIndex
44 , getIndex
45 , getSliceUnsafe
45 , getSliceUnsafe
46 , strip
46 , strip
47+
48+ -- * Deprecated
49+ , writeN
50+ , write
47 )
51 )
48where
52where
49
53
@@ -104,21 +108,33 @@ nil = unsafePerformIO $ unsafeFreeze <$> MArray.nil
104-- Construction - Folds
108-- Construction - Folds
105-------------------------------------------------------------------------------
109-------------------------------------------------------------------------------
106
110
107−{-# INLINE_NORMAL writeN #-}
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 #-}
108writeN :: MonadIO m => Int -> Fold m a (Array a)
118writeN :: MonadIO m => Int -> Fold m a (Array a)
109−writeN = fmap unsafeFreeze <$> MArray.writeN
119+writeN = createOf
110
120
111{-# INLINE_NORMAL writeWith #-}
121{-# INLINE_NORMAL writeWith #-}
112writeWith :: MonadIO m => Int -> Fold m a (Array a)
122writeWith :: MonadIO m => Int -> Fold m a (Array a)
113−writeWith elemCount = unsafeFreeze <$> MArray.writeWith elemCount
123+writeWith elemCount = unsafeFreeze <$> MArray.createWith elemCount
114
124
115-- | Fold the whole input to a single array.
125-- | Fold the whole input to a single array.
116--
126--
117-- /Caution! Do not use this on infinite streams./
127-- /Caution! Do not use this on infinite streams./
118--
128--
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." #-}
119{-# INLINE write #-}
135{-# INLINE write #-}
120write :: MonadIO m => Fold m a (Array a)
136write :: MonadIO m => Fold m a (Array a)
121−write = fmap unsafeFreeze MArray.write
137+write = create
122
138
123fromPureStream :: Stream Identity a -> Array a
139fromPureStream :: Stream Identity a -> Array a
124fromPureStream x =
140fromPureStream x =
core/src/Streamly/Internal/Data/Array/Type.hs+131−46
@@ -1,4 +1,8 @@
1{-# LANGUAGE CPP #-}
1{-# 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 #-}
2-- |
6-- |
3-- Module : Streamly.Internal.Data.Array.Type
7-- Module : Streamly.Internal.Data.Array.Type
4-- Copyright : (c) 2020 Composewell Technologies
8-- Copyright : (c) 2020 Composewell Technologies
@@ -28,10 +32,10 @@ module Streamly.Internal.Data.Array.Type
28 , isPinned
32 , isPinned
29
33
30 -- *** Casting
34 -- *** Casting
31− , asPtrUnsafe
35+ , unsafePinnedAsPtr
32
36
33 -- ** Construction
37 -- ** Construction
34− , nil
38+ , empty
35
39
36 -- *** Cloning
40 -- *** Cloning
37 -- XXX Why would we clone an immutable array?
41 -- XXX Why would we clone an immutable array?
@@ -45,15 +49,13 @@ module Streamly.Internal.Data.Array.Type
45
49
46 -- *** Stream Folds
50 -- *** Stream Folds
47 , unsafeMakePure
51 , unsafeMakePure
48− , writeWith
52+ , createOf
49− , writeN
53+ , pinnedCreateOf
50− , pinnedWriteN
54+ , unsafeCreateOf
51− , writeNUnsafe
55+ , unsafePinnedCreateOf
52− , pinnedWriteNUnsafe
56+ , create
53− -- , MA.ArrayUnsafe (..)
57+ , pinnedCreate
54− , pinnedWriteNAligned
58+ , createWith
55− , write
56− , pinnedWrite
57
59
58 -- *** From containers
60 -- *** From containers
59 , fromListN
61 , fromListN
@@ -75,8 +77,8 @@ module Streamly.Internal.Data.Array.Type
75 -- ** Reading
77 -- ** Reading
76
78
77 -- *** Indexing
79 -- *** Indexing
78− , unsafeIndexIO -- XXX rename to getIndexUnsafeIO
80+ , unsafeIndexIO -- XXX unsafeGetIndexIO
79− , getIndexUnsafe
81+ , getIndexUnsafe -- XXX unsafeGetIndex
80
82
81 -- *** To Streams
83 -- *** To Streams
82 , read
84 , read
@@ -123,12 +125,14 @@ module Streamly.Internal.Data.Array.Type
123
125
124 -- *** Compact
126 -- *** Compact
125 -- | Append the arrays in a stream to form a stream of larger arrays.
127 -- | Append the arrays in a stream to form a stream of larger arrays.
126− , compactLE
127 , fCompactGE
128 , fCompactGE
129+ , fPinnedCompactGE
128 , lCompactGE
130 , lCompactGE
131+ , lPinnedCompactGE
129 , compactGE
132 , compactGE
130
133
131 -- ** Deprecated
134 -- ** Deprecated
135+ , asPtrUnsafe
132 , unsafeIndex
136 , unsafeIndex
133 , bufferChunks
137 , bufferChunks
134 , flattenArrays
138 , flattenArrays
@@ -140,6 +144,15 @@ module Streamly.Internal.Data.Array.Type
140 , toStreamDRev
144 , toStreamDRev
141 , toStream
145 , toStream
142 , toStreamRev
146 , toStreamRev
147+ , nil
148+ , writeWith
149+ , writeN
150+ , pinnedWriteN
151+ , writeNUnsafe
152+ , pinnedWriteNUnsafe
153+ , pinnedWriteNAligned
154+ , write
155+ , pinnedWrite
143 )
156 )
144where
157where
145
158
@@ -230,15 +243,20 @@ data Array a =
230
243
231-- | Use an @Array a@ as @Ptr a@.
244-- | Use an @Array a@ as @Ptr a@.
232--
245--
233−-- See 'MA.asPtrUnsafe' in the Mutable array module for more details.
246+-- See 'MA.unsafePinnedAsPtr' in the Mutable array module for more details.
234--
247--
235-- /Unsafe/
248-- /Unsafe/
236--
249--
237-- /Pre-release/
250-- /Pre-release/
238--
251--
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." #-}
239{-# INLINE asPtrUnsafe #-}
257{-# INLINE asPtrUnsafe #-}
240asPtrUnsafe :: MonadIO m => Array a -> (Ptr a -> m b) -> m b
258asPtrUnsafe :: MonadIO m => Array a -> (Ptr a -> m b) -> m b
241−asPtrUnsafe arr = MA.asPtrUnsafe (unsafeThaw arr)
259+asPtrUnsafe = unsafePinnedAsPtr
242
260
243-------------------------------------------------------------------------------
261-------------------------------------------------------------------------------
244-- Freezing and Thawing
262-- Freezing and Thawing
@@ -459,12 +477,13 @@ pinnedChunksOf n str = D.map unsafeFreeze $ MA.pinnedChunksOf n str
459-- >>> concat = Stream.unfoldMany Array.reader
477-- >>> concat = Stream.unfoldMany Array.reader
460--
478--
461{-# INLINE_NORMAL concat #-}
479{-# INLINE_NORMAL concat #-}
462−concat :: (MonadIO m, Unbox a) => Stream m (Array a) -> Stream m a
480+concat :: (Monad m, Unbox a) => Stream m (Array a) -> Stream m a
463-- XXX this requires MonadIO whereas the unfoldMany version does not
481-- XXX this requires MonadIO whereas the unfoldMany version does not
464−concat = MA.concat . D.map unsafeThaw
482+concat = MA.concatWith (pure . unsafeInlineIO) . D.map unsafeThaw
465-- concat = D.unfoldMany reader
483-- concat = D.unfoldMany reader
466
484
467{-# DEPRECATED flattenArrays "Please use \"unfoldMany reader\" instead." #-}
485{-# DEPRECATED flattenArrays "Please use \"unfoldMany reader\" instead." #-}
486+{-# INLINE flattenArrays #-}
468flattenArrays :: forall m a. (MonadIO m, Unbox a)
487flattenArrays :: forall m a. (MonadIO m, Unbox a)
469 => D.Stream m (Array a) -> D.Stream m a
488 => D.Stream m (Array a) -> D.Stream m a
470flattenArrays = concat
489flattenArrays = concat
@@ -475,13 +494,14 @@ flattenArrays = concat
475-- >>> concatRev = Stream.unfoldMany Array.readerRev
494-- >>> concatRev = Stream.unfoldMany Array.readerRev
476--
495--
477{-# INLINE_NORMAL concatRev #-}
496{-# INLINE_NORMAL concatRev #-}
478−concatRev :: forall m a. (MonadIO m, Unbox a)
497+concatRev :: forall m a. (Monad m, Unbox a)
479 => D.Stream m (Array a) -> D.Stream m a
498 => D.Stream m (Array a) -> D.Stream m a
480-- XXX this requires MonadIO whereas the unfoldMany version does not
499-- XXX this requires MonadIO whereas the unfoldMany version does not
481−concatRev = MA.concatRev . D.map unsafeThaw
500+concatRev = MA.concatRevWith (pure . unsafeInlineIO) . D.map unsafeThaw
482-- concatRev = D.unfoldMany readerRev
501-- concatRev = D.unfoldMany readerRev
483
502
484{-# DEPRECATED flattenArraysRev "Please use \"unfoldMany readerRev\" instead." #-}
503{-# DEPRECATED flattenArraysRev "Please use \"unfoldMany readerRev\" instead." #-}
504+{-# INLINE flattenArraysRev #-}
485flattenArraysRev :: forall m a. (MonadIO m, Unbox a)
505flattenArraysRev :: forall m a. (MonadIO m, Unbox a)
486 => D.Stream m (Array a) -> D.Stream m a
506 => D.Stream m (Array a) -> D.Stream m a
487flattenArraysRev = concatRev
507flattenArraysRev = concatRev
@@ -495,26 +515,28 @@ flattenArraysRev = concatRev
495-- arrays would have no capacity to append, therefore, a copy will be forced
515-- arrays would have no capacity to append, therefore, a copy will be forced
496-- anyway.
516-- anyway.
497
517
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−
506-- | Fold @fCompactGE n@ coalesces adjacent arrays in the input stream
518-- | Fold @fCompactGE n@ coalesces adjacent arrays in the input stream
507-- until the size becomes greater than or equal to n.
519-- until the size becomes greater than or equal to n.
508--
520--
521+-- Generates unpinned arrays irrespective of the pinning status of input
522+-- arrays.
509{-# INLINE_NORMAL fCompactGE #-}
523{-# INLINE_NORMAL fCompactGE #-}
510fCompactGE :: (MonadIO m, Unbox a) => Int -> Fold m (Array a) (Array a)
524fCompactGE :: (MonadIO m, Unbox a) => Int -> Fold m (Array a) (Array a)
511fCompactGE n = fmap unsafeFreeze $ Fold.lmap unsafeThaw $ MA.fCompactGE n
525fCompactGE n = fmap unsafeFreeze $ Fold.lmap unsafeThaw $ MA.fCompactGE n
512
526
527+-- | PInned version of 'fCompactGE'.
528+{-# INLINE_NORMAL fPinnedCompactGE #-}
529+fPinnedCompactGE :: (MonadIO m, Unbox a) => Int -> Fold m (Array a) (Array a)
530+fPinnedCompactGE n =
531+ fmap unsafeFreeze $ Fold.lmap unsafeThaw $ MA.fPinnedCompactGE n
532+
513-- | @compactGE n stream@ coalesces adjacent arrays in the @stream@ until
533-- | @compactGE n stream@ coalesces adjacent arrays in the @stream@ until
514-- the size becomes greater than or equal to @n@.
534-- the size becomes greater than or equal to @n@.
515--
535--
516-- >>> compactGE n = Stream.foldMany (Array.fCompactGE n)
536-- >>> compactGE n = Stream.foldMany (Array.fCompactGE n)
517--
537--
538+-- Generates unpinned arrays irrespective of the pinning status of input
539+-- arrays.
518{-# INLINE compactGE #-}
540{-# INLINE compactGE #-}
519compactGE ::
541compactGE ::
520 (MonadIO m, Unbox a)
542 (MonadIO m, Unbox a)
@@ -526,12 +548,21 @@ compactGE n stream =
526--
548--
527-- >>> lCompactGE n = Fold.many (Array.fCompactGE n)
549-- >>> lCompactGE n = Fold.many (Array.fCompactGE n)
528--
550--
551+-- Generates unpinned arrays irrespective of the pinning status of input
552+-- arrays.
529{-# INLINE_NORMAL lCompactGE #-}
553{-# INLINE_NORMAL lCompactGE #-}
530lCompactGE :: (MonadIO m, Unbox a)
554lCompactGE :: (MonadIO m, Unbox a)
531 => Int -> Fold m (Array a) () -> Fold m (Array a) ()
555 => Int -> Fold m (Array a) () -> Fold m (Array a) ()
532lCompactGE n fld =
556lCompactGE n fld =
533 Fold.lmap unsafeThaw $ MA.lCompactGE n (Fold.lmap unsafeFreeze fld)
557 Fold.lmap unsafeThaw $ MA.lCompactGE n (Fold.lmap unsafeFreeze fld)
534
558
559+-- | Pinned version of 'lCompactGE'.
560+{-# INLINE_NORMAL lPinnedCompactGE #-}
561+lPinnedCompactGE :: (MonadIO m, Unbox a)
562+ => Int -> Fold m (Array a) () -> Fold m (Array a) ()
563+lPinnedCompactGE n fld =
564+ Fold.lmap unsafeThaw $ MA.lPinnedCompactGE n (Fold.lmap unsafeFreeze fld)
565+
535-------------------------------------------------------------------------------
566-------------------------------------------------------------------------------
536-- Splitting
567-- Splitting
537-------------------------------------------------------------------------------
568-------------------------------------------------------------------------------
@@ -726,17 +757,28 @@ toList s = build (\c n -> toListFB c n s)
726-- Folds
757-- Folds
727-------------------------------------------------------------------------------
758-------------------------------------------------------------------------------
728
759
729−-- | @writeN n@ folds a maximum of @n@ elements from the input stream to an
760+-- | @createOf n@ folds a maximum of @n@ elements from the input stream to an
730-- 'Array'.
761-- 'Array'.
731--
762--
732−{-# INLINE_NORMAL writeN #-}
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 #-}
733writeN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
770writeN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
734−writeN = fmap unsafeFreeze . MA.writeN
771+writeN = createOf
735
772
736−-- | Like 'fromListN' but creates a pinned array.
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." #-}
737−{-# INLINE_NORMAL pinnedWriteN #-}
779+{-# INLINE pinnedWriteN #-}
738pinnedWriteN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
780pinnedWriteN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (Array a)
739−pinnedWriteN = fmap unsafeFreeze . MA.pinnedWriteN
781+pinnedWriteN = pinnedCreateOf
740
782
741-- | @pinnedWriteNAligned alignment n@ folds a maximum of @n@ elements from the input
783-- | @pinnedWriteNAligned alignment n@ folds a maximum of @n@ elements from the input
742-- stream to an 'Array' aligned to the given size.
784-- stream to an 'Array' aligned to the given size.
@@ -744,44 +786,74 @@ pinnedWriteN = fmap unsafeFreeze . MA.pinnedWriteN
744-- /Pre-release/
786-- /Pre-release/
745--
787--
746{-# INLINE_NORMAL pinnedWriteNAligned #-}
788{-# INLINE_NORMAL pinnedWriteNAligned #-}
789+{-# DEPRECATED pinnedWriteNAligned "To be removed." #-}
747pinnedWriteNAligned :: forall m a. (MonadIO m, Unbox a)
790pinnedWriteNAligned :: forall m a. (MonadIO m, Unbox a)
748 => Int -> Int -> Fold m a (Array a)
791 => Int -> Int -> Fold m a (Array a)
749pinnedWriteNAligned alignSize = fmap unsafeFreeze . MA.pinnedWriteNAligned alignSize
792pinnedWriteNAligned alignSize = fmap unsafeFreeze . MA.pinnedWriteNAligned alignSize
750
793
751−-- | Like 'writeN' but does not check the array bounds when writing. The fold
794+-- | Like 'createOf' but does not check the array bounds when writing. The fold
752-- driver must not call the step function more than 'n' times otherwise it will
795-- driver must not call the step function more than 'n' times otherwise it will
753-- corrupt the memory and crash. This function exists mainly because any
796-- corrupt the memory and crash. This function exists mainly because any
754-- conditional in the step function blocks fusion causing 10x performance
797-- conditional in the step function blocks fusion causing 10x performance
755-- slowdown.
798-- slowdown.
756--
799--
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." #-}
757−{-# INLINE_NORMAL writeNUnsafe #-}
806+{-# INLINE writeNUnsafe #-}
758writeNUnsafe :: forall m a. (MonadIO m, Unbox a)
807writeNUnsafe :: forall m a. (MonadIO m, Unbox a)
759 => Int -> Fold m a (Array a)
808 => Int -> Fold m a (Array a)
760−writeNUnsafe n = unsafeFreeze <$> MA.writeNUnsafe n
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
761
815
816+{-# DEPRECATED pinnedWriteNUnsafe "Please use unsafePinnedCreateOf instead." #-}
762−{-# INLINE_NORMAL pinnedWriteNUnsafe #-}
817+{-# INLINE pinnedWriteNUnsafe #-}
763pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a)
818pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a)
764 => Int -> Fold m a (Array a)
819 => Int -> Fold m a (Array a)
765−pinnedWriteNUnsafe n = unsafeFreeze <$> MA.pinnedWriteNUnsafe n
820+pinnedWriteNUnsafe = unsafePinnedCreateOf
766
821
767−{-# INLINE_NORMAL writeWith #-}
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 #-}
768writeWith :: forall m a. (MonadIO m, Unbox a)
830writeWith :: forall m a. (MonadIO m, Unbox a)
769 => Int -> Fold m a (Array a)
831 => Int -> Fold m a (Array a)
770−-- writeWith n = FL.rmapM spliceArrays $ toArraysOf n
832+writeWith = createWith
771−writeWith elemCount = unsafeFreeze <$> MA.writeWith elemCount
772
833
773-- | Fold the whole input to a single array.
834-- | Fold the whole input to a single array.
774--
835--
775-- /Caution! Do not use this on infinite streams./
836-- /Caution! Do not use this on infinite streams./
776--
837--
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." #-}
777{-# INLINE write #-}
844{-# INLINE write #-}
778write :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
845write :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
779−write = fmap unsafeFreeze MA.write
846+write = create
780
847
781−-- | Like 'write' but creates a pinned array.
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." #-}
782{-# INLINE pinnedWrite #-}
854{-# INLINE pinnedWrite #-}
783pinnedWrite :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
855pinnedWrite :: forall m a. (MonadIO m, Unbox a) => Fold m a (Array a)
784−pinnedWrite = fmap unsafeFreeze MA.pinnedWrite
856+pinnedWrite = pinnedCreate
785
857
786-- | Fold "step" has a dependency on "initial", and each step is dependent on
858-- | Fold "step" has a dependency on "initial", and each step is dependent on
787-- the previous invocation of step due to state passing, finally extract
859-- the previous invocation of step due to state passing, finally extract
@@ -957,11 +1029,16 @@ MK_EQ_INSTANCE(Char)
957MK_EQ_INSTANCE(Word8)
1029MK_EQ_INSTANCE(Word8)
958MK_EQ_INSTANCE(Word16)
1030MK_EQ_INSTANCE(Word16)
959MK_EQ_INSTANCE(Word32)
1031MK_EQ_INSTANCE(Word32)
1032+
1033+-- XXX The Word64 default instance should be as fast because we are comparing
1034+-- 64-bit at a time.
960MK_EQ_INSTANCE(Word64)
1035MK_EQ_INSTANCE(Word64)
961MK_EQ_INSTANCE(Int)
1036MK_EQ_INSTANCE(Int)
962MK_EQ_INSTANCE(Int8)
1037MK_EQ_INSTANCE(Int8)
963MK_EQ_INSTANCE(Int16)
1038MK_EQ_INSTANCE(Int16)
964MK_EQ_INSTANCE(Int32)
1039MK_EQ_INSTANCE(Int32)
1040+
1041+-- XXX The Int64 default instance should be as fast.
965MK_EQ_INSTANCE(Int64)
1042MK_EQ_INSTANCE(Int64)
966
1043
967-- | If the type allows a byte-by-byte comparison this instance can be
1044-- | If the type allows a byte-by-byte comparison this instance can be
@@ -1051,12 +1128,20 @@ instance Foldable Array where
1051instance Unbox a => Semigroup (Array a) where
1128instance Unbox a => Semigroup (Array a) where
1052 arr1 <> arr2 = unsafePerformIO $ splice arr1 arr2
1129 arr1 <> arr2 = unsafePerformIO $ splice arr1 arr2
1053
1130
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." #-}
1054nil ::
1139nil ::
1055#ifdef DEVBUILD
1140#ifdef DEVBUILD
1056 Unbox a =>
1141 Unbox a =>
1057#endif
1142#endif
1058 Array a
1143 Array a
1059−nil = Array Unboxed.nil 0 0
1144+nil = empty
1060
1145
1061instance Unbox a => Monoid (Array a) where
1146instance Unbox a => Monoid (Array a) where
1062 mempty = nil
1147 mempty = nil
core/src/Streamly/Internal/Data/IsMap.hs+4
@@ -1,3 +1,7 @@
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 #-}
1-- |
5-- |
2-- Module : Streamly.Internal.Data.IsMap
6-- Module : Streamly.Internal.Data.IsMap
3-- Copyright : (c) 2022 Composewell Technologies
7-- Copyright : (c) 2022 Composewell Technologies
core/src/Streamly/Internal/Data/MutArray.hs+20−3
@@ -14,6 +14,7 @@ module Streamly.Internal.Data.MutArray
14 , sliceIndexerFromLen
14 , sliceIndexerFromLen
15 , slicerFromLen
15 , slicerFromLen
16 , compactLE
16 , compactLE
17+ , pinnedCompactLE
17 , compactOnByte
18 , compactOnByte
18 , compactOnByteSuffix
19 , compactOnByteSuffix
19 -- * Unboxed IORef
20 -- * Unboxed IORef
@@ -29,6 +30,7 @@ where
29
30
30import Control.Monad.IO.Class (MonadIO(..))
31import Control.Monad.IO.Class (MonadIO(..))
31import Data.Word (Word8)
32import Data.Word (Word8)
33+import Streamly.Internal.Data.MutByteArray.Type (PinnedState(..))
32import Streamly.Internal.Data.Stream.Type (Stream)
34import Streamly.Internal.Data.Stream.Type (Stream)
33import Streamly.Internal.Data.Unbox (Unbox)
35import Streamly.Internal.Data.Unbox (Unbox)
34import Streamly.Internal.Data.Unfold.Type (Unfold(..))
36import Streamly.Internal.Data.Unfold.Type (Unfold(..))
@@ -91,15 +93,30 @@ getSlicesFromLen = slicerFromLen
91-- Compacting Streams of Arrays
93-- Compacting Streams of Arrays
92-------------------------------------------------------------------------------
94-------------------------------------------------------------------------------
93
95
94−-- | Scan @compactLE n@ coalesces adjacent arrays in the input stream
96+-- | @compactLE maxElems@ coalesces adjacent arrays in the input stream
95−-- only if the combined size would be less than or equal to n.
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.
96{-# INLINE compactLE #-}
105{-# INLINE compactLE #-}
97compactLE :: (MonadIO m, Unbox a) =>
106compactLE :: (MonadIO m, Unbox a) =>
98 Int -> Stream m (MutArray a) -> Stream m (MutArray a)
107 Int -> Stream m (MutArray a) -> Stream m (MutArray a)
99-- XXX compactLE can be moved to MutArray/Type if we are not using the parser
108-- XXX compactLE can be moved to MutArray/Type if we are not using the parser
100-- to implement it.
109-- to implement it.
110+compactLE = compactLeAs Unpinned
111+-- The parser version turns out to be a little bit slower.
101-- compactLE n = Stream.catRights . Stream.parseManyD (pCompactLE n)
112-- compactLE n = Stream.catRights . Stream.parseManyD (pCompactLE n)
113+
102−compactLE = rCompactLE
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)
103
120
104data SplitState s arr
121data SplitState s arr
105 = Initial s
122 = Initial s
core/src/Streamly/Internal/Data/MutArray/Generic.hs+59−24
@@ -19,14 +19,14 @@ module Streamly.Internal.Data.MutArray.Generic
19 , nil
19 , nil
20
20
21 -- *** Uninitialized Arrays
21 -- *** Uninitialized Arrays
22− , new
22+ , emptyOf
23 -- , newArrayWith
23 -- , newArrayWith
24
24
25 -- *** From streams
25 -- *** From streams
26− , writeNUnsafe
26+ , unsafeCreateOf
27− , writeN
27+ , createOf
28− , writeWith
28+ , createWith -- createOfMin/createMin/createGE?
29− , write
29+ , create
30 , fromStreamN
30 , fromStreamN
31 , fromStream
31 , fromStream
32 , fromPureStream
32 , fromPureStream
@@ -160,6 +160,13 @@ module Streamly.Internal.Data.MutArray.Generic
160 -- , appendSliceFrom
160 -- , appendSliceFrom
161
161
162 , clone
162 , clone
163+
164+ -- * Deprecated
165+ , new
166+ , writeNUnsafe
167+ , writeN
168+ , writeWith
169+ , write
163 )
170 )
164where
171where
165
172
@@ -236,13 +243,13 @@ bottomElement =
236-- XXX Would be nice if GHC can provide something like newUninitializedArray# so
243-- XXX Would be nice if GHC can provide something like newUninitializedArray# so
237-- that we do not have to write undefined or error in the whole array.
244-- that we do not have to write undefined or error in the whole array.
238
245
239−-- | @new count@ allocates a zero length array that can be extended to hold
246+-- | @emptyOf count@ allocates a zero length array that can be extended to hold
240-- up to 'count' items without reallocating.
247-- up to 'count' items without reallocating.
241--
248--
242-- /Pre-release/
249-- /Pre-release/
243−{-# INLINE new #-}
250+{-# INLINE emptyOf #-}
244−new :: MonadIO m => Int -> m (MutArray a)
251+emptyOf :: MonadIO m => Int -> m (MutArray a)
245−new n@(I# n#) =
252+emptyOf n@(I# n#) =
246 liftIO
253 liftIO
247 $ IO
254 $ IO
248 $ \s# ->
255 $ \s# ->
@@ -251,6 +258,12 @@ new n@(I# n#) =
251 let ma = MutArray arr# 0 0 n
258 let ma = MutArray arr# 0 0 n
252 in (# s1#, ma #)
259 in (# s1#, ma #)
253
260
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+
254-- XXX This could be pure?
267-- XXX This could be pure?
255
268
256-- |
269-- |
@@ -589,16 +602,16 @@ readRev arr@MutArray{..} =
589arrayChunkSize :: Int
602arrayChunkSize :: Int
590arrayChunkSize = 1024
603arrayChunkSize = 1024
591
604
592−-- | Like 'writeN' but does not check the array bounds when writing. The fold
605+-- | Like 'createOf' but does not check the array bounds when writing. The fold
593-- driver must not call the step function more than 'n' times otherwise it will
606-- driver must not call the step function more than 'n' times otherwise it will
594-- corrupt the memory and crash. This function exists mainly because any
607-- corrupt the memory and crash. This function exists mainly because any
595-- conditional in the step function blocks fusion causing 10x performance
608-- conditional in the step function blocks fusion causing 10x performance
596-- slowdown.
609-- slowdown.
597--
610--
598-- /Pre-release/
611-- /Pre-release/
599−{-# INLINE_NORMAL writeNUnsafe #-}
612+{-# INLINE_NORMAL unsafeCreateOf #-}
600−writeNUnsafe :: MonadIO m => Int -> Fold m a (MutArray a)
613+unsafeCreateOf :: MonadIO m => Int -> Fold m a (MutArray a)
601−writeNUnsafe n = Fold step initial return return
614+unsafeCreateOf n = Fold step initial return return
602
615
603 where
616 where
604
617
@@ -606,36 +619,47 @@ writeNUnsafe n = Fold step initial return return
606
619
607 step arr x = FL.Partial <$> snocUnsafe arr x
620 step arr x = FL.Partial <$> snocUnsafe arr x
608
621
622+{-# DEPRECATED writeNUnsafe "Please use unsafeCreateOf instead." #-}
623+{-# INLINE writeNUnsafe #-}
624+writeNUnsafe :: MonadIO m => Int -> Fold m a (MutArray a)
625+writeNUnsafe = unsafeCreateOf
626+
609−-- | @writeN n@ folds a maximum of @n@ elements from the input stream to an
627+-- | @createOf n@ folds a maximum of @n@ elements from the input stream to an
610-- 'Array'.
628-- 'Array'.
611--
629--
612−-- >>> writeN n = Fold.take n (MutArray.writeNUnsafe n)
630+-- >>> createOf n = Fold.take n (MutArray.unsafeCreateOf n)
613--
631--
614-- /Pre-release/
632-- /Pre-release/
615−{-# INLINE_NORMAL writeN #-}
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 #-}
616writeN :: MonadIO m => Int -> Fold m a (MutArray a)
640writeN :: MonadIO m => Int -> Fold m a (MutArray a)
617−writeN n = FL.take n $ writeNUnsafe n
641+writeN = createOf
618
642
619-- >>> f n = MutArray.writeAppendWith (* 2) (MutArray.pinnedNew n)
643-- >>> f n = MutArray.writeAppendWith (* 2) (MutArray.pinnedNew n)
620-- >>> writeWith n = Fold.rmapM MutArray.rightSize (f n)
644-- >>> writeWith n = Fold.rmapM MutArray.rightSize (f n)
621-- >>> writeWith n = Fold.rmapM MutArray.fromArrayStreamK (MutArray.writeChunks n)
645-- >>> writeWith n = Fold.rmapM MutArray.fromArrayStreamK (MutArray.writeChunks n)
622
646
623−-- | @writeWith minCount@ folds the whole input to a single array. The array
647+-- | @createWith minCount@ folds the whole input to a single array. The array
624-- starts at a size big enough to hold minCount elements, the size is doubled
648-- starts at a size big enough to hold minCount elements, the size is doubled
625-- every time the array needs to be grown.
649-- every time the array needs to be grown.
626--
650--
627-- /Caution! Do not use this on infinite streams./
651-- /Caution! Do not use this on infinite streams./
628--
652--
629-- /Pre-release/
653-- /Pre-release/
630−{-# INLINE_NORMAL writeWith #-}
654+{-# INLINE_NORMAL createWith #-}
631−writeWith :: MonadIO m => Int -> Fold m a (MutArray a)
655+createWith :: MonadIO m => Int -> Fold m a (MutArray a)
632-- writeWith n = FL.rmapM rightSize $ writeAppendWith (* 2) (pinnedNew n)
656-- writeWith n = FL.rmapM rightSize $ writeAppendWith (* 2) (pinnedNew n)
633−writeWith elemCount = FL.rmapM extract $ FL.foldlM' step initial
657+createWith elemCount = FL.rmapM extract $ FL.foldlM' step initial
634
658
635 where
659 where
636
660
637 initial = do
661 initial = do
638− when (elemCount < 0) $ error "writeWith: elemCount is negative"
662+ when (elemCount < 0) $ error "createWith: elemCount is negative"
639 new elemCount
663 new elemCount
640
664
641 step arr@(MutArray _ start end bound) x
665 step arr@(MutArray _ start end bound) x
@@ -649,16 +673,27 @@ writeWith elemCount = FL.rmapM extract $ FL.foldlM' step initial
649 -- extract = rightSize
673 -- extract = rightSize
650 extract = return
674 extract = return
651
675
676+{-# DEPRECATED writeWith "Please use createWith instead." #-}
677+{-# INLINE writeWith #-}
678+writeWith :: MonadIO m => Int -> Fold m a (MutArray a)
679+writeWith = createWith
680+
652-- | Fold the whole input to a single array.
681-- | Fold the whole input to a single array.
653--
682--
654−-- Same as 'writeWith' using an initial array size of 'arrayChunkSize' bytes
683+-- Same as 'createWith' using an initial array size of 'arrayChunkSize' bytes
655-- rounded up to the element size.
684-- rounded up to the element size.
656--
685--
657-- /Caution! Do not use this on infinite streams./
686-- /Caution! Do not use this on infinite streams./
658--
687--
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." #-}
659{-# INLINE write #-}
694{-# INLINE write #-}
660write :: MonadIO m => Fold m a (MutArray a)
695write :: MonadIO m => Fold m a (MutArray a)
661−write = writeWith arrayChunkSize
696+write = create
662
697
663-- | Create a 'MutArray' from the first @n@ elements of a stream. The
698-- | Create a 'MutArray' from the first @n@ elements of a stream. The
664-- array is allocated to size @n@, if the stream terminates before @n@
699-- array is allocated to size @n@, if the stream terminates before @n@
core/src/Streamly/Internal/Data/MutArray/Type.hs+429−214
@@ -40,22 +40,22 @@ module Streamly.Internal.Data.MutArray.Type
40
40
41 -- ** Casting
41 -- ** Casting
42 , cast
42 , cast
43− , castUnsafe
43+ , castUnsafe -- XXX unsafeCast
44 , asBytes
44 , asBytes
45− , asPtrUnsafe
45+ , unsafePinnedAsPtr
46− , asUnpinnedPtrUnsafe
46+ , unsafeAsPtr
47
47
48 -- ** Construction
48 -- ** Construction
49− , nil
49+ , empty
50
50
51 -- *** New
51 -- *** New
52 -- | New arrays are always empty arrays with some reserve capacity to
52 -- | New arrays are always empty arrays with some reserve capacity to
53 -- extend the length without reallocating.
53 -- extend the length without reallocating.
54− , new
54+ , emptyOf
55− , newArrayWith
55+ , newArrayWith -- emptyAlignedWith
56− , pinnedNew
56+ , pinnedEmptyOf
57− , pinnedNewBytes
58− , pinnedNewAligned
57+ , pinnedNewAligned -- XXX not required
58+ -- , new -- uninitialized array of specified length
59
59
60 -- *** Cloning
60 -- *** Cloning
61 , clone
61 , clone
@@ -63,27 +63,25 @@ module Streamly.Internal.Data.MutArray.Type
63
63
64 -- *** Slicing
64 -- *** Slicing
65 -- | Get a subarray without copying
65 -- | Get a subarray without copying
66− , getSliceUnsafe
66+ , getSliceUnsafe -- XXX unsafeGetSlice
67 , getSlice
67 , getSlice
68 , splitAt -- XXX should be able to express using getSlice
68 , splitAt -- XXX should be able to express using getSlice
69 , breakOn
69 , breakOn
70
70
71 -- *** Stream Folds
71 -- *** Stream Folds
72 , ArrayUnsafe (..)
72 , ArrayUnsafe (..)
73− , writeNWithUnsafe
73+ , unsafeCreateOfWith
74− , writeNWith
74+ , unsafeCreateOf
75− , writeNUnsafe
75+ , unsafePinnedCreateOf
76− , pinnedWriteNUnsafe
76+ , pinnedCreateOf
77− , writeN
77+ , createOfWith
78− , pinnedWriteN
78+ , createOf
79− , pinnedWriteNAligned
79+ , revCreateOf
80−
80+
81− , writeWith
81+ , pinnedCreate
82− , write
82+ , createWith
83− , pinnedWrite
83+ , create
84−
84+ -- , revCreate
85− , writeRevN
86− -- , writeRev
87
85
88 -- *** From containers
86 -- *** From containers
89 , fromListN
87 , fromListN
@@ -99,11 +97,11 @@ module Streamly.Internal.Data.MutArray.Type
99 , fromByteStr#
97 , fromByteStr#
100 , fromPtrN
98 , fromPtrN
101 , fromChunksK
99 , fromChunksK
102− , fromChunksRealloced
100+ , fromChunksRealloced -- fromSmallChunks
103
101
104 -- ** Random writes
102 -- ** Random writes
105 , putIndex
103 , putIndex
106− , putIndexUnsafe
104+ , putIndexUnsafe -- XXX unsafePutIndex
107 , putIndices
105 , putIndices
108 -- , putFromThenTo
106 -- , putFromThenTo
109 -- , putFrom -- start writing at the given position
107 -- , putFrom -- start writing at the given position
@@ -111,7 +109,7 @@ module Streamly.Internal.Data.MutArray.Type
111 -- , putFromTo
109 -- , putFromTo
112 -- , putFromRev
110 -- , putFromRev
113 -- , putUptoRev
111 -- , putUptoRev
114− , modifyIndexUnsafe
112+ , modifyIndexUnsafe -- XXX unsafeModifyIndex
115 , modifyIndex
113 , modifyIndex
116 , modifyIndices
114 , modifyIndices
117 , modify
115 , modify
@@ -122,9 +120,9 @@ module Streamly.Internal.Data.MutArray.Type
122
120
123 -- *** Indexing
121 -- *** Indexing
124 , getIndex
122 , getIndex
125− , getIndexUnsafe
123+ , getIndexUnsafe -- XXX unsafeGetIndex
126 -- , getFromThenTo
124 -- , getFromThenTo
127− , getIndexRev
125+ , getIndexRev -- getRevIndex?
128 , indexReader
126 , indexReader
129 , indexReaderWith
127 , indexReaderWith
130
128
@@ -195,20 +193,20 @@ module Streamly.Internal.Data.MutArray.Type
195 , snoc
193 , snoc
196 , snocLinear
194 , snocLinear
197 , snocMay
195 , snocMay
198− , snocUnsafe
196+ , snocUnsafe -- XXX unsafeSnoc
199
197
200 -- *** Appending streams
198 -- *** Appending streams
201− , writeAppendNUnsafe
199+ , unsafeAppendN
202− , writeAppendN
200+ , appendN
203− , writeAppendWith
201+ , appendWith
204− , writeAppend
202+ , append
205
203
206 -- *** Appending arrays
204 -- *** Appending arrays
207 , spliceCopy
205 , spliceCopy
208 , spliceWith
206 , spliceWith
209 , splice
207 , splice
210 , spliceExp
208 , spliceExp
211− , spliceUnsafe
209+ , spliceUnsafe -- XXX unsafeSplice
212 -- , putSlice
210 -- , putSlice
213 -- , appendSlice
211 -- , appendSlice
214 -- , appendSliceFrom
212 -- , appendSliceFrom
@@ -216,12 +214,12 @@ module Streamly.Internal.Data.MutArray.Type
216 -- ** Serialization using Unbox
214 -- ** Serialization using Unbox
217 , pokeAppend
215 , pokeAppend
218 , pokeAppendMay
216 , pokeAppendMay
219− , pokeSkipUnsafe
217+ , pokeSkipUnsafe -- unsafePokeSkip
220
218
221 -- ** Deserialization using Unbox
219 -- ** Deserialization using Unbox
222 , peekUncons
220 , peekUncons
223− , peekUnconsUnsafe
221+ , peekUnconsUnsafe -- unsafePeekUncons
224− , peekSkipUnsafe
222+ , peekSkipUnsafe -- unsafePeekSkip
225
223
226 -- Arrays of arrays
224 -- Arrays of arrays
227 -- We can add dimensionality parameter to the array type to get
225 -- We can add dimensionality parameter to the array type to get
@@ -244,6 +242,8 @@ module Streamly.Internal.Data.MutArray.Type
244
242
245 -- *** Concat
243 -- *** Concat
246 -- | Append the arrays in a stream to form a stream of elements.
244 -- | Append the arrays in a stream to form a stream of elements.
245+ , concatWith
246+ , concatRevWith
247 , concat
247 , concat
248 , concatRev
248 , concatRev
249
249
@@ -251,9 +251,12 @@ module Streamly.Internal.Data.MutArray.Type
251 -- | Append the arrays in a stream to form a stream of larger arrays.
251 -- | Append the arrays in a stream to form a stream of larger arrays.
252 , SpliceState (..)
252 , SpliceState (..)
253 , pCompactLE
253 , pCompactLE
254− , rCompactLE
254+ , pPinnedCompactLE
255+ , compactLeAs
255 , fCompactGE
256 , fCompactGE
257+ , fPinnedCompactGE
256 , lCompactGE
258 , lCompactGE
259+ , lPinnedCompactGE
257 , compactGE
260 , compactGE
258 , compactEQ
261 , compactEQ
259
262
@@ -264,6 +267,7 @@ module Streamly.Internal.Data.MutArray.Type
264 , c_memchr
267 , c_memchr
265
268
266 -- * Deprecated
269 -- * Deprecated
270+ , asPtrUnsafe
267 , writeChunks
271 , writeChunks
268 , flattenArrays
272 , flattenArrays
269 , flattenArraysRev
273 , flattenArraysRev
@@ -275,6 +279,25 @@ module Streamly.Internal.Data.MutArray.Type
275 , getIndicesWith
279 , getIndicesWith
276 , resize
280 , resize
277 , resizeExp
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
278 )
301 )
279where
302where
280
303
@@ -456,6 +479,8 @@ isPinned MutArray{..} = Unboxed.isPinned arrContents
456-- we need more than that. See stg_pinnedNewAlignedByteArrayzh and
479-- we need more than that. See stg_pinnedNewAlignedByteArrayzh and
457-- allocatePinned in GHC source.
480-- allocatePinned in GHC source.
458
481
482+-- XXX Rename to emptyAlignedWith, alignSize should be first arg.
483+
459-- | @newArrayWith allocator alignment count@ allocates a new array of zero
484-- | @newArrayWith allocator alignment count@ allocates a new array of zero
460-- length and with a capacity to hold @count@ elements, using @allocator
485-- length and with a capacity to hold @count@ elements, using @allocator
461-- size alignment@ as the memory allocator function.
486-- size alignment@ as the memory allocator function.
@@ -479,12 +504,25 @@ newArrayWith alloc alignSize count = do
479 , arrBound = size
504 , arrBound = size
480 }
505 }
481
506
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." #-}
482nil ::
520nil ::
483#ifdef DEVBUILD
521#ifdef DEVBUILD
484 Unbox a =>
522 Unbox a =>
485#endif
523#endif
486 MutArray a
524 MutArray a
487−nil = MutArray Unboxed.nil 0 0 0
525+nil = empty
488
526
489{-# INLINE newBytesAs #-}
527{-# INLINE newBytesAs #-}
490newBytesAs :: MonadIO m =>
528newBytesAs :: MonadIO m =>
@@ -507,6 +545,7 @@ newBytesAs ps bytes = do
507--
545--
508-- /Pre-release/
546-- /Pre-release/
509{-# INLINE pinnedNewBytes #-}
547{-# INLINE pinnedNewBytes #-}
548+{-# DEPRECATED pinnedNewBytes "Please use pinnedEmptyOf with appropriate calculation" #-}
510pinnedNewBytes :: MonadIO m =>
549pinnedNewBytes :: MonadIO m =>
511#ifdef DEVBUILD
550#ifdef DEVBUILD
512 Unbox a =>
551 Unbox a =>
@@ -531,21 +570,31 @@ newAs ps =
531 (error "new: alignment is not used in unpinned arrays.")
570 (error "new: alignment is not used in unpinned arrays.")
532
571
533-- XXX can unaligned allocation be more efficient when alignment is not needed?
572-- XXX can unaligned allocation be more efficient when alignment is not needed?
534−--
573+
535−-- | Allocates an empty pinned array that can hold 'count' items. The memory of
574+-- | Allocates a pinned array of zero length but growable to the specified
536−-- the array is uninitialized and the allocation is aligned as per the 'Unboxed'
575+-- capacity without reallocation.
537−-- instance of the type.
576+{-# INLINE pinnedEmptyOf #-}
538−--
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." #-}
539{-# INLINE pinnedNew #-}
582{-# INLINE pinnedNew #-}
540pinnedNew :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a)
583pinnedNew :: forall m a. (MonadIO m, Unbox a) => Int -> m (MutArray a)
541−pinnedNew = newAs Pinned
584+pinnedNew = pinnedEmptyOf
542
585
543−-- | Allocates an empty unpinned array that can hold 'count' items. The memory
586+-- | Allocates an unpinned array of zero length but growable to the specified
544−-- of the array is uninitialized.
587+-- capacity without reallocation.
545--
588--
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." #-}
546{-# INLINE new #-}
595{-# INLINE new #-}
547new :: (MonadIO m, Unbox a) => Int -> m (MutArray a)
596new :: (MonadIO m, Unbox a) => Int -> m (MutArray a)
548−new = newAs Unpinned
597+new = emptyOf
549
598
550-------------------------------------------------------------------------------
599-------------------------------------------------------------------------------
551-- Random writes
600-- Random writes
@@ -793,15 +842,15 @@ roundDownTo elemSize size = size - (size `mod` elemSize)
793-- Since this is not inlined Unboxed consrraint leads to dictionary passing
842-- Since this is not inlined Unboxed consrraint leads to dictionary passing
794-- which complicates some inspection tests.
843-- which complicates some inspection tests.
795--
844--
796−{-# NOINLINE reallocExplicit #-}
845+{-# NOINLINE reallocExplicitAs #-}
797−reallocExplicit :: Int -> Int -> MutArray a -> IO (MutArray a)
846+reallocExplicitAs :: PinnedState -> Int -> Int -> MutArray a -> IO (MutArray a)
798−reallocExplicit elemSize newCapacityInBytes MutArray{..} = do
847+reallocExplicitAs ps elemSize newCapacityInBytes MutArray{..} = do
799 assertM(arrEnd <= arrBound)
848 assertM(arrEnd <= arrBound)
800
849
801 -- Allocate new array
850 -- Allocate new array
802 let newCapMaxInBytes = roundUpLargeArray newCapacityInBytes
851 let newCapMaxInBytes = roundUpLargeArray newCapacityInBytes
803 contents <-
852 contents <-
804− if Unboxed.isPinned arrContents
853+ if ps == Pinned
805 then Unboxed.pinnedNew newCapMaxInBytes
854 then Unboxed.pinnedNew newCapMaxInBytes
806 else Unboxed.new newCapMaxInBytes
855 else Unboxed.new newCapMaxInBytes
807 let !(MutByteArray mbarrFrom#) = arrContents
856 let !(MutByteArray mbarrFrom#) = arrContents
@@ -841,7 +890,12 @@ reallocExplicit elemSize newCapacityInBytes MutArray{..} = do
841-- If the original array is pinned, the newly allocated array is also pinned.
890-- If the original array is pinned, the newly allocated array is also pinned.
842{-# INLINABLE realloc #-}
891{-# INLINABLE realloc #-}
843realloc :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m (MutArray a)
892realloc :: forall m a. (MonadIO m, Unbox a) => Int -> MutArray a -> m (MutArray a)
893+realloc bytes arr =
894+ let ps =
895+ if isPinned arr
896+ then Pinned
897+ else Unpinned
844−realloc bytes arr = liftIO $ reallocExplicit (SIZE_OF(a)) bytes arr
898+ in liftIO $ reallocExplicitAs ps (SIZE_OF(a)) bytes arr
845
899
846-- | @reallocWith label capSizer minIncrBytes array@. The label is used
900-- | @reallocWith label capSizer minIncrBytes array@. The label is used
847-- in error messages and the capSizer is used to determine the capacity of the
901-- in error messages and the capSizer is used to determine the capacity of the
@@ -890,6 +944,7 @@ grow nElems arr@MutArray{..} = do
890 else realloc req arr
944 else realloc req arr
891
945
892{-# DEPRECATED resize "Please use grow instead." #-}
946{-# DEPRECATED resize "Please use grow instead." #-}
947+{-# INLINE resize #-}
893resize :: forall m a. (MonadIO m, Unbox a) =>
948resize :: forall m a. (MonadIO m, Unbox a) =>
894 Int -> MutArray a -> m (MutArray a)
949 Int -> MutArray a -> m (MutArray a)
895resize = grow
950resize = grow
@@ -913,6 +968,7 @@ growExp nElems arr@MutArray{..} = do
913 else realloc req1 arr
968 else realloc req1 arr
914
969
915{-# DEPRECATED resizeExp "Please use growExp instead." #-}
970{-# DEPRECATED resizeExp "Please use growExp instead." #-}
971+{-# INLINE resizeExp #-}
916resizeExp :: forall m a. (MonadIO m, Unbox a) =>
972resizeExp :: forall m a. (MonadIO m, Unbox a) =>
917 Int -> MutArray a -> m (MutArray a)
973 Int -> MutArray a -> m (MutArray a)
918resizeExp = growExp
974resizeExp = growExp
@@ -1246,6 +1302,7 @@ indexReaderWith liftio (D.Stream stepi sti) = Unfold step inject
1246 D.Stop -> return D.Stop
1302 D.Stop -> return D.Stop
1247
1303
1248{-# DEPRECATED getIndicesWith "Please use indexReaderWith instead." #-}
1304{-# DEPRECATED getIndicesWith "Please use indexReaderWith instead." #-}
1305+{-# INLINE getIndicesWith #-}
1249getIndicesWith :: (Monad m, Unbox a) =>
1306getIndicesWith :: (Monad m, Unbox a) =>
1250 (forall b. IO b -> m b) -> D.Stream m Int -> Unfold m (MutArray a) a
1307 (forall b. IO b -> m b) -> D.Stream m Int -> Unfold m (MutArray a) a
1251getIndicesWith = indexReaderWith
1308getIndicesWith = indexReaderWith
@@ -1261,6 +1318,7 @@ indexReader = indexReaderWith liftIO
1261
1318
1262-- XXX DO NOT REMOVE, change the signature to use Stream instead of unfold
1319-- XXX DO NOT REMOVE, change the signature to use Stream instead of unfold
1263{-# DEPRECATED getIndices "Please use indexReader instead." #-}
1320{-# DEPRECATED getIndices "Please use indexReader instead." #-}
1321+{-# INLINE getIndices #-}
1264getIndices :: (MonadIO m, Unbox a) => Stream m Int -> Unfold m (MutArray a) a
1322getIndices :: (MonadIO m, Unbox a) => Stream m Int -> Unfold m (MutArray a) a
1265getIndices = indexReader
1323getIndices = indexReader
1266
1324
@@ -1557,7 +1615,7 @@ chunksOfAs ps n (D.Stream step state) =
1557--
1615--
1558-- Same as the following but may be more efficient:
1616-- Same as the following but may be more efficient:
1559--
1617--
1560−-- >>> chunksOf n = Stream.foldMany (MutArray.writeN n)
1618+-- >>> chunksOf n = Stream.foldMany (MutArray.createOf n)
1561--
1619--
1562-- /Pre-release/
1620-- /Pre-release/
1563{-# INLINE_NORMAL chunksOf #-}
1621{-# INLINE_NORMAL chunksOf #-}
@@ -1566,14 +1624,14 @@ chunksOf :: forall m a. (MonadIO m, Unbox a)
1566-- XXX the idiomatic implementation leads to large regression in the D.reverse'
1624-- XXX the idiomatic implementation leads to large regression in the D.reverse'
1567-- benchmark. It seems it has difficulty producing optimized code when
1625-- benchmark. It seems it has difficulty producing optimized code when
1568-- converting to StreamK. Investigate GHC optimizations.
1626-- converting to StreamK. Investigate GHC optimizations.
1569−-- chunksOf n = D.foldMany (writeN n)
1627+-- chunksOf n = D.foldMany (createOf n)
1570chunksOf = chunksOfAs Unpinned
1628chunksOf = chunksOfAs Unpinned
1571
1629
1572-- | Like 'chunksOf' but creates pinned arrays.
1630-- | Like 'chunksOf' but creates pinned arrays.
1573{-# INLINE_NORMAL pinnedChunksOf #-}
1631{-# INLINE_NORMAL pinnedChunksOf #-}
1574pinnedChunksOf :: forall m a. (MonadIO m, Unbox a)
1632pinnedChunksOf :: forall m a. (MonadIO m, Unbox a)
1575 => Int -> D.Stream m a -> D.Stream m (MutArray a)
1633 => Int -> D.Stream m a -> D.Stream m (MutArray a)
1576−-- pinnedChunksOf n = D.foldMany (pinnedWriteN n)
1634+-- pinnedChunksOf n = D.foldMany (pinnedCreateOf n)
1577pinnedChunksOf = chunksOfAs Pinned
1635pinnedChunksOf = chunksOfAs Pinned
1578
1636
1579-- | When we are buffering a stream of unknown size into an array we do not
1637-- | When we are buffering a stream of unknown size into an array we do not
@@ -1606,16 +1664,10 @@ data FlattenState s contents a =
1606 OuterLoop s
1664 OuterLoop s
1607 | InnerLoop s contents !Int !Int
1665 | InnerLoop s contents !Int !Int
1608
1666
1609−-- | Use the "reader" unfold instead.
1610−--
1611−-- @concat = unfoldMany reader@
1612−--
1613−-- We can try this if there are any fusion issues in the unfold.
1614−--
1615−{-# INLINE_NORMAL concat #-}
1667+{-# INLINE_NORMAL concatWith #-}
1616−concat :: forall m a. (MonadIO m, Unbox a)
1668+concatWith :: forall m a. (Monad m, Unbox a)
1617− => D.Stream m (MutArray a) -> D.Stream m a
1669+ => (forall b. IO b -> m b) -> D.Stream m (MutArray a) -> D.Stream m a
1618−concat (D.Stream step state) = D.Stream step' (OuterLoop state)
1670+concatWith liftio (D.Stream step state) = D.Stream step' (OuterLoop state)
1619
1671
1620 where
1672 where
1621
1673
@@ -1632,24 +1684,30 @@ concat (D.Stream step state) = D.Stream step' (OuterLoop state)
1632 return $ D.Skip $ OuterLoop st
1684 return $ D.Skip $ OuterLoop st
1633
1685
1634 step' _ (InnerLoop st contents p end) = do
1686 step' _ (InnerLoop st contents p end) = do
1635− x <- liftIO $ peekAt p contents
1687+ x <- liftio $ peekAt p contents
1636 return $ D.Yield x (InnerLoop st contents (INDEX_NEXT(p,a)) end)
1688 return $ D.Yield x (InnerLoop st contents (INDEX_NEXT(p,a)) end)
1637
1689
1638−{-# DEPRECATED flattenArrays "Please use \"unfoldMany reader\" instead." #-}
1639−flattenArrays :: forall m a. (MonadIO m, Unbox a)
1640− => D.Stream m (MutArray a) -> D.Stream m a
1641−flattenArrays = concat
1642−
1643−-- | Use the "readerRev" unfold instead.
1690+-- | Use the "reader" unfold instead.
1644--
1691--
1645−-- @concat = unfoldMany readerRev@
1692+-- @concat = unfoldMany reader@
1646--
1693--
1647-- We can try this if there are any fusion issues in the unfold.
1694-- We can try this if there are any fusion issues in the unfold.
1648--
1695--
1649−{-# INLINE_NORMAL concatRev #-}
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+
1701+{-# DEPRECATED flattenArrays "Please use \"unfoldMany reader\" instead." #-}
1702+{-# INLINE flattenArrays #-}
1650−concatRev :: forall m a. (MonadIO m, Unbox a)
1703+flattenArrays :: forall m a. (MonadIO m, Unbox a)
1651 => D.Stream m (MutArray a) -> D.Stream m a
1704 => D.Stream m (MutArray a) -> D.Stream m a
1705+flattenArrays = concat
1706+
1707+{-# INLINE_NORMAL concatRevWith #-}
1708+concatRevWith :: forall m a. (Monad m, Unbox a)
1709+ => (forall b. IO b -> m b) -> D.Stream m (MutArray a) -> D.Stream m a
1652−concatRev (D.Stream step state) = D.Stream step' (OuterLoop state)
1710+concatRevWith liftio (D.Stream step state) = D.Stream step' (OuterLoop state)
1653
1711
1654 where
1712 where
1655
1713
@@ -1667,11 +1725,23 @@ concatRev (D.Stream step state) = D.Stream step' (OuterLoop state)
1667 return $ D.Skip $ OuterLoop st
1725 return $ D.Skip $ OuterLoop st
1668
1726
1669 step' _ (InnerLoop st contents p start) = do
1727 step' _ (InnerLoop st contents p start) = do
1670− x <- liftIO $ peekAt p contents
1728+ x <- liftio $ peekAt p contents
1671 let cur = INDEX_PREV(p,a)
1729 let cur = INDEX_PREV(p,a)
1672 return $ D.Yield x (InnerLoop st contents cur start)
1730 return $ D.Yield x (InnerLoop st contents cur start)
1673
1731
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+
1674{-# DEPRECATED flattenArraysRev "Please use \"unfoldMany readerRev\" instead." #-}
1743{-# DEPRECATED flattenArraysRev "Please use \"unfoldMany readerRev\" instead." #-}
1744+{-# INLINE flattenArraysRev #-}
1675flattenArraysRev :: forall m a. (MonadIO m, Unbox a)
1745flattenArraysRev :: forall m a. (MonadIO m, Unbox a)
1676 => D.Stream m (MutArray a) -> D.Stream m a
1746 => D.Stream m (MutArray a) -> D.Stream m a
1677flattenArraysRev = concatRev
1747flattenArraysRev = concatRev
@@ -1903,7 +1973,7 @@ foldr f z arr = D.foldr f z $ read arr
1903
1973
1904-- XXX Keep the bound intact to not lose any free space? Perf impact?
1974-- XXX Keep the bound intact to not lose any free space? Perf impact?
1905
1975
1906−-- | @writeAppendNUnsafe n arr@ appends up to @n@ input items to the supplied
1976+-- | @unsafeAppendN n arr@ appends up to @n@ input items to the supplied
1907-- array.
1977-- array.
1908--
1978--
1909-- Unsafe: Do not drive the fold beyond @n@ elements, it will lead to memory
1979-- Unsafe: Do not drive the fold beyond @n@ elements, it will lead to memory
@@ -1912,13 +1982,12 @@ foldr f z arr = D.foldr f z $ read arr
1912-- Any free space left in the array after appending @n@ elements is lost.
1982-- Any free space left in the array after appending @n@ elements is lost.
1913--
1983--
1914-- /Internal/
1984-- /Internal/
1915−{-# INLINE_NORMAL writeAppendNUnsafe #-}
1985+{-# INLINE_NORMAL unsafeAppendN #-}
1916−writeAppendNUnsafe :: forall m a. (MonadIO m, Unbox a) =>
1986+unsafeAppendN :: forall m a. (MonadIO m, Unbox a) =>
1917 Int
1987 Int
1918 -> m (MutArray a)
1988 -> m (MutArray a)
1919 -> Fold m a (MutArray a)
1989 -> Fold m a (MutArray a)
1920−writeAppendNUnsafe n action =
1921− fmap fromArrayUnsafe $ FL.foldlM' step initial
1990+unsafeAppendN n action = fmap fromArrayUnsafe $ FL.foldlM' step initial
1922
1991
1923 where
1992 where
1924
1993
@@ -1931,7 +2000,7 @@ writeAppendNUnsafe n action =
1931 -- otherwise we lose that space.
2000 -- otherwise we lose that space.
1932 arr1 <-
2001 arr1 <-
1933 if free < needed
2002 if free < needed
1934− then noinline reallocWith "writeAppendNUnsafeWith" (+ needed) needed arr
2003+ then noinline reallocWith "unsafeAppendN" (+ needed) needed arr
1935 else return arr
2004 else return arr
1936 return $ toArrayUnsafe arr1
2005 return $ toArrayUnsafe arr1
1937
2006
@@ -1939,30 +2008,51 @@ writeAppendNUnsafe n action =
1939 liftIO $ pokeAt end contents x
2008 liftIO $ pokeAt end contents x
1940 return $ ArrayUnsafe contents start (INDEX_NEXT(end,a))
2009 return $ ArrayUnsafe contents start (INDEX_NEXT(end,a))
1941
2010
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+
1942-- | Append @n@ elements to an existing array. Any free space left in the array
2019-- | Append @n@ elements to an existing array. Any free space left in the array
1943-- after appending @n@ elements is lost.
2020-- after appending @n@ elements is lost.
1944--
2021--
1945−-- >>> writeAppendN n initial = Fold.take n (MutArray.writeAppendNUnsafe n initial)
2022+-- >>> appendN n initial = Fold.take n (MutArray.unsafeAppendN n initial)
1946--
2023--
1947−{-# INLINE_NORMAL writeAppendN #-}
2024+{-# INLINE_NORMAL appendN #-}
2025+appendN :: forall m a. (MonadIO m, Unbox a) =>
2026+ Int -> m (MutArray a) -> Fold m a (MutArray a)
2027+appendN n initial = FL.take n (unsafeAppendN n initial)
2028+
2029+-- XXX Deprecate in major
2030+-- {-# DEPRECATED writeAppendN "Please use appendN instead." #-}
2031+{-# INLINE writeAppendN #-}
1948writeAppendN :: forall m a. (MonadIO m, Unbox a) =>
2032writeAppendN :: forall m a. (MonadIO m, Unbox a) =>
1949 Int -> m (MutArray a) -> Fold m a (MutArray a)
2033 Int -> m (MutArray a) -> Fold m a (MutArray a)
1950−writeAppendN n initial = FL.take n (writeAppendNUnsafe n initial)
2034+writeAppendN = appendN
1951
2035
1952−-- | @writeAppendWith realloc action@ mutates the array generated by @action@ to
2036+-- | @appendWith realloc action@ mutates the array generated by @action@ to
1953-- append the input stream. If there is no reserved space available in the
2037-- append the input stream. If there is no reserved space available in the
1954-- array it is reallocated to a size in bytes determined by @realloc oldSize@,
2038-- array it is reallocated to a size in bytes determined by @realloc oldSize@,
1955-- where @oldSize@ is the current size of the array in bytes.
2039-- where @oldSize@ is the current size of the array in bytes.
1956--
2040--
1957-- Note that the returned array may be a mutated version of original array.
2041-- Note that the returned array may be a mutated version of original array.
1958--
2042--
1959−-- >>> writeAppendWith sizer = Fold.foldlM' (MutArray.snocWith sizer)
2043+-- >>> appendWith sizer = Fold.foldlM' (MutArray.snocWith sizer)
1960--
2044--
1961-- /Pre-release/
2045-- /Pre-release/
2046+{-# INLINE appendWith #-}
2047+appendWith :: forall m a. (MonadIO m, Unbox a) =>
2048+ (Int -> Int) -> m (MutArray a) -> Fold m a (MutArray a)
2049+appendWith sizer = FL.foldlM' (snocWith sizer)
2050+
2051+{-# DEPRECATED writeAppendWith "Please use appendWith instead." #-}
1962{-# INLINE writeAppendWith #-}
2052{-# INLINE writeAppendWith #-}
1963writeAppendWith :: forall m a. (MonadIO m, Unbox a) =>
2053writeAppendWith :: forall m a. (MonadIO m, Unbox a) =>
1964 (Int -> Int) -> m (MutArray a) -> Fold m a (MutArray a)
2054 (Int -> Int) -> m (MutArray a) -> Fold m a (MutArray a)
1965−writeAppendWith sizer = FL.foldlM' (snocWith sizer)
2055+writeAppendWith = appendWith
1966
2056
1967-- | @append action@ mutates the array generated by @action@ to append the
2057-- | @append action@ mutates the array generated by @action@ to append the
1968-- input stream. If there is no reserved space available in the array it is
2058-- input stream. If there is no reserved space available in the array it is
@@ -1970,26 +2060,33 @@ writeAppendWith sizer = FL.foldlM' (snocWith sizer)
1970--
2060--
1971-- Note that the returned array may be a mutated version of original array.
2061-- Note that the returned array may be a mutated version of original array.
1972--
2062--
1973−-- >>> writeAppend = MutArray.writeAppendWith (* 2)
2063+-- >>> append = MutArray.appendWith (* 2)
1974--
2064--
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." #-}
1975{-# INLINE writeAppend #-}
2072{-# INLINE writeAppend #-}
1976writeAppend :: forall m a. (MonadIO m, Unbox a) =>
2073writeAppend :: forall m a. (MonadIO m, Unbox a) =>
1977 m (MutArray a) -> Fold m a (MutArray a)
2074 m (MutArray a) -> Fold m a (MutArray a)
1978−writeAppend = writeAppendWith (* 2)
2075+writeAppend = append
1979
2076
1980-- XXX We can carry bound as well in the state to make sure we do not lose the
2077-- XXX We can carry bound as well in the state to make sure we do not lose the
1981-- remaining capacity. Need to check perf impact.
2078-- remaining capacity. Need to check perf impact.
1982--
2079--
1983−-- | Like 'writeNUnsafe' but takes a new array allocator @alloc size@ function
2080+-- | Like 'unsafeCreateOf' but takes a new array allocator @alloc size@
1984−-- as argument.
2081+-- function as argument.
1985--
2082--
1986−-- >>> writeNWithUnsafe alloc n = MutArray.writeAppendNUnsafe (alloc n) n
2083+-- >>> unsafeCreateOfWith alloc n = MutArray.unsafeAppendN (alloc n) n
1987--
2084--
1988-- /Pre-release/
2085-- /Pre-release/
1989−{-# INLINE_NORMAL writeNWithUnsafe #-}
2086+{-# INLINE_NORMAL unsafeCreateOfWith #-}
1990−writeNWithUnsafe :: forall m a. (MonadIO m, Unbox a)
2087+unsafeCreateOfWith :: forall m a. (MonadIO m, Unbox a)
1991 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
2088 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
1992−writeNWithUnsafe alloc n = fromArrayUnsafe <$> FL.foldlM' step initial
2089+unsafeCreateOfWith alloc n = fromArrayUnsafe <$> FL.foldlM' step initial
1993
2090
1994 where
2091 where
1995
2092
@@ -2000,40 +2097,64 @@ writeNWithUnsafe alloc n = fromArrayUnsafe <$> FL.foldlM' step initial
2000 return
2097 return
2001 $ ArrayUnsafe contents start (INDEX_NEXT(end,a))
2098 $ ArrayUnsafe contents start (INDEX_NEXT(end,a))
2002
2099
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+
2003{-# INLINE_NORMAL writeNUnsafeAs #-}
2106{-# INLINE_NORMAL writeNUnsafeAs #-}
2004writeNUnsafeAs :: forall m a. (MonadIO m, Unbox a)
2107writeNUnsafeAs :: forall m a. (MonadIO m, Unbox a)
2005 => PinnedState -> Int -> Fold m a (MutArray a)
2108 => PinnedState -> Int -> Fold m a (MutArray a)
2006−writeNUnsafeAs ps = writeNWithUnsafe (newAs ps)
2109+writeNUnsafeAs ps = unsafeCreateOfWith (newAs ps)
2007
2110
2008−-- | Like 'writeN' but does not check the array bounds when writing. The fold
2111+-- | Like 'createOf' but does not check the array bounds when writing. The fold
2009-- driver must not call the step function more than 'n' times otherwise it will
2112-- driver must not call the step function more than 'n' times otherwise it will
2010-- corrupt the memory and crash. This function exists mainly because any
2113-- corrupt the memory and crash. This function exists mainly because any
2011-- conditional in the step function blocks fusion causing 10x performance
2114-- conditional in the step function blocks fusion causing 10x performance
2012-- slowdown.
2115-- slowdown.
2013--
2116--
2014−-- >>> writeNUnsafe = MutArray.writeNWithUnsafe MutArray.new
2117+-- >>> unsafeCreateOf = MutArray.unsafeCreateOfWith MutArray.emptyOf
2015--
2118--
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." #-}
2016−{-# INLINE_NORMAL writeNUnsafe #-}
2125+{-# INLINE writeNUnsafe #-}
2017writeNUnsafe :: forall m a. (MonadIO m, Unbox a)
2126writeNUnsafe :: forall m a. (MonadIO m, Unbox a)
2018 => Int -> Fold m a (MutArray a)
2127 => Int -> Fold m a (MutArray a)
2019−writeNUnsafe = writeNUnsafeAs Unpinned
2128+writeNUnsafe = unsafeCreateOf
2129+
2130+-- | Like 'unsafeCreateOf' but creates a pinned array.
2131+{-# INLINE_NORMAL unsafePinnedCreateOf #-}
2132+unsafePinnedCreateOf :: forall m a. (MonadIO m, Unbox a)
2133+ => Int -> Fold m a (MutArray a)
2134+unsafePinnedCreateOf = writeNUnsafeAs Pinned
2020
2135
2021−-- | Like 'writeNUnsafe' but creates a pinned array.
2136+{-# DEPRECATED pinnedWriteNUnsafe "Please use unsafePinnedCreateOf instead." #-}
2022−{-# INLINE_NORMAL pinnedWriteNUnsafe #-}
2137+{-# INLINE pinnedWriteNUnsafe #-}
2023pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a)
2138pinnedWriteNUnsafe :: forall m a. (MonadIO m, Unbox a)
2024 => Int -> Fold m a (MutArray a)
2139 => Int -> Fold m a (MutArray a)
2025−pinnedWriteNUnsafe = writeNUnsafeAs Pinned
2140+pinnedWriteNUnsafe = unsafePinnedCreateOf
2026
2141
2027−-- | @writeNWith alloc n@ folds a maximum of @n@ elements into an array
2142+-- | @createOfWith alloc n@ folds a maximum of @n@ elements into an array
2028-- allocated using the @alloc@ function.
2143-- allocated using the @alloc@ function.
2029--
2144--
2030−-- >>> writeNWith alloc n = Fold.take n (MutArray.writeNWithUnsafe alloc n)
2145+-- >>> createOfWith alloc n = Fold.take n (MutArray.unsafeCreateOfWith alloc n)
2031−-- >>> writeNWith alloc n = MutArray.writeAppendN (alloc n) n
2146+-- >>> createOfWith alloc n = MutArray.appendN (alloc n) n
2032--
2147--
2033−{-# INLINE_NORMAL writeNWith #-}
2148+{-# INLINE_NORMAL createOfWith #-}
2149+createOfWith :: forall m a. (MonadIO m, Unbox a)
2150+ => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
2151+createOfWith alloc n = FL.take n (unsafeCreateOfWith alloc n)
2152+
2153+-- {-# DEPRECATED writeNWith "Please use createOfWith instead." #-}
2154+{-# INLINE writeNWith #-}
2034writeNWith :: forall m a. (MonadIO m, Unbox a)
2155writeNWith :: forall m a. (MonadIO m, Unbox a)
2035 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
2156 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
2036−writeNWith alloc n = FL.take n (writeNWithUnsafe alloc n)
2157+writeNWith = createOfWith
2037
2158
2038{-# INLINE_NORMAL writeNAs #-}
2159{-# INLINE_NORMAL writeNAs #-}
2039writeNAs ::
2160writeNAs ::
@@ -2041,28 +2162,42 @@ writeNAs ::
2041 => PinnedState
2162 => PinnedState
2042 -> Int
2163 -> Int
2043 -> Fold m a (MutArray a)
2164 -> Fold m a (MutArray a)
2044−writeNAs ps = writeNWith (newAs ps)
2165+writeNAs ps = createOfWith (newAs ps)
2045
2166
2046−-- | @writeN n@ folds a maximum of @n@ elements from the input stream to an
2167+-- | @createOf n@ folds a maximum of @n@ elements from the input stream to an
2047-- 'MutArray'.
2168-- 'MutArray'.
2048--
2169--
2049−-- >>> writeN = MutArray.writeNWith MutArray.new
2170+-- >>> createOf = MutArray.createOfWith MutArray.new
2050−-- >>> writeN n = Fold.take n (MutArray.writeNUnsafe n)
2171+-- >>> createOf n = Fold.take n (MutArray.unsafeCreateOf n)
2051−-- >>> writeN n = MutArray.writeAppendN n (MutArray.new n)
2172+-- >>> createOf n = MutArray.appendN n (MutArray.emptyOf n)
2052--
2173--
2053−{-# INLINE_NORMAL writeN #-}
2174+{-# INLINE_NORMAL createOf #-}
2175+createOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
2176+createOf = writeNAs Unpinned
2177+
2178+-- XXX Deprecate in major
2179+-- {-# DEPRECATED writeN "Please use createOf instead." #-}
2180+{-# INLINE writeN #-}
2054writeN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
2181writeN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
2055−writeN = writeNAs Unpinned
2182+writeN = createOf
2183+
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
2056
2191
2057−-- | Like 'writeN' but creates a pinned array.
2192+{-# DEPRECATED pinnedWriteN "Please use pinnedCreateOf instead." #-}
2058−{-# INLINE_NORMAL pinnedWriteN #-}
2193+{-# INLINE pinnedWriteN #-}
2059pinnedWriteN ::
2194pinnedWriteN ::
2060 forall m a. (MonadIO m, Unbox a)
2195 forall m a. (MonadIO m, Unbox a)
2061 => Int
2196 => Int
2062 -> Fold m a (MutArray a)
2197 -> Fold m a (MutArray a)
2063−pinnedWriteN = writeNAs Pinned
2198+pinnedWriteN = pinnedCreateOf
2064
2199
2065−-- | Like writeNWithUnsafe but writes the array in reverse order.
2200+-- | Like unsafeCreateOfWith but writes the array in reverse order.
2066--
2201--
2067-- /Internal/
2202-- /Internal/
2068{-# INLINE_NORMAL writeRevNWithUnsafe #-}
2203{-# INLINE_NORMAL writeRevNWithUnsafe #-}
@@ -2083,7 +2218,7 @@ writeRevNWithUnsafe alloc n = fromArrayUnsafe <$> FL.foldlM' step initial
2083 return
2218 return
2084 $ ArrayUnsafe contents ptr end
2219 $ ArrayUnsafe contents ptr end
2085
2220
2086−-- | Like writeNWith but writes the array in reverse order.
2221+-- | Like createOfWith but writes the array in reverse order.
2087--
2222--
2088-- /Internal/
2223-- /Internal/
2089{-# INLINE_NORMAL writeRevNWith #-}
2224{-# INLINE_NORMAL writeRevNWith #-}
@@ -2091,31 +2226,36 @@ writeRevNWith :: forall m a. (MonadIO m, Unbox a)
2091 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
2226 => (Int -> m (MutArray a)) -> Int -> Fold m a (MutArray a)
2092writeRevNWith alloc n = FL.take n (writeRevNWithUnsafe alloc n)
2227writeRevNWith alloc n = FL.take n (writeRevNWithUnsafe alloc n)
2093
2228
2094−-- | Like writeN but writes the array in reverse order.
2229+-- | Like 'createOf' but writes the array in reverse order.
2095--
2230--
2096-- /Pre-release/
2231-- /Pre-release/
2097−{-# INLINE_NORMAL writeRevN #-}
2232+{-# INLINE_NORMAL revCreateOf #-}
2233+revCreateOf :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
2234+revCreateOf = writeRevNWith new
2235+
2236+{-# DEPRECATED writeRevN "Please use revCreateOf instead." #-}
2237+{-# INLINE writeRevN #-}
2098writeRevN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
2238writeRevN :: forall m a. (MonadIO m, Unbox a) => Int -> Fold m a (MutArray a)
2099−writeRevN = writeRevNWith new
2239+writeRevN = revCreateOf
2100
2240
2101-- | @pinnedWriteNAligned align n@ folds a maximum of @n@ elements from the
2241-- | @pinnedWriteNAligned align n@ folds a maximum of @n@ elements from the
2102-- input stream to a 'MutArray' aligned to the given size.
2242-- input stream to a 'MutArray' aligned to the given size.
2103--
2243--
2104−-- >>> pinnedWriteNAligned align = MutArray.writeNWith (MutArray.pinnedNewAligned align)
2244+-- >>> pinnedWriteNAligned align = MutArray.createOfWith (MutArray.pinnedNewAligned align)
2105−-- >>> pinnedWriteNAligned align n = MutArray.writeAppendN n (MutArray.pinnedNewAligned align n)
2245+-- >>> pinnedWriteNAligned align n = MutArray.appendN n (MutArray.pinnedNewAligned align n)
2106--
2246--
2107-- /Pre-release/
2247-- /Pre-release/
2108--
2248--
2109{-# INLINE_NORMAL pinnedWriteNAligned #-}
2249{-# INLINE_NORMAL pinnedWriteNAligned #-}
2110pinnedWriteNAligned :: forall m a. (MonadIO m, Unbox a)
2250pinnedWriteNAligned :: forall m a. (MonadIO m, Unbox a)
2111 => Int -> Int -> Fold m a (MutArray a)
2251 => Int -> Int -> Fold m a (MutArray a)
2112−pinnedWriteNAligned align = writeNWith (pinnedNewAligned align)
2252+pinnedWriteNAligned align = createOfWith (pinnedNewAligned align)
2113
2253
2114-- XXX Buffer to a list instead?
2254-- XXX Buffer to a list instead?
2115
2255
2116-- | Buffer a stream into a stream of arrays.
2256-- | Buffer a stream into a stream of arrays.
2117--
2257--
2118−-- >>> buildChunks n = Fold.many (MutArray.writeN n) Fold.toStreamK
2258+-- >>> buildChunks n = Fold.many (MutArray.createOf n) Fold.toStreamK
2119--
2259--
2120-- Breaking an array into an array stream can be useful to consume a large
2260-- Breaking an array into an array stream can be useful to consume a large
2121-- array sequentially such that memory of the array is released incrementatlly.
2261-- array sequentially such that memory of the array is released incrementatlly.
@@ -2127,9 +2267,10 @@ pinnedWriteNAligned align = writeNWith (pinnedNewAligned align)
2127{-# INLINE_NORMAL buildChunks #-}
2267{-# INLINE_NORMAL buildChunks #-}
2128buildChunks :: (MonadIO m, Unbox a) =>
2268buildChunks :: (MonadIO m, Unbox a) =>
2129 Int -> Fold m a (StreamK n (MutArray a))
2269 Int -> Fold m a (StreamK n (MutArray a))
2130−buildChunks n = FL.many (writeN n) FL.toStreamK
2270+buildChunks n = FL.many (createOf n) FL.toStreamK
2131
2271
2132{-# DEPRECATED writeChunks "Please use buildChunks instead." #-}
2272{-# DEPRECATED writeChunks "Please use buildChunks instead." #-}
2273+{-# INLINE writeChunks #-}
2133writeChunks :: (MonadIO m, Unbox a) =>
2274writeChunks :: (MonadIO m, Unbox a) =>
2134 Int -> Fold m a (StreamK n (MutArray a))
2275 Int -> Fold m a (StreamK n (MutArray a))
2135writeChunks = buildChunks
2276writeChunks = buildChunks
@@ -2137,29 +2278,29 @@ writeChunks = buildChunks
2137{-# INLINE_NORMAL writeWithAs #-}
2278{-# INLINE_NORMAL writeWithAs #-}
2138writeWithAs :: forall m a. (MonadIO m, Unbox a)
2279writeWithAs :: forall m a. (MonadIO m, Unbox a)
2139 => PinnedState -> Int -> Fold m a (MutArray a)
2280 => PinnedState -> Int -> Fold m a (MutArray a)
2140−-- writeWithAs ps n = FL.rmapM rightSize $ writeAppendWith (* 2) (newAs ps n)
2281+-- writeWithAs ps n = FL.rmapM rightSize $ appendWith (* 2) (newAs ps n)
2141writeWithAs ps elemCount =
2282writeWithAs ps elemCount =
2142 FL.rmapM extract $ FL.foldlM' step initial
2283 FL.rmapM extract $ FL.foldlM' step initial
2143
2284
2144 where
2285 where
2145
2286
2146 initial = do
2287 initial = do
2147− when (elemCount < 0) $ error "writeWith: elemCount is negative"
2288+ when (elemCount < 0) $ error "createWith: elemCount is negative"
2148 newAs ps elemCount
2289 newAs ps elemCount
2149
2290
2150 step arr@(MutArray _ start end bound) x
2291 step arr@(MutArray _ start end bound) x
2151 | INDEX_NEXT(end,a) > bound = do
2292 | INDEX_NEXT(end,a) > bound = do
2152 let oldSize = end - start
2293 let oldSize = end - start
2153 newSize = max (oldSize * 2) 1
2294 newSize = max (oldSize * 2) 1
2154− arr1 <- liftIO $ reallocExplicit (SIZE_OF(a)) newSize arr
2295+ arr1 <- liftIO $ reallocExplicitAs ps (SIZE_OF(a)) newSize arr
2155 snocUnsafe arr1 x
2296 snocUnsafe arr1 x
2156 step arr x = snocUnsafe arr x
2297 step arr x = snocUnsafe arr x
2157
2298
2158 extract = liftIO . rightSize
2299 extract = liftIO . rightSize
2159
2300
2160−-- XXX Compare writeWith with fromStreamD which uses an array of streams
2301+-- XXX Compare createWith with fromStreamD which uses an array of streams
2161-- implementation. We can write this using buildChunks above if that is faster.
2302-- implementation. We can write this using buildChunks above if that is faster.
2162−-- If writeWith is faster then we should use that to implement
2303+-- If createWith is faster then we should use that to implement
2163-- fromStreamD.
2304-- fromStreamD.
2164--
2305--
2165-- XXX The realloc based implementation needs to make one extra copy if we use
2306-- XXX The realloc based implementation needs to make one extra copy if we use
@@ -2174,39 +2315,56 @@ writeWithAs ps elemCount =
2174-- XXX check if GHC's memory allocator is efficient enough. We can try the C
2315-- XXX check if GHC's memory allocator is efficient enough. We can try the C
2175-- malloc to compare against.
2316-- malloc to compare against.
2176
2317
2177−-- | @writeWith minCount@ folds the whole input to a single array. The array
2318+-- | @createWith minCount@ folds the whole input to a single array. The array
2178-- starts at a size big enough to hold minCount elements, the size is doubled
2319-- starts at a size big enough to hold minCount elements, the size is doubled
2179-- every time the array needs to be grown.
2320-- every time the array needs to be grown.
2180--
2321--
2181-- /Caution! Do not use this on infinite streams./
2322-- /Caution! Do not use this on infinite streams./
2182--
2323--
2183−-- >>> f n = MutArray.writeAppendWith (* 2) (MutArray.new n)
2324+-- >>> f n = MutArray.appendWith (* 2) (MutArray.emptyOf n)
2184−-- >>> writeWith n = Fold.rmapM MutArray.rightSize (f n)
2325+-- >>> createWith n = Fold.rmapM MutArray.rightSize (f n)
2185−-- >>> writeWith n = Fold.rmapM MutArray.fromChunksK (MutArray.buildChunks n)
2326+-- >>> createWith n = Fold.rmapM MutArray.fromChunksK (MutArray.buildChunks n)
2186--
2327--
2187-- /Pre-release/
2328-- /Pre-release/
2188−{-# INLINE_NORMAL writeWith #-}
2329+{-# INLINE_NORMAL createWith #-}
2330+createWith :: forall m a. (MonadIO m, Unbox a)
2331+ => Int -> Fold m a (MutArray a)
2332+-- createWith n = FL.rmapM rightSize $ appendWith (* 2) (emptyOf n)
2333+createWith = writeWithAs Unpinned
2334+
2335+{-# DEPRECATED writeWith "Please use createWith instead." #-}
2336+{-# INLINE writeWith #-}
2189writeWith :: forall m a. (MonadIO m, Unbox a)
2337writeWith :: forall m a. (MonadIO m, Unbox a)
2190 => Int -> Fold m a (MutArray a)
2338 => Int -> Fold m a (MutArray a)
2191−-- writeWith n = FL.rmapM rightSize $ writeAppendWith (* 2) (new n)
2339+writeWith = createWith
2192−writeWith = writeWithAs Unpinned
2193
2340
2194-- | Fold the whole input to a single array.
2341-- | Fold the whole input to a single array.
2195--
2342--
2196−-- Same as 'writeWith' using an initial array size of 'arrayChunkBytes' bytes
2343+-- Same as 'createWith' using an initial array size of 'arrayChunkBytes' bytes
2197-- rounded up to the element size.
2344-- rounded up to the element size.
2198--
2345--
2199-- /Caution! Do not use this on infinite streams./
2346-- /Caution! Do not use this on infinite streams./
2200--
2347--
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." #-}
2201{-# INLINE write #-}
2354{-# INLINE write #-}
2202write :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
2355write :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
2203−write = writeWith (allocBytesToElemCount (undefined :: a) arrayChunkBytes)
2356+write = create
2204
2357
2205−-- | Like 'write' but creates a pinned array.
2358+-- | Like 'create' but creates a pinned array.
2359+{-# INLINE pinnedCreate #-}
2360+pinnedCreate :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
2361+pinnedCreate =
2362+ writeWithAs Pinned (allocBytesToElemCount (undefined :: a) arrayChunkBytes)
2363+
2364+{-# DEPRECATED pinnedWrite "Please use pinnedCreate instead." #-}
2206{-# INLINE pinnedWrite #-}
2365{-# INLINE pinnedWrite #-}
2207pinnedWrite :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
2366pinnedWrite :: forall m a. (MonadIO m, Unbox a) => Fold m a (MutArray a)
2208−pinnedWrite =
2367+pinnedWrite = pinnedCreate
2209− writeWithAs Pinned (allocBytesToElemCount (undefined :: a) arrayChunkBytes)
2210
2368
2211-------------------------------------------------------------------------------
2369-------------------------------------------------------------------------------
2212-- construct from streams, known size
2370-- construct from streams, known size
@@ -2226,17 +2384,18 @@ fromStreamDNAs ps limit str = do
2226 liftIO $ pokeAt ptr arrContents x
2384 liftIO $ pokeAt ptr arrContents x
2227 return $ INDEX_NEXT(ptr,a)
2385 return $ INDEX_NEXT(ptr,a)
2228
2386
2229−-- | Use the 'writeN' fold instead.
2387+-- | Use the 'createOf' fold instead.
2230--
2388--
2231−-- >>> fromStreamN n = Stream.fold (MutArray.writeN n)
2389+-- >>> fromStreamN n = Stream.fold (MutArray.createOf n)
2232--
2390--
2233{-# INLINE_NORMAL fromStreamN #-}
2391{-# INLINE_NORMAL fromStreamN #-}
2234fromStreamN :: forall m a. (MonadIO m, Unbox a)
2392fromStreamN :: forall m a. (MonadIO m, Unbox a)
2235 => Int -> D.Stream m a -> m (MutArray a)
2393 => Int -> D.Stream m a -> m (MutArray a)
2236−-- fromStreamDN n = D.fold (writeN n)
2394+-- fromStreamDN n = D.fold (createOf n)
2237fromStreamN = fromStreamDNAs Unpinned
2395fromStreamN = fromStreamDNAs Unpinned
2238
2396
2239{-# DEPRECATED fromStreamDN "Please use fromStreamN instead." #-}
2397{-# DEPRECATED fromStreamDN "Please use fromStreamN instead." #-}
2398+{-# INLINE fromStreamDN #-}
2240fromStreamDN :: forall m a. (MonadIO m, Unbox a)
2399fromStreamDN :: forall m a. (MonadIO m, Unbox a)
2241 => Int -> D.Stream m a -> m (MutArray a)
2400 => Int -> D.Stream m a -> m (MutArray a)
2242fromStreamDN = fromStreamN
2401fromStreamDN = fromStreamN
@@ -2259,20 +2418,20 @@ pinnedFromListN n xs = fromStreamDNAs Pinned n $ D.fromList xs
2259-- /Pre-release/
2418-- /Pre-release/
2260{-# INLINE fromListRevN #-}
2419{-# INLINE fromListRevN #-}
2261fromListRevN :: (MonadIO m, Unbox a) => Int -> [a] -> m (MutArray a)
2420fromListRevN :: (MonadIO m, Unbox a) => Int -> [a] -> m (MutArray a)
2262−fromListRevN n xs = D.fold (writeRevN n) $ D.fromList xs
2421+fromListRevN n xs = D.fold (revCreateOf n) $ D.fromList xs
2263
2422
2264-- | Convert a pure stream in Identity monad to a mutable array.
2423-- | Convert a pure stream in Identity monad to a mutable array.
2265{-# INLINABLE fromPureStreamN #-}
2424{-# INLINABLE fromPureStreamN #-}
2266fromPureStreamN :: (MonadIO m, Unbox a) =>
2425fromPureStreamN :: (MonadIO m, Unbox a) =>
2267 Int -> Stream Identity a -> m (MutArray a)
2426 Int -> Stream Identity a -> m (MutArray a)
2268fromPureStreamN n xs =
2427fromPureStreamN n xs =
2269− D.fold (writeN n) $ D.morphInner (return . runIdentity) xs
2428+ D.fold (createOf n) $ D.morphInner (return . runIdentity) xs
2270
2429
2271-- | Convert a pure stream in Identity monad to a mutable array.
2430-- | Convert a pure stream in Identity monad to a mutable array.
2272{-# INLINABLE fromPureStream #-}
2431{-# INLINABLE fromPureStream #-}
2273fromPureStream :: (MonadIO m, Unbox a) => Stream Identity a -> m (MutArray a)
2432fromPureStream :: (MonadIO m, Unbox a) => Stream Identity a -> m (MutArray a)
2274fromPureStream xs =
2433fromPureStream xs =
2275− D.fold write $ D.morphInner (return . runIdentity) xs
2434+ D.fold create $ D.morphInner (return . runIdentity) xs
2276
2435
2277{-# INLINABLE fromPtrN #-}
2436{-# INLINABLE fromPtrN #-}
2278fromPtrN :: MonadIO m => Int -> Ptr Word8 -> m (MutArray Word8)
2437fromPtrN :: MonadIO m => Int -> Ptr Word8 -> m (MutArray Word8)
@@ -2281,7 +2440,7 @@ fromPtrN len addr = do
2281 -- XXX We can implement a stream copy in a similar way by streaming Word64
2440 -- XXX We can implement a stream copy in a similar way by streaming Word64
2282 -- first and then remaining Word8.
2441 -- first and then remaining Word8.
2283 arr <- new len
2442 arr <- new len
2284− _ <- asUnpinnedPtrUnsafe arr
2443+ _ <- unsafeAsPtr arr
2285 (\ptr -> liftIO $ c_memcpy ptr addr (fromIntegral len))
2444 (\ptr -> liftIO $ c_memcpy ptr addr (fromIntegral len))
2286 return (arr {arrEnd = len})
2445 return (arr {arrEnd = len})
2287
2446
@@ -2297,7 +2456,7 @@ fromByteStr# addr = do
2297 len <- liftIO $ c_strlen (Ptr addr)
2456 len <- liftIO $ c_strlen (Ptr addr)
2298 let lenInt = fromIntegral len
2457 let lenInt = fromIntegral len
2299 arr <- new lenInt
2458 arr <- new lenInt
2300− _ <- asUnpinnedPtrUnsafe arr (\ptr -> liftIO $ c_memcpy ptr (Ptr addr) len)
2459+ _ <- unsafeAsPtr arr (\ptr -> liftIO $ c_memcpy ptr (Ptr addr) len)
2301 return (arr {arrEnd = lenInt})
2460 return (arr {arrEnd = lenInt})
2302
2461
2303-------------------------------------------------------------------------------
2462-------------------------------------------------------------------------------
@@ -2356,6 +2515,7 @@ fromChunksK :: (Unbox a, MonadIO m) =>
2356fromChunksK = fromChunkskAs Unpinned
2515fromChunksK = fromChunkskAs Unpinned
2357
2516
2358{-# DEPRECATED fromArrayStreamK "Please use fromChunksK instead." #-}
2517{-# DEPRECATED fromArrayStreamK "Please use fromChunksK instead." #-}
2518+{-# INLINE fromArrayStreamK #-}
2359fromArrayStreamK :: (Unbox a, MonadIO m) =>
2519fromArrayStreamK :: (Unbox a, MonadIO m) =>
2360 StreamK m (MutArray a) -> m (MutArray a)
2520 StreamK m (MutArray a) -> m (MutArray a)
2361fromArrayStreamK = fromChunksK
2521fromArrayStreamK = fromChunksK
@@ -2367,7 +2527,7 @@ fromStreamDAs ps m =
2367 arrayStreamKFromStreamDAs Unpinned m >>= fromChunkskAs ps
2527 arrayStreamKFromStreamDAs Unpinned m >>= fromChunkskAs ps
2368
2528
2369-- | Create an 'Array' from a stream. This is useful when we want to create a
2529-- | Create an 'Array' from a stream. This is useful when we want to create a
2370−-- single array from a stream of unknown size. 'writeN' is at least twice
2530+-- single array from a stream of unknown size. 'createOf' is at least twice
2371-- as efficient when the size is already known.
2531-- as efficient when the size is already known.
2372--
2532--
2373-- Note that if the input stream is too large memory allocation for the array
2533-- Note that if the input stream is too large memory allocation for the array
@@ -2379,19 +2539,19 @@ fromStreamDAs ps m =
2379fromStream :: (MonadIO m, Unbox a) => Stream m a -> m (MutArray a)
2539fromStream :: (MonadIO m, Unbox a) => Stream m a -> m (MutArray a)
2380fromStream = fromStreamDAs Unpinned
2540fromStream = fromStreamDAs Unpinned
2381
2541
2382−-- fromStream (Stream m) = P.fold write m
2542+-- fromStream (Stream m) = P.fold create m
2383-- CAUTION: a very large number (millions) of arrays can degrade performance
2543-- CAUTION: a very large number (millions) of arrays can degrade performance
2384-- due to GC overhead because we need to buffer the arrays before we flatten
2544-- due to GC overhead because we need to buffer the arrays before we flatten
2385-- all the arrays.
2545-- all the arrays.
2386--
2546--
2387−-- XXX Compare if this is faster or "fold write".
2547+-- XXX Compare if this is faster or "fold create".
2388--
2548--
2389-- | We could take the approach of doubling the memory allocation on each
2549-- | We could take the approach of doubling the memory allocation on each
2390-- overflow. This would result in more or less the same amount of copying as in
2550-- overflow. This would result in more or less the same amount of copying as in
2391-- the chunking approach. However, if we have to shrink in the end then it may
2551-- the chunking approach. However, if we have to shrink in the end then it may
2392-- result in an extra copy of the entire data.
2552-- result in an extra copy of the entire data.
2393--
2553--
2394−-- >>> fromStreamD = StreamD.fold MutArray.write
2554+-- >>> fromStreamD = StreamD.fold MutArray.create
2395--
2555--
2396{-# INLINE fromStreamD #-}
2556{-# INLINE fromStreamD #-}
2397{-# DEPRECATED fromStreamD "Please use fromStream instead." #-}
2557{-# DEPRECATED fromStreamD "Please use fromStream instead." #-}
@@ -2421,6 +2581,10 @@ fromListRev xs = fromListRevN (Prelude.length xs) xs
2421-- Cloning
2581-- Cloning
2422-------------------------------------------------------------------------------
2582-------------------------------------------------------------------------------
2423
2583
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+
2424{-# INLINE cloneAs #-}
2588{-# INLINE cloneAs #-}
2425cloneAs ::
2589cloneAs ::
2426 ( MonadIO m
2590 ( MonadIO m
@@ -2512,7 +2676,7 @@ spliceWith :: forall m a. (MonadIO m, Unbox a) =>
2512 (Int -> Int -> Int) -> MutArray a -> MutArray a -> m (MutArray a)
2676 (Int -> Int -> Int) -> MutArray a -> MutArray a -> m (MutArray a)
2513spliceWith sizer dst@(MutArray _ start end bound) src = do
2677spliceWith sizer dst@(MutArray _ start end bound) src = do
2514{-
2678{-
2515− let f = writeAppendWith (`sizer` byteLength src) (return dst)
2679+ let f = appendWith (`sizer` byteLength src) (return dst)
2516 in D.fold f (toStreamD src)
2680 in D.fold f (toStreamD src)
2517-}
2681-}
2518 assert (end <= bound) (return ())
2682 assert (end <= bound) (return ())
@@ -2580,7 +2744,7 @@ splitOn predicate arr =
2580{-# INLINE breakOn #-}
2744{-# INLINE breakOn #-}
2581breakOn :: MonadIO m
2745breakOn :: MonadIO m
2582 => Word8 -> MutArray Word8 -> m (MutArray Word8, Maybe (MutArray Word8))
2746 => Word8 -> MutArray Word8 -> m (MutArray Word8, Maybe (MutArray Word8))
2583−breakOn sep arr@MutArray{..} = asUnpinnedPtrUnsafe arr $ \p -> liftIO $ do
2747+breakOn sep arr@MutArray{..} = unsafeAsPtr arr $ \p -> liftIO $ do
2584 -- XXX We do not need memchr here, we can use a Haskell equivalent.
2748 -- XXX We do not need memchr here, we can use a Haskell equivalent.
2585 -- Need efficient stream based primitives that work on Word64.
2749 -- Need efficient stream based primitives that work on Word64.
2586 loc <- c_memchr p sep (fromIntegral $ byteLength arr)
2750 loc <- c_memchr p sep (fromIntegral $ byteLength arr)
@@ -2687,9 +2851,13 @@ cast arr =
2687-- guarantees that unsafe calls will be performed in the calling thread. Making
2851-- guarantees that unsafe calls will be performed in the calling thread. Making
2688-- it safe to pass heap-allocated objects to unsafe functions.
2852-- it safe to pass heap-allocated objects to unsafe functions.
2689
2853
2690−-- Should we just name it asPtr, the unsafety is implicit for any pointer
2854+-- XXX Should we just name it asPtr, the unsafety is implicit for any pointer
2691-- operations. And we are safe from Haskell perspective because we will be
2855-- operations. And we are safe from Haskell perspective because we will be
2692-- pinning the memory.
2856-- 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.
2693
2861
2694-- | Use a @MutArray a@ as @Ptr a@. This is useful when we want to pass an
2862-- | Use a @MutArray a@ as @Ptr a@. This is useful when we want to pass an
2695-- array as a pointer to some operating system call or to a "safe" FFI call.
2863-- array as a pointer to some operating system call or to a "safe" FFI call.
@@ -2707,16 +2875,21 @@ cast arr =
2707--
2875--
2708-- /Pre-release/
2876-- /Pre-release/
2709--
2877--
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." #-}
2710{-# INLINE asPtrUnsafe #-}
2885{-# INLINE asPtrUnsafe #-}
2711asPtrUnsafe :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
2886asPtrUnsafe :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
2712−asPtrUnsafe arr f =
2887+asPtrUnsafe = unsafePinnedAsPtr
2713− Unboxed.asPtrUnsafe
2714− (arrContents arr) (\ptr -> f (ptr `plusPtr` arrStart arr))
2715
2888
2716−{-# INLINE asUnpinnedPtrUnsafe #-}
2889+{-# INLINE unsafeAsPtr #-}
2717−asUnpinnedPtrUnsafe :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
2890+unsafeAsPtr :: MonadIO m => MutArray a -> (Ptr a -> m b) -> m b
2718−asUnpinnedPtrUnsafe arr f =
2891+unsafeAsPtr arr f =
2719− Unboxed.asUnpinnedPtrUnsafe
2892+ Unboxed.unsafeAsPtr
2720 (arrContents arr) (\ptr -> f (ptr `plusPtr` arrStart arr))
2893 (arrContents arr) (\ptr -> f (ptr `plusPtr` arrStart arr))
2721
2894
2722-------------------------------------------------------------------------------
2895-------------------------------------------------------------------------------
@@ -2778,19 +2951,11 @@ byteEq arr1 arr2 = fmap (EQ ==) $ byteCmp arr1 arr2
2778-- can leave some memory unused. They can split the last array to fit it
2951-- can leave some memory unused. They can split the last array to fit it
2779-- exactly in the space.
2952-- exactly in the space.
2780
2953
2781−-- | Parser @pCompactLE maxElems@ coalesces adjacent arrays in the input stream
2782−-- only if the combined size would be less than or equal to @maxElems@
2783−-- elements. Note that it won't split an array if the original array is already
2784−-- larger than maxElems.
2785−--
2786−-- @maxElems@ must be greater than 0.
2787−--
2788−-- /Internal/
2789−{-# INLINE_NORMAL pCompactLE #-}
2954+{-# INLINE_NORMAL pCompactLeAs #-}
2790−pCompactLE ::
2955+pCompactLeAs ::
2791 forall m a. (MonadIO m, Unbox a)
2956 forall m a. (MonadIO m, Unbox a)
2792− => Int -> Parser (MutArray a) m (MutArray a)
2957+ => PinnedState -> Int -> Parser (MutArray a) m (MutArray a)
2793−pCompactLE maxElems = Parser step initial extract
2958+pCompactLeAs ps maxElems = Parser step initial extract
2794
2959
2795 where
2960 where
2796
2961
@@ -2821,7 +2986,8 @@ pCompactLE maxElems = Parser step initial extract
2821 else do
2986 else do
2822 buf1 <-
2987 buf1 <-
2823 if byteCapacity buf < maxBytes
2988 if byteCapacity buf < maxBytes
2989+ then liftIO $ reallocExplicitAs
2824− then realloc maxBytes buf
2990+ ps (SIZE_OF(a)) maxBytes buf
2825 else return buf
2991 else return buf
2826 buf2 <- spliceUnsafe buf1 arr
2992 buf2 <- spliceUnsafe buf1 arr
2827 return $ Parser.Partial 0 (Just buf2)
2993 return $ Parser.Partial 0 (Just buf2)
@@ -2829,6 +2995,30 @@ pCompactLE maxElems = Parser step initial extract
2829 extract Nothing = return $ Parser.Done 0 nil
2995 extract Nothing = return $ Parser.Done 0 nil
2830 extract (Just buf) = return $ Parser.Done 0 buf
2996 extract (Just buf) = return $ Parser.Done 0 buf
2831
2997
2998+-- | Parser @pCompactLE maxElems@ coalesces adjacent arrays in the input stream
2999+-- only if the combined size would be less than or equal to @maxElems@
3000+-- elements. Note that it won't split an array if the original array is already
3001+-- larger than maxElems.
3002+--
3003+-- @maxElems@ must be greater than 0.
3004+--
3005+-- Generates unpinned arrays irrespective of the pinning status of input
3006+-- arrays.
3007+--
3008+-- /Internal/
3009+{-# INLINE pCompactLE #-}
3010+pCompactLE ::
3011+ forall m a. (MonadIO m, Unbox a)
3012+ => Int -> Parser (MutArray a) m (MutArray a)
3013+pCompactLE = pCompactLeAs Unpinned
3014+
3015+-- | Pinned version of 'pCompactLE'.
3016+{-# INLINE pPinnedCompactLE #-}
3017+pPinnedCompactLE ::
3018+ forall m a. (MonadIO m, Unbox a)
3019+ => Int -> Parser (MutArray a) m (MutArray a)
3020+pPinnedCompactLE = pCompactLeAs Pinned
3021+
2832data SpliceState s arr
3022data SpliceState s arr
2833 = SpliceInitial s
3023 = SpliceInitial s
2834 | SpliceBuffering s arr
3024 | SpliceBuffering s arr
@@ -2840,18 +3030,10 @@ data SpliceState s arr
2840-- immutable array never has additional space so a new array is allocated
3030-- immutable array never has additional space so a new array is allocated
2841-- instead of mutating it.
3031-- instead of mutating it.
2842
3032
2843−-- | Scan @rCompactLE maxElems@ coalesces adjacent arrays in the input stream
2844−-- only if the combined size would be less than or equal to @maxElems@
2845−-- elements. Note that it won't split an array if the original array is already
2846−-- larger than maxElems.
2847−--
2848−-- @maxElems@ must be greater than 0.
2849−--
2850−-- /Internal/
2851−{-# INLINE_NORMAL rCompactLE #-}
3033+{-# INLINE_NORMAL compactLeAs #-}
2852−rCompactLE :: forall m a. (MonadIO m, Unbox a)
3034+compactLeAs :: forall m a. (MonadIO m, Unbox a)
2853− => Int -> D.Stream m (MutArray a) -> D.Stream m (MutArray a)
3035+ => PinnedState -> Int -> D.Stream m (MutArray a) -> D.Stream m (MutArray a)
2854−rCompactLE maxElems (D.Stream step state) =
3036+compactLeAs ps maxElems (D.Stream step state) =
2855 D.Stream step' (SpliceInitial state)
3037 D.Stream step' (SpliceInitial state)
2856
3038
2857 where
3039 where
@@ -2887,7 +3069,8 @@ rCompactLE maxElems (D.Stream step state) =
2887 D.Skip (SpliceYielding buf (SpliceBuffering s arr))
3069 D.Skip (SpliceYielding buf (SpliceBuffering s arr))
2888 else do
3070 else do
2889 buf1 <- if byteCapacity buf < maxBytes
3071 buf1 <- if byteCapacity buf < maxBytes
3072+ then liftIO $ reallocExplicitAs
2890− then realloc maxBytes buf
3073+ ps (SIZE_OF(a)) maxBytes buf
2891 else return buf
3074 else return buf
2892 buf2 <- spliceUnsafe buf1 arr
3075 buf2 <- spliceUnsafe buf1 arr
2893 return $ D.Skip (SpliceBuffering s buf2)
3076 return $ D.Skip (SpliceBuffering s buf2)
@@ -2898,14 +3081,12 @@ rCompactLE maxElems (D.Stream step state) =
2898
3081
2899 step' _ (SpliceYielding arr next) = return $ D.Yield arr next
3082 step' _ (SpliceYielding arr next) = return $ D.Yield arr next
2900
3083
2901−-- | Fold @fCompactGE minElems@ coalesces adjacent arrays in the input stream
3084+
2902−-- until the size becomes greater than or equal to @minElems@.
2903−--
2904−{-# INLINE_NORMAL fCompactGE #-}
3085+{-# INLINE_NORMAL fCompactGeAs #-}
2905−fCompactGE ::
3086+fCompactGeAs ::
2906 forall m a. (MonadIO m, Unbox a)
3087 forall m a. (MonadIO m, Unbox a)
2907− => Int -> FL.Fold m (MutArray a) (MutArray a)
3088+ => PinnedState -> Int -> FL.Fold m (MutArray a) (MutArray a)
2908−fCompactGE minElems = Fold step initial extract extract
3089+fCompactGeAs ps minElems = Fold step initial extract extract
2909
3090
2910 where
3091 where
2911
3092
@@ -2933,7 +3114,8 @@ fCompactGE minElems = Fold step initial extract extract
2933 let len = byteLength buf + byteLength arr
3114 let len = byteLength buf + byteLength arr
2934 buf1 <-
3115 buf1 <-
2935 if byteCapacity buf < len
3116 if byteCapacity buf < len
3117+ then liftIO $ reallocExplicitAs
2936− then realloc (max len minBytes) buf
3118+ ps (SIZE_OF(a)) (max minBytes len) buf
2937 else return buf
3119 else return buf
2938 buf2 <- spliceUnsafe buf1 arr
3120 buf2 <- spliceUnsafe buf1 arr
2939 if len >= minBytes
3121 if len >= minBytes
@@ -2943,15 +3125,30 @@ fCompactGE minElems = Fold step initial extract extract
2943 extract Nothing = return nil
3125 extract Nothing = return nil
2944 extract (Just buf) = return buf
3126 extract (Just buf) = return buf
2945
3127
2946−-- | Like 'compactGE' but for transforming folds instead of stream.
3128+-- | Fold @fCompactGE minElems@ coalesces adjacent arrays in the input stream
2947−--
3129+-- until the size becomes greater than or equal to @minElems@.
2948−-- >>> lCompactGE n = Fold.many (MutArray.fCompactGE n)
2949--
3130--
3131+-- Generates unpinned arrays irrespective of the pinning status of input
3132+-- arrays.
3133+{-# INLINE fCompactGE #-}
3134+fCompactGE ::
3135+ forall m a. (MonadIO m, Unbox a)
3136+ => Int -> FL.Fold m (MutArray a) (MutArray a)
3137+fCompactGE = fCompactGeAs Unpinned
3138+
3139+-- | Pinned version of 'fCompactGE'.
3140+{-# INLINE fPinnedCompactGE #-}
3141+fPinnedCompactGE ::
3142+ forall m a. (MonadIO m, Unbox a)
3143+ => Int -> FL.Fold m (MutArray a) (MutArray a)
3144+fPinnedCompactGE = fCompactGeAs Pinned
3145+
2950−{-# INLINE_NORMAL lCompactGE #-}
3146+{-# INLINE_NORMAL lCompactGeAs #-}
2951−lCompactGE :: forall m a. (MonadIO m, Unbox a)
3147+lCompactGeAs :: forall m a. (MonadIO m, Unbox a)
2952− => Int -> Fold m (MutArray a) () -> Fold m (MutArray a) ()
3148+ => PinnedState -> Int -> Fold m (MutArray a) () -> Fold m (MutArray a) ()
2953−-- lCompactGE n = Fold.many (fCompactGE n)
3149+-- The fold version turns out to be a little bit slower.
3150+-- lCompactGeAs ps n = FL.many (fCompactGeAs ps n)
2954−lCompactGE minElems (Fold step1 initial1 _ final1) =
3151+lCompactGeAs ps minElems (Fold step1 initial1 _ final1) =
2955 Fold step initial extract final
3152 Fold step initial extract final
2956
3153
2957 where
3154 where
@@ -2989,7 +3186,8 @@ lCompactGE minElems (Fold step1 initial1 _ final1) =
2989 step (Tuple' (Just buf) r1) arr = do
3186 step (Tuple' (Just buf) r1) arr = do
2990 let len = byteLength buf + byteLength arr
3187 let len = byteLength buf + byteLength arr
2991 buf1 <- if byteCapacity buf < len
3188 buf1 <- if byteCapacity buf < len
3189+ then liftIO $ reallocExplicitAs
2992− then realloc (max minBytes len) buf
3190+ ps (SIZE_OF(a)) (max minBytes len) buf
2993 else return buf
3191 else return buf
2994 buf2 <- spliceUnsafe buf1 arr
3192 buf2 <- spliceUnsafe buf1 arr
2995 runInner len r1 buf2
3193 runInner len r1 buf2
@@ -3009,6 +3207,23 @@ lCompactGE minElems (Fold step1 initial1 _ final1) =
3009 FL.Partial rr -> final1 rr
3207 FL.Partial rr -> final1 rr
3010 FL.Done _ -> return ()
3208 FL.Done _ -> return ()
3011
3209
3210+-- | Like 'compactGE' but for transforming folds instead of stream.
3211+--
3212+-- >>> lCompactGE n = Fold.many (MutArray.fCompactGE n)
3213+--
3214+-- Generates unpinned arrays irrespective of the pinning status of input
3215+-- arrays.
3216+{-# INLINE lCompactGE #-}
3217+lCompactGE :: forall m a. (MonadIO m, Unbox a)
3218+ => Int -> Fold m (MutArray a) () -> Fold m (MutArray a) ()
3219+lCompactGE = lCompactGeAs Unpinned
3220+
3221+-- | Pinned version of 'lCompactGE'.
3222+{-# INLINE lPinnedCompactGE #-}
3223+lPinnedCompactGE :: forall m a. (MonadIO m, Unbox a)
3224+ => Int -> Fold m (MutArray a) () -> Fold m (MutArray a) ()
3225+lPinnedCompactGE = lCompactGeAs Pinned
3226+
3012-- | @compactGE n stream@ coalesces adjacent arrays in the @stream@ until
3227-- | @compactGE n stream@ coalesces adjacent arrays in the @stream@ until
3013-- the size becomes greater than or equal to @n@.
3228-- the size becomes greater than or equal to @n@.
3014--
3229--
core/src/Streamly/Internal/Data/MutByteArray/Type.hs+35−16
@@ -13,7 +13,7 @@ module Streamly.Internal.Data.MutByteArray.Type
13 -- ** MutByteArray
13 -- ** MutByteArray
14 MutByteArray(..)
14 MutByteArray(..)
15 , MutableByteArray
15 , MutableByteArray
16− , getMutableByteArray#
16+ , getMutableByteArray# -- XXX getMutByteArray#
17
17
18 -- ** Pinning
18 -- ** Pinning
19 , PinnedState(..)
19 , PinnedState(..)
@@ -22,20 +22,24 @@ module Streamly.Internal.Data.MutByteArray.Type
22 , unpin
22 , unpin
23
23
24 -- ** Allocation
24 -- ** Allocation
25− , nil
25+ , empty
26− , newBytesAs
26+ , newBytesAs -- XXX should be removed
27 , new
27 , new
28 , pinnedNew
28 , pinnedNew
29− , pinnedNewAlignedBytes
29+ , pinnedNewAlignedBytes -- XXX should be removed
30
30
31 -- ** Access
31 -- ** Access
32− , sizeOfMutableByteArray
32+ , sizeOfMutableByteArray -- XXX length
33 , putSliceUnsafe
33 , putSliceUnsafe
34 , cloneSliceUnsafeAs
34 , cloneSliceUnsafeAs
35 , cloneSliceUnsafe
35 , cloneSliceUnsafe
36 , pinnedCloneSliceUnsafe
36 , pinnedCloneSliceUnsafe
37+ , unsafePinnedAsPtr
38+ , unsafeAsPtr
39+
40+ -- ** Deprecated
37 , asPtrUnsafe
41 , asPtrUnsafe
38− , asUnpinnedPtrUnsafe
42+ , nil
39 ) where
43 ) where
40
44
41import Control.Monad.IO.Class (MonadIO(..))
45import Control.Monad.IO.Class (MonadIO(..))
@@ -54,7 +58,7 @@ import GHC.Exts
54
58
55data PinnedState
59data PinnedState
56 = Pinned
60 = Pinned
57− | Unpinned
61+ | Unpinned deriving (Show, Eq)
58
62
59-- XXX can use UnliftedNewtypes
63-- XXX can use UnliftedNewtypes
60
64
@@ -114,9 +118,9 @@ touch (MutByteArray contents) =
114--
118--
115-- /Pre-release/
119-- /Pre-release/
116--
120--
117−{-# INLINE asPtrUnsafe #-}
121+{-# INLINE unsafePinnedAsPtr #-}
118−asPtrUnsafe :: MonadIO m => MutByteArray -> (Ptr a -> m b) -> m b
122+unsafePinnedAsPtr :: MonadIO m => MutByteArray -> (Ptr a -> m b) -> m b
119−asPtrUnsafe arr f = do
123+unsafePinnedAsPtr arr f = do
120 contents <- liftIO $ pin arr
124 contents <- liftIO $ pin arr
121 let !ptr = Ptr (byteArrayContents#
125 let !ptr = Ptr (byteArrayContents#
122 (unsafeCoerce# (getMutableByteArray# contents)))
126 (unsafeCoerce# (getMutableByteArray# contents)))
@@ -124,10 +128,15 @@ asPtrUnsafe arr f = do
124 liftIO $ touch contents
128 liftIO $ touch contents
125 return r
129 return r
126
130
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+
127-- | For use with unsafe FFI functions. Does not force pin the array memory.
136-- | For use with unsafe FFI functions. Does not force pin the array memory.
128−{-# INLINE asUnpinnedPtrUnsafe #-}
137+{-# INLINE unsafeAsPtr #-}
129−asUnpinnedPtrUnsafe :: MonadIO m => MutByteArray -> (Ptr a -> m b) -> m b
138+unsafeAsPtr :: MonadIO m => MutByteArray -> (Ptr a -> m b) -> m b
130−asUnpinnedPtrUnsafe arr f = do
139+unsafeAsPtr arr f = do
131 let !ptr = Ptr (byteArrayContents#
140 let !ptr = Ptr (byteArrayContents#
132 (unsafeCoerce# (getMutableByteArray# arr)))
141 (unsafeCoerce# (getMutableByteArray# arr)))
133 r <- f ptr
142 r <- f ptr
@@ -138,9 +147,13 @@ asUnpinnedPtrUnsafe arr f = do
138-- Creation
147-- Creation
139--------------------------------------------------------------------------------
148--------------------------------------------------------------------------------
140
149
141−{-# NOINLINE nil #-}
150+{-# NOINLINE empty #-}
151+empty :: MutByteArray
152+empty = unsafePerformIO $ new 0
153+
154+{-# DEPRECATED nil "Please use empty instead" #-}
142nil :: MutByteArray
155nil :: MutByteArray
143−nil = unsafePerformIO $ new 0
156+nil = empty
144
157
145-- XXX add "newRounded" to round up the large size to the next page boundary
158-- XXX add "newRounded" to round up the large size to the next page boundary
146-- and return the allocated size.
159-- and return the allocated size.
@@ -157,7 +170,7 @@ new (I# nbytes) = IO $ \s ->
157{-# INLINE pinnedNew #-}
170{-# INLINE pinnedNew #-}
158pinnedNew :: Int -> IO MutByteArray
171pinnedNew :: Int -> IO MutByteArray
159pinnedNew nbytes | nbytes < 0 =
172pinnedNew nbytes | nbytes < 0 =
160− errorWithoutStackTrace "pinnedNewByteArray: size must be >= 0"
173+ errorWithoutStackTrace "pinnedNew: size must be >= 0"
161pinnedNew (I# nbytes) = IO $ \s ->
174pinnedNew (I# nbytes) = IO $ \s ->
162 case newPinnedByteArray# nbytes s of
175 case newPinnedByteArray# nbytes s of
163 (# s', mbarr# #) ->
176 (# s', mbarr# #) ->
@@ -183,6 +196,12 @@ newBytesAs Pinned = pinnedNew
183-- Copying
196-- Copying
184-------------------------------------------------------------------------------
197-------------------------------------------------------------------------------
185
198
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+
186-- | Put a sub range of a source array into a subrange of a destination array.
205-- | Put a sub range of a source array into a subrange of a destination array.
187-- This is not safe as it does not check the bounds of neither the src array
206-- This is not safe as it does not check the bounds of neither the src array
188-- nor the destination array.
207-- nor the destination array.
core/src/Streamly/Internal/Data/Serialize/TH.hs+5−1
@@ -7,7 +7,11 @@
7-- Maintainer : streamly@composewell.com
7-- Maintainer : streamly@composewell.com
8-- Stability : experimental
8-- Stability : experimental
9-- Portability : GHC
9-- Portability : GHC
10−--
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+
11module Streamly.Internal.Data.Serialize.TH
15module Streamly.Internal.Data.Serialize.TH
12 (
16 (
13 -- Deriving
17 -- Deriving
core/src/Streamly/Internal/Data/Stream/Container.hs+56−48
@@ -11,16 +11,17 @@
11
11
12module Streamly.Internal.Data.Stream.Container
12module Streamly.Internal.Data.Stream.Container
13 (
13 (
14− nub
14+ -- * Deduplication
15+ ordNub
15
16
16− -- * Joins for unconstrained types
17+ -- * Joins
17− , joinLeftGeneric
18+ , leftJoin
18− , joinOuterGeneric
19+ , outerJoin
19
20
20− -- * Joins with Ord constraint
21+ -- * Ord Joins
21− , joinInner
22+ , innerOrdJoin
22− , joinLeft
23+ , leftOrdJoin
23− , joinOuter
24+ , outerOrdJoin
24 )
25 )
25where
26where
26
27
@@ -47,12 +48,15 @@ import qualified Streamly.Internal.Data.Stream.Transformer as Stream
47
48
48#include "DocTestDataStream.hs"
49#include "DocTestDataStream.hs"
49
50
51+-- | @nub@ specialized to 'Ord' types for better performance. Returns a
52+-- subsequence of the stream removing any duplicate elements.
53+--
50−-- | The memory used is proportional to the number of unique elements in the
54+-- 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
55+-- stream. One way to limit the memory is to use @take@ on the resulting
52−-- uniq elements in the stream.
56+-- stream to limit the unique elements in the stream.
53−{-# INLINE_NORMAL nub #-}
57+{-# INLINE_NORMAL ordNub #-}
54−nub :: (Monad m, Ord a) => Stream m a -> Stream m a
58+ordNub :: (Monad m, Ord a) => Stream m a -> Stream m a
55−nub (Stream step1 state1) = Stream step (Set.empty, state1)
59+ordNub (Stream step1 state1) = Stream step (Set.empty, state1)
56
60
57 where
61 where
58
62
@@ -78,8 +82,8 @@ toMap =
78--
82--
79-- XXX An IntMap may be faster when the keys are Int.
83-- XXX An IntMap may be faster when the keys are Int.
80-- XXX Use hashmap instead of map?
84-- XXX Use hashmap instead of map?
81−--
85+
82−-- | Like 'joinInner' but uses a 'Map' for efficiency.
86+-- | 'innerJoin' specialized to 'Ord' types for better performance.
83--
87--
84-- If the input streams have duplicate keys, the behavior is undefined.
88-- If the input streams have duplicate keys, the behavior is undefined.
85--
89--
@@ -90,10 +94,10 @@ toMap =
90-- Time: O(m + n)
94-- Time: O(m + n)
91--
95--
92-- /Pre-release/
96-- /Pre-release/
93−{-# INLINE joinInner #-}
97+{-# INLINE innerOrdJoin #-}
94−joinInner :: (Monad m, Ord k) =>
98+innerOrdJoin :: (Monad m, Ord k) =>
95 Stream m (k, a) -> Stream m (k, b) -> Stream m (k, a, b)
99 Stream m (k, a) -> Stream m (k, b) -> Stream m (k, a, b)
96−joinInner s1 s2 =
100+innerOrdJoin s1 s2 =
97 Stream.concatEffect $ do
101 Stream.concatEffect $ do
98 km <- toMap s2
102 km <- toMap s2
99 pure $ Stream.mapMaybe (joinAB km) s1
103 pure $ Stream.mapMaybe (joinAB km) s1
@@ -106,32 +110,33 @@ joinInner s1 s2 =
106 Nothing -> Nothing
110 Nothing -> Nothing
107
111
108-- XXX We can do this concurrently.
112-- XXX We can do this concurrently.
113+-- XXX Check performance of StreamD vs StreamK
109-- XXX If the second stream is sorted and passed as an Array or a seek capable
114-- XXX If the second stream is sorted and passed as an Array or a seek capable
110-- stream then we could use binary search if we have an Ord instance or
115-- stream then we could use binary search if we have an Ord instance or
111-- Ordering returning function. The time complexity would then become (m x log
116-- Ordering returning function. The time complexity would then become (m x log
112-- n).
117-- n).
113
118
114−-- XXX Check performance of StreamD vs StreamK
119+-- | Like 'innerJoin' but emits @(a, Just b)@ whenever a and b are equal, for
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)@.
120+-- those @a@'s that are not equal to any @b@ emits @(a, Nothing)@.
118--
121--
119−-- The second stream is evaluated multiple times. If the stream is a
122+-- This is a generalization of 'innerJoin' to include all elements from the
120−-- consume-once stream then the caller should cache it in an 'Data.Array.Array'
123+-- left stream and not just those which have an equal in the right stream. This
121−-- before calling this function. Caching may also improve performance if the
124+-- is not a commutative operation, the order of the stream arguments matters.
122−-- stream is expensive to evaluate.
123--
125--
124−-- >>> joinRightGeneric eq = flip (Stream.joinLeftGeneric eq)
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:
128+--
129+-- >>> rightJoin eq = flip (Stream.leftJoin eq)
125--
130--
126-- Space: O(n) assuming the second stream is cached in memory.
131-- Space: O(n) assuming the second stream is cached in memory.
127--
132--
128-- Time: O(m x n)
133-- Time: O(m x n)
129--
134--
130-- /Unimplemented/
135-- /Unimplemented/
131−{-# INLINE joinLeftGeneric #-}
136+{-# INLINE leftJoin #-}
132−joinLeftGeneric :: Monad m =>
137+leftJoin :: Monad m =>
133 (a -> b -> Bool) -> Stream m a -> Stream m b -> Stream m (a, Maybe b)
138 (a -> b -> Bool) -> Stream m a -> Stream m b -> Stream m (a, Maybe b)
134−joinLeftGeneric eq s1 s2 = Stream.evalStateT (return False) $ unCross $ do
139+leftJoin eq s1 s2 = Stream.evalStateT (return False) $ unCross $ do
135 a <- mkCross (Stream.liftInner s1)
140 a <- mkCross (Stream.liftInner s1)
136 -- XXX should we use StreamD monad here?
141 -- XXX should we use StreamD monad here?
137 -- XXX Is there a better way to perform some action at the end of a loop
142 -- XXX Is there a better way to perform some action at the end of a loop
@@ -152,19 +157,17 @@ joinLeftGeneric eq s1 s2 = Stream.evalStateT (return False) $ unCross $ do
152 else mkCross Stream.nil
157 else mkCross Stream.nil
153 Nothing -> return (a, Nothing)
158 Nothing -> return (a, Nothing)
154
159
155−-- XXX rename to joinLeftOrd?
160+-- | 'leftJoin' specialized to 'Ord' types for better performance.
156−
157−-- | A more efficient 'joinLeft' using a hashmap for efficiency.
158--
161--
159-- Space: O(n)
162-- Space: O(n)
160--
163--
161-- Time: O(m + n)
164-- Time: O(m + n)
162--
165--
163-- /Pre-release/
166-- /Pre-release/
164−{-# INLINE joinLeft #-}
167+{-# INLINE leftOrdJoin #-}
165−joinLeft :: (Ord k, Monad m) =>
168+leftOrdJoin :: (Ord k, Monad m) =>
166 Stream m (k, a) -> Stream m (k, b) -> Stream m (k, a, Maybe b)
169 Stream m (k, a) -> Stream m (k, b) -> Stream m (k, a, Maybe b)
167−joinLeft s1 s2 =
170+leftOrdJoin s1 s2 =
168 Stream.concatEffect $ do
171 Stream.concatEffect $ do
169 km <- toMap s2
172 km <- toMap s2
170 return $ fmap (joinAB km) s1
173 return $ fmap (joinAB km) s1
@@ -177,14 +180,19 @@ joinLeft s1 s2 =
177 Nothing -> (k, a, Nothing)
180 Nothing -> (k, a, Nothing)
178
181
179-- XXX We can do this concurrently.
182-- XXX We can do this concurrently.
183+-- XXX Check performance of StreamD vs StreamK cross operation.
180
184
181−-- XXX Check performance of StreamD vs StreamK
182−
183−-- | Like 'joinLeft' but emits a @(Just a, Just b)@. Like 'joinLeft', for those
185+-- | Like 'leftJoin' but emits a @(Just a, Just b)@. Like 'leftJoin', for those
184-- @a@'s that are not equal to any @b@ emit @(Just a, Nothing)@, but
186-- @a@'s that are not equal to any @b@ emit @(Just a, Nothing)@, but
185-- additionally, for those @b@'s that are not equal to any @a@ emit @(Nothing,
187-- additionally, for those @b@'s that are not equal to any @a@ emit @(Nothing,
186-- Just b)@.
188-- Just b)@.
187--
189--
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+--
188-- For space efficiency use the smaller stream as the second stream.
196-- For space efficiency use the smaller stream as the second stream.
189--
197--
190-- Space: O(n)
198-- Space: O(n)
@@ -192,15 +200,15 @@ joinLeft s1 s2 =
192-- Time: O(m x n)
200-- Time: O(m x n)
193--
201--
194-- /Pre-release/
202-- /Pre-release/
195−{-# INLINE joinOuterGeneric #-}
203+{-# INLINE outerJoin #-}
196−joinOuterGeneric :: MonadIO m =>
204+outerJoin :: MonadIO m =>
197 (a -> b -> Bool)
205 (a -> b -> Bool)
198 -> Stream m a
206 -> Stream m a
199 -> Stream m b
207 -> Stream m b
200 -> Stream m (Maybe a, Maybe b)
208 -> Stream m (Maybe a, Maybe b)
201−joinOuterGeneric eq s1 s =
209+outerJoin eq s1 s2 =
202 Stream.concatEffect $ do
210 Stream.concatEffect $ do
203− inputArr <- Array.fromStream s
211+ inputArr <- Array.fromStream s2
204 let len = Array.length inputArr
212 let len = Array.length inputArr
205 foundArr <-
213 foundArr <-
206 Stream.fold
214 Stream.fold
@@ -254,18 +262,18 @@ joinOuterGeneric eq s1 s =
254-- a flag. At the end go through @Stream m b@ and find those that are not in that
262-- a flag. At the end go through @Stream m b@ and find those that are not in that
255-- hash to return (Nothing, b).
263-- hash to return (Nothing, b).
256
264
257−-- | Like 'joinOuter' but uses a 'Map' for efficiency.
265+-- | 'outerJoin' specialized to 'Ord' types for better performance.
258--
266--
259-- Space: O(m + n)
267-- Space: O(m + n)
260--
268--
261-- Time: O(m + n)
269-- Time: O(m + n)
262--
270--
263-- /Pre-release/
271-- /Pre-release/
264−{-# INLINE joinOuter #-}
272+{-# INLINE outerOrdJoin #-}
265−joinOuter ::
273+outerOrdJoin ::
266 (Ord k, MonadIO m) =>
274 (Ord k, MonadIO m) =>
267 Stream m (k, a) -> Stream m (k, b) -> Stream m (k, Maybe a, Maybe b)
275 Stream m (k, a) -> Stream m (k, b) -> Stream m (k, Maybe a, Maybe b)
268−joinOuter s1 s2 =
276+outerOrdJoin s1 s2 =
269 Stream.concatEffect $ do
277 Stream.concatEffect $ do
270 km1 <- kvFold s1
278 km1 <- kvFold s1
271 km2 <- kvFold s2
279 km2 <- kvFold s2
core/src/Streamly/Internal/Data/Stream/Eliminate.hs+33−25
@@ -13,36 +13,24 @@
13--
13--
14module Streamly.Internal.Data.Stream.Eliminate
14module Streamly.Internal.Data.Stream.Eliminate
15 (
15 (
16− -- * Running a 'Fold'
16+ -- * Running a Parser
17− fold
18−
19− -- -- * Running a 'Parser'
20− , parse
17+ parse
21 , parseD
18 , parseD
22 , parseBreak
19 , parseBreak
23 , parseBreakD
20 , parseBreakD
24
21
25− -- * Stream Deconstruction
22+ -- * Deconstruction
26 , uncons
23 , uncons
27
24
28 -- * Right Folds
25 -- * Right Folds
29− , foldrM
30− , foldr
31− , foldrMx
32 , foldr1
26 , foldr1
33
27
34− -- * Left Folds
35− , foldlM'
36− , foldl'
37− , foldlMx'
38− , foldlx'
39−
40 -- * Specific Fold Functions
28 -- * Specific Fold Functions
41− , drain
42 , mapM_ -- Map and Fold
29 , mapM_ -- Map and Fold
43 , null
30 , null
44 , head
31 , head
45 , headElse
32 , headElse
33+ , init
46 , tail
34 , tail
47 , last
35 , last
48 , elem
36 , elem
@@ -60,16 +48,9 @@ module Streamly.Internal.Data.Stream.Eliminate
60 , the
48 , the
61
49
62 -- * To containers
50 -- * To containers
63− , toList
64 , toListRev
51 , toListRev
65
52
66 -- * Multi-Stream Folds
53 -- * Multi-Stream Folds
67− -- ** Comparisons
68− -- | These should probably be expressed using zipping operations.
69− , eqBy
70− , cmpBy
71−
72− -- ** Substreams
73 -- | These should probably be expressed using parsers.
54 -- | These should probably be expressed using parsers.
74 , isPrefixOf
55 , isPrefixOf
75 , isInfixOf
56 , isInfixOf
@@ -90,7 +71,7 @@ import Foreign.Storable (Storable)
90import GHC.Exts (SpecConstrAnnotation(..))
71import GHC.Exts (SpecConstrAnnotation(..))
91import GHC.Types (SPEC(..))
72import GHC.Types (SPEC(..))
92import Streamly.Internal.Data.Parser (ParseError(..))
73import Streamly.Internal.Data.Parser (ParseError(..))
93−import Streamly.Internal.Data.SVar.Type (defState)
74+import Streamly.Internal.Data.SVar.Type (adaptState, defState)
94import Streamly.Internal.Data.Unbox (Unbox)
75import Streamly.Internal.Data.Unbox (Unbox)
95
76
96import Streamly.Internal.Data.Maybe.Strict (Maybe'(..))
77import Streamly.Internal.Data.Maybe.Strict (Maybe'(..))
@@ -105,7 +86,7 @@ import qualified Streamly.Internal.Data.Stream.Transform as StreamD
105
86
106import Prelude hiding
87import Prelude hiding
107 ( Foldable(..), all, any, head, last, lookup, mapM, mapM_
88 ( Foldable(..), all, any, head, last, lookup, mapM, mapM_
108− , notElem, splitAt, tail, (!!))
89+ , notElem, splitAt, init, tail, (!!))
109import Data.Foldable (length)
90import Data.Foldable (length)
110import Streamly.Internal.Data.Stream.Type
91import Streamly.Internal.Data.Stream.Type
111
92
@@ -391,9 +372,35 @@ head = foldrM (\x _ -> return (Just x)) (return Nothing)
391headElse :: Monad m => a -> Stream m a -> m a
372headElse :: Monad m => a -> Stream m a -> m a
392headElse a = foldrM (\x _ -> return x) (return a)
373headElse a = foldrM (\x _ -> return x) (return a)
393
374
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+--
394-- Does not fuse, has the same performance as the StreamK version.
398-- Does not fuse, has the same performance as the StreamK version.
399+--
395{-# INLINE_NORMAL tail #-}
400{-# INLINE_NORMAL tail #-}
396tail :: Monad m => Stream m a -> m (Maybe (Stream m a))
401tail :: Monad m => Stream m a -> m (Maybe (Stream m a))
402+tail = fmap (fmap snd) . uncons
403+{-
397tail (UnStream step state) = go SPEC state
404tail (UnStream step state) = go SPEC state
398 where
405 where
399 go !_ st = do
406 go !_ st = do
@@ -402,6 +409,7 @@ tail (UnStream step state) = go SPEC state
402 Yield _ s -> return (Just $ Stream step s)
409 Yield _ s -> return (Just $ Stream step s)
403 Skip s -> go SPEC s
410 Skip s -> go SPEC s
404 Stop -> return Nothing
411 Stop -> return Nothing
412+-}
405
413
406-- XXX will it fuse? need custom impl?
414-- XXX will it fuse? need custom impl?
407{-# INLINE_NORMAL last #-}
415{-# INLINE_NORMAL last #-}
core/src/Streamly/Internal/Data/Stream/Exception.hs+9−6
@@ -9,17 +9,20 @@
9
9
10module Streamly.Internal.Data.Stream.Exception
10module Streamly.Internal.Data.Stream.Exception
11 (
11 (
12− gbracket_
12+ -- * Resources
13− , gbracket
14− , before
13+ before
15− , afterUnsafe
16 , afterIO
14 , afterIO
15+ , afterUnsafe
16+ , finallyIO
17+ , finallyUnsafe
18+ , gbracket_
19+ , gbracket
17 , bracketUnsafe
20 , bracketUnsafe
18 , bracketIO3
21 , bracketIO3
19 , bracketIO
22 , bracketIO
23+
24+ -- * Exceptions
20 , onException
25 , onException
21− , finallyUnsafe
22− , finallyIO
23 , ghandle
26 , ghandle
24 , handle
27 , handle
25 )
28 )
core/src/Streamly/Internal/Data/Stream/Generate.hs−12
@@ -16,20 +16,13 @@ module Streamly.Internal.Data.Stream.Generate
16 (
16 (
17 -- * Primitives
17 -- * Primitives
18 nil
18 nil
19− , nilM
20 , cons
19 , cons
21− , consM
22−
23− -- * From 'Unfold'
24− , unfold
25
20
26 -- * Unfolding
21 -- * Unfolding
27 , unfoldr
22 , unfoldr
28 , unfoldrM
23 , unfoldrM
29
24
30 -- * From Values
25 -- * From Values
31− , fromPure
32− , fromEffect
33 , repeat
26 , repeat
34 , repeatM
27 , repeatM
35 , replicate
28 , replicate
@@ -95,7 +88,6 @@ module Streamly.Internal.Data.Stream.Generate
95 -- * From Containers
88 -- * From Containers
96 -- | Transform an input structure into a stream.
89 -- | Transform an input structure into a stream.
97
90
98− , fromList
99 , fromListM
91 , fromListM
100 , fromFoldable
92 , fromFoldable
101 , fromFoldableM
93 , fromFoldableM
@@ -104,10 +96,6 @@ module Streamly.Internal.Data.Stream.Generate
104 , fromPtr
96 , fromPtr
105 , fromPtrN
97 , fromPtrN
106 , fromByteStr#
98 , fromByteStr#
107−
108− -- * Conversions
109− , fromStreamK
110− , toStreamK
111 )
99 )
112where
100where
113
101
core/src/Streamly/Internal/Data/Stream/Nesting.hs+10−64
@@ -55,11 +55,6 @@ module Streamly.Internal.Data.Stream.Nesting
55 -- yields an element. A special case of unfoldRoundRobin.
55 -- yields an element. A special case of unfoldRoundRobin.
56 , roundRobin -- interleaveFair?/ParallelFair
56 , roundRobin -- interleaveFair?/ParallelFair
57
57
58− -- *** Zipping
59− -- | Zip corresponding elements of two streams.
60− , zipWith
61− , zipWithM
62−
63 -- *** Merging
58 -- *** Merging
64 -- | Interleave elements from two streams based on a condition.
59 -- | Interleave elements from two streams based on a condition.
65 , mergeBy
60 , mergeBy
@@ -76,17 +71,10 @@ module Streamly.Internal.Data.Stream.Nesting
76 -- unfoldMany: Unfold m a b -> t m a -> t m b
71 -- unfoldMany: Unfold m a b -> t m a -> t m b
77 -- @
72 -- @
78
73
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−
85 -- *** ConcatUnfold
74 -- *** ConcatUnfold
86 -- | Generate streams by using an unfold on each element of an input
75 -- | Generate streams by using an unfold on each element of an input
87 -- stream, append the resulting streams and flatten. A special case of
76 -- stream, append the resulting streams and flatten. A special case of
88 -- gintercalate.
77 -- gintercalate.
89− , unfoldMany
90 , ConcatUnfoldInterleaveState (..)
78 , ConcatUnfoldInterleaveState (..)
91 , unfoldInterleave
79 , unfoldInterleave
92 , unfoldRoundRobin
80 , unfoldRoundRobin
@@ -118,11 +106,8 @@ module Streamly.Internal.Data.Stream.Nesting
118
106
119 -- ** Folding
107 -- ** Folding
120 -- | Apply folds on a stream.
108 -- | Apply folds on a stream.
121− , foldMany
122− , refoldMany
123 , foldSequence
109 , foldSequence
124 , foldIterateM
110 , foldIterateM
125− , refoldIterateM
126
111
127 -- ** Parsing
112 -- ** Parsing
128 -- | Parsing is opposite to flattening. 'parseMany' is dual to concatMap or
113 -- | Parsing is opposite to flattening. 'parseMany' is dual to concatMap or
@@ -139,7 +124,6 @@ module Streamly.Internal.Data.Stream.Nesting
139
124
140 -- ** Grouping
125 -- ** Grouping
141 -- | Group segments of a stream and fold. Special case of parsing.
126 -- | Group segments of a stream and fold. Special case of parsing.
142− , groupsOf
143 , groupsBy
127 , groupsBy
144 , groupsWhile
128 , groupsWhile
145 , groupsRollingBy
129 , groupsRollingBy
@@ -147,8 +131,8 @@ module Streamly.Internal.Data.Stream.Nesting
147 -- ** Splitting
131 -- ** Splitting
148 -- | A special case of parsing.
132 -- | A special case of parsing.
149 , wordsBy
133 , wordsBy
150− , splitOnSeq
134+ , splitOnSeq -- XXX splitOnSeg
151− , splitOnSuffixSeq
135+ , splitOnSuffixSeq -- XXX splitOnSegSuffix, splitOnTrailer
152
136
153 -- XXX Implement these as folds or parsers instead.
137 -- XXX Implement these as folds or parsers instead.
154 , splitOnSuffixSeqAny
138 , splitOnSuffixSeqAny
@@ -157,9 +141,8 @@ module Streamly.Internal.Data.Stream.Nesting
157
141
158 -- * Transform (Nested Containers)
142 -- * Transform (Nested Containers)
159 -- | Opposite to compact in ArrayStream
143 -- | Opposite to compact in ArrayStream
160− , splitInnerBy
144+ , splitInnerBy -- XXX innerSplitOn
161− , splitInnerBySuffix
145+ , splitInnerBySuffix -- XXX innerSplitOnSuffix
162− , intersectBySorted
163
146
164 -- * Reduce By Streams
147 -- * Reduce By Streams
165 , dropPrefix
148 , dropPrefix
@@ -609,49 +592,6 @@ mergeFstBy :: -- Monad m =>
609mergeFstBy _f _m1 _m2 = undefined
592mergeFstBy _f _m1 _m2 = undefined
610 -- fromStreamK $ D.mergeFstBy f (toStreamD m1) (toStreamD m2)
593 -- fromStreamK $ D.mergeFstBy f (toStreamD m1) (toStreamD m2)
611
594
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−
655------------------------------------------------------------------------------
595------------------------------------------------------------------------------
656-- Combine N Streams - unfoldMany
596-- Combine N Streams - unfoldMany
657------------------------------------------------------------------------------
597------------------------------------------------------------------------------
@@ -3046,6 +2986,8 @@ splitInnerBySuffix isEmpty splitter joiner (Stream step1 state1) =
3046--
2986--
3047-- Space: @O(1)@
2987-- Space: @O(1)@
3048--
2988--
2989+-- See also stripPrefix.
2990+--
3049-- /Unimplemented/
2991-- /Unimplemented/
3050{-# INLINE dropPrefix #-}
2992{-# INLINE dropPrefix #-}
3051dropPrefix ::
2993dropPrefix ::
@@ -3058,6 +3000,8 @@ dropPrefix = error "Not implemented yet!"
3058--
3000--
3059-- Space: @O(n)@ where n is the length of the infix.
3001-- Space: @O(n)@ where n is the length of the infix.
3060--
3002--
3003+-- See also stripInfix.
3004+--
3061-- /Unimplemented/
3005-- /Unimplemented/
3062{-# INLINE dropInfix #-}
3006{-# INLINE dropInfix #-}
3063dropInfix ::
3007dropInfix ::
@@ -3070,6 +3014,8 @@ dropInfix = error "Not implemented yet!"
3070--
3014--
3071-- Space: @O(n)@ where n is the length of the suffix.
3015-- Space: @O(n)@ where n is the length of the suffix.
3072--
3016--
3017+-- See also stripSuffix.
3018+--
3073-- /Unimplemented/
3019-- /Unimplemented/
3074{-# INLINE dropSuffix #-}
3020{-# INLINE dropSuffix #-}
3075dropSuffix ::
3021dropSuffix ::
core/src/Streamly/Internal/Data/Stream/Top.hs+243−115
@@ -8,38 +8,73 @@
8-- Portability : GHC
8-- Portability : GHC
9--
9--
10-- Top level module that can depend on all other lower level Stream modules.
10-- 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.
11
48
12module Streamly.Internal.Data.Stream.Top
49module Streamly.Internal.Data.Stream.Top
13 (
50 (
14− -- * Transformation
15− -- ** Sampling
51+ -- * Sampling
16 -- | Value agnostic filtering.
52 -- | Value agnostic filtering.
17 strideFromThen
53 strideFromThen
18
54
19− -- * Nesting
55+ -- * Straight Joins
20− -- ** Set like operations
21− -- | These are not exactly set operations because streams are not
56+ -- | These are set-like operations but not exactly set operations because
22− -- necessarily sets, they may have duplicated elements. These operations
57+ -- streams are not necessarily sets, they may have duplicated elements.
23− -- are generic i.e. they work on streams of unconstrained types, therefore,
58+ -- These operations are generic i.e. they work on streams of unconstrained
24− -- they have quadratic performance characterstics. For better performance
59+ -- types, therefore, they have quadratic performance characterstics. For
60+ -- better performance using Set or Map structures see the
25− -- using Set structures see the Streamly.Internal.Data.Stream.Container
61+ -- Streamly.Internal.Data.Stream.Container module.
26− -- module.
62+ , intersectBy
27− , filterInStreamGenericBy
63+ , deleteFirstsBy
28− , deleteInStreamGenericBy
64+ , unionBy
29− , unionWithStreamGenericBy
65+
30−
31− -- ** Set like operations on sorted streams
66+ -- Set like operations on sorted streams
32− , filterInStreamAscBy
67+ , sortedIntersectBy
33− , deleteInStreamAscBy
68+ , sortedDeleteFirstsBy
34− , unionWithStreamAscBy
69+ , sortedUnionBy
35−
70+
36− -- ** Join operations
71+ -- * Cross Joins
37− , joinInnerGeneric
72+ , innerJoin
38−
73+
39− -- * Joins on sorted stream
74+ -- Joins on sorted stream
40− , joinInnerAscBy
75+ , innerSortedJoin
41− , joinLeftAscBy
76+ , leftSortedJoin
42− , joinOuterAscBy
77+ , outerSortedJoin
43 )
78 )
44where
79where
45
80
@@ -48,7 +83,7 @@ where
48import Control.Monad.IO.Class (MonadIO(..))
83import Control.Monad.IO.Class (MonadIO(..))
49import Data.IORef (newIORef, readIORef, modifyIORef')
84import Data.IORef (newIORef, readIORef, modifyIORef')
50import Streamly.Internal.Data.Fold.Type (Fold)
85import Streamly.Internal.Data.Fold.Type (Fold)
51−import Streamly.Internal.Data.Stream.Type (Stream, cross)
86+import Streamly.Internal.Data.Stream.Type (Stream(..), Step(..), cross)
52
87
53import qualified Data.List as List
88import qualified Data.List as List
54import qualified Streamly.Internal.Data.Fold as Fold
89import qualified Streamly.Internal.Data.Fold as Fold
@@ -110,29 +145,40 @@ strideFromThen offset stride =
110-- binary search if we have an Ord instance or Ordering returning function. The
145-- binary search if we have an Ord instance or Ordering returning function. The
111-- time complexity would then become (m x log n).
146-- time complexity would then become (m x log n).
112
147
113−-- | Like 'cross' but emits only those tuples where @a == b@ using the
148+-- | Like 'cross' but emits only those tuples where @a == b@ using the supplied
114−-- supplied equality predicate.
149+-- equality predicate. This is essentially a @cross intersection@ of two
150+-- streams.
115--
151--
116-- Definition:
152-- Definition:
117--
153--
118−-- >>> joinInnerGeneric eq s1 s2 = Stream.filter (\(a, b) -> a `eq` b) $ Stream.cross s1 s2
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.
119--
162--
120−-- You should almost always prefer @joinInnerOrd@ over 'joinInnerGeneric' if
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
121−-- possible. @joinInnerOrd@ is an order of magnitude faster but may take more
166+-- are sorted. 'innerOrdJoin' is an order of magnitude faster alternative when
122−-- space for caching the second stream.
167+-- the type has an 'Ord' instance.
123--
168--
124−-- See 'Streamly.Internal.Data.Unfold.joinInnerGeneric' for a much faster fused
169+-- Note: Conceptually, this is a commutative operation. Result includes all the
125−-- alternative.
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.
126--
172--
127-- Time: O(m x n)
173-- Time: O(m x n)
128--
174--
129-- /Pre-release/
175-- /Pre-release/
130−{-# INLINE joinInnerGeneric #-}
176+{-# INLINE innerJoin #-}
131−joinInnerGeneric :: Monad m =>
177+innerJoin :: Monad m =>
132 (a -> b -> Bool) -> Stream m a -> Stream m b -> Stream m (a, b)
178 (a -> b -> Bool) -> Stream m a -> Stream m b -> Stream m (a, b)
133−joinInnerGeneric eq s1 s2 = Stream.filter (\(a, b) -> a `eq` b) $ cross s1 s2
179+innerJoin eq s1 s2 = Stream.filter (\(a, b) -> a `eq` b) $ cross s1 s2
134{-
180{-
135−joinInnerGeneric eq s1 s2 = do
181+innerJoin eq s1 s2 = do
136 -- ConcatMap works faster than bind
182 -- ConcatMap works faster than bind
137 Stream.concatMap (\a ->
183 Stream.concatMap (\a ->
138 Stream.concatMap (\b ->
184 Stream.concatMap (\b ->
@@ -143,44 +189,44 @@ joinInnerGeneric eq s1 s2 = do
143 ) s1
189 ) s1
144-}
190-}
145
191
146−-- | A more efficient 'joinInner' for sorted streams.
192+-- | A more efficient 'innerJoin' for sorted streams.
147--
193--
148-- Space: O(1)
194-- Space: O(1)
149--
195--
150-- Time: O(m + n)
196-- Time: O(m + n)
151--
197--
152-- /Unimplemented/
198-- /Unimplemented/
153−{-# INLINE joinInnerAscBy #-}
199+{-# INLINE innerSortedJoin #-}
154−joinInnerAscBy ::
200+innerSortedJoin ::
155 (a -> b -> Ordering) -> Stream m a -> Stream m b -> Stream m (a, b)
201 (a -> b -> Ordering) -> Stream m a -> Stream m b -> Stream m (a, b)
156−joinInnerAscBy = undefined
202+innerSortedJoin = undefined
157
203
158−-- | A more efficient 'joinLeft' for sorted streams.
204+-- | A more efficient 'leftJoin' for sorted streams.
159--
205--
160-- Space: O(1)
206-- Space: O(1)
161--
207--
162-- Time: O(m + n)
208-- Time: O(m + n)
163--
209--
164-- /Unimplemented/
210-- /Unimplemented/
165−{-# INLINE joinLeftAscBy #-}
211+{-# INLINE leftSortedJoin #-}
166−joinLeftAscBy :: -- Monad m =>
212+leftSortedJoin :: -- Monad m =>
167 (a -> b -> Ordering) -> Stream m a -> Stream m b -> Stream m (a, Maybe b)
213 (a -> b -> Ordering) -> Stream m a -> Stream m b -> Stream m (a, Maybe b)
168−joinLeftAscBy _eq _s1 _s2 = undefined
214+leftSortedJoin _eq _s1 _s2 = undefined
169
215
170−-- | A more efficient 'joinOuter' for sorted streams.
216+-- | A more efficient 'outerJoin' for sorted streams.
171--
217--
172-- Space: O(1)
218-- Space: O(1)
173--
219--
174-- Time: O(m + n)
220-- Time: O(m + n)
175--
221--
176-- /Unimplemented/
222-- /Unimplemented/
177−{-# INLINE joinOuterAscBy #-}
223+{-# INLINE outerSortedJoin #-}
178−joinOuterAscBy :: -- Monad m =>
224+outerSortedJoin :: -- Monad m =>
179 (a -> b -> Ordering)
225 (a -> b -> Ordering)
180 -> Stream m a
226 -> Stream m a
181 -> Stream m b
227 -> Stream m b
182 -> Stream m (Maybe a, Maybe b)
228 -> Stream m (Maybe a, Maybe b)
183−joinOuterAscBy _eq _s1 _s2 = undefined
229+outerSortedJoin _eq _s1 _s2 = undefined
184
230
185------------------------------------------------------------------------------
231------------------------------------------------------------------------------
186-- Set operations (special joins)
232-- Set operations (special joins)
@@ -190,8 +236,8 @@ joinOuterAscBy _eq _s1 _s2 = undefined
190-- the best would be to use an Array with linear search. If the second stream
236-- the best would be to use an Array with linear search. If the second stream
191-- is sorted we can also use a binary search, using Ord constraint.
237-- is sorted we can also use a binary search, using Ord constraint.
192
238
193−-- | Keep only those elements in the second stream that are present in the
239+-- | Keep only those elements in the first stream that are present in the
194−-- first stream too. The first stream is folded to a container using the
240+-- second stream too. The second stream is folded to a container using the
195-- supplied fold and then the elements in the container are looked up using the
241-- supplied fold and then the elements in the container are looked up using the
196-- supplied lookup function.
242-- supplied lookup function.
197--
243--
@@ -206,23 +252,30 @@ filterStreamWith :: Monad m =>
206filterStreamWith fld member s1 s2 =
252filterStreamWith fld member s1 s2 =
207 Stream.concatEffect
253 Stream.concatEffect
208 $ do
254 $ do
209− xs <- Stream.fold fld s1
255+ xs <- Stream.fold fld s2
210− return $ Stream.filter (`member` xs) s2
256+ return $ Stream.filter (`member` xs) s1
211
257
212−-- | 'filterInStreamGenericBy' retains only those elements in the second stream that
258+-- XXX instead of folding the second stream to a list we could use it directly.
213−-- are present in the first stream.
259+-- If the user wants they can generate the stream from an array and also call
214−--
260+-- uniq or nub on it. We can provide a convenience Stream -> Stream to cache
215−-- >>> Stream.fold Fold.toList $ Stream.filterInStreamGenericBy (==) (Stream.fromList [1,2,2,4]) (Stream.fromList [2,1,1,3])
261+-- a finite stream in an array and serve it from the cache. The user can decide
216−-- [2,1,1]
262+-- what is best based on the context. They can also choose to use a boxed or
217−--
263+-- unboxed array for caching. To force caching we can make the second stream
218−-- >>> Stream.fold Fold.toList $ Stream.filterInStreamGenericBy (==) (Stream.fromList [2,1,1,3]) (Stream.fromList [1,2,2,4])
264+-- monad type Identity. But that may be less flexible. One option is to use
219−-- [1,2,2]
265+-- cachedIntersectBy etc for automatic caching.
266+
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'.
220--
272--
221−-- Similar to the list intersectBy operation but with the stream argument order
273+-- >>> f s1 s2 = Stream.fold Fold.toList $ Stream.intersectBy (==) (Stream.fromList s1) (Stream.fromList s2)
222−-- flipped.
274+-- >>> f [1,3,4,4,5]) [2,3,4,5,5]
275+-- [3,4,4,5]
223--
276--
224−-- The first stream must be finite and must not block. Second stream is
277+-- First stream can be infinite, the second stream must be finite and must be
225−-- processed only after the first stream is fully realized.
278+-- capable of multiple evaluations.
226--
279--
227-- Space: O(n) where @n@ is the number of elements in the second stream.
280-- Space: O(n) where @n@ is the number of elements in the second stream.
228--
281--
@@ -230,46 +283,87 @@ filterStreamWith fld member s1 s2 =
230-- @n@ is the number of elements in the second stream.
283-- @n@ is the number of elements in the second stream.
231--
284--
232-- /Pre-release/
285-- /Pre-release/
233−{-# INLINE filterInStreamGenericBy #-}
286+{-# INLINE intersectBy #-}
234−filterInStreamGenericBy :: Monad m =>
287+intersectBy :: Monad m =>
235 (a -> a -> Bool) -> Stream m a -> Stream m a -> Stream m a
288 (a -> a -> Bool) -> Stream m a -> Stream m a -> Stream m a
236−filterInStreamGenericBy eq =
289+intersectBy eq =
237 -- XXX Use an (unboxed) array instead.
290 -- XXX Use an (unboxed) array instead.
238 filterStreamWith
291 filterStreamWith
239 (Fold.scanMaybe (Fold.uniqBy eq) Fold.toListRev)
292 (Fold.scanMaybe (Fold.uniqBy eq) Fold.toListRev)
240 (List.any . eq)
293 (List.any . eq)
241
294
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+
242−-- | Like 'filterInStreamGenericBy' but assumes that the input streams are sorted in
303+-- | Like 'intersectBy' but assumes that the input streams are sorted in
243-- ascending order. To use it on streams sorted in descending order pass an
304-- ascending order. To use it on streams sorted in descending order pass an
244-- inverted comparison function returning GT for less than and LT for greater
305-- inverted comparison function returning GT for less than and LT for greater
245-- than.
306-- than.
246--
307--
308+-- Both streams can be infinite.
309+--
247-- Space: O(1)
310-- Space: O(1)
248--
311--
249-- Time: O(m+n)
312-- Time: O(m+n)
250--
313--
251-- /Pre-release/
314-- /Pre-release/
252−{-# INLINE filterInStreamAscBy #-}
315+{-# INLINE_NORMAL sortedIntersectBy #-}
253−filterInStreamAscBy :: Monad m =>
316+sortedIntersectBy :: Monad m =>
254 (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
317 (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
255−filterInStreamAscBy eq s1 s2 = Stream.intersectBySorted eq s2 s1
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+ )
256
325
257−-- | Delete all elements of the first stream from the seconds stream. If an
326+ where
258−-- element occurs multiple times in the first stream as many occurrences of it
327+
259−-- are deleted from the second stream.
328+ {-# INLINE_LATE step #-}
260−--
329+ -- step 1, fetch the first value
261−-- >>> Stream.fold Fold.toList $ Stream.deleteInStreamGenericBy (==) (Stream.fromList [1,2,3]) (Stream.fromList [1,2,2])
330+ step gst (sa, sb, Nothing, b) = do
262−-- [2]
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'.
263--
356--
264−-- The following laws hold:
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]
265--
360--
266−-- > deleteInStreamGenericBy (==) s1 (s1 `append` s2) === s2
361+-- The following holds:
267−-- > deleteInStreamGenericBy (==) s1 (s1 `interleave` s2) === s2
268--
362--
269−-- Same as the list 'Data.List.//' operation but with argument order flipped.
363+-- > deleteFirstsBy (==) (Stream.nub s2 `append` s1) s2 === s1
364+-- > deleteFirstsBy (==) (Stream.nub s2 `interleave` s1) s2 === s1
270--
365--
271−-- The first stream must be finite and must not block. Second stream is
366+-- First stream can be infinite, second stream must be finite.
272−-- processed only after the first stream is fully realized.
273--
367--
274-- Space: O(m) where @m@ is the number of elements in the first stream.
368-- Space: O(m) where @m@ is the number of elements in the first stream.
275--
369--
@@ -277,58 +371,83 @@ filterInStreamAscBy eq s1 s2 = Stream.intersectBySorted eq s2 s1
277-- @n@ is the number of elements in the second stream.
371-- @n@ is the number of elements in the second stream.
278--
372--
279-- /Pre-release/
373-- /Pre-release/
280−{-# INLINE deleteInStreamGenericBy #-}
374+{-# INLINE deleteFirstsBy #-}
281−deleteInStreamGenericBy :: Monad m =>
375+deleteFirstsBy :: Monad m =>
282 (a -> a -> Bool) -> Stream m a -> Stream m a -> Stream m a
376 (a -> a -> Bool) -> Stream m a -> Stream m a -> Stream m a
283−deleteInStreamGenericBy eq s1 s2 =
377+deleteFirstsBy eq s2 s1 =
284− Stream.concatEffect
378+ -- XXX s2 can be a sorted mutable array and we can use binary
285− $ do
379+ -- search to find. Mark the element deleted, count the deletions
286− -- This may work well if s1 is small
380+ -- and reconsolidate the array when a min number of elements is
287− -- If s1 is big we can go through s1, deleting elements from s2 and
381+ -- deleted.
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
294
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
402+
295−-- | A more efficient 'deleteInStreamGenericBy' for streams sorted in ascending order.
403+-- | A more efficient 'deleteFirstsBy' for streams sorted in ascending order.
404+--
405+-- Both streams can be infinite.
296--
406--
297-- Space: O(1)
407-- Space: O(1)
298--
408--
299-- /Unimplemented/
409-- /Unimplemented/
300−{-# INLINE deleteInStreamAscBy #-}
410+{-# INLINE sortedDeleteFirstsBy #-}
301−deleteInStreamAscBy :: -- (Monad m) =>
411+sortedDeleteFirstsBy :: -- (Monad m) =>
302 (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
412 (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
303−deleteInStreamAscBy _eq _s1 _s2 = undefined
413+sortedDeleteFirstsBy _eq _s1 _s2 = undefined
304
414
305-- XXX Remove the MonadIO constraint. We can just cache one stream and then
415-- XXX Remove the MonadIO constraint. We can just cache one stream and then
306-- implement using differenceEqBy.
416-- implement using differenceEqBy.
307
417
308−-- | This essentially appends to the second stream all the occurrences of
418+-- | Returns the first stream appended with those unique elements from the
309−-- elements in the first stream that are not already present in the second
419+-- second stream that are not already present in the first stream. Note that
310−-- stream.
420+-- this is not a commutative operation unlike a set union, argument order
421+-- matters. The behavior is similar to the 'Data.List.unionBy'.
311--
422--
312-- Equivalent to the following except that @s2@ is evaluated only once:
423-- Equivalent to the following except that @s2@ is evaluated only once:
313--
424--
314−-- >>> unionWithStreamGenericBy eq s1 s2 = s2 `Stream.append` (Stream.deleteInStreamGenericBy eq s2 s1)
425+-- >>> unionBy eq s1 s2 = s1 `Stream.append` Stream.deleteFirstsBy eq s1 (Stream.nub s2)
315--
426--
316-- Example:
427-- Example:
317--
428--
318−-- >>> Stream.fold Fold.toList $ Stream.unionWithStreamGenericBy (==) (Stream.fromList [1,1,2,3]) (Stream.fromList [1,2,2,4])
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]
319-- [1,2,2,4,3]
431-- [1,2,2,4,3]
320--
432--
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+--
321-- Space: O(n)
438-- Space: O(n)
322--
439--
323-- Time: O(m x n)
440-- Time: O(m x n)
324--
441--
325-- /Pre-release/
442-- /Pre-release/
326−{-# INLINE unionWithStreamGenericBy #-}
443+{-# INLINE unionBy #-}
327−unionWithStreamGenericBy :: MonadIO m =>
444+unionBy :: MonadIO m =>
328 (a -> a -> Bool) -> Stream m a -> Stream m a -> Stream m a
445 (a -> a -> Bool) -> Stream m a -> Stream m a -> Stream m a
329−unionWithStreamGenericBy eq s1 s2 =
446+unionBy eq s2 s1 =
330 Stream.concatEffect
447 Stream.concatEffect
331 $ do
448 $ 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.
332 xs <- Stream.fold Fold.toList s1
451 xs <- Stream.fold Fold.toList s1
333 -- XXX we can use postscanlMAfter' instead of IORef
452 -- XXX we can use postscanlMAfter' instead of IORef
334 ref <- liftIO $ newIORef $! List.nubBy eq xs
453 ref <- liftIO $ newIORef $! List.nubBy eq xs
@@ -341,12 +460,21 @@ unionWithStreamGenericBy eq s1 s2 =
341 return $ Stream.fromList xs1
460 return $ Stream.fromList xs1
342 return $ Stream.mapM f s2 `Stream.append` s3
461 return $ Stream.mapM f s2 `Stream.append` s3
343
462
344−-- | A more efficient 'unionWithStreamGenericBy' for sorted streams.
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.
345--
471--
346-- Space: O(1)
472-- Space: O(1)
347--
473--
474+-- Both streams can be infinite.
475+--
348-- /Unimplemented/
476-- /Unimplemented/
349−{-# INLINE unionWithStreamAscBy #-}
477+{-# INLINE sortedUnionBy #-}
350−unionWithStreamAscBy :: -- (Monad m) =>
478+sortedUnionBy :: -- (Monad m) =>
351 (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
479 (a -> a -> Ordering) -> Stream m a -> Stream m a -> Stream m a
352−unionWithStreamAscBy _eq _s1 _s2 = undefined
480+sortedUnionBy _eq _s1 _s2 = undefined
core/src/Streamly/Internal/Data/Stream/Transform.hs+52−26
@@ -21,8 +21,6 @@ module Streamly.Internal.Data.Stream.Transform
21
21
22 -- * Mapping
22 -- * Mapping
23 -- | Stateless one-to-one maps.
23 -- | Stateless one-to-one maps.
24− , map
25− , mapM
26 , sequence
24 , sequence
27
25
28 -- * Mapping Effects
26 -- * Mapping Effects
@@ -75,7 +73,7 @@ module Streamly.Internal.Data.Stream.Transform
75 , scanMaybe
73 , scanMaybe
76 , filter
74 , filter
77 , filterM
75 , filterM
78− , deleteBy
76+ , deleteBy -- deleteOnceBy?
79 , uniqBy
77 , uniqBy
80 , uniq
78 , uniq
81 , prune
79 , prune
@@ -83,9 +81,8 @@ module Streamly.Internal.Data.Stream.Transform
83
81
84 -- * Trimming
82 -- * Trimming
85 -- | Produce a subset of the stream trimmed at ends.
83 -- | Produce a subset of the stream trimmed at ends.
86− , take
84+ , initNonEmpty
87− , takeWhile
85+ , tailNonEmpty
88− , takeWhileM
89 , takeWhileLast
86 , takeWhileLast
90 , takeWhileAround
87 , takeWhileAround
91 , drop
88 , drop
@@ -132,7 +129,6 @@ module Streamly.Internal.Data.Stream.Transform
132 -- * Searching
129 -- * Searching
133 , findIndices
130 , findIndices
134 , elemIndices
131 , elemIndices
135− , slicesBy
136
132
137 -- * Rolling map
133 -- * Rolling map
138 -- | Map using the previous element.
134 -- | Map using the previous element.
@@ -1074,6 +1070,55 @@ repeated = undefined
1074-- Trimming
1070-- Trimming
1075------------------------------------------------------------------------------
1071------------------------------------------------------------------------------
1076
1072
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+
1077-- | Take all consecutive elements at the end of the stream for which the
1122-- | Take all consecutive elements at the end of the stream for which the
1078-- predicate is true.
1123-- predicate is true.
1079--
1124--
@@ -1709,25 +1754,6 @@ findIndices p (Stream step state) = Stream step' (state, 0)
1709elemIndices :: (Monad m, Eq a) => a -> Stream m a -> Stream m Int
1754elemIndices :: (Monad m, Eq a) => a -> Stream m a -> Stream m Int
1710elemIndices a = findIndices (== a)
1755elemIndices a = findIndices (== a)
1711
1756
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−
1731------------------------------------------------------------------------------
1757------------------------------------------------------------------------------
1732-- Rolling map
1758-- Rolling map
1733------------------------------------------------------------------------------
1759------------------------------------------------------------------------------
core/src/Streamly/Internal/Data/Stream/Transformer.hs+2−1
@@ -11,10 +11,11 @@
11
11
12module Streamly.Internal.Data.Stream.Transformer
12module Streamly.Internal.Data.Stream.Transformer
13 (
13 (
14+ -- * Fold to Transformer Monad
14 foldlT
15 foldlT
15 , foldrT
16 , foldrT
16
17
17− -- * Transform Inner Monad
18+ -- * Inner Monad Operations
18 , liftInner
19 , liftInner
19 , runReaderT
20 , runReaderT
20 , usingReaderT
21 , usingReaderT
core/src/Streamly/Internal/Data/Stream/Type.hs+37−3
@@ -1,5 +1,11 @@
1{-# LANGUAGE CPP #-}
1{-# 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 #-}
2{-# LANGUAGE UndecidableInstances #-}
7{-# LANGUAGE UndecidableInstances #-}
8+{-# LANGUAGE ViewPatterns #-}
3
9
4-- |
10-- |
5-- Module : Streamly.Internal.Data.Stream.Type
11-- Module : Streamly.Internal.Data.Stream.Type
@@ -16,18 +22,18 @@
16
22
17module Streamly.Internal.Data.Stream.Type
23module Streamly.Internal.Data.Stream.Type
18 (
24 (
19− -- * The stream type
25+ -- * Type
20 Step (..)
26 Step (..)
21 -- XXX UnStream is exported to avoid a performance issue in some
27 -- XXX UnStream is exported to avoid a performance issue in some
22 -- combinators if we use the pattern synonym "Stream".
28 -- combinators if we use the pattern synonym "Stream".
23 , Stream (Stream, UnStream)
29 , Stream (Stream, UnStream)
24
30
25− -- * CrossStream type wrapper
31+ -- * CrossStream
26 , CrossStream
32 , CrossStream
27 , unCross
33 , unCross
28 , mkCross
34 , mkCross
29
35
30− -- * Conversion to StreamK
36+ -- * To StreamK
31 , fromStreamK
37 , fromStreamK
32 , toStreamK
38 , toStreamK
33
39
@@ -85,6 +91,7 @@ module Streamly.Internal.Data.Stream.Type
85
91
86 -- * Combining Two Streams
92 -- * Combining Two Streams
87 -- ** Zipping
93 -- ** Zipping
94+ -- | Zip corresponding elements of two streams.
88 , zipWithM
95 , zipWithM
89 , zipWith
96 , zipWith
90
97
@@ -100,6 +107,8 @@ module Streamly.Internal.Data.Stream.Type
100 , unfoldMany
107 , unfoldMany
101
108
102 -- * Concat
109 -- * Concat
110+ -- | Generate streams by mapping a stream generator on each element of an
111+ -- input stream, append the resulting streams and flatten.
103 , concatEffect
112 , concatEffect
104 , concatMap
113 , concatMap
105 , concatMapM
114 , concatMapM
@@ -133,6 +142,7 @@ module Streamly.Internal.Data.Stream.Type
133 , indexOnSuffix
142 , indexOnSuffix
134
143
135 -- * Multi-stream folds
144 -- * Multi-stream folds
145+ -- | These should probably be expressed using zipping operations.
136 , eqBy
146 , eqBy
137 , cmpBy
147 , cmpBy
138
148
@@ -562,8 +572,12 @@ foldAdd f =
562-- >>> Stream.foldrM step (return False) s
572-- >>> Stream.foldrM step (return False) s
563-- True
573-- True
564--
574--
575+-- >>> import Control.Monad (join)
576+-- >>> foldrM f z = join $ Stream.foldr f z
577+--
565{-# INLINE_NORMAL foldrM #-}
578{-# INLINE_NORMAL foldrM #-}
566foldrM :: Monad m => (a -> m b -> m b) -> m b -> Stream m a -> m b
579foldrM :: 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
567foldrM f z (Stream step state) = go SPEC state
581foldrM f z (Stream step state) = go SPEC state
568 where
582 where
569 {-# INLINE_LATE go #-}
583 {-# INLINE_LATE go #-}
@@ -2062,6 +2076,26 @@ indexOnSuffix predicate =
2062 (indexerBy (FL.takeEndBy_ predicate FL.length) 1)
2076 (indexerBy (FL.takeEndBy_ predicate FL.length) 1)
2063 (return (-1, 0))
2077 (return (-1, 0))
2064
2078
2079+-- Alternate implementation
2080+{-# INLINE_NORMAL _indexOnSuffix #-}
2081+_indexOnSuffix :: Monad m => (a -> Bool) -> Stream m a -> Stream m (Int, Int)
2082+_indexOnSuffix p (Stream step1 state1) = Stream step (Just (state1, 0, 0))
2083+
2084+ where
2085+
2086+ {-# INLINE_LATE step #-}
2087+ step gst (Just (st, i, len)) = i `seq` len `seq` do
2088+ r <- step1 (adaptState gst) st
2089+ return
2090+ $ case r of
2091+ Yield x s ->
2092+ if p x
2093+ then Yield (i, len + 1) (Just (s, i + len + 1, 0))
2094+ else Skip (Just (s, i, len + 1))
2095+ Skip s -> Skip (Just (s, i, len))
2096+ Stop -> if len == 0 then Stop else Yield (i, len) Nothing
2097+ step _ Nothing = return Stop
2098+
2065{-# DEPRECATED sliceOnSuffix "Please use indexOnSuffix instead." #-}
2099{-# DEPRECATED sliceOnSuffix "Please use indexOnSuffix instead." #-}
2066sliceOnSuffix :: Monad m => (a -> Bool) -> Stream m a -> Stream m (Int, Int)
2100sliceOnSuffix :: Monad m => (a -> Bool) -> Stream m a -> Stream m (Int, Int)
2067sliceOnSuffix = indexOnSuffix
2101sliceOnSuffix = indexOnSuffix
core/src/Streamly/Internal/Data/StreamK.hs+19−8
@@ -16,16 +16,15 @@ module Streamly.Internal.Data.StreamK
16 --
16 --
17 -- $setup
17 -- $setup
18
18
19− -- * The stream type
20 module Streamly.Internal.Data.StreamK.Type
19 module Streamly.Internal.Data.StreamK.Type
20+ -- * Transformer
21 , module Streamly.Internal.Data.StreamK.Transformer
21 , module Streamly.Internal.Data.StreamK.Transformer
22
22
23− , StreamK(..)
23+ -- * From containers
24 , fromList
24 , fromList
25 , fromStream
25 , fromStream
26− , toStream
27
26
28− -- ** Specialized Generation
27+ -- * Specialized Generation
29 , repeatM
28 , repeatM
30 , replicate
29 , replicate
31 , replicateM
30 , replicateM
@@ -67,13 +66,13 @@ module Streamly.Internal.Data.StreamK
67 , find
66 , find
68 , (!!)
67 , (!!)
69
68
69+ -- ** To Containers
70+ , toList
71+ , toStream
72+
70 -- ** Map and Fold
73 -- ** Map and Fold
71 , mapM_
74 , mapM_
72
75
73− -- ** Conversions
74− , toList
75− , hoist
76−
77 -- * Transformation
76 -- * Transformation
78 -- ** By folding (scans)
77 -- ** By folding (scans)
79 , scanl'
78 , scanl'
@@ -100,6 +99,7 @@ module Streamly.Internal.Data.StreamK
100
99
101 -- ** Reordering
100 -- ** Reordering
102 , sortBy
101 , sortBy
102+ , sortOn
103
103
104 -- ** Map and Filter
104 -- ** Map and Filter
105 , mapMaybe
105 , mapMaybe
@@ -115,6 +115,9 @@ module Streamly.Internal.Data.StreamK
115 -- ** Transformation comprehensions
115 -- ** Transformation comprehensions
116 , the
116 , the
117
117
118+ -- ** Transforming Inner Monad
119+ , hoist
120+
118 -- * Exceptions
121 -- * Exceptions
119 , handle
122 , handle
120
123
@@ -131,6 +134,7 @@ import Control.Exception (mask_, Exception)
131import Control.Monad (void, join)
134import Control.Monad (void, join)
132import Control.Monad.Catch (MonadCatch)
135import Control.Monad.Catch (MonadCatch)
133import Control.Monad.IO.Class (MonadIO(..))
136import Control.Monad.IO.Class (MonadIO(..))
137+import Data.Ord (comparing)
134import Data.Proxy (Proxy(..))
138import Data.Proxy (Proxy(..))
135import GHC.Types (SPEC(..))
139import GHC.Types (SPEC(..))
136import Streamly.Internal.Data.Array.Type (Array(..))
140import Streamly.Internal.Data.Array.Type (Array(..))
@@ -1717,3 +1721,10 @@ sortBy cmp =
1717 . Stream.catRights -- its a non-failing backtracking parser
1721 . Stream.catRights -- its a non-failing backtracking parser
1718 . Stream.parseMany (fmap (either id id) p)
1722 . Stream.parseMany (fmap (either id id) p)
1719 . Stream.fromStreamK
1723 . 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+60−11
@@ -1,4 +1,8 @@
1{-# LANGUAGE CPP #-}
1{-# 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 #-}
2{-# LANGUAGE UndecidableInstances #-}
6{-# LANGUAGE UndecidableInstances #-}
3-- |
7-- |
4-- Module : Streamly.Internal.Data.StreamK.Type
8-- Module : Streamly.Internal.Data.StreamK.Type
@@ -93,8 +97,11 @@ module Streamly.Internal.Data.StreamK.Type
93 -- ** Specific Folds
97 -- ** Specific Folds
94 , drain
98 , drain
95 , null
99 , null
100+ , headNonEmpty
96 , tail
101 , tail
102+ , tailNonEmpty
97 , init
103 , init
104+ , initNonEmpty
98
105
99 -- * Mapping
106 -- * Mapping
100 , map
107 , map
@@ -1807,14 +1814,42 @@ iterateMWith cns step = go
1807 !next <- s
1814 !next <- s
1808 foldStreamShared st stp sng yld (return next `cns` go (step next))
1815 foldStreamShared st stp sng yld (return next `cns` go (step next))
1809
1816
1810−{-# INLINE headPartial #-}
1817+-- | head for non-empty streams, fails for empty stream case.
1818+--
1819+{-# INLINE headNonEmpty #-}
1811−headPartial :: Monad m => StreamK m a -> m a
1820+headNonEmpty :: Monad m => StreamK m a -> m a
1812−headPartial = foldrM (\x _ -> return x) (error "head of nil")
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
1813
1843
1814−{-# INLINE tailPartial #-}
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 #-}
1815−tailPartial :: StreamK m a -> StreamK m a
1850+tailNonEmpty :: StreamK m a -> StreamK m a
1816−tailPartial m = mkStream $ \st yld sng stp ->
1851+tailNonEmpty m = mkStream $ \st yld sng stp ->
1817− let stop = error "tail of nil"
1852+ let stop = error "tailNonEmpty: empty stream"
1818 single _ = stp
1853 single _ = stp
1819 yieldk _ r = foldStream st yld sng stp r
1854 yieldk _ r = foldStream st yld sng stp r
1820 in foldStream st yieldk single stop m
1855 in foldStream st yieldk single stop m
@@ -1879,10 +1914,10 @@ mfix f = mkStream $ \st yld sng stp ->
1879 where
1914 where
1880
1915
1881 -- fix the head element of the stream
1916 -- fix the head element of the stream
1882− xs = fix (f . headPartial)
1917+ xs = fix (f . headNonEmpty)
1883
1918
1884 -- now fix the tail recursively
1919 -- now fix the tail recursively
1885− ys = mfix (tailPartial . f)
1920+ ys = mfix (tailNonEmpty . f)
1886
1921
1887-------------------------------------------------------------------------------
1922-------------------------------------------------------------------------------
1888-- Conversions
1923-- Conversions
@@ -1913,6 +1948,15 @@ uncons m =
1913 yieldk a r = pure (Just (a, r))
1948 yieldk a r = pure (Just (a, r))
1914 in foldStream defState yieldk single stop m
1949 in foldStream defState yieldk single stop m
1915
1950
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+--
1916{-# INLINE tail #-}
1960{-# INLINE tail #-}
1917tail :: Applicative m => StreamK m a -> m (Maybe (StreamK m a))
1961tail :: Applicative m => StreamK m a -> m (Maybe (StreamK m a))
1918tail =
1962tail =
@@ -1921,9 +1965,14 @@ tail =
1921 yieldk _ r = pure $ Just r
1965 yieldk _ r = pure $ Just r
1922 in foldStream defState yieldk single stop
1966 in foldStream defState yieldk single stop
1923
1967
1924−-- | Extract all but the last element of the stream, if any.
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.
1925--
1970--
1926−-- Note: This will end up buffering the entire stream.
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.
1927--
1976--
1928-- /Pre-release/
1977-- /Pre-release/
1929{-# INLINE init #-}
1978{-# INLINE init #-}
core/src/Streamly/Internal/Data/Time/Units.hs−4
@@ -1,7 +1,3 @@
1−{-# LANGUAGE DataKinds #-}
2−{-# LANGUAGE PolyKinds #-}
3−{-# LANGUAGE UnboxedTuples #-}
4−
5-- |
1-- |
6-- Module : Streamly.Internal.Data.Time.Units
2-- Module : Streamly.Internal.Data.Time.Units
7-- Copyright : (c) 2019 Composewell Technologies
3-- Copyright : (c) 2019 Composewell Technologies
core/src/Streamly/Internal/Data/Unbox.hs+4−1
@@ -1,5 +1,8 @@
1{-# LANGUAGE DataKinds #-}
1{-# LANGUAGE DataKinds #-}
2−{-# LANGUAGE DefaultSignatures #-}
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 #-}
3{-# LANGUAGE UnboxedTuples #-}
6{-# LANGUAGE UnboxedTuples #-}
4{-# LANGUAGE UndecidableInstances #-}
7{-# LANGUAGE UndecidableInstances #-}
5
8
core/src/Streamly/Internal/Data/Unfold.hs+6−4
@@ -82,7 +82,7 @@ module Streamly.Internal.Data.Unfold
82 , dropWhileM
82 , dropWhileM
83
83
84 -- ** Cross product
84 -- ** Cross product
85− , joinInnerGeneric
85+ , innerJoin
86
86
87 -- ** Resource Management
87 -- ** Resource Management
88 -- | 'bracket' is the most general resource management operation, all other
88 -- | 'bracket' is the most general resource management operation, all other
@@ -677,10 +677,12 @@ dropWhileM f (Unfold step inject) = Unfold step' inject'
677dropWhile :: Monad m => (b -> Bool) -> Unfold m a b -> Unfold m a b
677dropWhile :: Monad m => (b -> Bool) -> Unfold m a b -> Unfold m a b
678dropWhile f = dropWhileM (return . f)
678dropWhile f = dropWhileM (return . f)
679
679
680+-- | Cross intersection of two unfolds. See
681+-- 'Streamly.Internal.Data.Stream.innerJoin' for more details.
680−{-# INLINE_NORMAL joinInnerGeneric #-}
682+{-# INLINE_NORMAL innerJoin #-}
681−joinInnerGeneric :: Monad m =>
683+innerJoin :: Monad m =>
682 (b -> c -> Bool) -> Unfold m a b -> Unfold m a c -> Unfold m a (b, c)
684 (b -> c -> Bool) -> Unfold m a b -> Unfold m a c -> Unfold m a (b, c)
683−joinInnerGeneric eq s1 s2 = filter (\(a, b) -> a `eq` b) $ cross s1 s2
685+innerJoin eq s1 s2 = filter (\(a, b) -> a `eq` b) $ cross s1 s2
684
686
685------------------------------------------------------------------------------
687------------------------------------------------------------------------------
686-- Exceptions
688-- Exceptions
core/src/Streamly/Internal/FileSystem/File.hs+2−2
@@ -103,7 +103,7 @@ import qualified Control.Monad.Catch as MC
103import qualified System.IO as SIO
103import qualified System.IO as SIO
104
104
105import Streamly.Data.Fold (groupsOf, drain)
105import Streamly.Data.Fold (groupsOf, drain)
106−import Streamly.Internal.Data.Array.Type (Array(..), pinnedWriteNUnsafe)
106+import Streamly.Internal.Data.Array.Type (Array(..))
107import Streamly.Internal.Data.Fold.Type (Fold(..))
107import Streamly.Internal.Data.Fold.Type (Fold(..))
108import Streamly.Data.Stream (Stream)
108import Streamly.Data.Stream (Stream)
109import Streamly.Internal.Data.Unfold.Type (Unfold(..))
109import Streamly.Internal.Data.Unfold.Type (Unfold(..))
@@ -462,7 +462,7 @@ writeChunks path = Fold step initial extract final
462writeWith :: (MonadIO m, MonadCatch m)
462writeWith :: (MonadIO m, MonadCatch m)
463 => Int -> FilePath -> Fold m Word8 ()
463 => Int -> FilePath -> Fold m Word8 ()
464writeWith n path =
464writeWith n path =
465− groupsOf n (pinnedWriteNUnsafe n) (writeChunks path)
465+ groupsOf n (A.unsafePinnedCreateOf n) (writeChunks path)
466
466
467{-# DEPRECATED writeWithBufferOf "Please use 'writeWith' instead" #-}
467{-# DEPRECATED writeWithBufferOf "Please use 'writeWith' instead" #-}
468{-# INLINE writeWithBufferOf #-}
468{-# INLINE writeWithBufferOf #-}
core/src/Streamly/Internal/FileSystem/Handle.hs+17−16
@@ -40,8 +40,8 @@ module Streamly.Internal.FileSystem.Handle
40
40
41 -- * Streams
41 -- * Streams
42 , read
42 , read
43− , readWith
43+ , readWith -- readConcatChunksOf
44− , readChunksWith
44+ , readChunksWith -- readChunksOf
45 , readChunks
45 , readChunks
46
46
47 -- * Unfolds
47 -- * Unfolds
@@ -59,10 +59,10 @@ module Streamly.Internal.FileSystem.Handle
59 -- , writeUtf8ByLines
59 -- , writeUtf8ByLines
60 -- , writeByFrames
60 -- , writeByFrames
61 -- , writeLines
61 -- , writeLines
62− , writeWith
62+ , writeWith -- writeChunksOf
63 , writeChunks
63 , writeChunks
64− , writeChunksWith
64+ , writeChunksWith -- writeCompactChunksOf
65− , writeMaybesWith
65+ , writeMaybesWith -- writeCompactJustsOf
66
66
67 -- * Refolds
67 -- * Refolds
68 , writer
68 , writer
@@ -131,14 +131,13 @@ import Streamly.Internal.Data.Fold (Fold)
131import Streamly.Internal.Data.Refold.Type (Refold(..))
131import Streamly.Internal.Data.Refold.Type (Refold(..))
132import Streamly.Internal.Data.Unfold.Type (Unfold(..))
132import Streamly.Internal.Data.Unfold.Type (Unfold(..))
133import Streamly.Internal.Data.Array.Type
133import Streamly.Internal.Data.Array.Type
134− (Array(..), pinnedWriteNUnsafe, unsafeFreezeWithShrink, byteLength)
134+ (Array(..), unsafeFreezeWithShrink, byteLength)
135import Streamly.Internal.Data.Stream.Type (Stream)
135import Streamly.Internal.Data.Stream.Type (Stream)
136-- import Streamly.String (encodeUtf8, decodeUtf8, foldLines)
136-- import Streamly.String (encodeUtf8, decodeUtf8, foldLines)
137import Streamly.Internal.System.IO (defaultChunkSize)
137import Streamly.Internal.System.IO (defaultChunkSize)
138
138
139import qualified Streamly.Data.Fold as FL
139import qualified Streamly.Data.Fold as FL
140−import qualified Streamly.Data.Array as A
140+import qualified Streamly.Internal.Data.Array as A
141−import qualified Streamly.Internal.Data.Array.Type as A
142import qualified Streamly.Internal.Data.MutArray.Type as MArray
141import qualified Streamly.Internal.Data.MutArray.Type as MArray
143import qualified Streamly.Internal.Data.Refold.Type as Refold
142import qualified Streamly.Internal.Data.Refold.Type as Refold
144import qualified Streamly.Internal.Data.Fold.Type as FL(refoldMany)
143import qualified Streamly.Internal.Data.Fold.Type as FL(refoldMany)
@@ -167,6 +166,8 @@ import qualified Streamly.Internal.Data.StreamK.Type as K (mkStream)
167-- Array IO (Input)
166-- Array IO (Input)
168-------------------------------------------------------------------------------
167-------------------------------------------------------------------------------
169
168
169+-- XXX add an API that compacts the arrays to an exact size.
170+
170-- | Read a 'ByteArray' consisting of one or more bytes from a file handle. If
171-- | Read a 'ByteArray' consisting of one or more bytes from a file handle. If
171-- no data is available on the handle it blocks until at least one byte becomes
172-- no data is available on the handle it blocks until at least one byte becomes
172-- available. If any data is available then it immediately returns that data
173-- available. If any data is available then it immediately returns that data
@@ -176,9 +177,9 @@ import qualified Streamly.Internal.Data.StreamK.Type as K (mkStream)
176{-# INLINABLE getChunk #-}
177{-# INLINABLE getChunk #-}
177getChunk :: MonadIO m => Int -> Handle -> m (Array Word8)
178getChunk :: MonadIO m => Int -> Handle -> m (Array Word8)
178getChunk size h = liftIO $ do
179getChunk size h = liftIO $ do
179− arr <- MArray.pinnedNewBytes size
180+ arr :: MArray.MutArray Word8 <- MArray.pinnedEmptyOf size
180 -- ptr <- mallocPlainForeignPtrAlignedBytes size (alignment (undefined :: Word8))
181 -- ptr <- mallocPlainForeignPtrAlignedBytes size (alignment (undefined :: Word8))
181− MArray.asPtrUnsafe arr $ \p -> do
182+ MArray.unsafePinnedAsPtr arr $ \p -> do
182 n <- hGetBufSome h p size
183 n <- hGetBufSome h p size
183 -- XXX shrink only if the diff is significant
184 -- XXX shrink only if the diff is significant
184 return $
185 return $
@@ -378,12 +379,12 @@ read = A.concat . readChunks
378{-# INLINABLE putChunk #-}
379{-# INLINABLE putChunk #-}
379putChunk :: MonadIO m => Handle -> Array a -> m ()
380putChunk :: MonadIO m => Handle -> Array a -> m ()
380putChunk _ arr | byteLength arr == 0 = return ()
381putChunk _ arr | byteLength arr == 0 = return ()
381−putChunk h arr = A.asPtrUnsafe arr $ \ptr ->
382+putChunk h arr = A.unsafePinnedAsPtr arr $ \ptr ->
382 liftIO $ hPutBuf h ptr aLen
383 liftIO $ hPutBuf h ptr aLen
383
384
384 where
385 where
385
386
386− -- XXX We should have the length passed by asPtrUnsafe itself.
387+ -- XXX We should have the length passed by unsafePinnedAsPtr itself.
387 aLen = A.byteLength arr
388 aLen = A.byteLength arr
388
389
389-------------------------------------------------------------------------------
390-------------------------------------------------------------------------------
@@ -488,11 +489,11 @@ writeChunksWithBufferOf = writeChunksWith
488-- Bytes in the input stream are collected into a buffer until we have a chunk
489-- Bytes in the input stream are collected into a buffer until we have a chunk
489-- of @reqSize@ and then written to the IO device.
490-- of @reqSize@ and then written to the IO device.
490--
491--
491−-- >>> writeWith n h = Fold.groupsOf n (Array.writeNUnsafe n) (Handle.writeChunks h)
492+-- >>> writeWith n h = Fold.groupsOf n (Array.unsafeCreateOf n) (Handle.writeChunks h)
492--
493--
493{-# INLINE writeWith #-}
494{-# INLINE writeWith #-}
494writeWith :: MonadIO m => Int -> Handle -> Fold m Word8 ()
495writeWith :: MonadIO m => Int -> Handle -> Fold m Word8 ()
495−writeWith n h = FL.groupsOf n (pinnedWriteNUnsafe n) (writeChunks h)
496+writeWith n h = FL.groupsOf n (A.unsafePinnedCreateOf n) (writeChunks h)
496
497
497-- | Same as 'writeWith'
498-- | Same as 'writeWith'
498--
499--
@@ -510,7 +511,7 @@ writeWithBufferOf = writeWith
510writeMaybesWith :: (MonadIO m )
511writeMaybesWith :: (MonadIO m )
511 => Int -> Handle -> Fold m (Maybe Word8) ()
512 => Int -> Handle -> Fold m (Maybe Word8) ()
512writeMaybesWith n h =
513writeMaybesWith n h =
513− let writeNJusts = FL.lmap fromJust $ A.pinnedWriteN n
514+ let writeNJusts = FL.lmap fromJust $ A.pinnedCreateOf n
514 writeOnNothing = FL.takeEndBy_ isNothing writeNJusts
515 writeOnNothing = FL.takeEndBy_ isNothing writeNJusts
515 in FL.many writeOnNothing (writeChunks h)
516 in FL.many writeOnNothing (writeChunks h)
516
517
@@ -520,7 +521,7 @@ writeMaybesWith n h =
520{-# INLINE writerWith #-}
521{-# INLINE writerWith #-}
521writerWith :: MonadIO m => Int -> Refold m Handle Word8 ()
522writerWith :: MonadIO m => Int -> Refold m Handle Word8 ()
522writerWith n =
523writerWith n =
523− FL.refoldMany (FL.take n $ pinnedWriteNUnsafe n) chunkWriter
524+ FL.refoldMany (FL.take n $ A.unsafePinnedCreateOf n) chunkWriter
524
525
525-- | Write a byte stream to a file handle. Accumulates the input in chunks of
526-- | Write a byte stream to a file handle. Accumulates the input in chunks of
526-- up to 'Streamly.Internal.Data.Array.Type.defaultChunkSize' before writing
527-- up to 'Streamly.Internal.Data.Array.Type.defaultChunkSize' before writing
core/src/Streamly/Internal/Unicode/Stream.hs+1−1
@@ -1057,7 +1057,7 @@ stripHead = Stream.dropWhile isSpace
1057-- >>> Stream.fold Fold.toList $ Unicode.lines Fold.toList (Stream.fromList "lines\nthis\nstring\n\n\n")
1057-- >>> Stream.fold Fold.toList $ Unicode.lines Fold.toList (Stream.fromList "lines\nthis\nstring\n\n\n")
1058-- ["lines","this","string","",""]
1058-- ["lines","this","string","",""]
1059--
1059--
1060−-- > lines = Stream.splitOnSuffix (== '\n')
1060+-- >>> lines f = Stream.foldMany (Fold.takeEndBy_ (== '\n') f)
1061--
1061--
1062-- /Pre-release/
1062-- /Pre-release/
1063{-# INLINE lines #-}
1063{-# INLINE lines #-}
core/src/Streamly/Internal/Unicode/String.hs+7−7
@@ -39,14 +39,14 @@ module Streamly.Internal.Unicode.String
39 --
39 --
40 -- $setup
40 -- $setup
41
41
42− str
42+ str
43 ) where
43 ) where
44
44
45
45
46import Control.Applicative (Alternative(..))
46import Control.Applicative (Alternative(..))
47import Control.Exception (displayException)
47import Control.Exception (displayException)
48import Data.Functor.Identity (runIdentity)
48import Data.Functor.Identity (runIdentity)
49−import Streamly.Internal.Data.Parser (Parser)
49+import Streamly.Internal.Data.Parser (Parser, ParseError)
50
50
51import Language.Haskell.TH
51import Language.Haskell.TH
52import Language.Haskell.TH.Quote
52import Language.Haskell.TH.Quote
@@ -106,9 +106,12 @@ strSegmentExp (StrVar name) = do
106strExp :: [StrSegment] -> Q Exp
106strExp :: [StrSegment] -> Q Exp
107strExp xs = appE [| concat |] $ listE $ map strSegmentExp xs
107strExp xs = appE [| concat |] $ listE $ map strSegmentExp xs
108
108
109+parseStr :: String -> Either ParseError [StrSegment]
110+parseStr = runIdentity . Stream.parse strParser . Stream.fromList
111+
109expandVars :: String -> Q Exp
112expandVars :: String -> Q Exp
110−expandVars ln =
113+expandVars input =
111− case runIdentity $ Stream.parse strParser (Stream.fromList ln) of
114+ case parseStr input of
112 Left e ->
115 Left e ->
113 fail $ "str QuasiQuoter parse error: " ++ displayException e
116 fail $ "str QuasiQuoter parse error: " ++ displayException e
114 Right x ->
117 Right x ->
@@ -141,9 +144,6 @@ expandVars ln =
141-- :}
144-- :}
142-- "hello world!"
145-- "hello world!"
143--
146--
144−-- Bugs: because of a bug in parsers, a lone # at the end of input gets
145−-- removed.
146−--
147str :: QuasiQuoter
147str :: QuasiQuoter
148str =
148str =
149 QuasiQuoter
149 QuasiQuoter
core/streamly-core.cabal+14−10
@@ -1,6 +1,6 @@
1cabal-version: 2.2
1cabal-version: 2.2
2name: streamly-core
2name: streamly-core
3−version: 0.2.1
3+version: 0.2.2
4synopsis: Streaming, parsers, arrays, serialization and more
4synopsis: Streaming, parsers, arrays, serialization and more
5description:
5description:
6 For upgrading to streamly-0.9.0+ please read the
6 For upgrading to streamly-0.9.0+ please read the
@@ -116,6 +116,7 @@ extra-doc-files:
116 docs/*.md
116 docs/*.md
117 docs/ApiChangelogs/0.1.0.txt
117 docs/ApiChangelogs/0.1.0.txt
118 docs/ApiChangelogs/0.1.0-0.2.0.txt
118 docs/ApiChangelogs/0.1.0-0.2.0.txt
119+ docs/ApiChangelogs/0.2.0-0.2.2.txt
119
120
120source-repository head
121source-repository head
121 type: git
122 type: git
@@ -217,8 +218,6 @@ common compile-options
217common default-extensions
218common default-extensions
218 default-extensions:
219 default-extensions:
219 BangPatterns
220 BangPatterns
220− CApiFFI
221− CPP
222 ConstraintKinds
221 ConstraintKinds
223 DeriveDataTypeable
222 DeriveDataTypeable
224 DeriveGeneric
223 DeriveGeneric
@@ -229,24 +228,29 @@ common default-extensions
229 GeneralizedNewtypeDeriving
228 GeneralizedNewtypeDeriving
230 InstanceSigs
229 InstanceSigs
231 KindSignatures
230 KindSignatures
232− LambdaCase
233− MagicHash
234 MultiParamTypeClasses
231 MultiParamTypeClasses
235− PatternSynonyms
236 RankNTypes
232 RankNTypes
237− RecordWildCards
238 ScopedTypeVariables
233 ScopedTypeVariables
239 StandaloneDeriving
234 StandaloneDeriving
240 TupleSections
235 TupleSections
241 TypeApplications
236 TypeApplications
242− TypeFamilies
243 TypeOperators
237 TypeOperators
244− ViewPatterns
245
238
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
246 -- MonoLocalBinds, enabled by TypeFamilies, causes performance
250 -- MonoLocalBinds, enabled by TypeFamilies, causes performance
247 -- regressions. Disable it. This must come after TypeFamilies,
251 -- regressions. Disable it. This must come after TypeFamilies,
248 -- otherwise TypeFamilies will enable it again.
252 -- otherwise TypeFamilies will enable it again.
249− NoMonoLocalBinds
253+ -- NoMonoLocalBinds
250
254
251 -- UndecidableInstances -- Does not show any perf impact
255 -- UndecidableInstances -- Does not show any perf impact
252 -- UnboxedTuples -- interferes with (#.)
256 -- UnboxedTuples -- interferes with (#.)
docs/Developer/optimization-guidelines.md+12
@@ -191,6 +191,18 @@ the stages of a loop, it is often not useful to inline the whole loop
191itself, in fact we may have to occasionally use a `NOINLINE` so that the
191itself, in fact we may have to occasionally use a `NOINLINE` so that the
192compiler does not inline it.
192compiler does not inline it.
193
193
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+
194### NoSpecConstr
206### NoSpecConstr
195
207
196It is not always useful to specialize function calls for all constructors, some
208It is not always useful to specialize function calls for all constructors, some
docs/User/Project/Changelog.md+1−1
@@ -2,7 +2,7 @@
2
2
3<!-- See rendered changelog at https://streamly.composewell.com -->
3<!-- See rendered changelog at https://streamly.composewell.com -->
4
4
5−## Unreleased
5+## 0.10.1 (Jan 2024)
6
6
7* Fix TH macros in `Streamly.Data.Stream.MkType` for GHC 9.6 and above.
7* Fix TH macros in `Streamly.Data.Stream.MkType` for GHC 9.6 and above.
8
8
docs/User/Project/README.md+1
@@ -1,6 +1,7 @@
1# [Streamly][]: Idiomatic Haskell with C-Like Performance
1# [Streamly][]: Idiomatic Haskell with C-Like Performance
2
2
3[![Gitter chat](https://badges.gitter.im/composewell/gitter.svg)](https://gitter.im/composewell/streamly)
3[![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)
4[![Hackage](https://img.shields.io/hackage/v/streamly.svg?style=flat)](https://hackage.haskell.org/package/streamly)
5[![Hackage](https://img.shields.io/hackage/v/streamly.svg?style=flat)](https://hackage.haskell.org/package/streamly)
5
6
6## Upgrading to 0.9.0+
7## Upgrading to 0.9.0+
src/Streamly/Internal/Data/IsMap/HashMap.hs+5
@@ -1,3 +1,8 @@
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+
1{-# OPTIONS_GHC -Wno-orphans #-}
6{-# OPTIONS_GHC -Wno-orphans #-}
2
7
3-- |
8-- |
src/Streamly/Internal/Data/Stream/IsStream/Expand.hs+5
@@ -1,3 +1,8 @@
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+
1{-# OPTIONS_GHC -Wno-deprecations #-}
6{-# OPTIONS_GHC -Wno-deprecations #-}
2
7
3-- |
8-- |
src/Streamly/Internal/Data/Stream/IsStream/Top.hs+1−1
@@ -649,7 +649,7 @@ intersectBySorted :: (IsStream t, Monad m) =>
649 (a -> a -> Ordering) -> t m a -> t m a -> t m a
649 (a -> a -> Ordering) -> t m a -> t m a -> t m a
650intersectBySorted eq s1 =
650intersectBySorted eq s1 =
651 IsStream.fromStreamD
651 IsStream.fromStreamD
652− . StreamD.intersectBySorted eq (IsStream.toStreamD s1)
652+ . StreamD.sortedIntersectBy eq (IsStream.toStreamD s1)
653 . IsStream.toStreamD
653 . IsStream.toStreamD
654
654
655-- Roughly joinLeft s1 s2 = s1 `difference` s2 + s1 `intersection` s2
655-- Roughly joinLeft s1 s2 = s1 `difference` s2 + s1 `intersection` s2
src/Streamly/Internal/Data/Stream/Serial.hs+5
@@ -1,4 +1,9 @@
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 #-}
1{-# LANGUAGE UndecidableInstances #-}
5{-# LANGUAGE UndecidableInstances #-}
6+
2{-# OPTIONS_GHC -Wno-deprecations #-}
7{-# OPTIONS_GHC -Wno-deprecations #-}
3{-# OPTIONS_GHC -Wno-redundant-constraints #-}
8{-# OPTIONS_GHC -Wno-redundant-constraints #-}
4
9
src/Streamly/Internal/Data/Stream/Zip.hs+5
@@ -1,4 +1,9 @@
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 #-}
1{-# LANGUAGE UndecidableInstances #-}
5{-# LANGUAGE UndecidableInstances #-}
6+
2{-# OPTIONS_GHC -Wno-deprecations #-}
7{-# OPTIONS_GHC -Wno-deprecations #-}
3
8
4-- |
9-- |
src/Streamly/Internal/FileSystem/Event.hs+3
@@ -20,6 +20,9 @@
20-- * "Streamly.Internal.FileSystem.Event.Linux"
20-- * "Streamly.Internal.FileSystem.Event.Linux"
21-- * "Streamly.Internal.FileSystem.Event.Windows"
21-- * "Streamly.Internal.FileSystem.Event.Windows"
22
22
23+-- XXX Need to ensure that the signatures of the exported APIs are same on all
24+-- platforms.
25+
23module Streamly.Internal.FileSystem.Event
26module Streamly.Internal.FileSystem.Event
24 (
27 (
25 -- * Creating a Watch
28 -- * Creating a Watch
src/Streamly/Internal/FileSystem/Event/Darwin.hs+1−1
@@ -451,7 +451,7 @@ openWatch Config{..} paths = do
451
451
452 withPathName :: Array Word8 -> (PathName -> IO a) -> IO a
452 withPathName :: Array Word8 -> (PathName -> IO a) -> IO a
453 withPathName arr act = do
453 withPathName arr act = do
454− A.asPtrUnsafe arr $ \ptr ->
454+ A.unsafePinnedAsPtr arr $ \ptr ->
455 let pname = PathName (castPtr ptr) (fromIntegral (A.length arr))
455 let pname = PathName (castPtr ptr) (fromIntegral (A.length arr))
456 in act pname
456 in act pname
457
457
src/Streamly/Internal/FileSystem/Event/Linux.hs+2−2
@@ -188,7 +188,7 @@ import qualified Streamly.FileSystem.Handle as FH
188import qualified Streamly.Unicode.Stream as U
188import qualified Streamly.Unicode.Stream as U
189
189
190import qualified Streamly.Internal.Data.Array as A
190import qualified Streamly.Internal.Data.Array as A
191− ( fromStream, asCStringUnsafe, asPtrUnsafe
191+ ( fromStream, asCStringUnsafe, unsafePinnedAsPtr
192 , getSliceUnsafe, read
192 , getSliceUnsafe, read
193 )
193 )
194import qualified Streamly.Internal.FileSystem.Dir as Dir (readDirs)
194import qualified Streamly.Internal.FileSystem.Dir as Dir (readDirs)
@@ -809,7 +809,7 @@ readOneEvent :: Config -> Watch -> Parser Word8 IO Event
809readOneEvent cfg wt@(Watch _ wdMap) = do
809readOneEvent cfg wt@(Watch _ wdMap) = do
810 let headerLen = sizeOf (undefined :: CInt) + 12
810 let headerLen = sizeOf (undefined :: CInt) + 12
811 arr <- PR.takeEQ headerLen (A.writeN headerLen)
811 arr <- PR.takeEQ headerLen (A.writeN headerLen)
812− (ewd, eflags, cookie, pathLen) <- PR.fromEffect $ A.asPtrUnsafe arr readHeader
812+ (ewd, eflags, cookie, pathLen) <- PR.fromEffect $ A.unsafePinnedAsPtr arr readHeader
813 -- XXX need the "initial" in parsers to return a step type so that "take 0"
813 -- XXX need the "initial" in parsers to return a step type so that "take 0"
814 -- can return without an input. otherwise if pathLen is 0 we will keep
814 -- can return without an input. otherwise if pathLen is 0 we will keep
815 -- waiting to read one more char before we return this event.
815 -- 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
130import Streamly.Data.Array (Array, Unbox)
130import Streamly.Data.Array (Array, Unbox)
131import Streamly.Data.Stream (Stream)
131import Streamly.Data.Stream (Stream)
132
132
133−import Streamly.Internal.Data.Array (byteLength, unsafeFreeze, asPtrUnsafe)
133+import Streamly.Internal.Data.Array (byteLength, unsafeFreeze, unsafePinnedAsPtr)
134import Streamly.Internal.System.IO (defaultChunkSize)
134import Streamly.Internal.System.IO (defaultChunkSize)
135
135
136#if !defined(mingw32_HOST_OS)
136#if !defined(mingw32_HOST_OS)
@@ -147,7 +147,7 @@ import qualified Streamly.Internal.System.IOVec.Type as RawIO
147import qualified Streamly.Data.Array as A
147import qualified Streamly.Data.Array as A
148import qualified Streamly.Data.Fold as FL
148import qualified Streamly.Data.Fold as FL
149import qualified Streamly.Internal.Data.MutArray as MArray
149import qualified Streamly.Internal.Data.MutArray as MArray
150− (MutArray(..), asPtrUnsafe, pinnedNewBytes)
150+ (MutArray(..), unsafePinnedAsPtr, pinnedNewBytes)
151import qualified Streamly.Internal.Data.Array.Stream as AS
151import qualified Streamly.Internal.Data.Array.Stream as AS
152import qualified Streamly.Internal.Data.Stream as S
152import qualified Streamly.Internal.Data.Stream as S
153import qualified Streamly.Internal.Data.Stream as D
153import qualified Streamly.Internal.Data.Stream as D
@@ -220,7 +220,7 @@ readArrayUpto :: Int -> Handle -> IO (Array Word8)
220readArrayUpto size (Handle fd) = do
220readArrayUpto size (Handle fd) = do
221 arr <- MArray.pinnedNewBytes size
221 arr <- MArray.pinnedNewBytes size
222 -- ptr <- mallocPlainForeignPtrAlignedBytes size (alignment (undefined :: Word8))
222 -- ptr <- mallocPlainForeignPtrAlignedBytes size (alignment (undefined :: Word8))
223− MArray.asPtrUnsafe arr $ \p -> do
223+ MArray.unsafePinnedAsPtr arr $ \p -> do
224 -- n <- hGetBufSome h p size
224 -- n <- hGetBufSome h p size
225#if MIN_VERSION_base(4,15,0)
225#if MIN_VERSION_base(4,15,0)
226 n <- RawIO.read fd p 0 size
226 n <- RawIO.read fd p 0 size
@@ -244,7 +244,7 @@ readArrayUpto size (Handle fd) = do
244writeArray :: Unbox a => Handle -> Array a -> IO ()
244writeArray :: Unbox a => Handle -> Array a -> IO ()
245writeArray _ arr | A.length arr == 0 = return ()
245writeArray _ arr | A.length arr == 0 = return ()
246writeArray (Handle fd) arr =
246writeArray (Handle fd) arr =
247− asPtrUnsafe arr $ \p ->
247+ unsafePinnedAsPtr arr $ \p ->
248 -- RawIO.writeAll fd (castPtr p) aLen
248 -- RawIO.writeAll fd (castPtr p) aLen
249#if MIN_VERSION_base(4,15,0)
249#if MIN_VERSION_base(4,15,0)
250 RawIO.write fd (castPtr p) 0 aLen
250 RawIO.write fd (castPtr p) 0 aLen
@@ -270,7 +270,7 @@ writeArray (Handle fd) arr =
270writeIOVec :: Handle -> Array RawIO.IOVec -> IO ()
270writeIOVec :: Handle -> Array RawIO.IOVec -> IO ()
271writeIOVec _ iov | A.length iov == 0 = return ()
271writeIOVec _ iov | A.length iov == 0 = return ()
272writeIOVec (Handle fd) iov =
272writeIOVec (Handle fd) iov =
273− asPtrUnsafe iov $ \p ->
273+ unsafePinnedAsPtr iov $ \p ->
274 RawIO.writevAll fd p (A.length iov)
274 RawIO.writevAll fd p (A.length iov)
275-}
275-}
276#endif
276#endif
src/Streamly/Internal/Network/Inet/TCP.hs+3−3
@@ -116,7 +116,6 @@ import Prelude hiding (read)
116import Streamly.Internal.Control.Concurrent (MonadAsync)
116import Streamly.Internal.Control.Concurrent (MonadAsync)
117import Streamly.Internal.Control.ForkLifted (fork)
117import Streamly.Internal.Control.ForkLifted (fork)
118import Streamly.Data.Array (Array)
118import Streamly.Data.Array (Array)
119−import Streamly.Internal.Data.Array (pinnedWriteNUnsafe)
120import Streamly.Internal.Data.Fold ( Fold(..) )
119import Streamly.Internal.Data.Fold ( Fold(..) )
121import Streamly.Data.Stream (Stream)
120import Streamly.Data.Stream (Stream)
122import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
121import Streamly.Internal.Data.Tuple.Strict (Tuple'(..))
@@ -132,7 +131,8 @@ import qualified Streamly.Data.Array as A
132import qualified Streamly.Data.Fold as FL
131import qualified Streamly.Data.Fold as FL
133import qualified Streamly.Data.Stream as S
132import qualified Streamly.Data.Stream as S
134import qualified Streamly.Data.Unfold as UF
133import qualified Streamly.Data.Unfold as UF
135−import qualified Streamly.Internal.Data.Array as A (pinnedChunksOf)
134+import qualified Streamly.Internal.Data.Array as A
135+ (pinnedChunksOf, unsafePinnedCreateOf)
136import qualified Streamly.Internal.Data.Unfold as UF (bracketIO)
136import qualified Streamly.Internal.Data.Unfold as UF (bracketIO)
137import qualified Streamly.Internal.Data.Fold as FL (Step(..), reduce)
137import qualified Streamly.Internal.Data.Fold as FL (Step(..), reduce)
138
138
@@ -435,7 +435,7 @@ writeWithBufferOf
435 -> PortNumber
435 -> PortNumber
436 -> Fold m Word8 ()
436 -> Fold m Word8 ()
437writeWithBufferOf n addr port =
437writeWithBufferOf n addr port =
438− FL.groupsOf n (pinnedWriteNUnsafe n) (writeChunks addr port)
438+ FL.groupsOf n (A.unsafePinnedCreateOf n) (writeChunks addr port)
439
439
440-- | Write a stream to the supplied IPv4 host address and port number.
440-- | Write a stream to the supplied IPv4 host address and port number.
441--
441--
src/Streamly/Internal/Network/Socket.hs+10−8
@@ -98,10 +98,10 @@ import qualified Streamly.Data.Fold as FL
98import qualified Streamly.Data.Stream as S
98import qualified Streamly.Data.Stream as S
99import qualified Streamly.Data.Unfold as UF
99import qualified Streamly.Data.Unfold as UF
100import qualified Streamly.Internal.Data.Array as A
100import qualified Streamly.Internal.Data.Array as A
101− ( unsafeFreeze, asPtrUnsafe, byteLength, pinnedChunksOf,
101+ ( unsafeFreeze, unsafePinnedAsPtr, byteLength, pinnedChunksOf,
102− pinnedWriteN, pinnedWriteNUnsafe, lCompactGE )
102+ pinnedCreateOf, unsafePinnedCreateOf, lCompactGE )
103import qualified Streamly.Internal.Data.MutArray as MArray
103import qualified Streamly.Internal.Data.MutArray as MArray
104− (MutArray(..), asPtrUnsafe, pinnedNewBytes)
104+ (MutArray(..), unsafePinnedAsPtr, pinnedEmptyOf)
105import qualified Streamly.Internal.Data.Stream as S (fromStreamK, Stream(..), Step(..))
105import qualified Streamly.Internal.Data.Stream as S (fromStreamK, Stream(..), Step(..))
106import qualified Streamly.Internal.Data.StreamK as K (mkStream)
106import qualified Streamly.Internal.Data.StreamK as K (mkStream)
107
107
@@ -252,6 +252,8 @@ accept tcpListenQ spec addr =
252-- Array IO (Input)
252-- Array IO (Input)
253-------------------------------------------------------------------------------
253-------------------------------------------------------------------------------
254
254
255+-- XXX add an API that compacts the arrays to an exact size.
256+
255{-# INLINABLE readArrayUptoWith #-}
257{-# INLINABLE readArrayUptoWith #-}
256readArrayUptoWith
258readArrayUptoWith
257 :: (h -> Ptr Word8 -> Int -> IO Int)
259 :: (h -> Ptr Word8 -> Int -> IO Int)
@@ -259,9 +261,9 @@ readArrayUptoWith
259 -> h
261 -> h
260 -> IO (Array Word8)
262 -> IO (Array Word8)
261readArrayUptoWith f size h = do
263readArrayUptoWith f size h = do
262− arr <- MArray.pinnedNewBytes size
264+ arr <- MArray.pinnedEmptyOf size
263 -- ptr <- mallocPlainForeignPtrAlignedBytes size (alignment (undefined :: Word8))
265 -- ptr <- mallocPlainForeignPtrAlignedBytes size (alignment (undefined :: Word8))
264− MArray.asPtrUnsafe arr $ \p -> do
266+ MArray.unsafePinnedAsPtr arr $ \p -> do
265 n <- f h p size
267 n <- f h p size
266 let v = A.unsafeFreeze
268 let v = A.unsafeFreeze
267 $ arr { MArray.arrEnd = n, MArray.arrBound = size }
269 $ arr { MArray.arrEnd = n, MArray.arrBound = size }
@@ -309,7 +311,7 @@ writeArrayWith :: Unbox a
309 -> Array a
311 -> Array a
310 -> IO ()
312 -> IO ()
311writeArrayWith _ _ arr | A.length arr == 0 = return ()
313writeArrayWith _ _ arr | A.length arr == 0 = return ()
312−writeArrayWith f h arr = A.asPtrUnsafe arr $ \ptr -> f h (castPtr ptr) aLen
314+writeArrayWith f h arr = A.unsafePinnedAsPtr arr $ \ptr -> f h (castPtr ptr) aLen
313
315
314 where
316 where
315
317
@@ -503,7 +505,7 @@ putBytesWith n h m = putChunks h $ A.pinnedChunksOf n m
503--
505--
504{-# INLINE writeWith #-}
506{-# INLINE writeWith #-}
505writeWith :: MonadIO m => Int -> Socket -> Fold m Word8 ()
507writeWith :: MonadIO m => Int -> Socket -> Fold m Word8 ()
506−writeWith n h = FL.groupsOf n (A.pinnedWriteNUnsafe n) (writeChunks h)
508+writeWith n h = FL.groupsOf n (A.unsafePinnedCreateOf n) (writeChunks h)
507
509
508-- | Same as 'writeWith'
510-- | Same as 'writeWith'
509--
511--
@@ -521,7 +523,7 @@ writeWithBufferOf = writeWith
521writeMaybesWith :: (MonadIO m )
523writeMaybesWith :: (MonadIO m )
522 => Int -> Socket -> Fold m (Maybe Word8) ()
524 => Int -> Socket -> Fold m (Maybe Word8) ()
523writeMaybesWith n h =
525writeMaybesWith n h =
524− let writeNJusts = FL.lmap fromJust $ A.pinnedWriteN n
526+ let writeNJusts = FL.lmap fromJust $ A.pinnedCreateOf n
525 writeOnNothing = FL.takeEndBy_ isNothing writeNJusts
527 writeOnNothing = FL.takeEndBy_ isNothing writeNJusts
526 in FL.many writeOnNothing (writeChunks h)
528 in FL.many writeOnNothing (writeChunks h)
527
529
streamly.cabal+11−11
@@ -1,6 +1,6 @@
1cabal-version: 2.2
1cabal-version: 2.2
2name: streamly
2name: streamly
3−version: 0.10.0
3+version: 0.10.1
4synopsis: Streaming, dataflow programming and declarative concurrency
4synopsis: Streaming, dataflow programming and declarative concurrency
5description:
5description:
6 For upgrading to streamly-0.9.0+ please read the
6 For upgrading to streamly-0.9.0+ please read the
@@ -294,8 +294,6 @@ common compile-options
294common default-extensions
294common default-extensions
295 default-extensions:
295 default-extensions:
296 BangPatterns
296 BangPatterns
297− CApiFFI
298− CPP
299 ConstraintKinds
297 ConstraintKinds
300 DeriveDataTypeable
298 DeriveDataTypeable
301 DeriveGeneric
299 DeriveGeneric
@@ -306,23 +304,25 @@ common default-extensions
306 GeneralizedNewtypeDeriving
304 GeneralizedNewtypeDeriving
307 InstanceSigs
305 InstanceSigs
308 KindSignatures
306 KindSignatures
309− LambdaCase
310− MagicHash
311 MultiParamTypeClasses
307 MultiParamTypeClasses
312− PatternSynonyms
313 RankNTypes
308 RankNTypes
314− RecordWildCards
315 ScopedTypeVariables
309 ScopedTypeVariables
316 TupleSections
310 TupleSections
317 TypeApplications
311 TypeApplications
318− TypeFamilies
319 TypeOperators
312 TypeOperators
320− ViewPatterns
321
313
314+ -- Not GHC2021
315+ CApiFFI
316+ CPP
317+ LambdaCase
318+ MagicHash
319+ RecordWildCards
320+
321+ -- TypeFamilies -- required by IsHashMap type class
322 -- MonoLocalBinds, enabled by TypeFamilies, causes performance
322 -- MonoLocalBinds, enabled by TypeFamilies, causes performance
323 -- regressions. Disable it. This must come after TypeFamilies,
323 -- regressions. Disable it. This must come after TypeFamilies,
324 -- otherwise TypeFamilies will enable it again.
324 -- otherwise TypeFamilies will enable it again.
325− NoMonoLocalBinds
325+ -- NoMonoLocalBinds
326
326
327 -- UndecidableInstances -- Does not show any perf impact
327 -- UndecidableInstances -- Does not show any perf impact
328 -- UnboxedTuples -- interferes with (#.)
328 -- UnboxedTuples -- interferes with (#.)
@@ -513,7 +513,7 @@ library
513 , template-haskell >= 2.14 && < 2.22
513 , template-haskell >= 2.14 && < 2.22
514
514
515 -- The core streamly package
515 -- The core streamly package
516− , streamly-core >= 0.2.0 && < 0.2.2
516+ , streamly-core == 0.2.2
517
517
518 , hashable >= 1.3 && < 1.5
518 , hashable >= 1.3 && < 1.5
519 , unordered-containers >= 0.2 && < 0.3
519 , unordered-containers >= 0.2 && < 0.3
test/Streamly/Test/Data/Array.hs+2−2
@@ -185,7 +185,7 @@ testUnsafeIndxedFromList inp =
185testAsPtrUnsafeMA :: IO ()
185testAsPtrUnsafeMA :: IO ()
186testAsPtrUnsafeMA = do
186testAsPtrUnsafeMA = do
187 arr <- MA.fromList ([0 .. 99] :: [Int])
187 arr <- MA.fromList ([0 .. 99] :: [Int])
188− MA.asPtrUnsafe arr (getList (0 :: Int)) `shouldReturn` [0 .. 99]
188+ MA.unsafePinnedAsPtr arr (getList (0 :: Int)) `shouldReturn` [0 .. 99]
189
189
190 where
190 where
191
191
@@ -229,7 +229,7 @@ main =
229 prop "read . write === id" testFoldUnfold
229 prop "read . write === id" testFoldUnfold
230 prop "fromList" testFromList
230 prop "fromList" testFromList
231 prop "foldMany with writeNUnsafe concats to original"
231 prop "foldMany with writeNUnsafe concats to original"
232− (foldManyWith (\n -> Fold.take n (A.writeNUnsafe n)))
232+ (foldManyWith (\n -> Fold.take n (A.unsafeCreateOf n)))
233 describe "unsafeSlice" $ do
233 describe "unsafeSlice" $ do
234 it "partial" $ unsafeSlice 2 4 [1..10]
234 it "partial" $ unsafeSlice 2 4 [1..10]
235 it "none" $ unsafeSlice 10 0 [1..10]
235 it "none" $ unsafeSlice 10 0 [1..10]